Commit graph

242 commits

Author SHA1 Message Date
TonyBlu
33e6ae3388 fix: clear() deletes chapter/subtitle files + persist subtitle_files
Bug fixes from full codebase review:
- clear() with DELETE_FILE_ON_TRASHCAN now also deletes chapter_files
  and subtitle_files, not just the primary filename
- _PERSISTED_DOWNLOAD_FIELDS now includes 'subtitle_files' so subtitle
  file info survives app restart

Tests:
- Added test_subtitle_lang_list_with_region_variant_input (zh-Hans)
- Added test_subtitle_lang_list_dedup_region_variant (pt-BR)
2026-05-25 21:51:37 +08:00
TonyBlu
6d890021a6 feat(captions): P1/P2 improvements - region variant fallback, DownloadInfo init, subtitle_files UI
P1 fixes:
- _subtitle_lang_list now extracts base language from qualified tags
  (e.g. zh-Hans → zh base) so regional variants are still added as
  fallbacks. Original input is preserved as first priority.
- DownloadInfo.__init__ now explicitly initializes filename=None and
  chapter_files=[] to avoid AttributeError on dynamic attribute access.
- __setstate__ adds filename=None migration for old persistent data.
- Frontend Download interface gains subtitle_files field; completed
  downloads show each subtitle file with download link and CC icon.

P2 improvements:
- _LANGUAGE_REGION_VARIANTS expanded from 10 to 30 languages covering
  it/ja/ko/hi/th/vi/id/pl/uk/ru/cs/sv/da/no/fi/tr/el/he/hu/bn/ta.
- Languages with no regional variants use empty tuple (they still get
  -orig suffix when include_orig=True).
2026-05-25 21:48:27 +08:00
TonyBlu
b31f4e2fea fix(tests): update subtitle language list assertions for variant fallback
Update test expectations to match the new _subtitle_lang_list() output
which includes regional variants (e.g. fr-FR, en-GB) for better
subtitle matching.
2026-05-25 21:27:10 +08:00
TonyBlu
b25a2ad80a fix(captions): use getattr for filename check in _post_download_cleanup
DownloadInfo doesn't have a 'filename' attribute by default — it's only
set dynamically in update_status when a 'downloaded' status is received.
When captions are silently skipped by yt-dlp (no matching language), the
'downloaded' status is never emitted, so 'filename' doesn't exist on the
object at all. Using getattr(download.info, 'filename', None) instead of
direct attribute access prevents AttributeError.
2026-05-25 21:23:06 +08:00
TonyBlu
36b397ae93 fix(captions): add language variant fallback + error on no files
Two fixes for captions downloads:

1. Language variant fallback: When user requests 'en' but the video only
   has 'en-GB' (or other regional variants), yt-dlp silently skips
   subtitle extraction because it uses exact language matching. Now the
   subtitleslangs list includes common regional variants (e.g. en-US,
   en-GB, en-AU, etc.) so yt-dlp can match the first available variant.

2. Error on no files: When yt-dlp completes successfully (ret=0) but
   produces no subtitle files (e.g. no matching language at all), the
   download was incorrectly shown as 'completed'. Now it's marked as
   'error' with a descriptive message like 'No subtitles found for
   language "en"'. Same treatment for thumbnail downloads.
2026-05-25 21:16:10 +08:00
TonyBlu
e639caa21d fix: Codex review P2 issues + frontend test failure
- Reset download_phase when transitioning to paused (pause(), update_status(),
  _post_download_cleanup()) so UI shows 'Paused' instead of stale phase label
- Reset download_phase when starting/resuming download (start() preparing state)
- Count 'postprocessing' as active download in updateMetrics() so dashboard
  shows accurate counts during ffmpeg post-processing
- Add missing completedDownload Subject to DownloadsServiceStub in app.spec.ts
- Add Download type import to app.spec.ts

Fixes: TypeError Cannot read properties of undefined (reading 'pipe')
       at app.ts:300 (completedDownload not in test stub)
2026-05-25 20:09:17 +08:00
TonyBlu
03cee14948 fix: download phase label not working during downloads
- _download_phase_from_status now falls back to checking requested_formats
  when top-level vcodec/acodec are both 'none' (common when yt-dlp uses
  separate downloaders for video+audio streams)
- Clear download_phase on download completion/error (was persisting stale
  phase value in finished state)
- Add debug logging in put_status for phase detection
- Update docker-compose.local.yml to match docker-compose.yml structure
  with local image build (adds TARGETARCH build arg)
2026-05-25 19:45:43 +08:00
TonyBlur
6e161f4b4b Add auto download and pause resume controls 2026-05-25 16:28:15 +08:00
TonyBlur
0311df0b06 fix: Fixed audio file suffix when quality is 'best' and minor UI fixes 2026-05-07 07:25:54 +08:00
TonyBlur
8723ab0afe fix: Fixed suffix when quality is 'best' 2026-05-06 14:03:05 +08:00
TonyBlur
c755f394d1 feat: update icons, add suffix and fix bugs
- Removed shadow from URL entry wrap in app.html for a cleaner look.
- Updated various icon files to improve visual consistency across the application.
- Add suffix to identify different files of same video
- Fixed invisible download for short link

Co-authored-by: Copilot <copilot@github.com>
2026-05-04 14:14:26 +08:00
TonyBlur
85fd7e0328 Fix browser path in test environment setup to reflect project name change 2026-05-01 13:31:59 +08:00
TonyBlu
d78bc41124 Route public canceled events by composite download key 2026-05-01 13:19:37 +08:00
Alex Shnitman
5d96a581b9 allow filtering out members-only videos in subscriptions (closes #971) 2026-04-28 22:02:05 +03:00
Alex Shnitman
4f83174d05 implement time-clipped downloads (closes #969, replaces #907) 2026-04-26 23:07:50 +03:00
Alex Shnitman
91ee8312bf title filter for subscriptions (closes #968) 2026-04-26 22:51:48 +03:00
Alex Shnitman
23de9824f0 cr fixes 2026-04-21 16:13:58 +03:00
rdiaz738
0ea934c08f Updated import and fixed race condition 2026-04-20 17:24:16 -07:00
Alex Shnitman
e9f979b349 fix yt-dlp options overrides (closes #958) 2026-04-18 08:46:29 +03:00
Alex Shnitman
1a32eba474 fix PUBLIC_HOST_URL without a trailing slash (closes #959) 2026-04-16 22:08:08 +03:00
Alex Shnitman
03f71fd257 fix asterisk CORS_ALLOWED_ORIGINS, mentioned in #955 2026-04-13 19:02:27 +03:00
Alex Shnitman
388aeb180d Merge branch 'bgervan/master' 2026-04-10 08:10:00 +03:00
Benjamin Gervan
a6e8617ad8 Don't mark live streams as seen 2026-04-10 06:41:45 +02:00
az10b
0072d3488a Fix permissive CORS policy that allows cross-origin attacks
The on_prepare handler unconditionally reflected the Origin request
header into Access-Control-Allow-Origin, and Socket.IO was configured
with cors_allowed_origins='*'. This allowed any website to make
authenticated cross-origin requests to all API endpoints, enabling
cross-origin download initiation, cookie overwrite, and data deletion.

Replace the blanket origin reflection with an explicit allowlist via
the CORS_ALLOWED_ORIGINS environment variable. When unset, cross-origin
requests are denied by default. Users who need cross-origin access can
set CORS_ALLOWED_ORIGINS to a comma-separated list of trusted origins.
2026-04-09 19:45:51 -05:00
McSwindler
d38d7bd1b1 fix: handle playlists that don't supply video ids 2026-04-09 10:15:11 -05:00
jacinli
373692ac65 fix: parse string boolean values when updating subscriptions 2026-04-05 14:05:59 +08:00
Alex Shnitman
dd0f98d12f change option presets to be multi-select 2026-04-04 10:25:46 +03:00
copilot-swe-agent[bot]
6e9b2dd7b3
Gate manual yt-dlp overrides behind flag
Agent-Logs-Url: https://github.com/alexta69/metube/sessions/31b4274d-cf48-4260-b73b-633cbcd2bb09

Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-04-03 09:05:19 +00:00
copilot-swe-agent[bot]
565a715037
feat: add per-download yt-dlp presets and overrides
Agent-Logs-Url: https://github.com/alexta69/metube/sessions/8a3119fc-63d1-4508-a196-8c50ff248812

Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-04-03 06:16:12 +00:00
copilot-swe-agent[bot]
d7eaaaa94b Add clarifying comments for n_entries and __last_playlist_index fields (closes #692)
Agent-Logs-Url: https://github.com/alexta69/metube/sessions/b5aeb55a-3197-4a14-b8b4-96c9a67796e8

Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-04-02 10:51:03 +03:00
copilot-swe-agent[bot]
981e6c1003
Propagate missing playlist context fields (playlist_count, playlist_autonumber, n_entries, __last_playlist_index)
The playlist/channel processing loop now sets playlist_count,
playlist_autonumber, n_entries, and __last_playlist_index on each
video entry so that templates like %(playlist_autonumber)s,
%(playlist_count)s, and %(playlist_index&{} - |)s resolve correctly
instead of showing NA.

Also updates _compact_persisted_entry to preserve n_entries and
__last_playlist_index across restarts.

Fixes #692

Agent-Logs-Url: https://github.com/alexta69/metube/sessions/b5aeb55a-3197-4a14-b8b4-96c9a67796e8

Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-04-01 19:59:32 +00:00
copilot-swe-agent[bot]
b17e1e5668
Add explanatory comment for fake STR_FORMAT_RE_TMPL key group in tests
Agent-Logs-Url: https://github.com/alexta69/metube/sessions/0ae5ff34-540f-4fc8-a81c-358fb92b7c15

Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-04-01 19:34:09 +00:00
copilot-swe-agent[bot]
c1b5540332
Replace custom template substitution with yt-dlp's evaluate_outtmpl
Replace the hand-rolled _outtmpl_substitute_field() / _compile_outtmpl_pattern()
with a new _resolve_outtmpl_fields() that delegates to yt-dlp's
YoutubeDL.evaluate_outtmpl().  This gives playlist/channel output templates
access to yt-dlp's full template syntax: defaults (%(field|fallback)s),
conditional formatting (%(field&prefix {})s), math (%(field+N)d),
datetime formatting (%(field>%Y-%m-%d)s), and more.

Only field references whose root name matches the targeted prefix (e.g.
"playlist" or "channel") are resolved; all other references remain as
template placeholders for yt-dlp to fill during the actual download.

Agent-Logs-Url: https://github.com/alexta69/metube/sessions/0ae5ff34-540f-4fc8-a81c-358fb92b7c15

Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-04-01 19:31:27 +00:00
Alex Shnitman
483575d24a add subscriptions; change persistence file format to JSON (closes #901, #76, #113, #170, #242, #444, #503, #555, #566) 2026-04-01 14:33:24 +03:00
Alex Shnitman
84c6418f91 fix pickle (closes #814) 2026-03-21 12:42:17 +02:00
Alex Shnitman
a1f2fe3e73 implement tests 2026-03-20 13:12:31 +02:00
Alex Shnitman
7fa1fc7938 code review fixes 2026-03-15 20:53:13 +02:00
Alex Shnitman
5c321bfaca reoganize quality and codec selections 2026-03-13 19:47:36 +02:00
CyCl0ne
56826d33fd Add video codec selector and codec/quality columns in done list
Allow users to prefer a specific video codec (H.264, H.265, AV1, VP9)
when adding downloads. The selector filters available formats via
yt-dlp format strings, falling back to best available if the preferred
codec is not found. The completed downloads table now shows Quality
and Codec columns.
2026-03-09 08:59:01 +01:00
copilot-swe-agent[bot]
2736425e19 Revert #504 default change: restore original playlist/channel output templates
Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-03-07 14:00:29 +00:00
copilot-swe-agent[bot]
0d905c0b61 Fix issues #898, #542, #561, #504
Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-03-07 07:19:05 +00:00
copilot-swe-agent[bot]
6de4a56f28 Remove DEFAULT_DOWNLOAD_FOLDER feature
Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-03-07 06:37:09 +00:00
copilot-swe-agent[bot]
1f4c4df847 Implement DEFAULT_DOWNLOAD_FOLDER and CLEAR_COMPLETED_AFTER features (#875, #869)
Co-authored-by: alexta69 <7450369+alexta69@users.noreply.github.com>
2026-03-06 15:37:35 +00:00
Alex Shnitman
54e25484c5 some fixes in cookie upload functionality 2026-03-06 14:20:16 +02:00
ddmoney420
7cfb0c3a1d Add cookie file upload for authenticated downloads 2026-03-04 13:29:43 -07:00
ddmoney420
3587098e80 Fix deleted playlist videos being re-queued during add
When adding a playlist, deleting a video from the queue causes it to be
re-added on the next loop iteration because queue.exists() returns False
for the deleted key. Track canceled URLs in a set so __add_entry skips
them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:17:50 -07:00
Alex Shnitman
1915bdfc46 refactor: simplify filename generation by removing unnecessary relative path computation (closes #916, closes #917) 2026-03-02 20:29:29 +02:00
Alex Shnitman
58c317f7cd enhance playlist addition cancellation and improve error handling UI 2026-03-02 20:21:04 +02:00
ddmoney420
880eda8435 feat: cancel playlist adding mid-operation (closes #840) 2026-03-01 19:11:29 -07:00
Alex Shnitman
053e41cf52 code review fixes 2026-02-27 12:58:50 +02:00