diff options
| author | Patrick Leonard <patrickleonardiii@gmail.com> | 2024-12-29 04:25:56 -1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-29 16:25:56 +0200 |
| commit | 27b3f9d17958d76ced902787e387c15db720af0a (patch) | |
| tree | bf436b8711d2988027df5a8b73edec052324d0e1 /apps | |
| parent | aeedea1ac35f2c6651dea37b5ef2b907edf779ce (diff) | |
| download | karakeep-27b3f9d17958d76ced902787e387c15db720af0a.tar.zst | |
feat: add Linkwarden importer (#786)
* added in Linkwarden import
* simpler parsing
---------
Co-authored-by: Mohamed Bassem <me@mbassem.com>
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/components/settings/ImportExport.tsx | 17 | ||||
| -rw-r--r-- | apps/web/lib/i18n/locales/en/translation.json | 1 | ||||
| -rw-r--r-- | apps/web/lib/importBookmarkParser.ts | 36 |
3 files changed, 53 insertions, 1 deletions
diff --git a/apps/web/components/settings/ImportExport.tsx b/apps/web/components/settings/ImportExport.tsx index 34e069da..e38f629a 100644 --- a/apps/web/components/settings/ImportExport.tsx +++ b/apps/web/components/settings/ImportExport.tsx @@ -11,6 +11,7 @@ import { useTranslation } from "@/lib/i18n/client"; import { ParsedBookmark, parseHoarderBookmarkFile, + parseLinkwardenBookmarkFile, parseNetscapeBookmarkFile, parseOmnivoreBookmarkFile, parsePocketBookmarkFile, @@ -121,7 +122,7 @@ export function ImportExportRow() { source, }: { file: File; - source: "html" | "pocket" | "omnivore" | "hoarder"; + source: "html" | "pocket" | "omnivore" | "hoarder" | "linkwarden"; }) => { if (source === "html") { return await parseNetscapeBookmarkFile(file); @@ -131,6 +132,8 @@ export function ImportExportRow() { return await parseHoarderBookmarkFile(file); } else if (source === "omnivore") { return await parseOmnivoreBookmarkFile(file); + } else if (source === "linkwarden") { + return await parseLinkwardenBookmarkFile(file); } else { throw new Error("Unknown source"); } @@ -236,6 +239,18 @@ export function ImportExportRow() { multiple={false} className="flex items-center gap-2" onFileSelect={(file) => + runUploadBookmarkFile({ file, source: "linkwarden" }) + } + > + <Upload /> + <p>{t("settings.import.import_bookmarks_from_linkwarden_export")}</p> + </FilePickerButton> + <FilePickerButton + loading={false} + accept=".json" + multiple={false} + className="flex items-center gap-2" + onFileSelect={(file) => runUploadBookmarkFile({ file, source: "hoarder" }) } > diff --git a/apps/web/lib/i18n/locales/en/translation.json b/apps/web/lib/i18n/locales/en/translation.json index 0236b1c3..92f6e956 100644 --- a/apps/web/lib/i18n/locales/en/translation.json +++ b/apps/web/lib/i18n/locales/en/translation.json @@ -99,6 +99,7 @@ "import_bookmarks_from_html_file": "Import Bookmarks from HTML file", "import_bookmarks_from_pocket_export": "Import Bookmarks from Pocket export", "import_bookmarks_from_omnivore_export": "Import Bookmarks from Omnivore export", + "import_bookmarks_from_linkwarden_export": "Import Bookmarks from Linkwarden export", "import_bookmarks_from_hoarder_export": "Import Bookmarks from Hoarder export", "export_links_and_notes": "Export Links and Notes", "imported_bookmarks": "Imported Bookmarks" diff --git a/apps/web/lib/importBookmarkParser.ts b/apps/web/lib/importBookmarkParser.ts index f3819e79..69b8a78c 100644 --- a/apps/web/lib/importBookmarkParser.ts +++ b/apps/web/lib/importBookmarkParser.ts @@ -140,3 +140,39 @@ export async function parseOmnivoreBookmarkFile( }; }); } + +export async function parseLinkwardenBookmarkFile( + file: File, +): Promise<ParsedBookmark[]> { + const textContent = await file.text(); + const zLinkwardenExportSchema = z.object({ + collections: z.array( + z.object({ + links: z.array( + z.object({ + name: z.string(), + url: z.string(), + tags: z.array(z.object({ name: z.string() })), + createdAt: z.coerce.date(), + }), + ), + }), + ), + }); + + const parsed = zLinkwardenExportSchema.safeParse(JSON.parse(textContent)); + if (!parsed.success) { + throw new Error( + `The uploaded JSON file contains an invalid Linkwarden bookmark file: ${parsed.error.toString()}`, + ); + } + + return parsed.data.collections.flatMap((collection) => { + return collection.links.map((bookmark) => ({ + title: bookmark.name ?? "", + content: { type: BookmarkTypes.LINK as const, url: bookmark.url }, + tags: bookmark.tags.map((tag) => tag.name), + addDate: bookmark.createdAt.getTime() / 1000, + })); + }); +} |
