Skip to content

fix(uri): keep a subscribed private feed's secret out of the live episode - #423

Merged
chhoumann merged 10 commits into
masterfrom
fix/uri-private-feed-placeholder
Oct 12, 2026
Merged

chhoumann merged 10 commits into
masterfrom
fix/uri-private-feed-placeholder

Conversation

@chhoumann

@chhoumann chhoumann commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Why

A private feed is saved under a podnotes-private-feed: placeholder, and its real URL lives in SecretStorage. A podnotes link that carries the real secret URL instead (an old link, or one built outside PodNotes) opened through the raw-URL path, which builds the live episode with that URL as its feedUrl. Saving scrubs it, so data.json stayed clean, but every timestamp captured from the playing episode wrote the secret into the note.

What changed

  • podNotesURIHandler maps a link URL that isSavedFeed matches to that saved feed's own URL before anything else. For a private feed that is its placeholder, so the link runs exactly like the feed's own placeholder links and the live episode never holds the secret. A public feed maps to itself.
  • isSavedFeed compares URLs as a request sends them: scheme and host in any case, with or without a default port, name the same feed; path, query and trailing slash still have to match. OPML import and Settings use the same matcher, so a saved feed stored in another spelling is no longer imported or subscribed twice.
  • PlayerController.play reusing the loaded media for the same episode adopts the incoming copy when it is the subscription's protected form and the loaded one is not (an episode opened by its secret URL before subscribing). It never replaces a protected copy with a raw one, and it leaves the media element and position alone.

Scope

  • Covers subscribed private feeds whose secret is on this device, the case V-420 reported.

Blast radius

Only links whose URL equals a saved feed's URL or its resolved secret take a different path, and that path is the existing placeholder path. IAPI and the documented URI behavior are unchanged: links open the same episode at the same time.

Verification

  • Reproduced on master in Obsidian 1.13.7 (Linux headless, isolated vault, fixture private feed with a path and a query sentinel): the raw link played the episode with the secret as feedUrl, and Capture timestamp wrote it into the note while data.json stayed clean.
  • After the fix, the same link plays the same episode with the placeholder as feedUrl and url; the captured timestamp holds only the placeholder and seeks back to 19.36 s when clicked. An old capture that still holds the secret URL resumes the playing episode without a feed request.
  • V-423 cases, live on Obsidian 1.14.4: subscribing while the raw episode stays loaded and reopening the secret link now shows the placeholder with the same media element and no reload (12 s to 51 s); an uppercase-host link opened from another loaded episode keeps only the placeholder, and its capture seeks to 27.2 s. No sentinel reaches data.json or the feed cache.
  • New tests fail before their fix: the secret-URL link (live episode and needless refetch), the raw-loaded and protected-loaded reuse cases, four matching and four non-matching URL spellings opened from another episode, and OPML import and Settings with a differently spelled saved feed. The verifier's 22-case source matrix passes.
  • lint, format:check, typecheck, build, test (1,729 tests), test:tooling, docs:build and test:e2e (77 of 77) pass.
Master: the capture holds the secret Fixed: the capture holds the placeholder and seeks
Master capture Fixed capture

Screen recording: clicking the fixed capture

Follow-ups

Release impact

None to settings, storage, API or the URI format.

Note

Keep a subscribed private feed's secret URL out of the live episode

  • When a pasted URL matches a saved feed, podNotesURIHandler in URIHandler.ts now resolves it to the feed's placeholder URL before episode selection, so the saved secret URL is not carried into the selected episode
  • PlayerController.play in PlayerController.ts swaps a secret-bearing selected episode to its placeholder copy during same-episode playback without recreating the media element or resetting the playback position
  • isSavedFeed in privateFeeds.ts now canonicalizes both URLs via a new canonicalUrl helper, so scheme/host case and default ports count as matches, while path, trailing-slash, query, and scheme differences still do not
  • Behavioral Change: URL comparisons rely on URL parser serialization; two URLs that only differ in casing or default-port spelling are now treated as the same feed everywhere isSavedFeed is used (OPML import, query grid, URI handling)

Macroscope summarized 0e06666.

…ed by a raw link

A podnotes link whose url is a subscribed private feed's real URL now opens
as that feed's placeholder link. The player's episode carries the placeholder,
so timestamps captured from it no longer copy the secret URL into notes.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Deploying podnotes with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0e06666
Status: ✅  Deploy successful!
Preview URL: https://5871129f.podnotes.pages.dev
Branch Preview URL: https://fix-uri-private-feed-placeho.podnotes.pages.dev

View logs

@chhoumann
chhoumann merged commit 9cc3e94 into master Oct 12, 2026
15 checks passed
@chhoumann
chhoumann deleted the fix/uri-private-feed-placeholder branch October 12, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant