- GET /api/popular returns the ten most subscribed feeds. The new GET
/api/directory returns every feed that may be listed, sorted by name,
from the same list: everyone counted, you included, never a URL, never
a private feed or a feed inside an OPML. POST /api/popular/{id} still
subscribes to anything on it.
- A Directory button sits beside Popular; both open the same list
screen. The sidebar toolbar wraps rather than squeezing four buttons.
- Tests: the directory is A to Z, Popular is its top ten, Paid Show is
in neither, and subscribing works from the directory.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016HdTEWQNrzyFULijigkmMn
7.4 KiB
7.4 KiB
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
The long form, with what was wrong before and how it was found, is in docs/history.md.
Unreleased
Added
- A Popular button at the top of the feed list opens the popular list without going through Add feed.
- A Directory button lists every feed anyone on this server subscribes to, A to Z
(
GET /api/directory), with the same rules as Popular.
Changed
- Popular shows the top 10, not 20.
- The popular list counts everyone, you included. Your own feeds stay on it, marked Subscribed, and clicking one opens it.
0.3.0 - 2026-09-11
Added
- Add feed lists what other people on this server subscribe to, most subscribers first, and
subscribes you by id (
GET /api/popular,POST /api/popular/{id}). Feeds from an OPML, and feeds with a login or a key in their URL, are never listed. - Upload an OPML file to import, beside the paste box. The page checks it looks like OPML before sending it and clears the picker afterwards.
- Settings → Manage users: add and remove accounts, and choose who is an admin
(
GET/POST /api/users,PATCH/DELETE /api/users/{id}). - Per-user subscriptions, and per-user read, starred and playback state. The existing library is adopted by the admin on first start.
- Subscribing to a feed someone else already has costs no second fetch and no second copy. Scanning merges every subscriber's wants.
- Delete on a shared feed reads Delete for everyone, and the server answers
409while anyone else has starred the item or not played it (?force=trueoverrides). - A shared feed's header says how many other people read it.
docs/for configuration, the CLI, users, SSO and architecture, andCLAUDE.mdfor anyone working on the code.- Browser tests for OPML import and export by every route, user admin, unread ordering, and
ipx import/ipx export.
Changed
- Feeds inside an OPML subscription list the ones with unread items first.
- OPML import subscribes you to every feed in the file.
ipx importsubscribes the first admin. - OPML export lists only your own subscriptions.
- Production runs as a Docker image pushed to
192.168.1.130:5000and recreated withdocker compose. - This changelog follows Keep a Changelog. The long-form entries moved to
docs/history.md.
Fixed
- Importing another account's OPML export subscribed nobody and reported "Imported 0 feed(s)". Feeds it added had no subscriber, so they were never scanned.
- Importing something that is not OPML answered
500. It is now400"that is not an OPML file", refused before anything changes. - Starring stopped protecting a file from the quota and age sweeps once read state became per-user.
Security
- The log is admin-only (
GET /api/logsanswers403, and the Log button is hidden). It names every account, every feed and every failed sign-in. - OPML export no longer hands anyone signed in the whole catalogue, including other people's private feed URLs.
0.2.0 - 2026-09-10
Added
- Web UI served by the daemon: plain HTML and JS compiled into the binary, with feeds, items, filters, search, sanitised show notes and live progress over SSE.
- Player bar with resume, speed, keyboard shortcuts and lock-screen controls.
- Three-pane layout: feeds beside, items above, and the selected item's text and files below.
- Phone layout.
- Accounts and sign-in: Argon2id passwords, session cookies,
ipx user add|list|passwd|rm, and a trusted proxy header for Cloudflare Zero Trust or Authentik (docs/sso.md). - Subscribing to an OPML: it is re-read every scan and its feeds show as a folder. A feed dropped from it is removed unless it has downloads.
- Scheduling: a global interval with per-feed overrides (
every 30m,4h,1d,2w). [general] media_types, default audio and video, andmax_new_per_check, default 3.- Every enclosure of an item, a View link for files that are not audio or video, and per-item artwork.
- In-app log view with Daemon I/O, Scans and HTTP tabs.
- Mark all read on an OPML subscription.
- Editable feed URL with a copy button.
- Docker image whose healthcheck goes through the control socket.
- The iPodderX name, icon, and a colour scheme taken from the icon.
tests/page-smoke.jsand a Playwright browser suite.
Changed
- Global settings and scan schedules are admin-only. The per-feed schedule picker is gone.
- Feeds from an OPML live in the database, not
config.toml. - Opening an item marks it read. Playing it marks it read only at the end or past 90%.
- "Episodes" became "items", since half the library is text.
- A burst of scan events causes one refresh, not one per feed.
- All is the default filter. OPML import and export, Settings and Log moved out of the header.
- Torrents run detached, two at a time.
Fixed
- Download fetched the next queued episodes instead of the one clicked.
- Pressing play made an item vanish from the Unread list.
- Clearing a folder, schedule or cap from the UI did nothing.
- The daemon ignored SIGTERM until the current download finished.
- A missing function stopped the page script and left the whole UI dead.
- One download painted progress on every pending row.
- A torrent could freeze scanning for up to an hour.
- Downloading from an OPML feed failed with "belongs to unsubscribed feed".
- Image enclosures were downloaded, counted as episodes and given a play button.
- A feed whose entries had been deleted stayed empty, because the server kept answering
304. - An item with several enclosures kept only the last.
- OPML folders rendered open by default.
- Mark read in the text pane recursed until the stack overflowed.
- The Unread, Downloaded and Flagged filters answered
500without a search term. - An OPML subscription always showed 0 unread.
- Folder names kept doubled spaces where separators were stripped.
- Sidebar rows had four different left edges.
Security
- The web UI needs a token or a sign-in. The token is compared in constant time, and an empty token refuses to serve.
- Show notes are sanitised with
ammonia. - A proxy's user header is honoured only from an address in
trusted_proxies. - A feed URL must be http(s), so
file:///etc/passwdis refused. - Download folders are sanitised per path segment, so
../../etc/Showcannot climb out.
0.1.0 - 2026-09-09
Added
ipx, a Rust rewrite of the iPodderX engine: TOML config, SQLite state, andipx list,add,rmandfetch.- RSS and Atom parsing with conditional GET,
<ttl>and basic auth. - Streaming downloads with explicit, keyword and per-scan filters, deduplicated by enclosure URL.
- Quota and age retention that never touches a starred file, and
ipx reap [--dry-run]. ipx daemonwith a JSON-lines Unix socket. CLI commands proxy to a running daemon.- Torrent enclosures through librqbit, seeding to a ratio or a time, with a stall timeout.
ipx importandipx exportfor OPML, and systemd units incontrib/.