Commit Graph

29 Commits

Author SHA1 Message Date
Test User 659e678522 Web client: prompt for login on visit when auth is enabled
The browser client already sent stored credentials and showed a login
form, but only when the server answered UNAUTHENTICATED -- i.e. only
when every role was guarded. With a fallback role configured, an
anonymous browser silently connected as that role and was never offered
a way to log in as a higher one.

The server now reports its auth on/off switch on the InitResponse
(auth_enabled, field 8), which is reachable anonymously. The RPC handler
stamps it from Authenticator::enabled(); the playback loop, which owns
queue state and not the auth config, leaves it false.

On first connect with no stored credentials against an auth-enabled
server, the web client raises the login dialog. It is dismissible --
"continue as guest" keeps the unauthenticated fallback role -- and is
shown once per session so stream reconnects do not nag. When the server
denies anonymous access outright (UNAUTHENTICATED), the same dialog
appears without the guest option, because credentials are then the only
way in.

Docs: architecture/roles-auth.md and web-client.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 17:51:55 +02:00
Test User 21d4fddb2f Design the crabidy content store; add wire + fsdy foundations
Stage 1-2 of the crabidy-store dev-flow (architecture/crabidy-store.md,
quality/, plan/): one /crabidy provider replacing queues/bookmarks/
captures, with track tomls linking into a content-addressed store that
de-duplicates by provider id and content hash.

Additive, build stays green:
- proto: Track.provider_item_id + is_captured; LibraryNode.is_captured;
  LibraryNodeChild.is_captured (swept all literals).
- fsdy: Playable::Store + PlayableSpec.store, 5-way cardinality,
  from_track_store, Client.with_store_root + store resolution.
- crabidy_store.rs: StoreSidecar/ProviderEntry/StoreIndex/CrabidyStore
  type + method surface (bodies stubbed for the implement stage).
- supersede bookmarks/captures/capture-deletion docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 10:58:11 +02:00
Test User 572be04206 Add a server-streamed frequency spectrum visualizer
A row of frequency bars under the track progress, on by default and
toggleable with the client spectrum config option. Because the audio
plays on the server and clients may be remote, the spectrum is produced
server-side, not captured locally: audio-player taps its own output
into a lock-free ring on the audio thread (one store per sample, no
locks), crabidy-server runs a Hann + realfft over 2048 samples at 20fps,
folds it into log-spaced bars, and broadcasts them as a new SpectrumFrame
on the update stream. The task idles when nothing is playing or no
client is listening. The TUI renders block-glyph bars in the now-playing
pane; the web client renders the same bins as CSS bars.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 23:14:03 +02:00
Test User 1c83217745 Delete captures from disk at any depth, behind a confirmation
Deletion (d) previously reached only top-level folders of editable
stores. /captures now exposes its whole tree: nested folders delete
recursively, single tracks delete their metadata file plus the
downloaded audio next to it (never audio outside the instance root).
Tracks advertise this through the new LibraryNode.tracks_deletable
flag. Because these deletes destroy slow-to-redo downloads, the TUI
asks delete <title>? [y/N] first; cheap deletables (search terms,
bookmarks, saved queues) stay unconfirmed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 20:34:03 +02:00
Test User 214dece19f Make download captures incremental with skipped tracks and progress
Download captures now write straight into captures/<name>: satisfied
entries are reused, uncapturable tracks are recorded as skipped tomls
(a new fourth playable, marked red in the TUI and skipped by playback
with a bounded pass), and a failed run keeps its progress so capturing
the same name resumes it. The capture RPC replies on acceptance and
streams CaptureProgress over the update stream, rendered as status
lines in the library pane; help and the input overlay warn that
captures are slow. Colored list items switch to a dark foreground
under the focused selection bar so they stay readable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 15:45:04 +02:00
Test User 7f0e900c56 Capture library subtrees with downloaded audio
W on a downloadable library node mirrors the subtree into /captures
(a fourth fsdy instance) like a bookmark, but downloads every track's
audio next to its toml; the toml points at the sibling by relative
name, so captures play with no provider round trip. Nodes opt in via
the new is_downloadable flags — Tidal blesses queueable and
track-listing nodes. The bookmark walk is now the shared capture walk
parameterized by a per-track sink.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 13:45:04 +02:00
Test User 655e8054b8 Capture library subtrees as bookmarks
w on a queueable library selection snapshots the whole subtree into a
third fsdy instance at /bookmarks: the orchestrator walks the source
iteratively and mirrors it as order-prefixed folders of link track
files (shared naming with queue persistence), tmp-and-swapped with
size caps so a runaway tree cannot fill the disk. One additive rpc,
CaptureLibraryNode(path, name), carries the flow; the TUI reuses the
input overlay prefilled with the selection title.

fsdy instances can now opt into an editable top level: root child
folders carry is_editable/is_deletable and support no-merge rename and
idempotent delete. /bookmarks mounts with it, and /queues too
(reserving current), so saved queues are renamable and deletable
through the existing e/d flows without TUI changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 11:11:27 +02:00
Test User ccab43a133 Queue large collections progressively
Resolving a nested node used to collect every track before the queue
changed: one broadcast at the very end, playback only after the full
walk, and the playback loop blocked for the duration. Now provider
resolution streams bounded chunks (tidaldy: one per 50-track page), the
playback loop applies and broadcasts each chunk as it lands, playback
starts with the first chunk, and Replace/Clear cancel in-flight
resolves down to the HTTP fetch. Queue.resolving (additive proto field)
drives an animated-dots pseudo-item in the TUI queue pane.

Also fixes Enter on a non-queueable library item blanking the queue
while audio kept playing, and the reversed album order left by the old
LIFO walk.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 01:08:34 +02:00
Test User 333c6e040a Add rename and delete for modifiable library nodes
Search-term nodes created via % are now modifiable: e renames the
selected node (prefilled overlay; the new title re-runs the search,
colliding titles merge) and d deletes it, both gated on new additive
LibraryNodeChild.is_editable/is_deletable flags and marked [ed] in the
library list. Two new rpcs follow the create contract: RenameLibraryNode
returns the renamed node (the TUI navigates into it), DeleteLibraryNode
returns the refreshed parent listing. Queued tracks from a renamed or
deleted term keep playing; verified end-to-end against the live API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 23:34:47 +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 56bc0b0d04 Refactor provider addressing to filesystem-like paths
Identifiers like node:tidal / node:playlist:<id> / track:<id> are
replaced by absolute, hierarchical paths that encode the position in
the library tree:

  /                                  global root
  /tidal                             provider root
  /tidal/playlists/<id>              playlist (tracks inside)
  /tidal/playlists/<id>/<track>      track
  /tidal/artists/<id>/<album>        album
  /tidal/artists/<id>/<album>/<t>    track

- proto: uuid -> path, uuids -> paths (same field tags, wire
  compatible); crabidy-core gains ROOT_PATH, parent_path, join_path,
  path_segments helpers with unit tests
- ProviderClient gains is_track_path; the orchestrator routes by path
  prefix and exposes a single ResolveTracks command (track path ->
  that track, node path -> flattened subtree), replacing the
  track:-prefix sniffing in the playback loop
- tidaldy parses paths into a typed TidalPath enum; node parents are
  derived from the request path, which removes the album.artist
  unwrap() panic; the network-dependent scratch test is #[ignore]d
- TUI navigates by paths

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:53:12 +02:00
Hans Mündelein 5d1a62c630
Add exclude current clearing for the server
stable / cross-${{ matrix.target }} (aarch64-unknown-linux-gnu) Details
stable / cross-${{ matrix.target }} (armv7-unknown-linux-gnueabihf) Details
stable / cross-${{ matrix.target }} (x86_64-unknown-linux-gnu) Details
stable / fmt Details
2023-06-12 22:18:34 +02:00
Hans Mündelein 18671683ff
Add clear queue to server
stable / fmt Details
stable / cross-${{ matrix.target }} (x86_64-unknown-linux-gnu) Details
stable / cross-${{ matrix.target }} (armv7-unknown-linux-gnueabihf) Details
stable / cross-${{ matrix.target }} (aarch64-unknown-linux-gnu) Details
2023-06-12 20:49:37 +02:00
chmanie e71398d243 Add proto definition for ClearQueue
stable / cross-${{ matrix.target }} (aarch64-unknown-linux-gnu) Details
stable / fmt Details
stable / cross-${{ matrix.target }} (armv7-unknown-linux-gnueabihf) Details
stable / cross-${{ matrix.target }} (x86_64-unknown-linux-gnu) Details
2023-06-12 20:23:22 +02:00
chmanie 25e2e3ff83 Add is_queable prop to LibraryNodeChild 2023-06-09 17:08:44 +02:00
chmanie 3b84583e5c Move shuffle and repeat to QueueModifiers 2023-06-09 16:43:20 +02:00
chmanie 7f63a50ced Pluralize arrays in protobuf 2023-06-09 16:30:07 +02:00
Hans Mündelein 9be9039a05
Add shuffle and repeat for server 2023-06-09 16:02:35 +02:00
Hans Mündelein 4fbeccdde1
Implement init on the server 2023-06-02 19:20:30 +02:00
Hans Mündelein 5a42ddfbdb
Adjust server to new proto spec 2023-06-02 18:41:19 +02:00
chmanie 1e7203a9f5 Add spec for shuffle 2023-06-02 15:39:42 +02:00
chmanie 47b788bf9c Rename Queue current to current_position 2023-06-02 15:33:15 +02:00
chmanie fac450900c Complete overhaul of protobuf spec 2023-06-02 14:36:47 +02:00
Hans Mündelein ffec874584
Add title to LibraryNodeChildren 2023-05-26 16:22:29 +02:00
Hans Mündelein 035fdf1a4b
Add draft of working tidal playback
Streaming yet to come.
2023-05-26 12:06:35 +02:00
Hans Mündelein f4bb7c3872
Remove shared messages in proto spec 2023-05-23 12:18:58 +02:00
chmanie 248c833280 Fix proto lint issues as much as possible 2023-05-23 00:04:15 +02:00
Hans Mündelein b5f722f1cb
Disentangle conflicting proto versions
We diverged in working on the proto definition, which should now be
resolved.
2023-05-22 11:02:42 +02:00
chmanie b6bbd540dd Follow some guidelines for proto notation 2023-05-21 13:47:07 +02:00