diff --git a/README.md b/README.md index fe127ba..b5ff0e3 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,13 @@ FlaskFarm용 범용 다운로드 매니저 플러그인입니다. 여러 다운로더 플러그인(YouTube, Anime 등)의 다운로드 요청을 통합 관리하고 큐(Queue)를 제공합니다. -## v0.2.27 변경사항 (2026-01-09) -- **자가 업데이트 기능 추가**: 설정 페이지에서 "Update" 버튼 클릭으로 Git Pull 및 플러그인 핫 리로드 지원 -- **버전 체크 API**: GitHub에서 최신 버전 정보를 가져와 업데이트 알림 표시 (1시간 캐싱) +## v0.2.30 변경사항 (2026-01-12) +- **자막 자동 다운로드 및 변환**: `ytdlp_aria2` 다운로더에 VTT 자막 다운로드 및 SRT 자동 변환 로직 내장. +- **경로 정규화 강화**: `output_template` 생성 시 중복 구분자(`//`, `\.\`)를 제거하여 경로 오염 방지. +- **다운로드 완료 지점 최적화**: 비디오 다운로드 성공 직후 자막 처리가 이어지도록 흐름 개선. + +## v0.2.29 변경사항 (2026-01-11) +- **Anilife 고유 ID 지원**: 에피소드 고유 코드가 없는 경우 제목 기반 매칭 로직 보강. ## v0.2.24 변경사항 (2026-01-08) - **Chrome 확장프로그램 추가**: YouTube에서 GDM으로 바로 다운로드 전송 diff --git a/downloader/ytdlp_aria2.py b/downloader/ytdlp_aria2.py index 095b121..009ac5d 100644 --- a/downloader/ytdlp_aria2.py +++ b/downloader/ytdlp_aria2.py @@ -42,9 +42,9 @@ class YtdlpAria2Downloader(BaseDownloader): # 출력 템플릿 if filename: - output_template = os.path.join(save_path, filename) + output_template = os.path.normpath(os.path.join(save_path, filename)) else: - output_template = os.path.join(save_path, '%(title)s.%(ext)s') + output_template = os.path.normpath(os.path.join(save_path, '%(title)s.%(ext)s')) # yt-dlp 명령어 구성 cmd = [ @@ -267,6 +267,15 @@ class YtdlpAria2Downloader(BaseDownloader): if self._process.returncode == 0: if progress_callback: progress_callback(100, '', '') + + # 자막 다운로드 처리 + vtt_url = options.get('subtitles') + if vtt_url and final_filepath: + try: + self._download_subtitle(vtt_url, final_filepath, headers=options.get('headers')) + except Exception as e: + logger.error(f'[GDM] Subtitle download error: {e}') + return {'success': True, 'filepath': final_filepath} else: return {'success': False, 'error': f'Exit code: {self._process.returncode}'} @@ -318,3 +327,57 @@ class YtdlpAria2Downloader(BaseDownloader): return result.returncode == 0 except: return False + + def _download_subtitle(self, vtt_url: str, output_path: str, headers: Optional[dict] = None): + """자막 다운로드 및 SRT 변환""" + try: + import requests + # 자막 파일 경로 생성 (비디오 파일명.srt) + video_basename = os.path.splitext(output_path)[0] + srt_path = video_basename + ".srt" + + logger.info(f"[GDM] Downloading subtitle from: {vtt_url}") + response = requests.get(vtt_url, headers=headers, timeout=30) + + if response.status_code == 200: + vtt_content = response.text + srt_content = self._vtt_to_srt(vtt_content) + with open(srt_path, "w", encoding="utf-8") as f: + f.write(srt_content) + logger.info(f"[GDM] Subtitle saved to: {srt_path}") + return True + except Exception as e: + logger.error(f"[GDM] Failed to download subtitle: {e}") + return False + + def _vtt_to_srt(self, vtt_content: str) -> str: + """VTT 형식을 SRT 형식으로 간단히 변환""" + if not vtt_content.startswith("WEBVTT"): + return vtt_content + + lines = vtt_content.split("\n") + srt_lines = [] + cue_index = 1 + i = 0 + while i < len(lines): + line = lines[i].strip() + if line.startswith("WEBVTT") or line.startswith("NOTE") or line.startswith("STYLE"): + i += 1 + continue + if not line: + i += 1 + continue + if "-->" in line: + # VTT 타임코드를 SRT 형식으로 변환 (. -> ,) + srt_timecode = line.replace(".", ",") + srt_lines.append(str(cue_index)) + srt_lines.append(srt_timecode) + cue_index += 1 + i += 1 + while i < len(lines) and lines[i].strip(): + srt_lines.append(lines[i].rstrip()) + i += 1 + srt_lines.append("") + else: + i += 1 + return "\n".join(srt_lines) diff --git a/info.yaml b/info.yaml index 8ac22c1..4d63699 100644 --- a/info.yaml +++ b/info.yaml @@ -1,6 +1,6 @@ title: "GDM" package_name: gommi_downloader_manager -version: '0.2.29' +version: '0.2.31' description: FlaskFarm 범용 다운로더 큐 - YouTube, 애니24, 링크애니, Anilife 지원 developer: projectdx home: https://gitea.yommi.duckdns.org/projectdx/gommi_downloader_manager