add "captions" as download format

This commit is contained in:
vitaliibudnyi
2026-02-21 19:06:49 +02:00
committed by Alex Shnitman
parent e24890fd9b
commit 973a87ffc6
4 changed files with 48 additions and 4 deletions

View File

@@ -26,6 +26,10 @@ def get_format(format: str, quality: str) -> str:
# Quality is irrelevant in this case since we skip the download
return "bestaudio/best"
if format == "captions":
# Quality is irrelevant in this case since we skip the download
return "bestaudio/best"
if format in AUDIO_FORMATS:
# Audio quality needs to be set post-download, set in opts
return f"bestaudio[ext={format}]/bestaudio/best"
@@ -98,6 +102,13 @@ def get_opts(format: str, quality: str, ytdl_opts: dict) -> dict:
{"key": "FFmpegThumbnailsConvertor", "format": "jpg", "when": "before_dl"}
)
if format == "captions":
opts["skip_download"] = True
opts["writesubtitles"] = True
opts["writeautomaticsub"] = True
opts["subtitleslangs"] = ["en"]
opts["subtitlesformat"] = "vtt"
opts["postprocessors"] = postprocessors + (
opts["postprocessors"] if "postprocessors" in opts else []
)

View File

@@ -160,6 +160,14 @@ class Download:
else:
filename = filepath
self.status_queue.put({'status': 'finished', 'filename': filename})
# For captions-only downloads, yt-dlp may still report a media-like
# filepath in MoveFiles. Capture subtitle outputs explicitly so the
# UI can link to real caption files.
if self.info.format == 'captions':
requested_subtitles = d.get('info_dict', {}).get('requested_subtitles', {}) or {}
for subtitle in requested_subtitles.values():
if isinstance(subtitle, dict) and subtitle.get('filepath'):
self.status_queue.put({'subtitle_file': subtitle['filepath']})
# Capture all chapter files when SplitChapters finishes
elif d.get('postprocessor') == 'SplitChapters' and d.get('status') == 'finished':
@@ -260,10 +268,14 @@ class Download:
self.tmpfilename = status.get('tmpfilename')
if 'filename' in status:
fileName = status.get('filename')
self.info.filename = os.path.relpath(fileName, self.download_dir)
self.info.size = os.path.getsize(fileName) if os.path.exists(fileName) else None
if self.info.format == 'thumbnail':
self.info.filename = re.sub(r'\.webm$', '.jpg', self.info.filename)
rel_name = os.path.relpath(fileName, self.download_dir)
# For captions mode, ignore media-like placeholders and let subtitle_file
# statuses define the final file shown in the UI.
if not (self.info.format == 'captions' and not rel_name.endswith(('.vtt', '.srt', '.ass', '.ttml'))):
self.info.filename = rel_name
self.info.size = os.path.getsize(fileName) if os.path.exists(fileName) else None
if self.info.format == 'thumbnail':
self.info.filename = re.sub(r'\.webm$', '.jpg', self.info.filename)
# Handle chapter files
log.debug(f"Update status for {self.info.title}: {status}")
@@ -280,6 +292,21 @@ class Download:
# Skip the rest of status processing for chapter files
continue
if 'subtitle_file' in status:
subtitle_file = status.get('subtitle_file')
if not hasattr(self.info, 'subtitle_files'):
self.info.subtitle_files = []
rel_path = os.path.relpath(subtitle_file, self.download_dir)
file_size = os.path.getsize(subtitle_file) if os.path.exists(subtitle_file) else None
existing = next((sf for sf in self.info.subtitle_files if sf['filename'] == rel_path), None)
if not existing:
self.info.subtitle_files.append({'filename': rel_path, 'size': file_size})
# Prefer first subtitle file as the primary result link in captions mode.
if self.info.format == 'captions' and (not getattr(self.info, 'filename', None)):
self.info.filename = rel_path
self.info.size = file_size
continue
self.info.status = status['status']
self.info.msg = status.get('msg')
if 'downloaded_bytes' in status: