# bookmarks Firefox's bookmarks as a grid of cards across DP-1, grouped by folder, over a dimmed screen. SUPER+b opens it, Escape or a click outside closes it. Each card shows the favicon, the title, the host and, after a link check, a badge: red for a link that is gone (404, 410, a host that no longer resolves, a refused connection), yellow for one that may only be refusing a script (403, 429, a timeout, a TLS error, a 5xx). Type to filter (every word must match title, address or folder), arrows and PageUp/PageDown to move. Enter opens the bookmark with `xdg-open`, so it lands in the running Firefox profile rather than a new one. Tab shows only the dead ones; Ctrl+R checks every link again. The icon buttons sort, and Ctrl+S cycles them: Firefox's folder order, newest first (headed by year), title (headed by letter), site, most visited, and link state (dead, unsure, fine, not checked). Ties keep folder order. Outside folder order each card names its folder. The wheel scrolls three rows of cards a notch, set in the `MouseArea` over the grid; Flickable's own step was a few pixels. `bookmarks.py` builds the list on every opening, so a bookmark added in Firefox shows the next time. It reads `places.sqlite` and `favicons.sqlite` of the profile a running Firefox holds, found by its `lock` symlink's pid, else the one with the largest `places.sqlite` (`BOOKMARKS_PROFILE` overrides both). Firefox holds them in exclusive lock mode, so they are copied with their `-wal` to a temporary directory and the copy is read: the log is where Firefox puts recent changes, a deletion included, until a checkpoint. Nothing is ever written to them: deleting a dead bookmark is done in Firefox. Folders keep Firefox's order, toolbar first, but a folder's own bookmarks come before its subfolders rather than interleaved with them. Tags are left out. Favicons are extracted to `~/.cache/keystone/bookmarks/icons/`, named by content hash; a bookmark with no icon of its own takes any icon Firefox holds for the same host, and one with none at all shows the host's initial. The link check (`bookmarks.py --links`) sends one request to every http(s) bookmark, 32 at a time, HEAD and then GET if HEAD fails, and writes `~/.cache/keystone/bookmarks/links.json`. It took 22s over 503 links. It runs only when asked, and a site down at that moment reads dead until the next check. ## Running qs -p ./bookmarks qs -p ./bookmarks ipc call bookmarks toggle ## Blur Optional, in the Hyprland config: hl.layer_rule({ name = "blur-bookmarks", match = { namespace = "^(keystone-bookmarks)$" }, blur = true, xray = false, ignore_alpha = 0.1, }) ## Check /usr/bin/python3 bookmarks/bookmarks.py --check