/** * Moves site icons out of `rich_content.thumbnailUrl` into the new * `faviconUrl`. The metadata fetch used to fall back on the page's icon, and * then on a guessed `/favicon.ico`, so most thumbnails were a 16×16 icon, or a * 404, that the UI stretched over a 128×72 box. It now stops at real artwork, * and a missing `thumbnailUrl` means none, which the frontend draws a * placeholder for. This gives the older rows that meaning. * * It judges the stored URL alone and fetches nothing, so it doesn't fill * `accentColor`. The frontend derives a hue from the hostname when it is * missing, and refreshing a dump's metadata fetches the real one. * * @module */ import type { DatabaseSync } from "node:sqlite"; /** * Checks whether a stored thumbnail URL is a site icon. It is loose on * purpose, since artwork taken for an icon still shows whole on a tinted field, * only not cropped to fill the box. 0012 fixes the rows it got wrong. */ function isIconUrl(raw: string): boolean { let pathname: string; try { pathname = new URL(raw).pathname; } catch { return false; } return /favicon|apple-touch-icon|\/icons?\//i.test(pathname) || /\.(ico|svg)$/i.test(pathname); } /** * Run once by `runMigrations`. It leaves alone a row that already has a * `faviconUrl`, and one whose `rich_content` doesn't parse. 0012 undoes its * mistakes. */ export function up(db: DatabaseSync): void { const rows = db.prepare( `SELECT id, rich_content FROM dumps WHERE kind = 'url' AND rich_content IS NOT NULL;`, ).all() as { id: string; rich_content: string }[]; const update = db.prepare( `UPDATE dumps SET rich_content = ? WHERE id = ?;`, ); let patched = 0; for (const row of rows) { let rich: { thumbnailUrl?: string; faviconUrl?: string }; try { rich = JSON.parse(row.rich_content); } catch { continue; } if (rich.faviconUrl || !rich.thumbnailUrl) continue; if (!isIconUrl(rich.thumbnailUrl)) continue; const { thumbnailUrl: _dropped, ...rest } = rich; update.run( JSON.stringify({ ...rest, faviconUrl: rich.thumbnailUrl }), row.id, ); patched++; } if (patched > 0) { console.log( `[migrate] 0011: reclassified ${patched} favicon thumbnail(s)`, ); } }