Files
ipx/docs/users.md
rays ef8e2526f2 Show what a feed says it is on its page in the Directory (#130)
A feed's page in the Directory (#128) had its cover, category and latest items, but not the
feed's own description, which Apple's show page leads with: iPX read every item's description
and threw the channel's away, and the feeds table had nowhere to keep it.

It is parsed now, RSS's <description>, or iTunes' summary when that is empty, or Atom's
subtitle, kept in feeds.description (kept when a later read has none, as title and image are),
and sent, sanitized, with the items from /api/directory/{id}, which is now an object, not a
list. The page shows it as plain text under the header, three lines of it, with More when there
is more. A description that only repeats the title is left out.

feeds.description is the first column added to a table that already exists. create_missing
looks for it with a SELECT and runs the ALTER only when it is missing, since it runs on every
open, the healthcheck's included, and an ALTER's lock is what made that time out before. The
same once-only step forgets every feed's ETag and Last-Modified: a feed is read whole only when
it has changed, so its description would otherwise wait for its next item.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 16:46:22 +00:00

105 lines
5.3 KiB
Markdown

# Accounts, and what several people share
ipx serves any number of people from one copy of the data. The rule that decides everything else:
**there is one file on disk per enclosure URL.** Two people subscribed to the same show cost one
fetch, one parse and one file.
## What is yours, what is everyone's
| Yours alone | The same for everyone |
|---|---|
| Read, pinned, playback position | The feed's URL |
| Which feeds you see at all | Its download folder |
| Keywords, auto-download, explicit, per-scan cap | When it is scanned |
| | The file on disk |
The right-hand column describes the feed and the file rather than a preference — two people wanting
different folders would mean two copies. Those three are **admin-only**, and the API returns `403`
for anyone else rather than merely hiding the controls.
## How the scanner merges everyone's wants
One fetch serves every subscriber, so the policy is a union:
* an item is downloaded if **anyone** wants it — one person's keyword set matching is enough, and
one person with no keywords removes the filter for that feed entirely
* auto-download is on if **anyone** has it on
* the per-scan cap is the **largest** anyone asked for
So "auto-download off" means *I don't cause downloads*, not *I never see them*. If someone else's
subscription pulls an item, you see it listed as downloaded and can play it, because the enclosure
is shared.
## Deleting
Deleting a file deletes everyone's copy. A feed with other subscribers labels the button **Delete
for everyone** and names them in the confirmation, and the server has the last word: if anyone else
has pinned the item or not played it yet, `DELETE /api/enclosures/{id}` answers `409` with the
reason, and only `?force=true` goes through.
Retention follows the same rule: an item anyone pinned keeps its file, and it counts as read only once
every subscriber has read it.
## Signing in
Three ways, tried in order of how specific the claim is:
1. **A proxy header** naming the user — Cloudflare Zero Trust or Authentik. Honoured only from an
address in `trusted_proxies`. See [sso.md](sso.md).
2. **A session cookie** from signing in at `/login`. Argon2id hashes, sessions in the database,
idle timeout `session_days`.
3. **The shared `[web] token`**, which signs in as the admin — this is what the Docker healthcheck
and any scripts use.
A database with no accounts creates **admin / ipodderx** on the next daemon start and says so in
the log. Change it:
```sh
echo -n 'a good password' | ipx user passwd admin
```
## Adding someone
```sh
echo -n 'their password' | ipx user add sam
```
They sign in at `/login` and start with **no feeds**: subscriptions are per person. Adding a feed
someone else already has costs nothing — no second fetch, no second copy — it just appears on their
list with their own read state. Unsubscribing removes it from their list alone; only when the last
subscriber leaves does the feed stop being scanned, and even then its files and history stay, so
re-subscribing does not pull the back catalogue again.
**Directory** sits at the top of the feed list, above your own feeds. It opens on the ten feeds
with the most subscribers on this server, you included, ranked, then the categories, each a tile
showing a few of its shows' covers. A category has a page of its own: its most subscribed feeds,
then all of them as a grid of cover art, with its subcategories along the top (Tech News under
News, Video Games under Leisure) and a choice of order. See all lists every feed, and the search
box finds one by name. A feed you do not subscribe to opens a page of its own, with what it says it
is and its latest episodes or posts, so you can see what it is first. Every page can be narrowed to Podcasts (anything with audio or video) or
Blogs (the rest). A show's category is the one it gives itself in iTunes, or for one that names
none, one an admin or iPX picked for it. Your own feeds are marked Subscribed.
It shows a title, artwork and a count, never a URL or who reads it. An OPML subscription is listed
as the feeds inside it, one by one, and never the OPML itself, so you can take just the shows you
want. Anything that looks private is left out: a login configured for the feed, credentials in its URL,
or a key such as `auth=` or `token=` in the query, or a feed from a paid-feed service such as
Patreon or Supercast, which put the key in the path, and any feed inside an OPML that looks private
itself. Those are someone's paid subscriptions, and listing them would let anyone here read what
they pay for.
An admin can do the same from **Settings → Manage users…**: add someone (with a password, or none
for someone the proxy signs in), tick or untick Admin, or remove an account. Removing one takes its
subscriptions and read state with it; downloaded files stay. The only admin cannot be demoted or
removed there, so there is always someone who can manage the rest.
## Admin
The first account is an admin. An admin can change global settings (scanning interval, quota,
retention, media types, download folder), a feed's URL, folder and schedule, and who has an account
and who else is an admin, and read the log, which names everyone's feeds and sign-ins. Everyone else
gets the Settings and Log buttons hidden and a `403` if they ask anyway.
```sh
ipx user list # the admin column says who
```