Sweep of docs/ and every README against the code, after several features landed since the last one. Mechanical checks, which find what reading does not: SUMMARY covers every page and no more; every relative link resolves (docs/src/providers.md pointed a directory above the book, twice); every #anchor matches a real heading; every provider crate's Settings field is documented in both its README and its book page; the feature table matches Cargo.toml, which it did not -- `rss` was missing and "seven provider features" is now eight. Prose that predated recent work: the root README's client-config sample knew only `spectrum` and still claimed every option has a flag; its spectrum and web-client sections predated the colors, segments, shadows, pane tabs, register and seek; cbd-web/README.md likewise; intro.md's provider tree was missing /rss; clients.md omitted volume and mute from what the update stream carries; rssdy/README.md did not mention that only audio enclosures become episodes. The audit also found a defect the docs were right about: `Seek` was never added to `minimum_role`, so it fell through to the owner-only default while auth.md and architecture/roles-auth.md both promise a queue-owner may control playback. With auth configured a queue-owner could play, skip and change the volume, but got PermissionDenied on `,`/`.`. Seek now sits with the other playback verbs. The test meant to prevent that -- "a new RPC must be added to exactly one list" -- compared the role lists against a hardcoded 24, so a 25th method kept the suite green. It now reads the method names out of crabidy.proto and compares sets: a count copied out of a file is not a check against it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| src | ||
| Cargo.toml | ||
| README.md | ||
README.md
rssdy — the RSS podcast provider
Mounts the podcast feeds you subscribe to at /rss in the crabidy
library. Works with plain public feeds and with premium per-subscriber
URLs, and always shows the newest episodes.
Logging in
There is no login. A feed is either public or its URL is the credential — a paid podcast gives you a URL with a token in it:
https://feeds.economist.com/v1/rss/the-economist-podcasts/f74365b0-…
Anyone holding that URL has your subscription, so the provider treats it as a
secret: it is redacted from Debug, never logged, and never put in a
library path. Paths carry a slug of the subscription name and a hash of the
episode id instead — paths are displayed, logged, and persisted into saved
queues and bookmarks, so a URL in one would leak everywhere.
Keep rss.toml private; it holds the URLs in cleartext, like every other
provider credential.
Subscribing
Either edit the config (below), or from a client: press % on /rss, paste
the feed URL, and the provider fetches it once, names the subscription from
the feed's own title, and writes it into rss.toml. e renames a
subscription (its path changes with the name), d unsubscribes — that only
removes the config entry, never audio you captured from it.
How it works
/rss
├── <subscription> one node per feed, newest episodes first
│ └── <episode> a track; audio is the feed's enclosure URL
└── …
A subscription is queueable and downloadable, so you can queue or W-capture
a whole feed. Episodes stream directly from the enclosure URL — no sidecar,
no helper binary.
Only audio enclosures become episodes: an item is taken when its
enclosure type says audio, or when the type is missing or generic and the URL
looks like audio (including extensionless /feed/mp3-style URLs). Video and
image enclosures are skipped, so a show that publishes both plays its audio
and a blog feed does not list its featured images as tracks. See
docs/src/providers/rss.md for the exact rule.
Nothing is cached. Every visit to a subscription fetches the feed, so an episode published a minute ago is there. One memo exists purely so that listing a feed and then queueing its 40 episodes costs one fetch rather than 41: it is written by listings and read only when resolving a track, so it can never make a listing stale.
Episode paths are blake3(guid)[..16], which is stable as long as the
publisher keeps its guids stable. Two consequences worth knowing:
- A bookmark (
w) to an episode that has since aged out of the feed cannot resolve — there is nothing left to look up. Capture (W) what you want to keep. - A publisher that regenerates guids on every fetch invalidates bookmarks. Nothing can be done about that from this side.
Configuration — ~/.config/crabidy/rss.toml
# One table per subscription. `name` is yours and decides the path slug;
# duplicates get a numeric suffix.
[[feeds]]
name = "The Economist Podcasts"
url = "https://feeds.economist.com/v1/rss/…"
[[feeds]]
name = "Cautionary Tales"
url = "https://feeds.example.org/cautionary-tales"
# Optional, defaults shown.
# episodes_per_feed = 200 # episodes listed per feed
# call_timeout_secs = 30 # per-request timeout
# max_feed_bytes = 33554432 # 32 MiB cap on a feed body
A feed entry with no url is skipped with a warning. No feeds at all is fine:
/rss mounts empty and you can % into it.
Notes
- Feeds are read as RSS 2.0/1.0/0.x, Atom, or JSON Feed via
feed-rs. itunes:durationis parsed here rather than taken fromfeed-rs, which reads it as NPT — a format with noMM:SSform, so53:25came back as 53 seconds.S,MM:SSandHH:MM:SSall work now.- Build the server without the
rsscargo feature to leave this provider out of the binary entirely.