Commit Graph
5042 Commits
Author SHA1 Message Date
vicrodh 56c924d8ea feat(slint): Label landing page + All Releases sub-view
Port the Tauri LabelView module to native Slint, reusing existing
components and extending where needed (no duplication).

Landing (new LabelPageView): circular header + description read-more +
Follow toggle, sticky JUMP TO bar, Popular Tracks (multi-select, 5->20->50
reveal, Play all), and Releases (+ See all) / Critics' Picks / Playlists /
Artists / More Labels carousels.

All Releases sub-view (LabelReleasesView): circular header + album count,
toolbar (local search, group-by-artist, Hi-Res filter, sort) + grid/list
toggle, load-more, states. TYPE column now populated.

Split the label route: ContentView::label -> LabelPageView (landing),
ContentView::label-releases -> LabelReleasesView; add NavEntry::LabelReleases.
label.rs load_label_page parses /label/page + getAlbums + explore + the
favorite-labels set; derive_releases re-derives the sub-view list.
Reuse Carousel/PlaylistCarousel/ArtistCarousel/TrackRow/AlbumCard/
AlbumListRow/JumpNavBar/QbzSelect/ExpandableSearch; extend ArtistCard/
ArtistCarousel (follow-mode/follow-kind); promote CircleAction to a shared
primitive; JumpNavBar gains show-search. Wire label media-actions:
follow, play-top, open (more-labels), see-all.

cc
2026-05-26 18:35:42 -06:00
vicrodh b2004e6867 feat(slint): TrackRow favorites + artist/album links, PlaylistView, LabelView, scrollbar
CHECKPOINT — this batch is NOT yet acceptable; substantial feedback is pending. Committed so the work is preserved for rework next session, after a max-effort Tauri code review. Areas: TrackRow favorite toggle/state + clickable artist/album (TrackItem gains is-favorite/artist-id/album-id + fav_cache, populated across all builders); PlaylistView header buttons + cover-art hover overlay; LabelView full AlbumCard + grid/list toggle; vertical scrollbar moved to the right gutter across ~12 views.

cc
2026-05-26 16:36:02 -06:00
vicrodh a5383ba502 chore(slint): flag the remaining unwired Appearance settings red
Marks every non-functional Appearance row (Theme, Language, Font, UI Scale, notifications, window-title, player views, system tray, immersive) with the SettingRow 'unsupported' red label. Only the wired 'Show playlist cover collages' and the 'Detected' status row stay normal. Red = not actually connected, so what still needs wiring is visible at a glance.

cc
2026-05-26 16:36:02 -06:00
vicrodh 242511946a chore(scripts): add nightly parallel-frontend release dev build
slint-dev.sh runs qbz-slint via 'cargo +nightly run --release -Z threads', splitting the serial compile of the Slint-generated module across cores while producing an identical optimized release binary (no cranelift). RUSTFLAGS re-lists the AES-NI features from .cargo/config.toml since RUSTFLAGS overrides rather than merges it.

cc
2026-05-26 15:09:29 -06:00
vicrodh 4e329b4c8b chore(slint): flag unwired Appearance settings for the Tauri to Slint audit
Add a SettingRow 'unsupported' flag that renders the label red. Mark the Title Bar and Window Controls sections: that Tauri custom-window-decoration paradigm does not carry over to Slint's TitleBar/Plasma chrome.

cc
2026-05-26 15:09:29 -06:00
vicrodh 178d135328 feat(slint): Playlist Manager + search most-popular hero polish
Playlist Manager: list view renders compact rows with total play time; folder grid cards no longer clip the playlist count (content-driven height); list view shows compact folder chips; the move-to-folder menu gains a folder search and a 4-row scroll cap. Search: the most-popular track hero is resized to the artist-card height with the quality shown as centered text instead of a clipped badge.

cc
2026-05-26 15:09:29 -06:00
vicrodh 93a7bbbc3c feat(slint): double-click a track row to play/pause
Mirrors the play-cell click on the row body: double-clicking a track plays it, or toggles play/pause when it is already the current track. Applies to every TrackRow (album, artist, search, playlist, mix).

cc
2026-05-26 15:09:29 -06:00
vicrodh d30e3d658d feat(slint): sidebar context menus, in-app toast, SearchView + Playlist Manager polish
Sidebar:
- Fix "Recursion detected" panic from focusing the playlist search input in init (defer via a single-shot Timer).
- Right-click context menus: playlist (Edit, Hide from sidebar, Move to folder with folder search + Move to root) and folder (Edit, Hide from sidebar), built on ContextMenu/ContextMenuItem; remove the unreachable hover "..." button.
- Filter hidden playlists/folders out of the list; add folders::set_folder_hidden.
- Folder list in the move-to-folder menu scrolls (cap 5 rows); close-on-click-outside so the folder-search input no longer dismisses the menu.
- Sort-menu Refresh now uses a dedicated refresh-cw icon.

Toast: in-app ToastKind/ToastState + Toast overlay mounted at the app root, crate::toast (show/hide, per-kind auto-hide via a reusable Timer, cross-thread *_weak helpers); surface play album/artist load failures.

SearchView: title inline with NavButtons + searchType filters floated right; tab strip on its own row; Most-popular hero for a track uses the new SearchTrackHero, sized to the artist card.

Playlist Manager: list view renders compact PmListRow rows instead of cards; grid/folder card fonts tightened to match Tauri; folder card centered with hover-reveal edit; search input narrowed to 70%.

cc
2026-05-26 12:21:59 -06:00
vicrodh 2bf6feaa6d feat(slint): Playlist Manager view + shared nav/state/shell wiring
Port the Playlist Manager: header/toolbar (search/filter/sort/folder-flat
toggle/view-mode/new-folder/counter), FOLDERS card grid (accent icon, count,
edit), PLAYLISTS grid/list/tree, folder CRUD (FolderEditModal), move-to-
folder, per-card actions, and arrow-button reorder (custom sort). Reached
from the sidebar "Manage playlists" item; backend 100% reused via
QbzCore/library.db (no new commands). Pointer-event drag-and-drop and
gradient folder colors are deferred follow-ups.

This commit also carries the cross-cutting wiring the session's features all
share — state.slint globals/structs, NavEntry variants, main.rs dispatch +
action wiring, artwork targets, app.slint exports, AppShell mounts — so HEAD
is the verified-green tree (cargo check + release build clean).

cc
2026-05-26 01:07:08 -06:00
vicrodh 7aa3018cf6 feat(slint): replicate Settings > Appearance section (1:1 UI, mostly unwired)
Add an Appearance sub-section to the Slint settings, mirroring Tauri's:
theme + auto-theme, font/UI-scale/language, startup page, sidebar playlist
collage (wired to the sidebar flag), notifications/toasts/tray, title bar +
window controls, immersive + miniplayer. Controls reuse QbzToggle/QbzSelect
and the AudioSettings/PlaybackSettings layout. Most controls are visual
stubs (AppearanceState + TODO callbacks) pending backend wiring.

cc
2026-05-26 01:07:08 -06:00
vicrodh 9f70a5ac5a feat(slint): sidebar Playlists toolbar + folders + micro-collage refinements
PLAYLISTS header: smaller title, recursive search (hides title), create
modal at 1:1 with Tauri (name/description/folder/public), sort menu, and a
collapse chevron. Folders: accent-tinted icon, open/close chevron as the
primary affordance (no more purposeless "..."), count shown on hover only.
Playlists render a 2x2 micro-collage of track covers (opt-out) instead of
the glyph, sourced from the existing playlist images (no extra fetch).

cc
2026-05-26 01:07:08 -06:00
vicrodh c5c124fb0c feat(slint): Discover "View all" pages + reusable AlbumListRow + recently-played metadata
Per-module discover See-All pages (new releases, press accolades, ideal
discography, qobuzissimes, albums of the week, most streamed) reachable
from each carousel's "View all" link: a paginated grid OR list view with
client-side search, genre filter, and a fixed header. Adds a reusable
AlbumListRow (columns #/ITEM/TYPE/SOURCE/QUALITY/TRACKS/YEAR, SOURCE
hideable, reuses QualityBadgeFull) with play-on-hover + even/odd zebra.
Recently Played albums now carry genre + localized release date + quality
(captured at play time, no extra fetch). Shared home::map_album /
card_to_item reused; grid-only AlbumCardItem literals get ..Default.

cc
2026-05-26 01:07:08 -06:00
vicrodh 9f1e036308 feat(slint): album cards show genre + localized full release date (#469)
Album-card hover overlay now shows the full release date as "MMM D, YYYY"
(e.g. "Nov 6, 2025") instead of the year alone. New dates::release_label
helper keeps the month/day/year order fixed but localizes the month via
chrono format_localized (the app ships 5 languages; current_locale() is the
single hook to thread the real UI language once Slint wires translations —
English for now). Applied to the Discover and Favorites album mappings.

Also fixes Favorites > Albums cards, which hardcoded an empty genre and a
year-only label: they now read album.genre and the full date, matching the
Discover cards 1:1. The data was already in the getUserFavorites response
(qbz-models Album parses genre + release_date_original) — no backend change.

cc
2026-05-25 17:42:36 -06:00
vicrodh 21af0f63f8 feat(slint): favorites tabs as history pages + homologated nav-bar/title
Each favorites tab is now its own history entry (NavEntry::Favorites{tab},
mirroring Discover) recorded from both the header nav and the in-view tab
bar, so back/forward moves between tabs instead of exiting Favorites. Add
the back/forward NavButtons at the same position as every other page
(11px top padding + 22px gap) — FavoritesView was the only view missing
it — and shrink the "Favorites" heading to Typography.section (the album
name size in AlbumView).

cc
2026-05-25 17:41:35 -06:00
vicrodh abff875a0e fix(slint): album card title no longer clamped to the artist name width
The clickable-artist change bound the artist TouchArea width to the artist
text's preferred-width, which clamped the whole stretch:1 title column to
the (often short) artist name — truncating titles to a few letters and
shoving the quality badge inward instead of letting it float right. Drop
the explicit width; the inner Text fills the column (width: 100%) and elides.

cc
2026-05-25 17:05:44 -06:00
vicrodh 11a78ed2f6 feat(slint): resolve Auto backend to a concrete one in audio settings (#470)
Port #470's UI behavior: add an "Auto" entry at the top of the backend
dropdown that, on select, resolves to the best available backend (PipeWire
if present, else System) and persists that concrete value. The rebuilt
snapshot then moves the dropdown onto the resolved backend, so backend_type
is never left null/Auto. Concrete backends keep mapping by their shifted
index; System wiring comes from available_backends() (merged backend half).

cc
2026-05-25 17:05:44 -06:00
vicrodh e38dfb6235 chore(slint): restore qbz-slint deps in crates/Cargo.lock after the 1.2.14 merge
The catch-up merge staged the pre-release lock (--theirs) before cargo
regenerated it, so the committed lock dropped qbz-slint's GUI dependency
tree (slint / accesskit / winit / skia / ab_glyph, ...). Commit the
regenerated lock so the checked-in slint-mvp lock matches the workspace.

cc
2026-05-25 17:05:44 -06:00
vicrodh 022b3e46e6 Merge pre-release into slint-mvp (1.2.14 backend catch-up)
One-way backend catch-up bringing the 1.2.14 maintenance work into
slint-mvp: audio (#470/#449/#466), player/offline/prefetch (#467),
qobuz retry/backoff, credential-store + image-cache refactor, dep
bumps (cpal 0.17.3 / alsa 0.11 / tokio / ashpd / tower-http), and the
qbzd daemon removal.

Conflicts resolved:
- qbz-audio settings.rs: keep slint-mvp stream_first_track/buffer
  defaults (1/2, opt-out); adopt #470's CREATE-TABLE seed removal
  (row is seeded with backend_type below).
- crates/Cargo.toml: keep qbz-slint workspace member (qbzd removed
  upstream).
- crates/Cargo.lock: regenerated (no ratatui/qbzd; cpal/alsa bumped).

cargo check --workspace green.

cc
2026-05-25 15:12:58 -06:00
vicrodh f3bba60dd0 Merge branch 'chore/remove-qbzd' into pre-release
Remove the unshipped qbzd daemon experiment and its client integration.

cc
2026-05-25 15:08:44 -06:00
vicrodh 47db92ff92 chore: remove qbzd headless daemon and its client integration
qbzd was a premature daemon experiment that never shipped (gated off
behind QBZD_ENABLED, no user access). Its ratatui 0.29 dependency pinned
unicode-width =0.2.0, which conflicts with slint's annotate-snippets in a
shared workspace. Remove it entirely; it will be reimplemented from
scratch later on the clean, UI-agnostic shell.

- Delete crates/qbzd daemon crate + workspace member (drops ratatui,
  crossterm and the other qbzd-only deps from the lock).
- Delete src-tauri qbzd_discovery (mDNS) + its commands/state wiring in
  lib.rs; drop the direct mdns-sd dep (Chromecast keeps its own via
  qbz-cast).
- Delete remoteApi/remoteEvents/playbackTargetStore; neutralize
  commandRouter to local-only dispatch (isRemote/skipIfRemote are now
  always-false no-ops so the ~100 guard call-sites keep compiling).
- Strip qbzd branches from playbackService and the remote banner from
  NowPlayingBar; excise qbzd from CastPicker (Chromecast/DLNA kept).
- Remove qbzd i18n keys (5 locales), README daemon node, gitignore note.

cargo check (crates + src-tauri) and svelte-check all green.

cc
2026-05-25 15:08:14 -06:00
vicrodh 6ed659c318 chore: bump Nix flake hashes for v1.2.14
cc
2026-05-25 11:57:02 -06:00
vicrodh a62c2f26f2 docs(issue-template): emphasize log sharing and add log-access screenshot
cc
2026-05-25 09:58:30 -06:00
vicrodh 28faf2e075 docs(release): clarify 1.2.14 release notes intro
cc
2026-05-25 09:58:30 -06:00
dependabot[bot] e99a92aab8 chore(deps): bump openssl from 0.10.79 to 0.10.80 in /src-tauri (#473)
Bumps [openssl](https://github.com/rust-openssl/rust-openssl) from 0.10.79 to 0.10.80.
- [Release notes](https://github.com/rust-openssl/rust-openssl/releases)
- [Commits](https://github.com/rust-openssl/rust-openssl/compare/openssl-v0.10.79...openssl-v0.10.80)

---
updated-dependencies:
- dependency-name: openssl
  dependency-version: 0.10.80
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-25 09:54:28 -06:00
vicrodh 4e9cf815fe chore(release): bump snapcraft and flake to 1.2.14
snapcraft.yaml: version: '1.2.14' AND source-tag: v1.2.14 (both fields —
updating only one leaves the Snap Store building the previous tag).
packaging/snap/snapcraft.yaml is a symlink to it, so both stay in sync
automatically.

flake.nix: qbzVersion -> 1.2.14; srcHash/npmHash cleared, to be refilled
via `nix build` after the v1.2.14 tag exists, in a follow-up commit as in
prior releases.

cc
2026-05-25 08:38:00 -06:00
vicrodh 28bb5737ba chore(release): bump to 1.2.14 "Just cleaning"
- version: Cargo.toml, tauri.conf.json, package.json (+ Cargo.lock, package-lock.json)
- metainfo.xml: add 1.2.14 release entry
- About modal codename -> "Just cleaning"
- docs/release-1.2.14: TAG_DETAILS.md + CHANGELOG_FULL.md

Snap and Nix flake are intentionally left at 1.2.13: they pin a source
tag, and this is a no-tag, build-only cycle (no distribution).

cc
2026-05-25 07:50:34 -06:00
vicrodh 27cadc6fd5 fix(discovery): restore full release date (MMM D, YYYY) in album card hover overlay (#469)
The AlbumCardLite rewrite reduced the hover-overlay release line to the
year only. Thread the full release date through DiscoveryAlbumCard and
format it as "MMM D, YYYY" in the overlay (falling back to year), parsing
YYYY-MM-DD as a local date to avoid timezone day-shift. Restores the
pre-rewrite overlay behavior; does not adopt the reporter's YYYY/MM/DD ask.

cc
2026-05-24 22:33:42 -06:00
vicrodh 768811036b Merge branch 'bugfix/internal/audio-system-default-470' into pre-release 2026-05-24 21:13:51 -06:00
vicrodh a0051ab513 fix(audio): default to shared System output and resolve Auto to a concrete backend (#470)
OOTB playback froze (seekbar advancing, no audio) on hosts where the
configured backend was not usable — e.g. PipeWire as the Linux default but
`pactl` absent (minimal Debian/Ubuntu). "Auto" (a null backend_type) fell
through to a legacy CPAL path that forced the track rate onto the shared
default device, producing a suspended/silent stream and leaving a
process-wide stuck audio handle that survived Reset.

- Add a cross-platform "System" backend (CpalDefaultBackend now on Linux
  too): opens the OS default output at its negotiated rate with rodio
  resampling and an explicit ~100ms CPAL buffer (MixerDeviceSink has zero
  internal buffering, so the bare default underran and stayed suspended).
  Shared, no exclusivity, no `pactl` — mixes with other apps like any
  normal player.
- Make System the OOTB default and what Reset lands on; seed it on first
  run. Drop the per-startup #375 NULL->PipeWire backfill migration.
- Resolve a null backend_type to System in the player so the legacy CPAL
  path is never reached (covers legacy installs and headless callers).
- "Auto" in Settings is now a resolve-and-set action: it picks the best
  available backend (PipeWire if available, else System), stores that
  concrete value and updates the dropdown + device picker, so backend_type
  is never null.
- Explicit PipeWire (DAC passthrough) and ALSA Direct (exclusive) configs
  are untouched and remain bit-perfect.

cc
2026-05-24 21:13:11 -06:00
vicrodh 332c74bc39 chore(logging): redact query values and fragments in navigation logs
Add log_sanitize::redact_url, which preserves a URL's scheme, host, path
and query-parameter keys while masking every value and any fragment.

Apply it to the OAuth WebView navigation log lines (main on_navigation,
popup-window request, and popup on_navigation) so navigation traces stay
useful for debugging the flow without carrying parameter values into log
files or user-uploaded reports.

Covered by unit tests for code/token params, base64-padded values,
fragments, and query-less URLs.

cc
2026-05-24 07:59:03 -06:00
vicrodh bf56eefd7a chore(deps): bump cpal 0.17.1 -> 0.17.3 and alsa 0.10 -> 0.11
cpal 0.17.3 requires alsa 0.11, which in turn pulls alsa-sys 0.4. The
`links = "alsa"` constraint permits only one alsa-sys in the dependency
graph, so qbz-audio's direct alsa stack is raised in lockstep:
alsa 0.10 -> 0.11 and alsa-sys 0.3 -> 0.4. Both workspace lockfiles
(crates/ and src-tauri/) are updated to cpal 0.17.3 / alsa 0.11.0 /
alsa-sys 0.4.0.

No source changes required: alsa_direct.rs uses only the stable
high-level alsa API (pcm, HwParams, Format, Direction, ValueOr, mixer),
and the snd_lib_error_set_handler FFI in alsa_error_handler.rs is
unchanged in alsa-sys 0.4. Both workspaces pass cargo check.

cc
2026-05-23 22:25:26 -06:00
vicrodh bec71d58d5 chore(deps-dev): bump vite from 8.0.13 to 8.0.14
cc
2026-05-23 18:08:06 -06:00
vicrodh e9b021e7e5 chore(deps-dev): bump vitest to 4.1.7
cc
2026-05-23 17:17:55 -06:00
vicrodh a4a281221a chore(deps): bump @kawarp/core to 1.2.0
cc
2026-05-23 17:17:44 -06:00
vicrodh 81d3751cb9 chore(deps-dev): bump vite to 8.0.13
cc
2026-05-23 17:17:40 -06:00
vicrodh cb8421accc chore(deps-dev): bump @tauri-apps/cli to 2.11.2
cc
2026-05-23 17:17:32 -06:00
vicrodh b1c946de6c chore(deps-dev): bump @sveltejs/kit from 2.59.1 to 2.60.1
cc
2026-05-23 17:17:21 -06:00
vicrodh 97dd405bcf chore(deps): bump open from 5.3.4 to 5.3.5
cc
2026-05-23 14:04:48 -06:00
vicrodh 9b2c6743e6 chore(deps): bump tauri-build from 2.6.1 to 2.6.2
cc
2026-05-23 14:03:10 -06:00
vicrodh d5f9d0b83c chore(deps): bump tokio from 1.52.2 to 1.52.3
cc
2026-05-23 14:01:17 -06:00
vicrodh d5d2e93744 chore(deps): bump ashpd from 0.13.10 to 0.13.11
cc
2026-05-23 13:59:34 -06:00
vicrodh 9e505a9fa4 chore(deps): bump tower-http from 0.6.8 to 0.6.11
cc
2026-05-23 13:58:00 -06:00
vicrodh a8ee939dab Merge bugfix/internal/post-1.2.13: post-1.2.13 bugfixes
Fixes #467 (long-session offline death), #468 (favorite on see-all), #466
(PipeWire backend hidden without pactl), #452 (remix version on initial play
from favorites), #449 (sample-rate sync regression on PipeWire), and #453
(macOS queue drag — pending Mac confirmation). Includes the recovered adaptive
prefetch throttle that #467's offline-liveness signal builds on.

cc
2026-05-23 12:05:05 -06:00
vicrodh e437e620a1 fix(queue): restore drag-and-drop reordering on macOS (#453)
c1c151ee added `-webkit-user-select: none` to <body>; on macOS WKWebView this
also blocks dragstart on the draggable .queue-track rows (WebKit couples
selectability with draggability), so queue reordering and its blue insertion
line silently broke. Marking the rows as `-webkit-user-drag: element` restores
drag initiation. WebKitGTK (Linux) is unaffected. Needs confirmation on a Mac.

cc
2026-05-23 12:04:29 -06:00
vicrodh ee4c889c55 fix(player): rebuild output stream on sample-rate change for all backends (#449)
The stream-recreate decision only forced a rebuild on a decoded-format change
for bit-perfect backends (DAC passthrough, ALSA Direct, CoreAudio exclusive).
The default/PipeWire path relied on Stop dropping the stream to get a fresh one
at the new rate; once that drop was deferred to avoid a track-change click
(e93fcaec), the PipeWire node stayed locked to the first track's rate for all
subsequent tracks — a regression vs 1.2.10. Make any decoded-format change
rebuild the stream on every backend; same-rate tracks still reuse it, so the
click fix is preserved.

Verified on hardware via pw-top: PipeWire without passthrough now switches rate
per track; PipeWire with passthrough and ALSA Direct unchanged (no regression).

cc
2026-05-23 08:35:38 -06:00
vicrodh d075902380 fix(favorites): carry remix/edition version on initial click-to-play from the favorites tracks view (#452)
The favorites queue builder forwarded the track version, so skipping/seeking to
a track showed its remix subtitle, but buildDisplayTrack (used for the initial
click-to-play via onTrackPlay) dropped it — so the now-playing bar, queue,
MPRIS and Last.fm lost the version on first play. Add version to the
DisplayTrack interface and buildDisplayTrack.

cc
2026-05-22 23:16:53 -06:00
vicrodh 3a09ce7fe7 fix(audio): detect PipeWire via runtime socket so the backend is not hidden without pactl (#466)
is_pipewire_available() shelled out to `pactl info`, which lives in
pulseaudio-utils and is absent on PipeWire-only systems — hiding the PipeWire
backend even though PipeWire was running. Detect via the
$XDG_RUNTIME_DIR/pipewire-0 socket first (no extra package required), with
pw-cli and pactl as fallbacks.

cc
2026-05-22 23:16:53 -06:00
vicrodh f5de06aeef fix(discovery): wire favorite button on browse/see-all pages (#468)
The heart overlay on AlbumCardLite always renders and calls onFavorite, but
VirtualizedFavoritesAlbumGrid never forwarded onFavorite/isFavorite, so the
button was dead on every discover see-all page. Thread both through the grid
and wire DiscoverBrowseView to the shared albumFavoritesStore (same pattern as
the collapsed DiscoveryView). Fixes favoriting across all six browse pages.

cc
2026-05-22 21:46:34 -06:00
vicrodh 50384d3d3c fix(player): never skip the gapless target offline + bound the skip cascade (#467)
The offline-skip recursion walked the entire remaining queue synchronously,
desyncing the logical queue from the still-playing engine. Fixes:

- The gapless-transition target is the track the engine is already playing;
  never run the availability-skip branch for it.
- isTrackAvailable now counts the in-memory/disk cache (new v2_is_track_cached
  command), not just downloaded copies.
- Cap consecutive offline skips and play-failure auto-skips at 5 in both
  +page.svelte and playbackService.ts.

cc
2026-05-22 21:46:34 -06:00
vicrodh bdaee1af1a fix(qobuz): retry transient fetch failures with backoff instead of skipping (#467)
A single transient 5xx / timeout / reset on the next track's file/url or a CMAF
segment used to be terminal and skipped the track. Add a retry wrapper (3
attempts, exponential backoff + jitter) around get_file_url, the init segment,
and per-segment fetches. Retry only transient errors (network/timeout, 5xx, 429
honoring Retry-After); a real 404 is classified as TrackUnavailable and
propagates immediately to the bounded skip path.

cc
2026-05-22 21:46:33 -06:00