mirror of
https://github.com/RoyalnetworkTR/turkanime-client.git
synced 2026-09-25 01:39:54 +03:00
- README.md'yi yeni talimatlarla güncellendi - pyproject.toml bağımlılık yönetimi için değiştirildi - Anilist istemci entegrasyonu iyileştirildi - CLI ana, gereksinimler ve sürüm modülleri geliştirildi - GUI ana ve güncelleme yöneticisi rafine edildi - Daha iyi performans için nesneler ve kaynak adaptörleri güncellendi
257 lines
9.9 KiB
Python
257 lines
9.9 KiB
Python
from os import path,system,name,listdir
|
||
from shutil import move
|
||
import sys
|
||
import tempfile
|
||
import re
|
||
import subprocess as sp
|
||
import json
|
||
import platform
|
||
import os
|
||
from zipfile import ZipFile
|
||
from py7zr import SevenZipFile
|
||
import requests
|
||
import questionary as qa
|
||
|
||
from .dosyalar import Dosyalar
|
||
from .cli_tools import CliStatus,DownloadCLI
|
||
|
||
DL_URL = "https://raw.githubusercontent.com/KebabLord/turkanime-indirici/master/gereksinimler.json"
|
||
DEPENDS = ["yt-dlp","mpv","aria2c"]
|
||
|
||
NOT_WORKING = -1
|
||
MISSING = 0
|
||
SUCCESS = 1
|
||
|
||
class Gereksinimler:
|
||
def __init__(self):
|
||
self.tmp = tempfile.TemporaryDirectory()
|
||
self.folder = Dosyalar().ta_path
|
||
self._url_liste = None
|
||
self._eksikler = []
|
||
self._platform = self._get_platform()
|
||
self._arch = self._get_arch()
|
||
|
||
def _get_platform(self):
|
||
"""Mevcut platformu tespit et."""
|
||
system = platform.system().lower()
|
||
if system == "windows":
|
||
return "windows"
|
||
elif system == "linux":
|
||
return "linux"
|
||
elif system == "darwin":
|
||
return "macos"
|
||
else:
|
||
return "unknown"
|
||
|
||
def _get_arch(self):
|
||
"""Mevcut mimariyi tespit et."""
|
||
machine = platform.machine().lower()
|
||
if machine in ["x86_64", "amd64"]:
|
||
return "x64"
|
||
elif machine in ["i386", "i686"]:
|
||
return "x32"
|
||
elif machine in ["arm64", "aarch64"]:
|
||
return "arm64"
|
||
else:
|
||
return "x64" # fallback
|
||
|
||
def app_kontrol(self,app):
|
||
""" Gereksinimi çalıştırmayı deneyip exit kodunu öğren. """
|
||
try:
|
||
process = sp.Popen(f'{app} --version', stdout=sp.PIPE, stderr=sp.PIPE, shell=True)
|
||
exit_code = process.wait()
|
||
stdout = process.stdout.read().decode() if process.stdout else ""
|
||
if exit_code == 0:
|
||
return SUCCESS
|
||
if exit_code in (1,127,32512):
|
||
return MISSING
|
||
return NOT_WORKING
|
||
except Exception:
|
||
return MISSING
|
||
|
||
@property
|
||
def eksikler(self):
|
||
""" Bulunamayan veya çalıştırılamayan gereksinimleri tespit et. """
|
||
if self._eksikler == []:
|
||
for gereksinim in DEPENDS:
|
||
exit_code = self.app_kontrol(gereksinim)
|
||
if exit_code != SUCCESS:
|
||
if self.app_kontrol(gereksinim) is SUCCESS:
|
||
continue
|
||
self._eksikler.append((gereksinim,exit_code))
|
||
return self._eksikler
|
||
|
||
@property
|
||
def url_liste(self):
|
||
""" İndirme linklerinin bulunduğu Json dosyasını Dict olarak döndürür """
|
||
if self._url_liste is None:
|
||
try:
|
||
response = requests.get(DL_URL, timeout=10)
|
||
response.raise_for_status()
|
||
raw_data = json.loads(response.text)
|
||
|
||
# Yeni formatı eski formata dönüştür
|
||
converted_data = []
|
||
for item in raw_data:
|
||
if "platforms" in item:
|
||
# Yeni format - platform bilgisine göre URL seç
|
||
platform_data = item["platforms"].get(self._platform, {})
|
||
url = platform_data.get(self._arch, platform_data.get("x64", ""))
|
||
|
||
if url:
|
||
converted_item = {
|
||
"name": item["name"],
|
||
"type": item["type"],
|
||
"is_setup": item.get("is_setup", False),
|
||
"url": url
|
||
}
|
||
converted_data.append(converted_item)
|
||
else:
|
||
# Eski format - doğrudan kullan
|
||
converted_data.append(item)
|
||
|
||
self._url_liste = converted_data
|
||
except Exception as e:
|
||
print(f"Gereksinimler listesi alınamadı: {e}")
|
||
self._url_liste = []
|
||
return self._url_liste
|
||
|
||
def otomatik_indir(self, url_liste=None, break_on_fail = False, callback = None):
|
||
""" Tüm eksik dosyaları otomatik olarak indir. """
|
||
fail = []
|
||
url_liste = self.url_liste if url_liste is None else url_liste
|
||
for eksik, _ in self.eksikler:
|
||
meta = next(i for i in url_liste if i['name'] == eksik)
|
||
assert meta is not None
|
||
res = self.dosya_indir(meta["url"],callback=callback)
|
||
if "err_msg" in res:
|
||
fail += [{"name":eksik,"err_msg":res["err_msg"]}]
|
||
if break_on_fail:
|
||
break
|
||
continue
|
||
self.dosyayi_kur(eksik+".exe",res["path"])
|
||
ec = self.app_kontrol(eksik)
|
||
if ec != SUCCESS:
|
||
fail += [{"name":eksik,"ext_code":ec}]
|
||
return fail
|
||
|
||
def dosya_indir(self,url,callback = None):
|
||
""" URL'deki dosyayı indirir, belirtilmişse callback'e rapor eder. """
|
||
remote_file = url.split("/")[-1]
|
||
file_name = path.join(self.tmp.name, remote_file)
|
||
response = requests.get(url, stream=True, timeout=30)
|
||
if response.status_code != 200:
|
||
text = re.sub(" {2,6}"," ",re.sub("<.*?>","",response.text.replace("\n"," ")))
|
||
return {"err_msg": text}
|
||
total_size = int(response.headers.get('content-length', 0))
|
||
chunk_size, downloaded_size = 1024, 0
|
||
with open(file_name, 'wb') as file:
|
||
for data in response.iter_content(chunk_size=chunk_size):
|
||
file.write(data)
|
||
downloaded_size += len(data)
|
||
if callback:
|
||
hook = {"current":downloaded_size,"total":total_size,"file":remote_file}
|
||
callback(hook)
|
||
return {"path":file_name}
|
||
|
||
def dosyayi_kur(self,file_name,file_path,is_setup=False,is_dir=False):
|
||
""" 7z, Zip, Tar.xz veya Exe formatındaki indirilmiş dosyayı uygulama dizinine kurar. """
|
||
file_type = file_path.split(".")[-1].lower()
|
||
tmp = tempfile.TemporaryDirectory()
|
||
|
||
if is_dir: # Klasörü kopyala
|
||
from_ = tmp.name
|
||
to_ = path.join(self.folder, file_name.removesuffix("."+file_type))
|
||
else: # Klasörün içindeki dosyayı kopyala
|
||
from_ = path.join(tmp.name, file_name)
|
||
to_ = path.join(self.folder, file_name)
|
||
|
||
try:
|
||
if file_type == "7z":
|
||
with SevenZipFile(file_path, mode='r') as szip:
|
||
szip.extractall(path=tmp.name)
|
||
elif file_type == "zip":
|
||
with ZipFile(file_path, 'r') as zipf:
|
||
zipf.extractall(tmp.name)
|
||
elif file_type in ["xz", "gz", "bz2"]:
|
||
# Tar.xz, tar.gz gibi sıkıştırılmış dosyalar için
|
||
import tarfile
|
||
with tarfile.open(file_path, 'r:*') as tar:
|
||
tar.extractall(tmp.name)
|
||
elif file_type == "exe":
|
||
if is_setup:
|
||
system(file_path)
|
||
else:
|
||
move(file_path, to_)
|
||
return
|
||
|
||
# Dosya yolunu kontrol et ve taşı
|
||
if not path.exists(from_):
|
||
# Bazı arşivlerde dosya farklı bir yerde olabilir
|
||
extracted_files = []
|
||
for root, dirs, files in os.walk(tmp.name):
|
||
for file in files:
|
||
if file == file_name or file_name in file:
|
||
extracted_files.append(path.join(root, file))
|
||
|
||
if extracted_files:
|
||
from_ = extracted_files[0]
|
||
else:
|
||
# İlk dosyayı kullan
|
||
all_files = []
|
||
for root, dirs, files in os.walk(tmp.name):
|
||
for file in files:
|
||
all_files.append(path.join(root, file))
|
||
if all_files:
|
||
from_ = all_files[0]
|
||
file_name = path.basename(from_)
|
||
|
||
if path.exists(from_):
|
||
move(from_, path.join(self.folder, file_name))
|
||
|
||
except Exception as e:
|
||
print(f"Dosya kurulumu başarısız: {e}")
|
||
return False
|
||
return True
|
||
|
||
|
||
def gereksinim_kontrol_cli():
|
||
""" Gereksinimleri kontrol eder ve gerekirse indirip kurar."""
|
||
gerek = Gereksinimler()
|
||
with CliStatus("Gereksinimler kontrol ediliyor.."):
|
||
eksikler = gerek.eksikler
|
||
if eksikler:
|
||
eksik_msg = ""
|
||
guide_msg = "\nManuel indirmek için:\nhttps://github.com/KebabLord/turkanime-indirici/wiki"
|
||
for eksik,exit_code in eksikler:
|
||
if exit_code is MISSING:
|
||
eksik_msg += f"!) {eksik} yazılımı bulunamadı.\n"
|
||
else:
|
||
eksik_msg += f"!) {eksik} yazılımı bulundu ancak çalıştırılamadı.\n"
|
||
print(eksik_msg,end="\n\n")
|
||
if name=="nt" and qa.confirm("Otomatik kurulsun mu?").ask():
|
||
with CliStatus("Güncel indirme linkleri getiriliyor.."):
|
||
links = gerek.url_liste
|
||
dl_cli = DownloadCLI()
|
||
with dl_cli.progress:
|
||
fails = gerek.otomatik_indir(url_liste=links, callback=dl_cli.dl_callback)
|
||
eksik_msg = ""
|
||
for fail in fails:
|
||
if "err_msg" in fail:
|
||
eksik_msg += f"!) {fail['name']} indirilemedi\n"
|
||
if fail["err_msg"] != "":
|
||
eksik_msg += f" - {fail['err_msg'][:55]}...\n"
|
||
elif "ext_code" in fail:
|
||
if fail["ext_code"] is MISSING:
|
||
eksik_msg += f"!) {fail['name']} kurulamadı.\n"
|
||
else:
|
||
eksik_msg += f"!) {fail['name']} çalıştırılamadı.\n"
|
||
if fails:
|
||
print(eksik_msg + guide_msg)
|
||
input("\n(ENTER'a BASIN)")
|
||
sys.exit(1)
|
||
else:
|
||
print(guide_msg)
|
||
input("\n(ENTER'a BASIN)")
|
||
sys.exit(1)
|