Commit Graph

17 Commits

Author SHA1 Message Date
Test User 973bb7bbc6 Fetch streams in bounded windows and restore yt-dlp for stream URLs
YouTube caps tokenless stream URLs at exactly their leading 1 MiB:
plain, open-ended, and oversized requests get 403, and fresh URLs
refuse offset starts, so playback died mid-first-minute. PO tokens
would lift the cap but the token-capable Innertube clients need
signature deciphering that is broken in rustypipe upstream (botguard
was built and tested — ineffective through the iOS client).

The player now streams every http(s) source through a windowed
SourceStream (bounded ~1 MiB ranges, 200-body fallback, eager
seek/reconnect so rejected windows fail typed instead of retrying
forever) and the capture downloader windows the same way. Stream URLs
come from a minimal yt-dlp sidecar again — metadata stays on the
pure-Rust rustypipe extractor — whose cipher-solved URLs stream whole
files at a throttled ~32 KB/s; a missing binary degrades to 1 MiB
streams with a warning. botguard_bin is wired through so streams flip
back to pure Rust when upstream deciphering recovers. Live-verified on
the exact track from the failure log.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 18:18:40 +02:00
Test User 6f787285bf Replace the yt-dlp subprocess with the pure-Rust rustypipe client
Playback of YouTube tracks was broken: bestaudio selects WebM/Opus and
the rodio+symphonia player has no Opus decoder. The new extractor picks
the highest-bitrate audio/mp4 (AAC) stream instead, which decodes —
and captures get playable .m4a files. rusty_ytdl, rustube, and
rust-yt-downloader were evaluated live and rejected (broken or stale);
rustypipe works end to end and is actively maintained. Provider logic
now tests against a fake Extract seam, login keeps the cookies.txt
setting with rustypipe caching the rotated cookie, saved playlists
replace the unvalidated feed scrape, and yt-dlp leaves devenv.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 17:12:40 +02:00
Test User 58f7f9c66b Bundle server and TUI into a single cbd binary
crabidy-server and cbd-tui become libraries with thin mains:
crabidy_server::serve(addr) hosts the whole server stack,
cbd_tui::run(config) the client loops. The new cbd binary logs both
halves to one file, starts the server in-process, waits for the socket
(adopting an already-running standalone server on an occupied port),
and runs the TUI against it over the unchanged localhost gRPC wire.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 14:15:47 +02:00
Test User c6e9f71cf4 Add a YouTube provider backed by yt-dlp
The new ytdy crate mounts /youtube: login-free search terms exactly
like tidal's (creatable, renamable, deletable, results as queueable
downloadable tracks) and, when a cookies file is configured, the
user's playlists. All extraction runs through one bounded subprocess
seam (argv-only, per-call timeout, stdout cap, typed errors) so tests
drive the provider with a fake script. yt-dlp is declared in devenv;
a failed binary probe disables the provider, never the server.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 14:01:58 +02:00
Test User 4dd5f01217 Add a filesystem provider for serialized track nodes
A new fsdy crate exposes a configured root directory as /fs:
*.track.toml files are track nodes carrying metadata plus exactly one
playable reference — a local audio file, an http(s) URL, or a
crabidy-internal link. Link tracks rewrite Track.path to the target at
listing time, so playback routes through the existing prefix routing;
links into /fs are rejected, making chains impossible. Paths are
percent-encoded segments validated in one place (no root escape), the
orchestrator wires the provider optionally (a broken local config only
costs the /fs subtree), and the default chunked resolve walk provides
progressive queueing for free.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 01:58:55 +02:00
Test User d741523e53 Add Tidal search as creatable library nodes
Pressing % inside /tidal/search opens an input line; the entered term
becomes a tree node whose contents are the search results: track hits
queueable in place, artist and album hits as canonical /tidal/artists
paths. New CreateLibraryNode rpc + is_creatable flags (wire-compatible),
ProviderClient::create_lib_node routed by prefix, percent-encoded term
segments in crabidy-core, and a modal input overlay in the TUI with
creatable nodes marked [%]. Search terms live in memory for the process
lifetime; term nodes are deliberately not queueable so the resolve sweep
cannot drag whole discographies into the queue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 17:58:44 +02:00
AI User 21e1b10c0b Drop redundant log-to-tracing bridge init
tracing-subscriber .init() already installs the LogTracer via its
default tracing-log feature; the explicit init only produced a startup
warning. Remove it and the direct tracing-log dependency.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 22:01:22 +02:00
AI User d504ebc85f Fix intermittent playback stops and harden the queue
Root causes found and fixed:

- QueueManager could panic and kill the playback task permanently:
  is_last_track() underflowed on an empty queue, remove_tracks accepted
  pos == len (Vec::remove panic) and corrupted positions when removing
  multiple tracks (indices shifted mid-loop), shuffle_behind indexed
  out of range on an empty play order, insert_tracks shifted play-order
  entries by the queue length instead of the inserted count and then
  assert!()ed on the resulting inconsistency, and clear() left
  play_order stale. All mutation methods are now guarded, multi-remove
  works highest-position-first, and an inconsistent play order is
  rebuilt instead of panicking. Regression tests cover these cases.

- The tidal access token was only obtained at startup and never
  refreshed, so long-running sessions ended with every track fetch
  failing (playback just stopped at the next track boundary). Login
  state now lives behind a lock; tokens are refreshed proactively
  before expiry (5 min margin) and once reactively on a 401, and all
  API responses are status-checked (new ClientError::ApiError) instead
  of being fed to the JSON decoder blind. The http client also got a
  30s timeout so a hung connection cannot wedge the provider loop.

- (from the rodio rewrite, same bug class) end of stream used to be
  detected by string-comparing an io::Error message; any other decode
  or network error ended the stream silently without an EndOfStream
  message, so playback never advanced. EOS is now a guaranteed
  callback with a generation counter.

Plus workspace-wide clippy cleanup (zero warnings), cargo-machete
cleanup, and fmt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 22:00:22 +02:00
AI User 6eb5a87b15 Update all dependencies to current versions
- tonic 0.9 -> 0.14 (tonic-prost/tonic-prost-build split), prost 0.14
- ratatui 0.20 -> 0.30 (Frame no longer generic, Line instead of Spans),
  crossterm 0.29
- rodio 0.17 -> 0.22: replace the custom symphonia decoder with rodio's
  built-in decoder, seeking (try_seek) and position tracking (get_pos);
  end-of-stream is now signalled via an EmptyCallback source with a
  generation counter so a replaced track can never emit a stale EOS
- replace the vendored stream-download crate with the published
  stream-download 0.24 (rustls), with a 30s open timeout
- reqwest 0.12->0.13 (rustls/webpki-roots/query features), base64 0.22
  Engine API, rand 0.10, flume 0.12, thiserror 2, dirs 6, toml 1
- unify everything under [workspace.dependencies]; drop unused deps
  (once_cell, serde_json in server; confique, secrecy in tidaldy)
- devenv: add protobuf (protoc) for prost-build

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:41:10 +02:00
chmanie 51cdf13953 Add stream-download package 2023-06-08 18:55:11 +02:00
chmanie 7f1e7dfd00 Add audio-player PoC 2023-06-08 02:01:49 +02:00
chmanie 596a97c99d Remove crabidy, graphql from cbd-tui 2023-05-23 13:43:48 +02:00
Hans Mündelein 0af8829987
Add cargo-server with liby service draft
It is not smart, fetches everything all the time  and totally hardcoded with the tidal client
But tidal login and library discovery with tidal should somewhat work.
2023-05-22 22:05:38 +02:00
Hans Mündelein 19f19cba2d
Add tidal provider
First draft of tidaldy that implements the crabidy provider trait.
2023-05-22 09:31:02 +02:00
chmanie 73cb9ddbda Add test gRPC server 2023-05-21 14:25:30 +02:00
chmanie 861391f7d8 Add threaded ui model 2023-05-17 23:45:18 +02:00
Hans Mündelein 91e988f722
Add initial draft for core
First attempt for common types and the graphql schema
2023-05-17 18:30:26 +02:00