The Directory was one grid of every listed feed, 1,472 in production, under Podcasts and Blogs tabs, a wall of about 30 category buttons and a sort menu, with a picked category's subcategories appearing as a second row of buttons that looked like the first. It read as a list to scroll, and the two rows were hard to tell apart. It opens now on the ten most subscribed feeds, ranked, and the categories as tiles, each with three of its shows' covers fanned in its corner on the tint its initials would get, so the shows colour it and no theme's palette changes. A category has a page of its own: its most subscribed, its subcategories with how many each holds, and its grid. See all is every feed, as the grid was. Podcasts or Blogs holds across every page. Popular, the ten most subscribed, had a place of its own in the feed list; it is the Directory's first section instead, and its key, g p, is gone. /api/popular stays for scripts. The search box finds a feed in the Directory by name (#126). It said "Search items…" there and did nothing, since loadEntries returns early for a place that lists feeds. A feed you do not subscribe to opens a page of its own (#128): its cover, category (a link to that category's page), how many here subscribe, a subscribe button and its latest twenty items, each with its title, linking to the post where it has one, its first lines, date and length. Before, a click on it did nothing; only its + did. The items come from GET /api/directory/{id}, which answers only for a feed the Directory lists, so a guessed id reaches nothing private, and carries no file or its address. The feed's own description would belong at the top, but the database does not keep one. Every tile and chart row takes the keyboard, as the feed list's rows do. Feed text made plain keeps a space at a line break or a paragraph's end, which glued "2010)Recorded" together. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
105 lines
5.2 KiB
Markdown
105 lines
5.2 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 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
|
|
```
|