diff options
| author | Claude <noreply@anthropic.com> | 2026-09-21 07:05:24 +0000 |
|---|---|---|
| committer | Claude <noreply@anthropic.com> | 2026-09-21 07:05:24 +0000 |
| commit | e3ecae12d7a309eb5a6c8e62910257096cb99375 (patch) | |
| tree | 4f13a1e67dff0af95e5ff49126c75e56e49d83c6 /internal/feed/feed_test.go | |
| parent | 293a627358553c9f61802caf9d4bc76af9c2e239 (diff) | |
The machine that hosts a feed and the machine that downloads the audio do
not have to be the same, and usually shouldn't be: a datacentre IP is
treated very differently from a home connection by the larger video sites.
Downloading where the person actually is sidesteps that entirely, and means
the server needs no credentials for or route to the source.
- push/ingest: `podkit push` uploads a local library to a remote
`serve --ingest`, asking for a manifest first so only the difference is
sent. Uploads land via a temp file and rename, so an interrupted transfer
cannot be picked up as a short episode. Ingest is off by default and
refuses to start without a token.
- get: downloads a direct audio URL or every enclosure in an RSS feed,
with no extractor involved. Numbers RSS items in reverse so a mirrored
series plays in order rather than backwards.
Two bugs found by running it rather than by testing it:
- A tokened server produced enclosure URLs with no token. The feed loaded,
listed every episode, and all of them 404'd in a real client — the whole
point of the tool, broken in the default configuration. Feeds now carry
the token; regression test asserts enclosures from a tokened feed
actually resolve against a tokened server.
- Ingest ran filepath.Base before validating, so "../evil.mp3" was stored
as "evil.mp3" — contained, but under a name the client never asked for,
leaving push and the server disagreeing about the library. Names are now
validated raw and rejected.
Also: identify with a real user-agent (libsyn 403s Go's default), write
feed.xml via rename so a polling client never reads a truncated feed, and
match ingested file permissions to downloaded ones.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'internal/feed/feed_test.go')
| -rw-r--r-- | internal/feed/feed_test.go | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/internal/feed/feed_test.go b/internal/feed/feed_test.go index a529e6f..588c652 100644 --- a/internal/feed/feed_test.go +++ b/internal/feed/feed_test.go @@ -66,7 +66,7 @@ func TestParseName(t *testing.T) { // enclosure URL unescaped produces both an invalid URL and invalid XML — the // single most likely way a hand-rolled feed fails to load at all. func TestEnclosureURL_EscapesFilenames(t *testing.T) { - got, err := EnclosureURL("https://example.com/audio/", "10 - Probability & Uncertainty.mp3") + got, err := EnclosureURL("https://example.com/audio/", "10 - Probability & Uncertainty.mp3", "") if err != nil { t.Fatalf("EnclosureURL: %v", err) } @@ -85,7 +85,7 @@ func TestEnclosureURL_EscapesFilenames(t *testing.T) { } func TestEnclosureURL_HandlesMissingTrailingSlash(t *testing.T) { - got, err := EnclosureURL("https://example.com/audio", "01 - One.mp3") + got, err := EnclosureURL("https://example.com/audio", "01 - One.mp3", "") if err != nil { t.Fatalf("EnclosureURL: %v", err) } @@ -96,7 +96,7 @@ func TestEnclosureURL_HandlesMissingTrailingSlash(t *testing.T) { func TestEnclosureURL_RejectsBadBase(t *testing.T) { for _, bad := range []string{"", "not-a-url", "/just/a/path"} { - if _, err := EnclosureURL(bad, "a.mp3"); err == nil { + if _, err := EnclosureURL(bad, "a.mp3", ""); err == nil { t.Errorf("EnclosureURL(%q) should have failed", bad) } } |
