The last nineteen functions move to SeaORM: recording feeds, items and enclosures, managed OPML feeds, folding WordPress's repeated files, and handing a Patreon creator's files to its shows. Two SQLite-only forms go: GLOB becomes a LIKE with the underscore escaped (broader, harmlessly: the fold still keys on `_=` and digits), and UPDATE OR IGNORE becomes an UPDATE ... WHERE NOT EXISTS. The two transactions are SeaORM transactions. With nothing left on it, rusqlite goes, with the SQL schema and migrate(). The entities are the schema: create_missing makes whatever tables and indexes a database lacks, from them, with CREATE ... IF NOT EXISTS. Production's schema already has every column migrate() added and none it dropped. Not SeaORM's schema sync, used until now: despite its docs it drops a unique index the entities do not describe, so it dropped users_name_lower on every open. Every `ipx` command then took a write lock, and against a daemon busy writing, `ipx status` -- the healthcheck -- failed 7 times in 15 where the old code failed none. Now 15 in 15, as before. On Postgres it would not have started. WAL is set only when a file is not already in it: setting it takes a lock that cannot wait out a busy daemon. Checked on copies of production: a forced scan of all 162 feeds against the real feeds with no database errors; the feed list, filters, sorts, search and the reaper's candidates against the old code on the same data, earlier in the branch. The column comments from the SQL schema move to the entities. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
509 lines
28 KiB
Markdown
509 lines
28 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to this project will be documented in this file.
|
||
|
||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||
|
||
## [Unreleased]
|
||
|
||
### Changed
|
||
|
||
- The database is reached through SeaORM, on the way to Postgres (issue #18); it is still the
|
||
same SQLite file, and nothing you see changes. A database from before 0.7 has to be opened by a
|
||
0.7 release first, which brings its tables up to date.
|
||
- A pinned item sits at the top of its list, above everything else in whatever order you sort
|
||
by, and moves there the moment you pin it. Sorting by the pin column itself still goes both
|
||
ways, and Currently Listening keeps its own order.
|
||
|
||
## [0.7.0] - 2026-09-18
|
||
|
||
### Added
|
||
|
||
- Six more themes in Settings: Dracula, Material, Adwaita, Flat Remix, Paper and Nordic, beside
|
||
Classic and Modern (the existing dark and light). Each that comes both ways has its own Light,
|
||
Dark or Auto setting; Classic and Paper come one way only, so that setting is hidden for them.
|
||
A theme chosen before this carries over.
|
||
- Your theme is kept on your account rather than in the browser, so it follows you to another
|
||
browser or computer, and the page arrives in it with no flash of the default. The theme a
|
||
browser already had is saved to your account the first time you load the page.
|
||
- Pin a feed to the top of the feed list with the pin on its page, a feed from inside an OPML or
|
||
Patreon folder included, which comes out of the folder while pinned. Pins are yours alone.
|
||
- Touch gestures: pull the item list down from its top to check the feed for new items, and
|
||
swipe the item you are reading left for the next one and right for the one before, or back
|
||
to the list from the first.
|
||
|
||
### Changed
|
||
|
||
- The server's settings, the accounts and the log are on their own admin page, /admin, reached by
|
||
the wrench in the header. Only an admin is sent the page, its script, or the link to it.
|
||
Settings is now yours alone: your theme and your subscriptions.
|
||
- A feed that fails to check gets a red exclamation mark in the feed list, in the margin where a
|
||
folder's triangle sits, and its page says why, in place of a pop-up per failure that everyone
|
||
saw during a scan of every feed. A folder holding a failing feed has its triangle turn red.
|
||
- The theme is chosen in Settings only; the button beside the iPodderX name is gone.
|
||
- Add a feed asks only for the feed; Popular and Directory in the sidebar are where you browse.
|
||
- On a phone, an item's files, with play and delete, sit above its show notes rather than below
|
||
them, where long notes left them looking missing.
|
||
- On a phone, an item with no files goes straight to its text, without a box saying "No files".
|
||
- The page is served minified, about a quarter smaller. Its script is now TypeScript in
|
||
`web/src`, type-checked, and built with swc; building ipx needs node.
|
||
- The script is its own file, `/app.js`, rather than inside the page. Your browser keeps it
|
||
between visits and fetches it again only when an update changes it.
|
||
|
||
### Fixed
|
||
|
||
- Switching tabs straight after marking everything read no longer shows the previous tab's
|
||
items: of two lists asked for at once, only the later one is shown.
|
||
- ipx has a favicon: the logo, squared up, also at /favicon.ico for browsers that ask there on
|
||
their own, and on white for an iPhone's home screen.
|
||
- The file icon of an item not yet downloaded sits level with the rest of its row, instead of
|
||
higher than a downloaded one's.
|
||
- Images in posts from sites that refuse images to other sites' pages, such as Jeff Geerling's,
|
||
now show: ipx asks for them without saying it is the page showing them.
|
||
- While an episode plays, its play buttons in the files pane, its row and the toolbar show
|
||
pause, as the player bar's does, and pause it when pressed.
|
||
- An item you open stays read. A list refresh that crossed with marking it read could put its
|
||
unread dot back until the next refresh.
|
||
- On the Unread tab, the item you were reading leaves the list as soon as you move to the next
|
||
one, rather than a few read items lingering until a refresh cleared them.
|
||
- The Log button no longer shows for a moment on every load for anyone but an admin; the server
|
||
leaves it out of their page.
|
||
- An image or link in a post given relative to the post, such as The Observation Deck's, now
|
||
points at the post's site rather than at ipx, and shows.
|
||
|
||
## [0.6.1] - 2026-09-15
|
||
|
||
### Fixed
|
||
|
||
- Time left, and when an episode counts as finished, go by the length your player measured
|
||
rather than the feed's, which can be minutes out: one episode said 0:08 left with 2:33 to play.
|
||
- A player left open in another tab or on another device no longer saves its older place over
|
||
where you have got to since, which could drop an episode out of Currently Listening.
|
||
|
||
## [0.6.0] - 2026-09-15
|
||
|
||
### Added
|
||
|
||
- Each episode in Currently Listening has a cross that takes it off the list. It forgets where you
|
||
got to, so playing it again starts from the beginning.
|
||
- An admin can give a feed a Directory category in its settings (`category` in config.toml), for
|
||
the blogs and other feeds that name none of their own. A feed's own iTunes category still wins.
|
||
- Keyboard shortcuts after Feedly's: j and k through items, Shift-J and Shift-K through feeds,
|
||
g and a letter to go to a place, o to play, s to pin, and more. Press ? for the whole list.
|
||
- Directory can be filtered to Podcasts or Blogs, and by each show's own iTunes category as a row
|
||
of chips, the narrower one where a show gives two (Games, not Leisure). The two combine, and
|
||
both filter in place.
|
||
|
||
### Changed
|
||
|
||
- Currently Listening marks the episode in the player with the EQ bars, as the item list does,
|
||
and its progress and time left move as it plays. Each row says how much is left.
|
||
- Directory shows each feed as its cover art in a grid, title and subscriber count underneath,
|
||
instead of a list. Popular and the Add a feed dialog keep their rows.
|
||
- The pages are set in Inter, served by ipx itself. Classic keeps Lucida Grande.
|
||
- Keeping an item is now pinning it: a thumbtack in place of the flag, and Pin, Pinned and Unpin
|
||
in place of Keep, Kept and Stop keeping. A pinned item is still never deleted.
|
||
- Currently Listening is its own place in the feed list, below Popular, instead of a section at
|
||
the bottom of the Popular page.
|
||
- The first scan after upgrading fetches every feed in full once, on its usual schedule, so each
|
||
picks up its category without waiting for the publisher to change something.
|
||
|
||
### Fixed
|
||
|
||
- An episode that fails to load, or is paused before it has, no longer forgets where you left off
|
||
in it, and so no longer drops out of Currently Listening.
|
||
- Currently Listening lists the episodes you have started. It left out anything marked read, and
|
||
opening an episode marks it read, so it usually showed nothing. An episode now leaves the list
|
||
once 90% of it has played.
|
||
- A WordPress post that embeds the file it encloses no longer lists, and downloads, that file
|
||
twice. Items that already had it twice are folded into one at startup, and the spare copy
|
||
deleted.
|
||
- The pinned column's heading lines up with the pins under it, and every heading sits a pixel
|
||
further right, over its column.
|
||
- The feeds left behind by an OPML subscription removed before ipx retired them are cleared at
|
||
startup: forgotten if nothing was downloaded, kept as orphaned if something was. Feeds from it
|
||
that have since been given their own settings stay as they are, with their items. Removing an
|
||
OPML or Patreon subscription no longer deletes the items of a feed inside it that has its own
|
||
settings.
|
||
- Titles that arrive as HTML, such as The Verge's, no longer show their entities as text:
|
||
"Meta’s" reads "Meta’s". Titles already stored are corrected the next time their feed
|
||
changes.
|
||
|
||
## [0.5.5] - 2026-09-14
|
||
|
||
### Changed
|
||
|
||
- A feed whose site sends a message instead of the feed, such as "Unable to establish a DB
|
||
connection", now shows that message and is flagged as the publisher's problem, instead of two
|
||
parser errors about reaching the end of input.
|
||
|
||
### Removed
|
||
|
||
- An unused icon glyph (`minus`) left over from before Unsubscribe settled on `circleMinus`.
|
||
|
||
### Fixed
|
||
|
||
- Add a feed opened over Directory or Popular now shows its Popular list instead of staying on
|
||
"Loading…", and no longer cuts the Directory behind it down to ten.
|
||
|
||
## [0.5.4] - 2026-09-14
|
||
|
||
### Added
|
||
|
||
- Currently Listening, below Popular: episodes you started and have not finished, across every
|
||
feed you subscribe to. Tap one to pick up where you left off.
|
||
- Theme has an Auto option, alongside Dark, Light and Classic, that follows your system's
|
||
light/dark setting. All four are now also in Settings, as a dropdown next to the header
|
||
button's one-click-at-a-time toggle -- the same setting either way.
|
||
|
||
### Changed
|
||
|
||
- The feed (or Directory/Popular/All Subscriptions) and the tab you had open are remembered
|
||
across a reload or a new visit. A feed you no longer subscribe to, or a first visit with
|
||
nothing remembered yet, lands on All Subscriptions instead of the first feed alphabetically.
|
||
|
||
### Fixed
|
||
|
||
- On iOS, the topbar (the hamburger menu included) could stop responding to taps until a hard
|
||
refresh. The page sized itself with `100vh`, which iOS Safari measures against the address
|
||
bar's collapsed state rather than what is actually visible; `100dvh` tracks the real viewport
|
||
as the bar shows and hides.
|
||
|
||
## [0.5.3] - 2026-09-14
|
||
|
||
### Added
|
||
|
||
- A feed that has been failing for a day shows a plain-English reason in the sidebar and on its
|
||
own page, sorted from a 404, a 401/403, a 402, a name that no longer resolves, or a web page in
|
||
place of the feed -- with Unsubscribe or, when the page links its new feed, Use the new address.
|
||
A feed that fails once and reads fine again within a day is never flagged.
|
||
|
||
### Changed
|
||
|
||
- Unsubscribing from the last person's OPML or Patreon subscription now retires the feeds it
|
||
listed, the same as a feed the list itself drops: removed if nothing was downloaded, kept and
|
||
marked orphaned otherwise. Until now they stayed in the database and kept being scanned hourly
|
||
with auto-download on, which is how 922 defunct `davewiner` feeds outlived the OPML that listed
|
||
them.
|
||
|
||
### Fixed
|
||
|
||
- A feed whose XML uses a bare `&` instead of `&` (kcpw, both feedland feeds) is now read
|
||
instead of refused.
|
||
- A feed URL that now serves a web page says so, and names the feed the page links to when it has
|
||
one, instead of a raw XML parser error.
|
||
- A publisher answering with an empty body (British Antarctic Survey's 202) is read as nothing new
|
||
to report, not a parse failure.
|
||
- A link in an item's show notes opens in a new tab instead of navigating away from ipx.
|
||
- A video file plays as video, in a small floating pane above the player bar, instead of silently
|
||
as sound only.
|
||
- On the Unread tab, opening an item no longer makes it disappear from the list -- it stays until
|
||
you open a different one, even if a scan finishes and refreshes the list while it is open.
|
||
- Subscribe and Unsubscribe have their own icons (a circled check and a circled minus) instead of
|
||
sharing the generic plus and minus used for adding feeds, users and imports.
|
||
- Settings no longer disappears for a non-admin account. It was hiding the whole Settings modal
|
||
along with the log and the users screen, but a non-admin has settings of their own in there --
|
||
their subscriptions' Export and Import, and the schedule and quota are worth seeing even without
|
||
a say in them. Only the log and the users screen, which the server also refuses them, are gone.
|
||
|
||
## [0.5.2] - 2026-09-12
|
||
|
||
### Added
|
||
|
||
- Settings → Users and `ipx user list` show when each account was added and when it last signed
|
||
in, to the hour.
|
||
- `ipx user rename <name> <new name>` renames an account and keeps its feeds, read state and admin
|
||
rights. An account made before the proxy was set up can take the name the proxy signs it in as.
|
||
|
||
### Changed
|
||
|
||
- Directory and Popular list the feeds inside an OPML one by one, and no longer the OPML itself,
|
||
so you can subscribe to just the shows you want.
|
||
- The database no longer records when subscriptions and sign-in sessions were created. Nothing
|
||
ever read it, and an existing database drops the columns on its next start.
|
||
|
||
### Fixed
|
||
|
||
- Show notes that the podcast's host cut off in the middle of a tag no longer open with a scrap of
|
||
HTML: the item's other copy of its notes is used instead, from the next time the feed changes.
|
||
Daily Meditation Podcast had 57.
|
||
- Docker no longer shows ipodderx as starting, or calls it unhealthy, while it scans or downloads:
|
||
`ipx status` answers at once instead of waiting for the job in progress to finish.
|
||
- Signing out after signing in through Cloudflare Access no longer lands on ipodderx's own password
|
||
page. With the new `sign_out_url` set, Sign out ends the Access session, and the password page
|
||
sends anyone the proxy signs in straight to their feeds.
|
||
- The sign-in guide, `docs/sso.md`, describes the setup ipodderx.sdf1.net really runs: Authentik as
|
||
Cloudflare Access's identity provider, and how to find the address ipx has to trust. It had never
|
||
been checked against a real setup, and pointed at the wrong address.
|
||
|
||
## [0.5.1] - 2026-09-12
|
||
|
||
### Fixed
|
||
|
||
- The triangle that opens an OPML or Patreon folder was cramped against the folder's art. It has
|
||
more room now, and a wider target to click.
|
||
|
||
## [0.5.0] - 2026-09-12
|
||
|
||
### Added
|
||
|
||
- A Patreon token pasted into Add feed, or a creator's RSS link without `&show=`, becomes a folder
|
||
of that creator's shows, kept in step on every scan like a subscribed OPML. A creator with only
|
||
one show stays a plain feed. One already added as a single long feed is split into its shows on
|
||
its next scan, keeping its files and what you had read.
|
||
- Add feed has an "Allow items marked explicit" box, so a new feed's first scan no longer skips
|
||
every explicit item.
|
||
|
||
### Changed
|
||
|
||
- Unread counts, unread dots and download progress are amber, the colour of the icon's EQ bars.
|
||
Blue is kept for the primary action and links, so a count no longer looks like a button.
|
||
- What is playing is marked by small EQ bars, in its row and in the player. They move only while it
|
||
plays.
|
||
- A folder in the sidebar shows its first four shows' art as a mosaic, and its shows sit under its
|
||
title. Only folders have a triangle, so every feed lines up with Directory and Popular above.
|
||
- Feeds without art get initials in a colour of their own, instead of all the same grey.
|
||
- The Flagged tab is called Kept, as the Keep button and Settings already said.
|
||
- A feed's header is one short line; when it checks next is in its tooltip.
|
||
- The item list takes more of the window, and the Files pane shows only when the item has files.
|
||
- Column headings and tags are in sentence case, and fewer things are bold.
|
||
- Unsubscribe is a round button beside the feed's other actions.
|
||
- Export and Import in Settings say what they do.
|
||
- The sign-in page shows the original icon large.
|
||
- Nothing animates when your system asks for reduced motion.
|
||
- The pages are about 90 KB smaller: the icon is served once instead of written into each.
|
||
- A web token generated for a new install is 64 characters instead of 32.
|
||
- The README is a short overview of what ipx does and how to run it, and points into `docs/` for
|
||
the rest. It still described the layout from before 0.4.0.
|
||
|
||
### Removed
|
||
|
||
- The systemd units in `contrib/`. Run ipx with Docker, or point a unit of your own at
|
||
`ipx daemon`.
|
||
- Upgrading from before 0.3.0 directly: what was read, kept or part-played before accounts is no
|
||
longer carried over to the admin, and OPML feeds that old versions wrote into `config.toml` are
|
||
no longer moved out of it. Upgrade through 0.4.0 first.
|
||
- `interval_mins` in `config.toml` is ignored; use `schedule`.
|
||
|
||
### Fixed
|
||
|
||
- The feed list works from the keyboard: Tab reaches every feed, Enter opens it, and Right and Left
|
||
open and close a folder. Every button shows where the focus is, including in the toolbar, which
|
||
used to clip the ring.
|
||
- "1 items" reads "1 item".
|
||
- A selected feed without art no longer loses its initials tile in Dark and Light.
|
||
- The player shows the feed's initials when there is no art, not the episode's.
|
||
- Turning on Allow explicit, or changing keywords or auto-download, brings back what those settings
|
||
had skipped on the feed's next scan. Before, an item was judged once, when first seen, and a
|
||
skipped one stayed skipped whatever you changed.
|
||
- Feeds inside an OPML or a Patreon creator follow your settings on the folder unless you set their
|
||
own, as the folder's settings dialog said they did. Before, the folder's settings reached nothing
|
||
inside it.
|
||
- A new feed no longer takes the name of one you removed earlier and shows that feed's old items.
|
||
Re-adding the same feed still gets its old name, and its history, back.
|
||
|
||
## [0.4.0] - 2026-09-11
|
||
|
||
### Added
|
||
|
||
- A Classic theme after the 2004 Mac app, beside Dark and Light: brushed-metal toolbar, Aqua
|
||
blue selection, red unread badges, a striped table and Lucida Grande. The theme button steps
|
||
through all three and remembers the choice.
|
||
- A toolbar across the top, after the original iPodderX: add and unsubscribe, play, mark read
|
||
and keep for the selected item, scan, a search box for what is showing, and Settings and Log.
|
||
- Directory, Popular and All Subscriptions at the top of the feed list, opening in the main pane.
|
||
Directory lists every feed anyone here subscribes to, A to Z (`GET /api/directory`). All
|
||
Subscriptions lists every item from every feed you subscribe to (`GET /api/entries`).
|
||
- Items show as a table (unread, kept, title, feed, file, size, published) with a Files pane beside
|
||
it, and a status bar with the totals.
|
||
- Mark everything read from All Subscriptions, across every feed you subscribe to
|
||
(`POST /api/read-all`). It asks first. All Subscriptions can also check every feed from its header.
|
||
- Click a column heading in the item table to sort by it (kept, title, feed, file type, size,
|
||
published); click again to reverse. The server sorts, so it covers the whole list, not just the
|
||
fifty shown, and the choice is remembered.
|
||
|
||
### Changed
|
||
|
||
- Popular shows the top 10, not 20, and counts everyone, you included. Your own feeds stay on it,
|
||
marked Subscribed, and clicking one opens it.
|
||
- Adding a feed scans it straight away, and an OPML import that added feeds scans them, so their
|
||
items show without pressing Scan.
|
||
- A file deleted to save space, or by hand, looks as if it was never downloaded: no "reaped"
|
||
label, just the Download button. The retention summary says "deleted", not "reaped".
|
||
- Buttons are icons, with the words in their tooltips: the Files pane (save, delete, view,
|
||
download), an item's own buttons (mark read, keep, open the original), the feed header (scan,
|
||
download latest, mark all read, settings, unsubscribe), and the Settings, feed settings and
|
||
Download latest dialogs (save, download, cancel). The icons are Font Awesome Free, embedded as
|
||
SVG: only the ones used, no font to download, and nothing fetched from anyone else. They
|
||
replace font characters such as ⟳ ⤓ ↗, which came out thin and tiny and differed from font to
|
||
font. Keep is a flag everywhere, as it was in the original, and mark unread is an envelope.
|
||
- One meaning per icon. Minus unsubscribes, x closes or cancels, plus adds or subscribes, and a
|
||
dialog's confirm button carries the icon of what it does. The feed header's unsubscribe was an x
|
||
and read as closing the page. The remaining word buttons are icons too:
|
||
- Log, Add feed, Users, Unsubscribe and OPML.
|
||
- Popular's Subscribe, Copy and Sign out.
|
||
- The Subscribed label in Popular, the Directory and Add feed, which is now a green check.
|
||
- The player's back, play, forward and close, which were font characters, and the folder arrow.
|
||
- The toolbar's read and keep buttons show the selected item's state, with the same icons as the
|
||
item's own buttons. Play, read and keep sit together, and Scan sits with add and unsubscribe.
|
||
- An OPML subscription's page has the same header as a feed's, with its buttons in the same places.
|
||
- The item table's size has its own column, apart from the file's type, and shows KB for small
|
||
files instead of "0 MB". The Item heading is now Title.
|
||
- A file's type is an icon (audio, video, image, PDF, torrent, other), green once it is
|
||
downloaded and red when the download failed, with the details in its tooltip. One icon per
|
||
row keeps the column lined up. The DOWNLOADED and PENDING labels are gone.
|
||
|
||
### Fixed
|
||
|
||
- Playing a file from the Files pane played it twice at once, in the pane and in the player bar.
|
||
The pane has a play button now, and the player bar is the only player.
|
||
- The password box in Manage users was white in the dark theme.
|
||
- An item with no date showed a stray dot in its details.
|
||
- Escape did not close a dialog while the cursor was in one of its boxes, so Add feed, which opens
|
||
in its URL box, could not be closed with Escape.
|
||
|
||
### Security
|
||
|
||
- Feeds from paid-feed services (Patreon, Supercast, Supporting Cast, Glow, Memberful) are never
|
||
listed in Popular or the Directory. A Supercast feed, which keeps its key in the URL's path
|
||
rather than the query, was being listed.
|
||
|
||
## [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 `409` while anyone
|
||
else has starred the item or not played it (`?force=true` overrides).
|
||
- A shared feed's header says how many other people read it.
|
||
- `docs/` for configuration, the CLI, users, SSO and architecture, and `CLAUDE.md` for 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 import` subscribes the first admin.
|
||
- OPML export lists only your own subscriptions.
|
||
- Production runs as a Docker image pushed to `192.168.1.130:5000` and recreated with
|
||
`docker 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 now `400` "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/logs` answers `403`, 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, and `max_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.js` and 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 `500` without 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/passwd` is refused.
|
||
- Download folders are sanitised per path segment, so `../../etc/Show` cannot climb out.
|
||
|
||
## [0.1.0] - 2026-09-09
|
||
|
||
### Added
|
||
|
||
- `ipx`, a Rust rewrite of the iPodderX engine: TOML config, SQLite state, and `ipx list`, `add`,
|
||
`rm` and `fetch`.
|
||
- 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 daemon` with 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 import` and `ipx export` for OPML, and systemd units in `contrib/`.
|
||
|
||
[unreleased]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.6.1...main
|
||
[0.7.0]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.6.1...v0.7.0
|
||
[0.6.1]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.6.0...v0.6.1
|
||
[0.6.0]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.5.5...v0.6.0
|
||
[0.5.5]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.5.4...v0.5.5
|
||
[0.5.4]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.5.3...v0.5.4
|
||
[0.5.3]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.5.2...v0.5.3
|
||
[0.5.2]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.5.1...v0.5.2
|
||
[0.5.1]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.5.0...v0.5.1
|
||
[0.5.0]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.4.0...v0.5.0
|
||
[0.4.0]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.3.0...v0.4.0
|
||
[0.3.0]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.2.0...v0.3.0
|
||
[0.2.0]: https://git.sdf1.net/rays/ipodderx-rs/compare/v0.1.0...v0.2.0
|
||
[0.1.0]: https://git.sdf1.net/rays/ipodderx-rs/releases/tag/v0.1.0
|