Make the feed URL editable, with a copy button

Entries and history are keyed by feed id, so changing a URL keeps them --
the point being that a feed URL can carry an auth token that gets rotated.
Changing it clears the stored ETag/Last-Modified, which belong to the old
URL and could otherwise produce a bogus 304.

The copy button cannot use navigator.clipboard: that needs a secure
context and this is served over plain HTTP on a LAN address. Falls back to
execCommand.

Invalid input now returns 400 rather than 500.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPyeapneuXrCdojsaiXGbe
This commit is contained in:
2026-09-10 02:00:20 +00:00
parent 44623098ae
commit aecad18d22
4 changed files with 170 additions and 7 deletions

View File

@@ -56,6 +56,30 @@ and until now nothing set them.
---
## 2026-09-10 — Feed URL is editable, with a copy button
The URL in a feed's Settings is now an editable field paired with Copy. Entries and download
history are keyed by feed id, not URL, so changing it keeps everything — which is the point, since
a Patreon feed URL carries an auth token that gets rotated.
Two things that would otherwise have bitten:
- **`navigator.clipboard` does not exist here.** It requires a secure context, and this is served
over plain HTTP on a LAN address, so the button would have silently done nothing. Falls back to a
hidden textarea plus `execCommand('copy')`, and reports Copied/Failed either way.
- **Changing the URL clears the stored ETag/Last-Modified.** Those validators belong to the old URL;
carrying them over could yield a bogus 304 against the new one and make a working feed look empty.
`check_url` is a tested pure function: rejects empty, unparseable and non-http(s) URLs (so
`file:///etc/passwd` is refused), rejects a URL another feed already uses, and allows a feed to keep
its own URL unchanged. Validation failures and unknown feed ids now return **400**, not 500 — bad
input is the caller's mistake, and only genuine server faults are logged as errors.
Verified live: the three rejection cases return 400 with readable messages, a no-op save returns 204,
and the feed still reports 131 entries / 11 downloaded. `cargo test` 34/34.
---
## 2026-09-10 — Fixed: pressing play made an episode vanish from the list
Reported as "where did Session Zero go, and why do parts share a number?".