82 lines
2.3 KiB
TypeScript
82 lines
2.3 KiB
TypeScript
/**
|
|
* Adds the `start` parameter to the YouTube embed URLs stored before the
|
|
* YouTube provider carried it over. `rich_content.embedUrl` is computed when a
|
|
* dump is posted, and used to drop the source URL's `t` (`?t=1265`,
|
|
* `?t=1h2m3s`), so those videos played from 0:00.
|
|
*
|
|
* It reads the time from the stored source URL and fetches nothing. It keeps
|
|
* its own copy of the parsing, so that it migrates every database alike should
|
|
* the provider's change.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import type { DatabaseSync } from "node:sqlite";
|
|
|
|
/**
|
|
* Returns the seconds in `url`'s `t` or `start`, which may be plain seconds,
|
|
* `90s`, `20m5s` or `1h2m3s`.
|
|
*/
|
|
function extractStartSeconds(url: string): number | null {
|
|
let raw: string | null;
|
|
try {
|
|
const u = new URL(url);
|
|
raw = u.searchParams.get("t") ?? u.searchParams.get("start");
|
|
} catch {
|
|
return null;
|
|
}
|
|
if (!raw) return null;
|
|
|
|
if (/^\d+$/.test(raw)) return Number(raw);
|
|
|
|
const hms = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/i.exec(raw);
|
|
if (!hms || (!hms[1] && !hms[2] && !hms[3])) return null;
|
|
return Number(hms[1] ?? 0) * 3600 + Number(hms[2] ?? 0) * 60 +
|
|
Number(hms[3] ?? 0);
|
|
}
|
|
|
|
/**
|
|
* Run once by `runMigrations`. It leaves alone an embed URL that already has a
|
|
* `start`, and a row whose `rich_content` doesn't parse.
|
|
*/
|
|
export function up(db: DatabaseSync): void {
|
|
const rows = db.prepare(
|
|
`SELECT id, url, rich_content FROM dumps
|
|
WHERE kind = 'url' AND url IS NOT NULL AND rich_content IS NOT NULL;`,
|
|
).all() as { id: string; url: 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: { type?: string; embedUrl?: string };
|
|
try {
|
|
rich = JSON.parse(row.rich_content);
|
|
} catch {
|
|
continue;
|
|
}
|
|
if (rich.type !== "youtube" || !rich.embedUrl) continue;
|
|
|
|
const start = extractStartSeconds(row.url);
|
|
if (!start) continue;
|
|
|
|
let embed: URL;
|
|
try {
|
|
embed = new URL(rich.embedUrl);
|
|
} catch {
|
|
continue;
|
|
}
|
|
if (embed.searchParams.has("start")) continue;
|
|
|
|
embed.searchParams.set("start", String(start));
|
|
update.run(JSON.stringify({ ...rich, embedUrl: embed.toString() }), row.id);
|
|
patched++;
|
|
}
|
|
|
|
if (patched > 0) {
|
|
console.log(`[migrate] 0010: added start offset to ${patched} embed(s)`);
|
|
}
|
|
}
|