mirror of
https://github.com/Yuvi9587/Kemono-Downloader.git
synced 2025-12-29 16:14:44 +00:00
87 lines
3.5 KiB
Python
87 lines
3.5 KiB
Python
import os
|
|
import time
|
|
import requests
|
|
from PyQt5.QtCore import QThread, pyqtSignal
|
|
import cloudscraper
|
|
|
|
from ...core.rule34video_client import fetch_rule34video_data
|
|
from ...utils.file_utils import clean_folder_name
|
|
|
|
class Rule34VideoDownloadThread(QThread):
|
|
"""A dedicated QThread for handling rule34video.com downloads."""
|
|
progress_signal = pyqtSignal(str)
|
|
file_progress_signal = pyqtSignal(str, object)
|
|
finished_signal = pyqtSignal(int, int, bool) # dl_count, skip_count, cancelled
|
|
|
|
def __init__(self, url, output_dir, parent=None):
|
|
super().__init__(parent)
|
|
self.video_url = url
|
|
self.output_dir = output_dir
|
|
self.is_cancelled = False
|
|
|
|
def run(self):
|
|
download_count = 0
|
|
skip_count = 0
|
|
|
|
video_title, final_video_url = fetch_rule34video_data(self.video_url, self.progress_signal.emit)
|
|
|
|
if not final_video_url:
|
|
self.progress_signal.emit("❌ Failed to get video data. Aborting.")
|
|
self.finished_signal.emit(0, 1, self.is_cancelled)
|
|
return
|
|
|
|
# Create a safe filename from the title, defaulting if needed
|
|
safe_title = clean_folder_name(video_title if video_title else "rule34video_file")
|
|
filename = f"{safe_title}.mp4"
|
|
filepath = os.path.join(self.output_dir, filename)
|
|
|
|
if os.path.exists(filepath):
|
|
self.progress_signal.emit(f" -> Skip: '{filename}' already exists.")
|
|
self.finished_signal.emit(0, 1, self.is_cancelled)
|
|
return
|
|
|
|
self.progress_signal.emit(f" Downloading: '{filename}'...")
|
|
try:
|
|
scraper = cloudscraper.create_scraper()
|
|
# The CDN link might not require special headers, but a referer is good practice
|
|
headers = {'Referer': 'https://rule34video.com/'}
|
|
response = scraper.get(final_video_url, stream=True, headers=headers, timeout=90)
|
|
response.raise_for_status()
|
|
|
|
total_size = int(response.headers.get('content-length', 0))
|
|
downloaded_size = 0
|
|
last_update_time = time.time()
|
|
|
|
with open(filepath, 'wb') as f:
|
|
# Use a larger chunk size for video files
|
|
for chunk in response.iter_content(chunk_size=8192 * 4):
|
|
if self.is_cancelled:
|
|
break
|
|
if chunk:
|
|
f.write(chunk)
|
|
downloaded_size += len(chunk)
|
|
current_time = time.time()
|
|
if total_size > 0 and (current_time - last_update_time) > 0.5:
|
|
self.file_progress_signal.emit(filename, (downloaded_size, total_size))
|
|
last_update_time = current_time
|
|
|
|
if self.is_cancelled:
|
|
if os.path.exists(filepath):
|
|
os.remove(filepath)
|
|
skip_count = 1
|
|
self.progress_signal.emit(f" Download cancelled for '{filename}'.")
|
|
else:
|
|
download_count = 1
|
|
|
|
except Exception as e:
|
|
self.progress_signal.emit(f" ❌ Failed to download '{filename}': {e}")
|
|
if os.path.exists(filepath):
|
|
os.remove(filepath)
|
|
skip_count = 1
|
|
|
|
self.file_progress_signal.emit("", None)
|
|
self.finished_signal.emit(download_count, skip_count, self.is_cancelled)
|
|
|
|
def cancel(self):
|
|
self.is_cancelled = True
|
|
self.progress_signal.emit(" Cancellation signal received by Rule34Video thread.") |