diff options
| author | Yuiki Saito <yuikisaito@ysaito.win> | 2025-05-12 00:11:07 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-11 16:11:07 +0100 |
| commit | c03dcfdbbc5a99abdb7517a03482bccf875d1953 (patch) | |
| tree | 8e38cb4ed1bcfc170350bcd0c5f1be1d7f38196f /apps/web/lib/exportBookmarks.ts | |
| parent | 8b05515b565e2b63500dc93c57855b555b2880df (diff) | |
| download | karakeep-c03dcfdbbc5a99abdb7517a03482bccf875d1953.tar.zst | |
feat: Add NETSCAPE-Bookmark-file-1 export format support (#1374)
* Add function to export bookmarks in NETSCAPE-Bookmark-file-1 format
* Update export endpoint to support NETSCAPE format
* Add format selection to export UI
* include tags in the export
---------
Co-authored-by: Mohamed Bassem <me@mbassem.com>
Diffstat (limited to 'apps/web/lib/exportBookmarks.ts')
| -rw-r--r-- | apps/web/lib/exportBookmarks.ts | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/apps/web/lib/exportBookmarks.ts b/apps/web/lib/exportBookmarks.ts index 45db104f..67b0b5da 100644 --- a/apps/web/lib/exportBookmarks.ts +++ b/apps/web/lib/exportBookmarks.ts @@ -58,3 +58,52 @@ export function toExportFormat( note: bookmark.note ?? null, }; } + +export function toNetscapeFormat(bookmarks: ZBookmark[]): string { + const header = `<!DOCTYPE NETSCAPE-Bookmark-file-1> +<!-- This is an automatically generated file. + It will be read and overwritten. + DO NOT EDIT! --> +<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> +<TITLE>Bookmarks</TITLE> +<H1>Bookmarks</H1> +<DL><p>`; + + const footer = `</DL><p>`; + + const bookmarkEntries = bookmarks + .map((bookmark) => { + if (bookmark.content?.type !== BookmarkTypes.LINK) { + return ""; + } + const addDate = bookmark.createdAt + ? `ADD_DATE="${Math.floor(bookmark.createdAt.getTime() / 1000)}"` + : ""; + + const tagNames = bookmark.tags.map((t) => t.name).join(","); + const tags = tagNames.length > 0 ? `TAGS="${tagNames}"` : ""; + + const encodedUrl = encodeURI(bookmark.content.url); + const displayTitle = bookmark.title ?? bookmark.content.url; + const encodedTitle = escapeHtml(displayTitle); + + return ` <DT><A HREF="${encodedUrl}" ${addDate} ${tags}>${encodedTitle}</A>`; + }) + .filter(Boolean) + .join("\n"); + + return `${header}\n${bookmarkEntries}\n${footer}`; +} + +function escapeHtml(input: string): string { + const escapeMap: Record<string, string> = { + "&": "&", + "'": "'", + "`": "`", + '"': """, + "<": "<", + ">": ">", + }; + + return input.replace(/[&'`"<>]/g, (match) => escapeMap[match] || ""); +} |
