vitals/bookmark.py
CLU 95c1c1d3eb Live UI: stop the page from jumping, and put Vitals in the bookmark bar
The page rebuilt its whole header, bar and row list twice a second, so
numbers snapped, columns resized as digits changed, and rows swapped places
over a hundredth of a core.

- header values are tabular-width and tweened toward the newest sample
- machine-bar segments are keyed and reordered by flex order, so widths
  animate instead of being recreated mid-transition
- rows are keyed DOM nodes updated in place, sorted on a 0.1-core grid with
  the previous order as tiebreak, with hysteresis at the idle threshold
- tabs, banner and detail panes only re-render when their data changes
- poll every 700ms and drop repeat frames from the 2s sampler

bookmark.py puts a Vitals bookmark and a popup bookmarklet in the browser's
bookmark bar. It recomputes Chromium's bookmark checksum (MD5 over the
canonical node serialisation) and verifies it after writing, because a file
that fails that check leaves the browser showing an empty bar while the file
on disk still looks perfect. Refuses while the browser holds the profile,
keeps a timestamped backup, idempotent. install.sh runs it.

Co-developed-with: CLU
2026-10-20 13:52:49 -05:00

363 lines
12 KiB
Python

#!/usr/bin/env python3
"""Put Vitals in the browser's bookmark bar.
Chromium-family browsers (Brave, Chrome, Chromium) store bookmarks as a JSON
file with an MD5 checksum over a canonical serialisation of every node. If the
checksum does not match, the browser silently falls back to Bookmarks.bak and
the edit disappears, so this tool recomputes it and refuses to write a file it
cannot verify.
Checksum algorithm (components/bookmarks/browser/bookmark_codec.cc):
for each root folder, in order bookmark_bar, other, synced:
feed the root itself as a folder node
then every descendant, depth first, in order
folder node : id + name (UTF-16LE bytes) + b"folder"
url node : id + name (UTF-16LE bytes) + b"url" + url (UTF-8)
Verified by reproducing the stored checksum of a real 13.8 MB profile file.
Safe by construction: refuses while the browser owns the profile, writes through
a temp file with an atomic rename, keeps a timestamped backup, and re-reads the
file it just wrote to confirm the checksum lands.
Usage:
python3 bookmark.py --install # add Vitals + Vitals popup
python3 bookmark.py --install --wait 600 # wait up to 10 min for browser exit
python3 bookmark.py --status # what is in the bar right now
python3 bookmark.py --remove # take them back out
python3 bookmark.py --install --profile-dir /path/to/Profile
python3 bookmark.py --install --dry-run
"""
from __future__ import annotations
import argparse
import glob
import hashlib
import json
import os
import shutil
import sys
import time
import uuid
VITALS_URL = "http://127.0.0.1:8791/"
BOOKMARKLET = (
"javascript:(function(){window.open('http://127.0.0.1:8791/',"
"'vitals','width=1500,height=950,menubar=no,toolbar=no,location=no,"
"status=no');})();void(0);"
)
ROOTS = ("bookmark_bar", "other", "synced")
WINDOWS_EPOCH_OFFSET = 11644473600 # seconds between 1601-01-01 and 1970-01-01
# ---------------------------------------------------------------- checksum
def _u16(s: str) -> bytes:
return s.encode("utf-16-le")
def _feed_url(h, node) -> None:
h.update(str(node["id"]).encode())
h.update(_u16(node.get("name") or ""))
h.update(b"url")
h.update((node.get("url") or "").encode("utf-8"))
def _feed_folder(h, node) -> None:
h.update(str(node["id"]).encode())
h.update(_u16(node.get("name") or ""))
h.update(b"folder")
def _walk(h, node) -> None:
if node.get("type") == "url":
_feed_url(h, node)
else:
_feed_folder(h, node)
for child in node.get("children", []):
_walk(h, child)
def checksum(doc) -> str:
h = hashlib.md5()
for key in ROOTS:
root = doc["roots"].get(key)
if not root:
continue
_feed_folder(h, root)
for child in root.get("children", []):
_walk(h, child)
return h.hexdigest()
# ---------------------------------------------------------------- discovery
def candidate_profiles():
home = os.path.expanduser("~")
pats = [
# Flatpak builds keep their profile inside the sandbox.
f"{home}/.var/app/com.brave.Browser/config/BraveSoftware/Brave-Browser/Default",
f"{home}/.var/app/com.google.Chrome/config/google-chrome/Default",
f"{home}/.var/app/org.chromium.Chromium/config/chromium/Default",
# Native builds.
f"{home}/.config/BraveSoftware/Brave-Browser/Default",
f"{home}/.config/google-chrome/Default",
f"{home}/.config/chromium/Default",
# Chromium-family shells.
f"{home}/.config/microsoft-edge/Default",
f"{home}/.config/vivaldi/Default",
]
out = []
for p in pats:
if os.path.isfile(os.path.join(p, "Bookmarks")):
out.append(p)
return out
def profile_in_use(profile_dir: str) -> bool:
"""True when a browser currently owns this profile.
Chromium takes a SingletonLock in the user data dir (the parent of the
profile dir). Reading the bookmarks file under a live browser is pointless:
the in-memory model overwrites it on the next save.
"""
user_data_dir = os.path.dirname(profile_dir.rstrip("/"))
for name in ("SingletonLock", "SingletonSocket", "SingletonCookie"):
if os.path.exists(os.path.join(user_data_dir, name)):
return True
# Also catch a browser pointed at this profile with an explicit flag.
needle = os.path.abspath(profile_dir)
try:
pids = [p for p in os.listdir("/proc") if p.isdigit()]
except OSError:
return False
for pid in pids:
try:
with open(f"/proc/{pid}/cmdline", "rb") as f:
cmd = f.read().replace(b"\x00", b" ").decode("utf8", "replace")
except OSError:
continue
if "--type=" in cmd:
continue
if needle in cmd and any(b in cmd for b in ("brave", "chrome", "chromium", "edge", "vivaldi")):
return True
return False
def max_id(doc) -> int:
top = 0
def walk(node):
nonlocal top
try:
top = max(top, int(node.get("id", 0)))
except (TypeError, ValueError):
pass
for child in node.get("children", []):
walk(child)
for key in ROOTS:
if doc["roots"].get(key):
walk(doc["roots"][key])
return top
def now_micros() -> str:
return str(int((time.time() + WINDOWS_EPOCH_OFFSET) * 1_000_000))
def find_ours(doc):
"""Return (vitals_node, bookmarklet_node) currently in the bar, if any."""
plain = bm = None
def walk(node):
nonlocal plain, bm
if node.get("type") == "url":
url = node.get("url") or ""
if url == VITALS_URL:
plain = node
elif url.startswith("javascript:") and "8791" in url:
bm = node
for child in node.get("children", []):
walk(child)
for key in ROOTS:
if doc["roots"].get(key):
walk(doc["roots"][key])
return plain, bm
def make_node(node_id: int, name: str, url: str) -> dict:
stamp = now_micros()
return {
"date_added": stamp,
"date_last_used": "0",
"guid": str(uuid.uuid4()),
"id": str(node_id),
"name": name,
"type": "url",
"url": url,
}
# ---------------------------------------------------------------- operations
def load(profile_dir):
path = os.path.join(profile_dir, "Bookmarks")
with open(path, encoding="utf8") as f:
raw = f.read()
return path, raw, json.loads(raw)
def save(path, doc, raw_before) -> None:
doc["checksum"] = checksum(doc)
doc.pop("checksum_sha256", None) # browser rewrites it; absent is valid
text = json.dumps(doc, indent=3, sort_keys=True, ensure_ascii=True)
stamp = time.strftime("%Y%m%d-%H%M%S")
backup = f"{path}.pre-vitals-{stamp}.bak"
shutil.copy2(path, backup)
tmp = f"{path}.vitals.tmp"
with open(tmp, "w", encoding="utf8") as f:
f.write(text)
shutil.copystat(path, tmp)
os.replace(tmp, path)
print(f" backup: {backup}")
# Verify what actually landed on disk.
with open(path, encoding="utf8") as f:
check = json.load(f)
if checksum(check) != check.get("checksum"):
raise SystemExit("REFUSING: checksum did not verify after write")
if len(raw_before) and not check["roots"].get("bookmark_bar"):
raise SystemExit("REFUSING: bookmark bar missing after write")
def install(profile_dir, dry_run=False, name="Vitals", popup_name="Vitals popup") -> int:
path, raw, doc = load(profile_dir)
plain, bm = find_ours(doc)
next_id = max_id(doc) + 1
added = []
if plain is None:
doc["roots"]["bookmark_bar"].setdefault("children", []).append(
make_node(next_id, name, VITALS_URL)
)
next_id += 1
added.append(name)
elif plain.get("name") != name:
plain["name"] = name
added.append(f"{name} (renamed)")
if bm is None:
doc["roots"]["bookmark_bar"].setdefault("children", []).append(
make_node(next_id, popup_name, BOOKMARKLET)
)
added.append(popup_name)
if not added:
print(" already installed, nothing to do")
return 0
if dry_run:
probe = json.loads(raw)
probe["checksum"] = checksum(doc)
print(f" dry run: would add {added} | new checksum {probe['checksum']}")
return 0
print(f" profile: {profile_dir}")
print(f" adding: {', '.join(added)}")
save(path, doc, raw)
print(f" checksum: {doc['checksum']} verified on disk")
return 0
def remove(profile_dir, dry_run=False) -> int:
path, raw, doc = load(profile_dir)
plain, bm = find_ours(doc)
if plain is None and bm is None:
print(" nothing to remove")
return 0
removed = []
for key in ROOTS:
root = doc["roots"].get(key)
if not root:
continue
keep = []
for child in root.get("children", []):
if child is plain or child is bm:
removed.append(child.get("name"))
else:
keep.append(child)
root["children"] = keep
if dry_run:
print(f" dry run: would remove {removed}")
return 0
save(path, doc, raw)
print(f" removed: {removed}")
return 0
def status(profile_dir) -> int:
_, _, doc = load(profile_dir)
plain, bm = find_ours(doc)
bar = doc["roots"]["bookmark_bar"]
print(f" profile : {profile_dir}")
print(f" bar : {len(bar.get('children', []))} items")
print(f" Vitals : {plain.get('name') + ' -> ' + plain['url'] if plain else 'not present'}")
print(f" popup : {bm.get('name') if bm else 'not present'}")
stored = doc.get("checksum", "")
good = stored == checksum(doc)
print(f" checksum: {'valid' if good else 'MISMATCH'}")
return 0
def main(argv=None) -> int:
ap = argparse.ArgumentParser(description="Install Vitals into the bookmark bar")
ap.add_argument("--install", action="store_true")
ap.add_argument("--remove", action="store_true")
ap.add_argument("--status", action="store_true")
ap.add_argument("--profile-dir", default=None)
ap.add_argument("--name", default="Vitals")
ap.add_argument("--dry-run", action="store_true")
ap.add_argument("--wait", type=int, default=0,
help="seconds to wait for the browser to exit before giving up")
args = ap.parse_args(argv)
if not (args.install or args.remove or args.status):
ap.print_help()
return 2
profiles = [args.profile_dir] if args.profile_dir else candidate_profiles()
if not profiles:
print("no Chromium-family profile found; pass --profile-dir")
return 1
targets = []
for p in profiles:
if not os.path.isfile(os.path.join(p, "Bookmarks")):
print(f" skip {p}: no Bookmarks file")
continue
waited = 0
while profile_in_use(p) and waited < args.wait:
if waited == 0:
print(f" browser is running on {p}; waiting up to {args.wait}s")
time.sleep(2)
waited += 2
if profile_in_use(p):
print(f" skip {p}: browser holds the profile lock. Close the browser "
f"and re-run, or pass --wait N.")
continue
targets.append(p)
if not targets:
return 1
for p in targets:
if args.status:
status(p)
elif args.remove:
remove(p, args.dry_run)
else:
install(p, args.dry_run, name=args.name)
return 0
if __name__ == "__main__":
sys.exit(main())