aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/lib/importBookmarkParser.ts
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-08-30 15:26:02 +0000
committerMohamed Bassem <me@mbassem.com>2025-08-30 15:26:02 +0000
commitaecbe6ae8b3dbc7bcdcf33f1c8c086dafb77eb24 (patch)
tree33b57ccae4a7cf1fac3c01babb9c66c97c57089a /apps/web/lib/importBookmarkParser.ts
parentf1961822fc355569b431109f6a9a178aefa85dd2 (diff)
downloadkarakeep-aecbe6ae8b3dbc7bcdcf33f1c8c086dafb77eb24.tar.zst
fix: handle list with slashes in their names and truncate long list names. fixes #1597
Diffstat (limited to '')
-rw-r--r--packages/shared/import-export/parsers.ts (renamed from apps/web/lib/importBookmarkParser.ts)80
1 files changed, 47 insertions, 33 deletions
diff --git a/apps/web/lib/importBookmarkParser.ts b/packages/shared/import-export/parsers.ts
index 44fe872c..c969c615 100644
--- a/apps/web/lib/importBookmarkParser.ts
+++ b/packages/shared/import-export/parsers.ts
@@ -1,11 +1,19 @@
// 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 "@karakeep/shared/types/bookmarks";
+import { BookmarkTypes } from "../types/bookmarks";
+import { zExportSchema } from "./exporters";
-import { zExportSchema } from "./exportBookmarks";
+export type ImportSource =
+ | "html"
+ | "pocket"
+ | "omnivore"
+ | "karakeep"
+ | "linkwarden"
+ | "tab-session-manager";
export interface ParsedBookmark {
title: string;
@@ -19,11 +27,7 @@ export interface ParsedBookmark {
paths: string[][];
}
-export async function parseNetscapeBookmarkFile(
- file: File,
-): Promise<ParsedBookmark[]> {
- const textContent = await file.text();
-
+function parseNetscapeBookmarkFile(textContent: string): ParsedBookmark[] {
if (!textContent.startsWith("<!DOCTYPE NETSCAPE-Bookmark-file-1>")) {
throw Error("The uploaded html file does not seem to be a bookmark file");
}
@@ -66,11 +70,7 @@ export async function parseNetscapeBookmarkFile(
.get();
}
-export async function parsePocketBookmarkFile(
- file: File,
-): Promise<ParsedBookmark[]> {
- const textContent = await file.text();
-
+function parsePocketBookmarkFile(textContent: string): ParsedBookmark[] {
const records = parse(textContent, {
columns: true,
skip_empty_lines: true,
@@ -94,11 +94,7 @@ export async function parsePocketBookmarkFile(
});
}
-export async function parseKarakeepBookmarkFile(
- file: File,
-): Promise<ParsedBookmark[]> {
- const textContent = await file.text();
-
+function parseKarakeepBookmarkFile(textContent: string): ParsedBookmark[] {
const parsed = zExportSchema.safeParse(JSON.parse(textContent));
if (!parsed.success) {
throw new Error(
@@ -131,10 +127,7 @@ export async function parseKarakeepBookmarkFile(
});
}
-export async function parseOmnivoreBookmarkFile(
- file: File,
-): Promise<ParsedBookmark[]> {
- const textContent = await file.text();
+function parseOmnivoreBookmarkFile(textContent: string): ParsedBookmark[] {
const zOmnivoreExportSchema = z.array(
z.object({
title: z.string(),
@@ -164,10 +157,7 @@ export async function parseOmnivoreBookmarkFile(
});
}
-export async function parseLinkwardenBookmarkFile(
- file: File,
-): Promise<ParsedBookmark[]> {
- const textContent = await file.text();
+function parseLinkwardenBookmarkFile(textContent: string): ParsedBookmark[] {
const zLinkwardenExportSchema = z.object({
collections: z.array(
z.object({
@@ -201,11 +191,9 @@ export async function parseLinkwardenBookmarkFile(
});
}
-export async function parseTabSessionManagerStateFile(
- file: File,
-): Promise<ParsedBookmark[]> {
- const textContent = await file.text();
-
+function parseTabSessionManagerStateFile(
+ textContent: string,
+): ParsedBookmark[] {
const zTab = z.object({
url: z.string(),
title: z.string(),
@@ -242,9 +230,7 @@ export async function parseTabSessionManagerStateFile(
);
}
-export function deduplicateBookmarks(
- bookmarks: ParsedBookmark[],
-): ParsedBookmark[] {
+function deduplicateBookmarks(bookmarks: ParsedBookmark[]): ParsedBookmark[] {
const deduplicatedBookmarksMap = new Map<string, ParsedBookmark>();
const textBookmarks: ParsedBookmark[] = [];
@@ -284,3 +270,31 @@ export function deduplicateBookmarks(
return [...deduplicatedBookmarksMap.values(), ...textBookmarks];
}
+
+export function parseImportFile(
+ source: ImportSource,
+ textContent: string,
+): ParsedBookmark[] {
+ let result: ParsedBookmark[];
+ switch (source) {
+ case "html":
+ result = parseNetscapeBookmarkFile(textContent);
+ break;
+ case "pocket":
+ result = parsePocketBookmarkFile(textContent);
+ break;
+ case "karakeep":
+ result = parseKarakeepBookmarkFile(textContent);
+ break;
+ case "omnivore":
+ result = parseOmnivoreBookmarkFile(textContent);
+ break;
+ case "linkwarden":
+ result = parseLinkwardenBookmarkFile(textContent);
+ break;
+ case "tab-session-manager":
+ result = parseTabSessionManagerStateFile(textContent);
+ break;
+ }
+ return deduplicateBookmarks(result);
+}