aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorPatrick Leonard <patrickleonardiii@gmail.com>2024-12-29 04:25:56 -1000
committerGitHub <noreply@github.com>2024-12-29 16:25:56 +0200
commit27b3f9d17958d76ced902787e387c15db720af0a (patch)
treebf436b8711d2988027df5a8b73edec052324d0e1 /apps
parentaeedea1ac35f2c6651dea37b5ef2b907edf779ce (diff)
downloadkarakeep-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.tsx17
-rw-r--r--apps/web/lib/i18n/locales/en/translation.json1
-rw-r--r--apps/web/lib/importBookmarkParser.ts36
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,
+ }));
+ });
+}