feat: Implement early download slot release for special CDNs, add mobile UI fixes, and introduce new plugin structure.
This commit is contained in:
@@ -20,14 +20,16 @@ logger = logging.getLogger(__name__)
|
||||
class CdndaniaDownloader:
|
||||
"""cdndania.com 전용 다운로더 (세션 기반 보안 우회)"""
|
||||
|
||||
def __init__(self, iframe_src, output_path, referer_url=None, callback=None, proxy=None, threads=16):
|
||||
def __init__(self, iframe_src, output_path, referer_url=None, callback=None, proxy=None, threads=16, on_download_finished=None):
|
||||
self.iframe_src = iframe_src # cdndania.com 플레이어 iframe URL
|
||||
self.output_path = output_path
|
||||
self.referer_url = referer_url or "https://ani.ohli24.com/"
|
||||
self.callback = callback
|
||||
self.proxy = proxy
|
||||
self.threads = threads
|
||||
self.on_download_finished = on_download_finished
|
||||
self.cancelled = False
|
||||
self.released = False # 조기 반환 여부
|
||||
|
||||
# 진행 상황 추적
|
||||
self.start_time = None
|
||||
@@ -92,6 +94,13 @@ class CdndaniaDownloader:
|
||||
content = f.read().strip()
|
||||
if content:
|
||||
progress = json.loads(content)
|
||||
# 조기 반환 체크 (merging 상태이면 네트워크 완료로 간주)
|
||||
status = progress.get('status', 'downloading')
|
||||
if status == 'merging' and not self.released:
|
||||
if self.on_download_finished:
|
||||
self.on_download_finished()
|
||||
self.released = True
|
||||
|
||||
if self.callback and progress.get('percent', 0) > 0:
|
||||
self.callback(
|
||||
percent=progress.get('percent', 0),
|
||||
@@ -164,17 +173,21 @@ def _download_worker(iframe_src, output_path, referer_url, proxy, progress_path,
|
||||
)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def update_progress(percent, current, total, speed, elapsed):
|
||||
def update_progress(percent, current, total, speed, elapsed, status=None):
|
||||
"""진행 상황을 파일에 저장"""
|
||||
try:
|
||||
data = {
|
||||
'percent': percent,
|
||||
'current': current,
|
||||
'total': total,
|
||||
'speed': speed,
|
||||
'elapsed': elapsed
|
||||
}
|
||||
if status:
|
||||
data['status'] = status
|
||||
|
||||
with open(progress_path, 'w') as f:
|
||||
json.dump({
|
||||
'percent': percent,
|
||||
'current': current,
|
||||
'total': total,
|
||||
'speed': speed,
|
||||
'elapsed': elapsed
|
||||
}, f)
|
||||
json.dump(data, f)
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -350,7 +363,8 @@ def _download_worker(iframe_src, output_path, referer_url, proxy, progress_path,
|
||||
total_segments = len(segments)
|
||||
|
||||
log.info(f"Temp directory: {temp_dir}")
|
||||
log.info(f"Starting parallel download with {threads} threads for {total_segments} segments...")
|
||||
# 다운로드 worker
|
||||
log.info(f"Starting optimized download: Binary Merge Mode (Threads: {threads})")
|
||||
|
||||
# 세그먼트 다운로드 함수
|
||||
def download_segment(index, url):
|
||||
@@ -422,6 +436,9 @@ def _download_worker(iframe_src, output_path, referer_url, proxy, progress_path,
|
||||
|
||||
log.info("All segments downloaded successfully.")
|
||||
|
||||
# 조기 반환 신호 (merging 상태 기록)
|
||||
update_progress(100, total_segments, total_segments, "", "", status="merging")
|
||||
|
||||
# 7. ffmpeg로 합치기
|
||||
log.info("Concatenating segments with ffmpeg...")
|
||||
concat_file = os.path.join(temp_dir, "concat.txt")
|
||||
|
||||
@@ -265,8 +265,8 @@ class FfmpegQueue(object):
|
||||
# [주의] cdndania는 yt-dlp로 받으면 14B 가짜 파일(보안 차단)이 받아지므로
|
||||
# aria2c 선택 여부와 무관하게 전용 다운로더(CdndaniaDownloader)를 써야 함.
|
||||
# 대신 CdndaniaDownloader 내부에 멀티스레드(16)를 구현하여 속도를 해결함.
|
||||
if 'cdndania.com' in video_url:
|
||||
logger.info(f"Detected cdndania.com URL - using Optimized CdndaniaDownloader (curl_cffi + {download_threads} threads)")
|
||||
if getattr(entity, 'need_special_downloader', False) or 'cdndania.com' in video_url or 'michealcdn.com' in video_url:
|
||||
logger.info(f"Detected special CDN requirement (flag={getattr(entity, 'need_special_downloader', False)}) - using Optimized CdndaniaDownloader")
|
||||
download_method = "cdndania"
|
||||
|
||||
logger.info(f"Download method: {download_method}")
|
||||
@@ -298,6 +298,14 @@ class FfmpegQueue(object):
|
||||
if not _iframe_src:
|
||||
# 폴백: headers의 Referer에서 가져오기
|
||||
_iframe_src = getattr(entity_ref, 'headers', {}).get('Referer', video_url)
|
||||
# 슬롯 조기 반환을 위한 콜백
|
||||
slot_released = [False]
|
||||
def release_slot():
|
||||
if not slot_released[0]:
|
||||
downloader_self.current_ffmpeg_count -= 1
|
||||
slot_released[0] = True
|
||||
logger.info(f"Download slot released early (Network finished), current_ffmpeg_count: {downloader_self.current_ffmpeg_count}/{downloader_self.max_ffmpeg_count}")
|
||||
|
||||
logger.info(f"CdndaniaDownloader iframe_src: {_iframe_src}")
|
||||
downloader = CdndaniaDownloader(
|
||||
iframe_src=_iframe_src,
|
||||
@@ -305,10 +313,13 @@ class FfmpegQueue(object):
|
||||
referer_url="https://ani.ohli24.com/",
|
||||
callback=progress_callback,
|
||||
proxy=_proxy,
|
||||
threads=download_threads
|
||||
threads=download_threads,
|
||||
on_download_finished=release_slot # 조기 반환 콜백 전달
|
||||
)
|
||||
elif method == "ytdlp" or method == "aria2c":
|
||||
# yt-dlp 사용 (aria2c 옵션 포함)
|
||||
# yt-dlp는 내부적으로 병합 과정을 포함하므로 조기 반환이 어려울 수 있음 (추후 지원 고려)
|
||||
slot_released = [False]
|
||||
from .ytdlp_downloader import YtdlpDownloader
|
||||
logger.info(f"Using yt-dlp downloader (method={method})...")
|
||||
# 엔티티에서 쿠키 파일 가져오기 (있는 경우)
|
||||
@@ -323,8 +334,8 @@ class FfmpegQueue(object):
|
||||
use_aria2c=(method == "aria2c"),
|
||||
threads=download_threads
|
||||
)
|
||||
|
||||
else:
|
||||
slot_released = [False]
|
||||
# 기본: HLS 다운로더 사용
|
||||
from .hls_downloader import HlsDownloader
|
||||
logger.info("Using custom HLS downloader for m3u8 URL...")
|
||||
@@ -344,14 +355,16 @@ class FfmpegQueue(object):
|
||||
downloader.cancel()
|
||||
entity_ref.ffmpeg_status_kor = "취소됨"
|
||||
entity_ref.refresh_status()
|
||||
downloader_self.current_ffmpeg_count -= 1
|
||||
if not slot_released[0]:
|
||||
downloader_self.current_ffmpeg_count -= 1
|
||||
return
|
||||
|
||||
success, message = downloader.download()
|
||||
|
||||
# 다운로드 완료 후 카운트 감소
|
||||
downloader_self.current_ffmpeg_count -= 1
|
||||
logger.info(f"Download finished, current_ffmpeg_count: {downloader_self.current_ffmpeg_count}/{downloader_self.max_ffmpeg_count}")
|
||||
# 다운로드 완료 후 카운트 감소 (이미 반환되었으면 스킵)
|
||||
if not slot_released[0]:
|
||||
downloader_self.current_ffmpeg_count -= 1
|
||||
logger.info(f"Download finished (Slot released normally), current_ffmpeg_count: {downloader_self.current_ffmpeg_count}/{downloader_self.max_ffmpeg_count}")
|
||||
|
||||
if success:
|
||||
entity_ref.ffmpeg_status = 7 # COMPLETED
|
||||
|
||||
Reference in New Issue
Block a user