diff options
Diffstat (limited to 'apps/web')
| -rw-r--r-- | apps/web/components/settings/ImportExport.tsx | 17 | ||||
| -rw-r--r-- | apps/web/lib/importBookmarkParser.ts | 31 |
2 files changed, 47 insertions, 1 deletions
diff --git a/apps/web/components/settings/ImportExport.tsx b/apps/web/components/settings/ImportExport.tsx index b6fa6e03..7889b4d8 100644 --- a/apps/web/components/settings/ImportExport.tsx +++ b/apps/web/components/settings/ImportExport.tsx @@ -11,6 +11,7 @@ import { ParsedBookmark, parseHoarderBookmarkFile, parseNetscapeBookmarkFile, + parseOmnivoreBookmarkFile, parsePocketBookmarkFile, } from "@/lib/importBookmarkParser"; import { cn } from "@/lib/utils"; @@ -128,7 +129,7 @@ export function ImportExportRow() { source, }: { file: File; - source: "html" | "pocket" | "hoarder"; + source: "html" | "pocket" | "omnivore" | "hoarder"; }) => { if (source === "html") { return await parseNetscapeBookmarkFile(file); @@ -136,6 +137,8 @@ export function ImportExportRow() { return await parsePocketBookmarkFile(file); } else if (source === "hoarder") { return await parseHoarderBookmarkFile(file); + } else if (source === "omnivore") { + return await parseOmnivoreBookmarkFile(file); } else { throw new Error("Unknown source"); } @@ -229,6 +232,18 @@ export function ImportExportRow() { multiple={false} className="flex items-center gap-2" onFileSelect={(file) => + runUploadBookmarkFile({ file, source: "omnivore" }) + } + > + <Upload /> + <p>Import Bookmarks from Omnivore 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/importBookmarkParser.ts b/apps/web/lib/importBookmarkParser.ts index 3262b170..f3819e79 100644 --- a/apps/web/lib/importBookmarkParser.ts +++ b/apps/web/lib/importBookmarkParser.ts @@ -1,6 +1,7 @@ // Copied from https://gist.github.com/devster31/4e8c6548fd16ffb75c02e6f24e27f9b9 import * as cheerio from "cheerio"; import { parse } from "csv-parse/sync"; +import { z } from "zod"; import { BookmarkTypes } from "@hoarder/shared/types/bookmarks"; @@ -109,3 +110,33 @@ export async function parseHoarderBookmarkFile( }; }); } + +export async function parseOmnivoreBookmarkFile( + file: File, +): Promise<ParsedBookmark[]> { + const textContent = await file.text(); + const zOmnivoreExportSchema = z.array( + z.object({ + title: z.string(), + url: z.string(), + labels: z.array(z.string()), + savedAt: z.coerce.date(), + }), + ); + + const parsed = zOmnivoreExportSchema.safeParse(JSON.parse(textContent)); + if (!parsed.success) { + throw new Error( + `The uploaded JSON file contains an invalid omnivore bookmark file: ${parsed.error.toString()}`, + ); + } + + return parsed.data.map((bookmark) => { + return { + title: bookmark.title ?? "", + content: { type: BookmarkTypes.LINK as const, url: bookmark.url }, + tags: bookmark.labels, + addDate: bookmark.savedAt.getTime() / 1000, + }; + }); +} |
