Keep every enclosure on an item, and view without downloading

The rss crate keeps at most one enclosure per item and, when a feed ships
several, silently keeps the last -- so a two-file item lost its first
file. enclosures_by_item reads them from the XML in document order,
unescaping attributes so a URL's & survives. The row summarises the
one you would act on and counts the rest; the pane below lists them all.

Non-media enclosures gain a View link opening in a new tab: the
publisher's URL, or the local copy once downloaded. A direct link, not a
proxy, so the daemon does not become a fetch-anything relay.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdXho5tTkjFLeUXKbEjKBh
This commit is contained in:
2026-09-10 18:01:25 +00:00
parent 6d6b4dd1e4
commit dd9c0881ee
11 changed files with 212 additions and 21 deletions

View File

@@ -56,6 +56,35 @@ and until now nothing set them.
---
## 2026-09-10 — Multiple enclosures per item, and viewing without downloading
**View without downloading.** A non-audio/video enclosure now carries a View link opening in a new
tab: the publisher's own URL when nothing is downloaded, the local copy at `/media/<id>` when it is.
Deliberately a direct link rather than a proxy — relaying arbitrary URLs through the daemon would
make it a fetch-anything service.
**Multiple enclosures.** Probed before assuming, and the result was worse than expected: the `rss`
crate models an item as having at most one enclosure (which is what RSS 2.0 says) and when a feed
carries several it silently keeps **the last**, dropping the rest. So a two-file item lost its first
file entirely.
`enclosures_by_item()` reads them straight from the XML with quick-xml, in document order,
unescaping attribute values — a feed URL's `&` arrives as `&amp;`, so skipping that would corrupt
every query string. It falls back to the parsed enclosure if the scan and the parser disagree on
item count. Atom already collected all `rel="enclosure"` links. The row now summarises the enclosure
you would act on (playable, else downloaded, else first) and says "+N more files"; the pane below
lists them all.
**A real limitation surfaced by a broken fixture.** Two browser tests failed with zero enclosures in
the detail pane. Not the new scanner — verified by running it against the fixture files directly,
which was right every time. The cause: my fixtures pointed two feeds at the *same* enclosure URL,
and `enclosures.url` is UNIQUE across the whole database, so whichever feed is scanned first claims
it and the other's entry gets nothing. That is the dedupe working as designed, but it means **two
feeds legitimately sharing a media URL will only ever show it under one of them** — worth knowing,
and worth revisiting if a network feed and a show feed ever overlap.
---
## 2026-09-10 — A file is not the same as a playable file
Reported: "Abort Retry Fail still shows downloaded and audio playback UI". The media-type filter