Fix subtitle positioning and show existing langs without re-downloading
- Strip yt-dlp's align:start position:0% cue settings from VTT files after both video download and subtitle-only download so CSS ::cue centers them - CC chip now shows already-downloaded langs (e.g. 'CC: en') directly from disk with a '+' button to add more — no YouTube call needed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -384,6 +384,25 @@ def fetch_channel_links(channel_id: str) -> list[str]:
|
|||||||
return list(channel_ids)
|
return list(channel_ids)
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_vtt_cue_settings(video_id: str) -> None:
|
||||||
|
"""Remove position/align/line cue settings from yt-dlp VTT files.
|
||||||
|
|
||||||
|
yt-dlp embeds 'align:start position:0%' in every cue header which pins
|
||||||
|
subtitles to the bottom-left. Stripping them lets CSS ::cue center them.
|
||||||
|
"""
|
||||||
|
for vtt in Path(settings.download_path).glob(f"{video_id}.*.vtt"):
|
||||||
|
try:
|
||||||
|
text = vtt.read_text(encoding="utf-8", errors="replace")
|
||||||
|
cleaned = re.sub(
|
||||||
|
r'(\d{1,2}:\d{2}:\d{2}\.\d{3} --> \d{1,2}:\d{2}:\d{2}\.\d{3})[^\n]*',
|
||||||
|
r'\1',
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
vtt.write_text(cleaned, encoding="utf-8")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def download_subs_only(video_id: str, subtitle_langs: str) -> bool:
|
def download_subs_only(video_id: str, subtitle_langs: str) -> bool:
|
||||||
"""Download subtitle files only (no video) for an already-downloaded video."""
|
"""Download subtitle files only (no video) for an already-downloaded video."""
|
||||||
url = f"https://www.youtube.com/watch?v={video_id}"
|
url = f"https://www.youtube.com/watch?v={video_id}"
|
||||||
@@ -397,6 +416,8 @@ def download_subs_only(video_id: str, subtitle_langs: str) -> bool:
|
|||||||
"-o", output_template,
|
"-o", output_template,
|
||||||
*_cookie_args(),
|
*_cookie_args(),
|
||||||
], timeout=60)
|
], timeout=60)
|
||||||
|
if code == 0:
|
||||||
|
_strip_vtt_cue_settings(video_id)
|
||||||
return code == 0
|
return code == 0
|
||||||
|
|
||||||
|
|
||||||
@@ -721,6 +742,7 @@ def start_download(
|
|||||||
|
|
||||||
process.wait()
|
process.wait()
|
||||||
if process.returncode == 0:
|
if process.returncode == 0:
|
||||||
|
_strip_vtt_cue_settings(video_id)
|
||||||
resolution = detect_resolution(file_path) if file_path else None
|
resolution = detect_resolution(file_path) if file_path else None
|
||||||
on_complete(download_id, file_path, resolution)
|
on_complete(download_id, file_path, resolution)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -995,15 +995,18 @@ export default function Watch() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{(() => {
|
{(() => {
|
||||||
// Subs already on disk → show indicator (player CC button handles the rest)
|
// Subs already on disk → show langs + "+" to add more
|
||||||
if (subtitleFiles.length > 0 && !subsRequested) return (
|
if (subtitleFiles.length > 0 && !subsRequested) return (
|
||||||
<button
|
<div className="flex items-center gap-1">
|
||||||
onClick={() => setSubsRequested(true)}
|
<span className="px-3 py-1.5 rounded-full bg-zinc-800 text-zinc-400 text-xs font-mono">
|
||||||
className="flex items-center gap-1 px-3 py-1.5 rounded-full bg-zinc-800 text-zinc-400 text-xs hover:bg-zinc-700 transition-colors"
|
CC: {subtitleFiles.map(s => s.lang).join(", ")}
|
||||||
title="Subtitles loaded — click to add more languages"
|
</span>
|
||||||
>
|
<button
|
||||||
CC ✓
|
onClick={() => setSubsRequested(true)}
|
||||||
</button>
|
className="px-2.5 py-1.5 rounded-full text-xs bg-zinc-800 text-zinc-500 hover:bg-zinc-700 transition-colors"
|
||||||
|
title="Add subtitle language"
|
||||||
|
>+</button>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
// Not yet asked → show CC chip
|
// Not yet asked → show CC chip
|
||||||
if (!subsRequested) return (
|
if (!subsRequested) return (
|
||||||
|
|||||||
Reference in New Issue
Block a user