aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/lib/importBookmarkParser.ts
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-06-01 22:43:13 +0000
committerMohamed Bassem <me@mbassem.com>2025-06-01 22:43:13 +0000
commit1bae66f7785289818eba3249f651a320f497c6a4 (patch)
tree9c01aca6f2d8924d912f05d90e3e8e768479740d /apps/web/lib/importBookmarkParser.ts
parente59be245d5e3005b5b5dadf78ad7115cc800c663 (diff)
downloadkarakeep-1bae66f7785289818eba3249f651a320f497c6a4.tar.zst
feat: Maintain list structure when importing from netscape. Fixes #538
Diffstat (limited to 'apps/web/lib/importBookmarkParser.ts')
-rw-r--r--apps/web/lib/importBookmarkParser.ts22
1 files changed, 21 insertions, 1 deletions
diff --git a/apps/web/lib/importBookmarkParser.ts b/apps/web/lib/importBookmarkParser.ts
index aba11689..2e354ffe 100644
--- a/apps/web/lib/importBookmarkParser.ts
+++ b/apps/web/lib/importBookmarkParser.ts
@@ -16,6 +16,7 @@ export interface ParsedBookmark {
addDate?: number;
notes?: string;
archived?: boolean;
+ paths: string[][];
}
export async function parseNetscapeBookmarkFile(
@@ -42,11 +43,24 @@ export async function parseNetscapeBookmarkFile(
/* empty */
}
const url = $a.attr("href");
+
+ // Build folder path by traversing up the hierarchy
+ const path: string[] = [];
+ let current = $a.parent();
+ while (current && current.length > 0) {
+ const h3 = current.find("> h3").first();
+ if (h3.length > 0) {
+ path.unshift(h3.text());
+ }
+ current = current.parent();
+ }
+
return {
title: $a.text(),
content: url ? { type: BookmarkTypes.LINK as const, url } : undefined,
tags,
addDate: typeof addDate === "undefined" ? undefined : parseInt(addDate),
+ paths: [path],
};
})
.get();
@@ -75,6 +89,7 @@ export async function parsePocketBookmarkFile(
tags: record.tags.length > 0 ? record.tags.split("|") : [],
addDate: parseInt(record.time_added),
archived: record.status === "archive",
+ paths: [], // TODO
};
});
}
@@ -111,6 +126,7 @@ export async function parseKarakeepBookmarkFile(
addDate: bookmark.createdAt,
notes: bookmark.note ?? undefined,
archived: bookmark.archived,
+ paths: [], // TODO
};
});
}
@@ -143,6 +159,7 @@ export async function parseOmnivoreBookmarkFile(
tags: bookmark.labels,
addDate: bookmark.savedAt.getTime() / 1000,
archived: bookmark.state === "Archived",
+ paths: [],
};
});
}
@@ -179,6 +196,7 @@ export async function parseLinkwardenBookmarkFile(
content: { type: BookmarkTypes.LINK as const, url: bookmark.url },
tags: bookmark.tags.map((tag) => tag.name),
addDate: bookmark.createdAt.getTime() / 1000,
+ paths: [], // TODO
}));
});
}
@@ -219,6 +237,7 @@ export async function parseTabSessionManagerStateFile(
content: { type: BookmarkTypes.LINK as const, url: tab.url },
tags: [],
addDate: tab.lastAccessed,
+ paths: [], // Tab Session Manager doesn't have folders
})),
);
}
@@ -236,7 +255,8 @@ export function deduplicateBookmarks(
const existing = deduplicatedBookmarksMap.get(url)!;
// Merge tags
existing.tags = [...new Set([...existing.tags, ...bookmark.tags])];
- // Keep earliest date
+ // Merge paths
+ existing.paths = [...existing.paths, ...bookmark.paths];
const existingDate = existing.addDate ?? Infinity;
const newDate = bookmark.addDate ?? Infinity;
if (newDate < existingDate) {