Commit Graph

33 Commits

Author SHA1 Message Date
Homer 3aca43b372 Give the app icons, tooltips and a finished theme
There was no icon system at all. Transport buttons called
QStyle.standardIcon(SP_MediaPlay), which returns the platform theme's dark
monochrome glyph -- painted onto the app's saturated red buttons at a fixed
36px with no text, that is the black square. Everything else called an icon
was an emoji baked into en.json, which is tofu wherever the emoji font is
missing. Qt stylesheets cannot recolour a QIcon, so the colour is an argument
to the new helper; that is the whole fix.

The SVGs are drawn here rather than vendored, which keeps a third-party
licence out of the tree, and they live in the module rather than as asset
files, which keeps them out of package-data and safe in a frozen build.

Tooltips were the other half: three widgets in the entire application had one
and nothing set an accessible name. Filling that in at the call sites would
have meant editing well over a hundred of them, most in upstream-owned files.
Instead one application-level event filter handles QEvent.Polish, which Qt
sends to every widget once before it is shown -- so it also reaches dialogs
built by upstream code, and survives the next merge. It maps placeholder
emoji to icons, fills empty tooltips from the button text, and logs icon-only
buttons that still have none so the gaps are findable.

StyleSheet.MAIN styles the window, inputs, buttons and tables and nothing
else, so the main tab bar, combos, sliders, lists, menus, splitters, tooltips
and the horizontal scrollbar fell through to the platform style. EXTRA_QSS
covers them, in a fork-owned module appended at the one application site.
SmoothTabWidget names its frame "tabContent" with the comment "We draw border
on content instead" -- that rule existed only inside two dialogs, and now
exists for the main window too.

Two corrections to rules that were already there: the pressed style changed
the padding, shifting every label two pixels and clipping fixed-width icon
buttons, and checkboxes were fully rounded, which reads as a radio button
rather than an on/off toggle.

Verified by screenshot on the real display: tab bar, buttons, combo carets
and checkboxes all render as intended, and all 35 icons rasterise non-empty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 00:58:38 +02:00
Homer 2420091a4e Check for SageTube updates, not YTSage's
The update check asked PyPI for the `ytsage` package's version, asked GitHub
for oop7/YTSage's release notes, and pointed the download button at upstream's
releases. None of that describes this program. Being reminded to install
YTSage was the visible symptom; the cause was that the check had never been
repointed when the fork was made.

It now reads SageTube's own releases from git.houmeres.sk. Gitea's release API
is shaped like GitHub's, so the dialog and the caller are unchanged -- the
class keeps its name and signal signature, and only its body moved out to
core/ytsage_app_update.py, which is fork-owned and will not conflict on the
next merge from upstream.

Upstream's inherited tags end in `b` (v5.3.0b and earlier). packaging reads
that as a beta marker, so they sort below v5.4.0 and a stable instance cannot
be handed one. Tag parsing is defensive anyway: one unparseable tag must not
take the whole check down with it.

Also: the check is rate-limited to once a day rather than every start, the
dialog gained a "Skip this version" that survives a restart, the thread is now
joined on close, and the About dialog says SageTube. The three binary updaters
-- yt-dlp, Deno, ffmpeg -- legitimately track their own upstreams and are
deliberately untouched; ytsage_app_update's docstring says so, because "update"
is an overloaded word in this codebase.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 00:36:14 +02:00
Jaroslav Beneš 8a05d5ff8f Rebrand user-visible surfaces to SageTube
The internal ytsage package name is kept deliberately - renaming it
would touch every file and destroy the ability to merge upstream
YTSage changes.

- pyproject: distribution name sagetube v0.1.0, sagetube entrypoint
  (ytsage alias retained), URLs point at the Gitea repo with an
  Upstream link to YTSage.
- Data dirs move to SageTube/ (fresh fork, fresh state) and the config
  file becomes sagetube_config.json; QApplication name and window
  title read SageTube.
- About dialog credits Houmeres and links "Based on YTSage by oop7".
- App self-update check against the upstream PyPI package is disabled
  by default; yt-dlp/deno/ffmpeg update flows are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 02:45:58 +02:00
Jaroslav Beneš a8ebe89cc1 Wire watch history, resume positions and persistent queue
WatchPage now records every played video in watch_history, saves the
playback position every 5 seconds and on stop/end (completed at >=95%),
and seeks back on replay when player.resume is "auto" - resume kicks in
between 30 seconds and 95% of the duration. The play queue persists
across restarts and reorders/removals write through immediately; the
main window's closeEvent flushes position and queue and releases libmpv.

PlayerPanel gains an automatic stall-retry: YouTube's CDN intermittently
serves stalled streams to non-browser clients (reproduced ~1/3 of
attempts headless with identical code), and a reload re-resolves onto a
healthy node - two retries after 25s of no playback, then a user-facing
error.

ytsage_constants now prepends the managed-binaries dir to PATH so
yt-dlp subprocesses (including mpv's ytdl_hook) can find the managed
Deno runtime - previously nothing exported APP_BIN_DIR, so the deno
integration silently never worked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 02:42:38 +02:00
Jaroslav Beneš 3afe96a8cd Add local subscriptions and the Feed tab
New ytsage/utils/ytsage_library_manager.py: sagetube_library.db
(separate from the upstream download-history DB) with WAL from day one,
holding subscriptions, cached feed_items, watch_history with resume
positions, and the persisted play_queue. Watch history and queue tables
are wired up by the next commit.

FeedPage:
- Local mode: FeedRefreshWorker refreshes each subscribed channel
  sequentially (feed.per_channel_items, default 15) and the grid fills
  incrementally per channel; results are cached so the feed is
  populated instantly on startup.
- Account mode: fetches youtube.com/feed/subscriptions with the user's
  browser cookies - the real logged-in feed; the option is enabled only
  while cookies are active and errors surface as a status banner.
- Sidebar lists subscriptions (double-click opens the channel in
  Browse; context menu unsubscribes). Browse's Subscribe button now
  toggles subscription state through the Feed page.

Verified live: subscribe -> refresh -> 15 videos cached in SQLite and
rendered as cards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 01:56:12 +02:00
Jaroslav Beneš 8e935c6116 Implement channel and playlist browsing
BrowsePage accepts pasted or routed channel/playlist URLs:
- Channels get Videos / Shorts / Live sub-tabs mapped to the channel's
  /videos, /shorts and /streams listings, lazily fetched 24 at a time
  with -I range pagination; channel title and id resolve from a cheap
  -I 1:1 metadata fetch. Subscribe emits subscribeRequested for the
  Feed page to wire up.
- Playlists get a single grid with Play all (bulk-enqueues into the
  Watch queue) and a Download button that deep-links the playlist into
  the Downloads tab.

Workers are parented to their pages and fetch errors surface as status
text instead of crashing (verified against a channel with no videos
tab). fetch_flat_info gains an items="1:1" limiter so metadata probes
no longer enumerate whole channels.

Verified live: kurzgesagt channel (24 cards, title+id resolved) and a
17-video playlist with Play-all queueing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 01:53:44 +02:00
Jaroslav Beneš 16be4b4afa Restructure main window into a watch-first tab shell
The single-page downloader layout becomes the Downloads tab of a
SmoothTabWidget with Watch / Search / Feed / Browse / Downloads pages.
The init_ui edit is deliberately small (the old central widget is now
self.download_page); all new behavior lives in new modules:

- ytsage_gui_router.py: AppRouter signal hub (playVideo, queueVideo,
  downloadVideo, openChannel, openPlaylist). A card's Download button
  deep-links into the Downloads tab with the URL prefilled and analysis
  started automatically.
- ytsage_gui_cards.py: VideoCard (thumbnail with disk cache under
  APP_THUMBNAILS_DIR, title/channel/duration, Play/Queue/Download
  actions, double-click to play) and VideoCardGrid (responsive grid,
  Load more pagination).
- ytsage_gui_watch.py: WatchPage hosting the mpv PlayerPanel and a
  drag-reorderable play queue with auto-advance on end of file.
- ytsage_gui_search.py: SearchPage running YtdlpClient.search off the
  GUI thread with Load more pagination.
- Browse and Feed pages are placeholders, implemented next.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 01:48:39 +02:00
Jaroslav Beneš f886125857 Add embedded mpv player (render API + QOpenGLWidget)
New ytsage/gui/ytsage_gui_player.py:
- MpvRenderWidget hosts libmpv through MpvRenderContext in a
  QOpenGLWidget - works on native Wayland where wid-embedding cannot -
  with all mpv-thread callbacks marshalled to the GUI thread via queued
  signals only.
- PlayerPanel adds transport controls: play/pause, seek slider, time
  display, quality selector (caps ytdl-format height and reloads in
  place), speed, volume (persisted), subtitle toggle, fullscreen
  (reparent to top-level window), and Space/F/Escape keys.
- Playback resolves watch URLs through mpv's ytdl_hook pointed at the
  app-managed SHA256-verified yt-dlp binary (script-opts
  ytdl_hook-ytdl_path), inheriting cookies and proxy settings via
  ytdl-raw-options - stream freshness, DASH muxing and nsig handling
  stay in yt-dlp's hands.

New ytsage/core/ytsage_mpv.py probes libmpv availability; without it
the Watch UI shows a per-OS install hint and everything else works.
python-mpv added to dependencies (libmpv itself is a system package).
Config gains player.* and feed.* defaults.

Verified on Wayland: real YouTube video streams with position/duration
signals flowing and no thread-safety errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 01:44:25 +02:00
oop7 e78b634bee Add remember_settings and private_video keys
Add two new localization keys across multiple language files: "remember_settings" (cookie dialog) and "private_video" (download/error message) to inform users about remembering cookie settings and private videos. Also fix minor formatting in en.json (split combined line for open_folder/save_playlist/reset). Updated locale files: ar, de, en, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh.
2026-04-28 13:31:07 +03:00
oop7 bb461898e4 Update translations across multiple locales
Update and improve translations for multiple language files (ar, de, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh). Key changes include localized strings for playlist saving ("Save Playlist As" -> localized), save/result/error messages, concurrent connections and help text, default selection/settings (video quality and subtitle language), and various wording/typo fixes. Also add/translate FFmpeg installation and yt-dlp setup messages in Turkish and Chinese. No functional code changes.
2026-04-25 17:42:36 +03:00
oop7 a2e11eec06 Update French translations
Translate several UI strings in ytsage/languages/fr.json from English to French: update `save_playlist`, `filter_playlist_placeholder`, and a group of settings strings (`concurrent_fragments`, `concurrent_fragments_help`, `defaults_settings`, `default_video_quality`, `default_subtitle_language`, `defaults_help`) to provide correct French localization and improve consistency.
2026-04-25 17:40:49 +03:00
oop7 9856dbf301 Update Spanish and Hindi translations
Improve localization by updating translations in ytsage/languages/es.json and ytsage/languages/hi.json. Spanish fixes provide full translations for interface help text, restart notice, playlist/save labels, dialog placeholders, and playlist save messages. Hindi adds translated strings for concurrent connections, related help text, and default selection settings for video quality and subtitles.
2026-04-25 17:40:24 +03:00
oop7 3d06c4dba6 Update German and Hindi translations
Translate several UI strings in ytsage/languages for German (de.json) and Hindi (hi.json). Changes include localized labels for saving playlists and filtering videos, dialog placeholders, and various settings text (e.g. concurrent connections and default selection help in German). Hindi updates add translated playlist save dialog messages and related UI strings.
2026-04-25 17:39:52 +03:00
oop7 d8c3ce8fa1 Add new i18n keys to language files
Add new localization keys across multiple ytsage language JSONs. Common addition: "filter_playlist_placeholder" added to most languages. Spanish, Turkish and Chinese receive several new strings for custom commands, proxy settings, FFmpeg installation messages, history loading, time/placeholders and validation messages. Also ensure files end with newline. Files modified: ar, de, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh.
2026-04-25 10:58:43 +03:00
oop7 57f5450725 Add save_playlist key to language files
Add a new "save_playlist" entry (placeholder "Save Playlist As") to multiple locale JSON files (ar, de, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh) to provide a translation key for saving playlists. Also adds the required trailing commas when inserting the new entries.
2026-04-25 10:39:00 +03:00
oop7 405ae07cac Add i18n entries for defaults and playlist save
Add new localization keys across multiple languages to support default selection settings and playlist saving UI. New keys include defaults_settings, default_video_quality, default_subtitle_language, defaults_help, and playlist save messages (save_as, save_success_title, saved_successfully, save_error_title, no_videos_to_save, save_error_msg). Files updated: ar, de, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh.
2026-04-25 10:37:40 +03:00
oop7 3b6ac7ce81 Add playlist save and default selection strings
Update English locale with new UI strings for playlist saving and default selections. Adds 'save_playlist' and related save messages (save_as, save_success_title, saved_successfully, save_error_title, no_videos_to_save, save_error_msg), adds default selection settings keys (defaults_settings, default_video_quality, default_subtitle_language, defaults_help), and documents the %(playlist_index)s variable in filename_format_help. Also minor formatting cleanup in the file.
2026-04-25 10:33:10 +03:00
oop7 e86536d585 Add concurrent connections i18n keys
Add new i18n keys "concurrent_fragments" and "concurrent_fragments_help" to multiple language JSON files (ar, de, en, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh). These expose a UI option for the number of concurrent connections per download with a help string (default: 1, warns about throttling/temporary blocks). Strings were added in English across locales and may need translation.
2026-04-09 18:27:50 +02:00
oop7 437344695d Add UI tab labels to translation files
Add "tab_general", "tab_format", and "tab_file" entries to multiple ytsage/languages/*.json files to provide localized labels for the UI tabs (General, Format, File). Also include a minor formatting/newline fix in en.json.
2026-03-21 16:26:41 +02:00
oop7 62b8ede273 Add audio normalization docs and translations
Document Audio Normalization (EBU R128) in README and translated READMEs, and add corresponding localization keys and help text in ytsage language files. Updates include README.md, readme-translations (ar,de,es,fr,hi,id,it,ja,pl,pt,ru,tr,zh) and ytsage/languages JSON files to explain the feature and note that normalization requires re-encoding and forcing a specific audio format (e.g. MP3 or M4A).
2026-03-21 15:21:40 +02:00
oop7 b048f8ce09 Add audio normalization option and support
Introduce an "audio_normalization" option across the app and implement normalization for audio-only downloads. Updates include: add config default (ConfigManager), new language strings, settings UI checkbox + help text and logic to auto-enable force-audio-format when normalization is enabled, and persist the setting. Pass the setting from main app to DownloadThread, and in the downloader force re-encoding to mp3 when necessary and append --postprocessor-args ExtractAudio:-af loudnorm=... to apply EBU R128 normalization. This ensures normalization works reliably (avoids ffmpeg stream-copy errors) and keeps the behavior scoped to ExtractAudio postprocessor.
2026-03-21 15:08:48 +02:00
oop7 fff674a0b8 Add check_app_updates key to locales
Add a new "check_app_updates" translation string to multiple language files so the UI can display the option to check for YTSage updates at startup. Updated languages: ar, de, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh.
2026-03-19 14:49:37 +02:00
oop7 4a16aad2ac Add check_app_updates setting and UI
Introduce a new "check_app_updates" configuration (default: true) to allow users to enable/disable automatic YTSage update checks. Adds a styled checkbox to the Updater tab with getter, loads the setting (defaults to enabled for older configs), and saves it from the custom options dialog. The main update check now respects this setting and will skip checking when disabled. Also include English localization entries for the new UI strings.
2026-03-19 14:45:56 +02:00
oop7 9afca46c5d Add generic-mode URL validation and UI
Introduce a "generic_mode" option to allow validating/downloading from non-YouTube sites and wire it through the UI, config, and validation logic. Key changes:

- Add generic_mode default to ConfigManager and persist setting from DownloadSettingsDialog (checkbox + help text).
- Extend validate_video_url to accept a generic_mode flag and allow any http/https URL with a domain when enabled; pass this flag from Analysis and Download flows.
- Update YTSageApp to load/save generic_mode, update URL placeholder and settings tooltip behavior, and refresh tooltip when settings change.
- Improve robustness in FormatTableMixin: handle None/incorrect types for format_note, abr, resolution, ext, and codec values to avoid type errors and ensure consistent display.
- Add localization entries for generic mode, placeholder, and related help text across multiple language files and update the in-app default localization strings.

These changes enable broader site support via yt-dlp while hardening UI format handling and keeping user settings persistent.
2026-03-12 11:10:10 +02:00
oop7 79f2613cf7 Add open_logs strings to localizations
Add open_logs and logs_tooltip localization entries across multiple language JSON files (ar, de, en, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh) so the About/System Info UI can expose an action to open the application logs folder. Also add an "about" section to ytsage/utils/ytsage_localization.py with default entries (open_logs, logs_tooltip, refresh). This wires the logs-folder UI text into the localization system.
2026-02-10 13:50:22 +02:00
oop7 04e043c689 Add app update strings to translations
Add 'app_updates_title' and 'check_beta_updates' translation keys to language files (ar, de, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh). These localized strings support the app updates settings UI (including an option to receive beta updates) and keep translations consistent with the existing auto-update-related entries.
2026-02-08 17:43:24 +02:00
oop7 d250c1b05f Add opt-in beta update UI and checks
Introduce an opt-in beta updates feature: add a styled "Receive Beta Updates" checkbox in the Updater UI with i18n strings, load/save logic in the custom options dialog, and a default config key (check_beta_updates=false).

Add _fetch_github_beta_version to the update thread to query GitHub releases (selecting the highest tag) and emit update_available for newer beta builds. When beta checking is enabled, the thread will perform the GitHub beta check and return early to avoid conflicting with the PyPI check. This enables users to opt into preview releases safely.
2026-02-08 17:41:13 +02:00
oop7 351504ade9 Add reset and filename_format translations
Add a "reset" button label and new "filename_format" + "filename_format_help" entries to multiple locale JSON files (ar, de, es, fr, hi, id, it, ja, pl, pt, ru, tr, zh). The help text documents supported yt-dlp output template variables (%(title)s, %(uploader)s, %(upload_date)s, %(resolution)s, %(id)s, %(ext)s) so the UI can accept a custom output filename format.
2026-02-07 15:55:10 +02:00
oop7 1fbc3a43c2 Add Reset button for filename format
Add a Reset button next to the filename format input so users can restore the default pattern. The filename input and reset button are grouped in a QHBoxLayout; the button is fixed width (70) and sets the field back to the default %(title)s_%(resolution)s.%(ext)s. Also add the corresponding i18n key (buttons.reset -> "Reset") to en.json.
2026-02-07 15:37:26 +02:00
oop7 ed1469898c Add configurable output filename format
Introduce a new filename_format setting and UI to control yt-dlp output templates. ConfigManager now includes a default filename_format (%(title)s_%(resolution)s.%(ext)s). The DownloadSettingsDialog exposes a text input and help text for the format and saves the value to ConfigManager. DownloadThread now accepts a filename_format argument and uses it when building output templates for single videos and playlists. YTSageApp reads the config and passes the filename format into the download thread. Added corresponding English language strings.
2026-02-07 15:28:06 +02:00
oop7 cd9e410ea3 Simplify analysis status messages in locales
Standardize and simplify analysis/status strings across multiple language files by removing percent-based prefixes and verbose phrasing, adding concise messages with trailing ellipses. This updates localization for ar, de, es, fr, hi, id, it, ja, pl, pt, ru, tr, and zh (ytsage/languages/*.json) to make progress messages cleaner and consistent for both regular and ytdlp-related steps.
2026-02-03 19:20:41 +02:00
oop7 e86704c5cd Simplify analyzing status messages
Update English UI strings in ytsage/languages/en.json to remove progress percentages and the repeated "Analyzing" prefix, replacing them with concise action messages (e.g., "Extracting basic info...", "Loading thumbnail..."). This makes status messages shorter and more consistent across regular and ytdlp-related entries without changing functionality.
2026-02-03 19:17:44 +02:00
oop7 acda70150f Move language files to ytsage/languages directory
Renamed and relocated all language JSON files from the root 'languages' directory to 'ytsage/languages' for improved project organization.
2026-01-25 14:03:01 +02:00