Major overhaul to the theme and now functioning.
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
import threading
|
||||
import datetime
|
||||
import re
|
||||
import os
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
from .downloader_core.bunkr import BunkrDownloader
|
||||
from .downloader_core.downloader import Downloader
|
||||
from .downloader_core.erome import EromeDownloader
|
||||
from .downloader_core.simpcity import SimpCity
|
||||
from .downloader_core.jpg5 import Jpg5Downloader
|
||||
from .samba_manager import SambaManager
|
||||
from .storage import SambaStorage
|
||||
from .config import settings
|
||||
|
||||
# Dummy translator
|
||||
def tr(key, **kwargs):
|
||||
return key.format(**kwargs)
|
||||
|
||||
def extract_ck_parameters(url):
|
||||
match = re.search(r"/(?P<service>[^/?]+)(/user/(?P<user>[^/?]+)(/post/(?P<post>[^/?]+))?)?", url.path)
|
||||
if match:
|
||||
return match.group("service"), match.group("user"), match.group("post")
|
||||
return None, None, None
|
||||
|
||||
def extract_ck_query(url):
|
||||
query = parse_qs(url.query)
|
||||
q = query.get("q")[0] if query.get("q") and len(query.get("q")) > 0 else "0"
|
||||
o = query.get("o")[0] if query.get("o") and len(query.get("o")) > 0 else "0"
|
||||
return q, int(o) if str.isdigit(o) else 0
|
||||
|
||||
class DownloaderManager:
|
||||
def __init__(self):
|
||||
self.active_downloader = None
|
||||
self.download_thread = None
|
||||
self.logs = []
|
||||
self.progress = {
|
||||
"status": "Idle",
|
||||
"active": False,
|
||||
"downloaded": 0,
|
||||
"total": 0,
|
||||
"speed": 0,
|
||||
"eta": 0,
|
||||
"current_file": ""
|
||||
}
|
||||
self.download_folder = os.path.join(os.getcwd(), "downloads")
|
||||
os.makedirs(self.download_folder, exist_ok=True)
|
||||
self.samba_manager = None
|
||||
|
||||
def log_callback(self, message):
|
||||
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
|
||||
self.logs.append(f"[{timestamp}] {message}")
|
||||
if len(self.logs) > 1000:
|
||||
self.logs.pop(0)
|
||||
|
||||
def update_progress_callback(self, downloaded, total, **kwargs):
|
||||
self.progress["downloaded"] = downloaded
|
||||
self.progress["total"] = total
|
||||
if "speed" in kwargs:
|
||||
self.progress["speed"] = kwargs["speed"]
|
||||
if "eta" in kwargs:
|
||||
self.progress["eta"] = kwargs["eta"]
|
||||
if "file_path" in kwargs:
|
||||
self.progress["current_file"] = os.path.basename(kwargs["file_path"])
|
||||
|
||||
def enable_widgets_callback(self):
|
||||
# Called when a single downloader finishes
|
||||
# We don't set active=False here because we might have more URLs
|
||||
pass
|
||||
|
||||
def start_download(self, urls, options):
|
||||
if self.progress["active"]:
|
||||
raise Exception("Download already in progress")
|
||||
|
||||
self.logs = []
|
||||
self.progress["active"] = True
|
||||
self.progress["status"] = "Starting..."
|
||||
self.progress["downloaded"] = 0
|
||||
self.progress["total"] = 0
|
||||
|
||||
self.download_thread = threading.Thread(target=self._run_download, args=(urls, options))
|
||||
self.download_thread.start()
|
||||
|
||||
def _run_download(self, urls, options):
|
||||
try:
|
||||
for i, url in enumerate(urls):
|
||||
# Check for cancellation between URLs
|
||||
if self.progress["status"] == "Cancelling...":
|
||||
self.log_callback("Queue processing cancelled.")
|
||||
break
|
||||
|
||||
self.log_callback(f"Processing URL {i+1}/{len(urls)}: {url}")
|
||||
try:
|
||||
self._process_single_url(url, options)
|
||||
except Exception as e:
|
||||
self.log_callback(f"Error processing URL {url}: {e}")
|
||||
# Continue to next URL? Yes, usually desired behavior for bulk.
|
||||
|
||||
except Exception as e:
|
||||
self.log_callback(f"Fatal error in download thread: {e}")
|
||||
self.progress["status"] = "Error"
|
||||
finally:
|
||||
self.progress["active"] = False
|
||||
self.progress["status"] = "Finished"
|
||||
if self.samba_manager:
|
||||
self.samba_manager.close()
|
||||
self.samba_manager = None
|
||||
self.active_downloader = None
|
||||
|
||||
def _process_single_url(self, url, options):
|
||||
# Options
|
||||
download_images = options.get("download_images", True)
|
||||
download_videos = options.get("download_videos", True)
|
||||
max_workers = options.get("max_workers", 3)
|
||||
force_overwrite = options.get("force_overwrite", False)
|
||||
|
||||
parsed_url = urlparse(url)
|
||||
target = None
|
||||
args = ()
|
||||
|
||||
# Cleanup previous samba manager if exists (though we try to clean up in finally)
|
||||
if self.samba_manager:
|
||||
self.samba_manager.close()
|
||||
self.samba_manager = None
|
||||
|
||||
# Dispatch Logic
|
||||
if "erome.com" in url:
|
||||
self.log_callback("Starting Erome Download")
|
||||
is_profile = "/a/" not in url
|
||||
self.active_downloader = EromeDownloader(
|
||||
download_folder=self.download_folder,
|
||||
log_callback=self.log_callback,
|
||||
enable_widgets_callback=self.enable_widgets_callback,
|
||||
update_progress_callback=self.update_progress_callback,
|
||||
tr=tr
|
||||
)
|
||||
if "/a/" in url:
|
||||
target = self.active_downloader.process_album_page
|
||||
args = (url, self.download_folder, download_images, download_videos)
|
||||
else:
|
||||
target = self.active_downloader.process_profile_page
|
||||
args = (url, self.download_folder, download_images, download_videos)
|
||||
|
||||
elif re.search(r"https?://([a-z0-9-]+\.)?bunkr\.[a-z]{2,}", url):
|
||||
self.log_callback("Starting Bunkr Download")
|
||||
self.active_downloader = BunkrDownloader(
|
||||
download_folder=self.download_folder,
|
||||
log_callback=self.log_callback,
|
||||
enable_widgets_callback=self.enable_widgets_callback,
|
||||
update_progress_callback=self.update_progress_callback,
|
||||
tr=tr
|
||||
)
|
||||
if any(sub in url for sub in ["/v/", "/i/", "/f/"]):
|
||||
target = self.active_downloader.descargar_post_bunkr
|
||||
args = (url,)
|
||||
else:
|
||||
target = self.active_downloader.descargar_perfil_bunkr
|
||||
args = (url,)
|
||||
|
||||
elif parsed_url.netloc in ["coomer.st", "kemono.cr", "coomer.su", "kemono.su"]:
|
||||
self.log_callback("Starting Coomer/Kemono Download (Direct SMB)")
|
||||
|
||||
try:
|
||||
self.samba_manager = SambaManager(
|
||||
settings.samba_server_ip,
|
||||
"isolation",
|
||||
settings.samba_username,
|
||||
settings.samba_password
|
||||
)
|
||||
self.log_callback(f"Connected to SMB Share: isolation at {settings.samba_server_ip}")
|
||||
|
||||
storage = SambaStorage(self.samba_manager, base_path="videos/coomerparty")
|
||||
|
||||
except Exception as e:
|
||||
self.log_callback(f"Failed to connect to SMB: {e}")
|
||||
raise e
|
||||
|
||||
self.active_downloader = Downloader(
|
||||
download_folder="",
|
||||
max_workers=max_workers,
|
||||
log_callback=self.log_callback,
|
||||
enable_widgets_callback=self.enable_widgets_callback,
|
||||
update_progress_callback=self.update_progress_callback,
|
||||
tr=tr,
|
||||
download_images=download_images,
|
||||
download_videos=download_videos,
|
||||
storage=storage,
|
||||
force_overwrite=force_overwrite
|
||||
)
|
||||
|
||||
site = parsed_url.netloc
|
||||
service, user, post = extract_ck_parameters(parsed_url)
|
||||
|
||||
if not service or not user:
|
||||
raise Exception("Invalid Coomer/Kemono URL")
|
||||
|
||||
if post:
|
||||
target = self.active_downloader.download_single_post
|
||||
args = (site, post, service, user)
|
||||
else:
|
||||
query, offset = extract_ck_query(parsed_url)
|
||||
target = self.active_downloader.download_media
|
||||
args = (site, user, service, query, True, offset)
|
||||
|
||||
elif "simpcity.cr" in url:
|
||||
self.log_callback("Starting SimpCity Download")
|
||||
self.active_downloader = SimpCity(
|
||||
download_folder=self.download_folder,
|
||||
log_callback=self.log_callback,
|
||||
enable_widgets_callback=self.enable_widgets_callback,
|
||||
update_progress_callback=self.update_progress_callback,
|
||||
tr=tr
|
||||
)
|
||||
target = self.active_downloader.download_images_from_simpcity
|
||||
args = (url,)
|
||||
|
||||
elif "jpg5.su" in url:
|
||||
self.log_callback("Starting Jpg5 Download")
|
||||
self.active_downloader = Jpg5Downloader(
|
||||
url=url,
|
||||
carpeta_destino=self.download_folder,
|
||||
log_callback=self.log_callback,
|
||||
tr=tr
|
||||
)
|
||||
target = self.active_downloader.descargar_imagenes
|
||||
args = ()
|
||||
|
||||
else:
|
||||
raise Exception(f"Unsupported URL: {url}")
|
||||
|
||||
# Execute
|
||||
self.progress["status"] = "Running"
|
||||
target(*args)
|
||||
|
||||
def cancel_download(self):
|
||||
self.progress["status"] = "Cancelling..."
|
||||
self.log_callback("Cancellation requested...")
|
||||
if self.active_downloader and hasattr(self.active_downloader, 'request_cancel'):
|
||||
self.active_downloader.request_cancel()
|
||||
|
||||
manager = DownloaderManager()
|
||||
Reference in New Issue
Block a user