A note-taking app inspired by nb
1import * as yaml from "@std/yaml";
2import { Command } from "@cliffy/command";
3
4import { Hsh } from "../hsh.ts";
5import { ensureSuffix } from "../utils.ts";
6import { toSnakeCase } from "@std/text/to-snake-case";
7import { format } from "@std/datetime/format";
8
9function register(cmd: Command, hsh: Hsh) {
10 cmd
11 .command("bookmark", "add a bookmark")
12 .alias("book")
13 .description("manage bookmarks")
14 .arguments("<url:string> [path:string]")
15 .option("--skip-fetch", "do not fetch the page")
16 .action(async ({ skipFetch }, url, path) => {
17 const p = path != null ? hsh.parse(path) : hsh.getNotebook().newPath();
18
19 let md = "";
20 let title: string | undefined;
21
22 if (!skipFetch) {
23 const { Readability } = await import("@mozilla/readability");
24 const { DOMParser } = await import("@b-fuze/deno-dom");
25 const { default: TurndownService } = await import("turndown");
26
27 const u = new URL(url);
28 const content = await (await fetch(u)).text();
29 const dom = new DOMParser().parseFromString(content, "text/html");
30 const readable = new Readability(dom);
31 const parsed = readable.parse();
32 if (parsed == null) {
33 console.error("WARNING: could not parse the upstream HTML page");
34 } else {
35 md = new TurndownService().turndown(parsed.content);
36 title = dom.title;
37 }
38 }
39
40 const frontMatter = {
41 title,
42 type: "bookmark",
43 url,
44 };
45
46 p.entry = ensureSuffix(
47 toSnakeCase(title ?? format(new Date(), "yyyyMMddHHmmss")),
48 ".bookmark.md",
49 );
50 p.write(`---\n${yaml.stringify(frontMatter)}---\n\n${md}`);
51 await hsh.emitNotebookChanged?.(p.notebook, `[hsh]: Bookmarked ${url}`);
52 });
53}
54
55export default { register };