Skip to content

feat(timestamps): capture timestamps as links on new installs - #369

Merged
chhoumann merged 9 commits into
masterfrom
feat/timestamp-link-default
Oct 11, 2026
Merged

chhoumann merged 9 commits into
masterfrom
feat/timestamp-link-default

Conversation

@chhoumann

@chhoumann chhoumann commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

New installs now capture timestamps as playable links. The default Capture timestamp format changes from - {{time}} to - {{linktime}} , so the first Capture Timestamp a new user runs inserts a link that seeks the player when clicked. Existing users keep the template saved in their data.json.

Fixes #345

How it works:

  • DEFAULT_SETTINGS.timestamp.template is - {{linktime}} .
  • A missing data.json is a new install. It decodes from structuredClone(DEFAULT_SETTINGS) and is saved as v2 right away, as before.
  • PodNotes has always saved the whole settings object, and the timestamp setting dates from the first feature commit. So every data.json it wrote holds timestamp.template, and no migration runs. Data without a template, or with a non-string one, is older or hand-edited. It falls back to the template it ran with, - {{time}} , so it doesn't switch to links behind the user's back.
  • docs/docs/timestamps.md now tells existing users how to get links. The docs already called {{linktime}} the default.
  • obsidian-e2e.config.mjs defaultData stays in sync with DEFAULT_SETTINGS, as enforced by scripts/e2e-config.test.ts.

Also in this PR:

  • Test titles. %p changes to %o in four it.each titles. Vitest 5 has no %p, so those titles printed a literal %p.
  • Stale comments. Out-of-date loadSettings notes come out of src/settingsMigrations.ts.
  • Verify recipe. The timestamps recipe in the project verify skill now uses a format the seeded default can't already satisfy.

Verification

Runtime: Obsidian 1.13.7 (installer 1.13.7), Linux, headless isolated worktree instance (npm run start:e2e-obsidian). Feed: the verify-skill fixture PodNotes Fixture served at http://127.0.0.1.nip.io:32045/feed.xml, Fixture Episode 1 (60 s WAV). All steps go through the user path with .claude/skills/verify/ui.mjs: Settings to add the feed, the PodNotes view to play, the command palette for Capture Timestamp, and a click on the link in Reading view.

Before, on master 1080891, new install. I deleted the vault's data.json and reloaded PodNotes. The plugin then held - {{time}} , and capture inserted plain text - 00:00:06.
master: plain text timestamp
screen recording

After, new install. The runner rewrites data.json from defaultData on every start when the file is missing, so a cold start does not exercise the missing-file path. Instead, with Obsidian running, I set a custom format + {{time}} custom in Settings, ran plugin:disable id=podnotes, deleted data.json (confirmed absent), and ran plugin:enable id=podnotes. The plugin loaded - {{linktime}} , not the custom value from memory, and wrote {"schemaVersion":2,"timestamp":{"template":"- {{linktime}} ","offset":0}}. After re-adding the fixture feed, capture inserted - [00:00:06](obsidian://podnotes?episodeName=Fixture%20Episode%201&url=...&time=6.195475). Clicking the link in Reading view moved playback from 16.35 s back to 9.02 s (api.currentTime, read about 3 s after the click), still on Fixture Episode 1.
new install: linked timestamp
screen recording of capture and click-to-seek

After, existing user. I took the data.json written by master (- {{time}} , one saved feed), rebuilt with this branch, and reloaded. The template stayed - {{time}} in memory and on disk, and capture inserted plain - 00:00:06.
existing user keeps plain format

Setting still applies. I filled * {{linktime}} - in Settings > PodNotes. It was persisted to data.json, and capture inserted * [00:00:06](obsidian://podnotes?...&time=6.22399) - . dev:errors reported no errors.
settings

Unit tests: new install (null and undefined data, plus the first saveData in loadSettings), a realistic v2 data.json keeping - {{time}} and a custom template through decode and encode, and v0 data with no timestamp setting, only an offset, or a non-string template. Each test was proven to fail on the defect it names by reverting the line it guards.

Checks on head 680ca82, after merging origin/master (Node 22.23.2):

  • npm run lint: pass
  • npm run format:check: pass ("All matched files use the correct format.")
  • npm run typecheck: pass
  • npm run build: pass
  • npm run test: pass (svelte-check 0 errors and 0 warnings; Vitest 80 files, 1209 tests)
  • npm run docs:build: the same mkdocs build -f docs/mkdocs.yml -d site, run through uv run --with-requirements docs/requirements.txt because mkdocs is not installed on this machine: pass

Release impact

Settings: the default timestamp.template for new installs changes to - {{linktime}} . No migration. Existing data.json files keep their saved template, and data without one keeps - {{time}} . No storage schema, API, or URI changes.

New installs default the timestamp template to "- {{linktime}} ", so a
captured timestamp is a playable obsidian://podnotes link. A missing
data.json now decodes from DEFAULT_SETTINGS.

Existing data keeps the template it has. PodNotes always writes the
template, so data without one is older or hand-edited and falls back to
the previous "- {{time}} " instead of the new default.

Refs #345
Vitest has no %p token, so these cases all shared one literal "%p" name.
Lists that hold an empty array use explicit argument rows, because
Vitest titles a bare [] in a mixed list as "undefined".
…oder

LEGACY_TIMESTAMP_TEMPLATE has one reader, decodeTimestamp, so it becomes a module-local const there. The settingsMigrations header now says where the helpers run (the persistence codec) and when a stored value is rewritten.
Older data.json with a malformed timestamp.template decodes to the legacy plain template and reports the codec warning. Each row now states its exact warnings.
Existing installs keep their saved Capture timestamp format, which is often plain {{time}}.
The seeded default is already - {{linktime}} , so filling that value could never fail. Fill * {{linktime}} - instead and expect it in data.json and in the captured line.
@cloudflare-workers-and-pages

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

Copy link
Copy Markdown

Deploying podnotes with  Cloudflare Pages  Cloudflare Pages

Latest commit: 680ca82
Status: ✅  Deploy successful!
Preview URL: https://bf61af8a.podnotes.pages.dev
Branch Preview URL: https://feat-timestamp-link-default.podnotes.pages.dev

View logs

@chhoumann
chhoumann merged commit 6a6ae2d into master Oct 11, 2026
11 of 12 checks passed
@chhoumann
chhoumann deleted the feat/timestamp-link-default branch October 11, 2026 01:32
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.

Default timestamp template inserts plain text instead of a playable link

1 participant