Skip to content

Instantly share code, notes, and snippets.

@U1F30C
Created March 24, 2025 00:29
Show Gist options
  • Select an option

  • Save U1F30C/19417c94a8b9cc65751f04a4b23f2ffc to your computer and use it in GitHub Desktop.

Select an option

Save U1F30C/19417c94a8b9cc65751f04a4b23f2ffc to your computer and use it in GitHub Desktop.
bookmarks.html to bookmarks.json
import { readFile, writeFile } from "fs-safe";
import { DomNode, LinkNode, parse } from "netscape-bookmark-tree";
const bookmarksDir = "data/bookmarks.html";
const outputDir = "data/bookmarks.json";
interface Link<Metadata = any> {
name: string;
url: string;
folder?: string;
metadata?: Metadata;
}
function printTree(entries: DomNode[], depth = 0) {
for (const entry of entries) {
if (entry.children) {
console.log(" ".repeat(depth * 2), "-", entry.name.slice(0, 50));
printTree(entry.children, depth + 1);
}
}
}
function getAllLinks(
dom: (DomNode | LinkNode)[],
links: Link<unknown>[] = [],
folder: string
) {
for (const entry of dom) {
if ("href" in entry) {
links.push({
name: entry.name,
url: entry.href,
folder: folder,
metadata: {},
});
} else {
getAllLinks(entry.children, links, entry.name);
}
}
}
async function main() {
const file = await readFile(bookmarksDir);
const dom: DomNode[] = parse(file);
printTree(dom);
const allLinks: Link<unknown>[] = [];
getAllLinks(dom, allLinks, "");
const result = {
links: allLinks,
};
await writeFile(outputDir, JSON.stringify(result, null, 2));
}
main();
declare module "netscape-bookmark-tree" {
export interface DomNode {
name: string;
index: number;
id: string;
children: (DomNode)[];
pid?: string;
unfiled_bookmarks_folder?: string;
add_date?: string;
last_modified?: string;
}
export interface LinkNode extends DomNode {
href: string;
icon_uri: string;
icon: string;
}
export function parse(body: string): DomNode[];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment