From c1c97176110ceee6d6662a1e1b3b6626662a341a Mon Sep 17 00:00:00 2001 From: Adib Hanna Date: Fri, 2 Oct 2026 16:49:05 -0500 Subject: [PATCH] Feat(vault): attached media embeds in the note instead of linking A file attached or imported into a note through the server wrote an embed only for images; a video, audio file or PDF got a Markdown link, so the note showed a file name where a player or document belonged. The desktop app and both phone shells make the same choice when they write the link themselves, and they now embed image, PDF, audio and video files (ZenNotes core 2.60.4); the server's makeAssetMarkdown follows the same rule so a browser or remote-vault client gets the same note. Any other file still gets a link. TestImportAssetEmbedsMediaAndLinksOtherFiles covers each kind. --- internal/vault/vault.go | 13 ++++++++----- internal/vault/vault_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/internal/vault/vault.go b/internal/vault/vault.go index 6f1f9b8..40e46a6 100644 --- a/internal/vault/vault.go +++ b/internal/vault/vault.go @@ -3051,12 +3051,15 @@ func cleanAssetFilename(name string) (string, error) { } // makeAssetMarkdown mirrors the desktop markdownForImportedAsset: everything is -// linked by VAULT-relative path, an image as a wikilink and anything else as a -// markdown link, which is the single form every client now writes. The link -// used to be relative to the note, so it broke as soon as the note moved to -// another depth (nothing rewrites relative asset paths on move). +// linked by VAULT-relative path, an image, PDF, audio or video file as an embed +// the note shows in place (a picture, a document, a player) and anything else +// as a markdown link, which is the single form every client now writes. The +// link used to be relative to the note, so it broke as soon as the note moved +// to another depth (nothing rewrites relative asset paths on move), and media +// used to be a bare link, so an attached video showed only its file name. func makeAssetMarkdown(vaultRelPath, kind, name string) string { - if kind == "image" { + switch kind { + case "image", "pdf", "audio", "video": return "![[" + vaultRelPath + "]]" } dest := "<" + strings.ReplaceAll(vaultRelPath, ">", "%3E") + ">" diff --git a/internal/vault/vault_test.go b/internal/vault/vault_test.go index 3616ca9..89bfedb 100644 --- a/internal/vault/vault_test.go +++ b/internal/vault/vault_test.go @@ -143,6 +143,30 @@ func TestImportAssetEmbedsImagesByVaultRelativeWikilink(t *testing.T) { } } +// Media embeds so the note shows a player or the document in place, the same +// rule the desktop and both phones follow; any other file stays a link. +func TestImportAssetEmbedsMediaAndLinksOtherFiles(t *testing.T) { + root := t.TempDir() + v, err := New(root, Options{}) + if err != nil { + t.Fatal(err) + } + for _, tc := range []struct{ name, kind, markdown string }{ + {"Clip.mov", "video", "![[assets/Clip.mov]]"}, + {"Talk.mp3", "audio", "![[assets/Talk.mp3]]"}, + {"Year end.pdf", "pdf", "![[assets/Year end.pdf]]"}, + {"Archive.zip", "file", "[Archive.zip]()"}, + } { + asset, err := v.ImportAsset("Note.md", tc.name, bytes.NewReader([]byte{1, 2, 3})) + if err != nil { + t.Fatalf("%s: %v", tc.name, err) + } + if asset.Kind != tc.kind || asset.Markdown != tc.markdown { + t.Fatalf("%s: kind %q markdown %q, want %q %q", tc.name, asset.Kind, asset.Markdown, tc.kind, tc.markdown) + } + } +} + func TestImportAssetScrubsNamesThatBreakWikilinks(t *testing.T) { root := t.TempDir() v, err := New(root, Options{})