Newlay's Blossom enabled on the relay box (blobs inside the data volume); Caddy + DNS + TLS wired. The app now uploads there first, keeping blossom.primal.net and blossom.band as mirrors, and includes it in BLOSSOM_MIRROR_HOSTS for read fallback.
51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
/**
|
|
* Photo redundancy helpers.
|
|
*
|
|
* SkateSpots uploads images to Blossom, which is CONTENT-ADDRESSED: a blob's URL
|
|
* is `<host>/<sha256>` (optionally with a file extension). That means a mirror of
|
|
* the same file on another known host is derivable from the URL alone — no extra
|
|
* bookkeeping needed — so a dead photo host never has to leave a blank spot.
|
|
*
|
|
* We only derive mirrors for Blossom-style hash paths; anything else is left
|
|
* untouched (an external image URL has no meaningful alternative location).
|
|
*/
|
|
|
|
/** Hosts the app uploads to, and therefore the hosts we can mirror across. */
|
|
export const BLOSSOM_MIRROR_HOSTS = ['blossom.skate-spots.org', 'blossom.primal.net', 'blossom.band'];
|
|
|
|
/** `<64-hex>` or `<64-hex>.<ext>` */
|
|
const HASH_RE = /^([0-9a-f]{64})(\.[a-z0-9]+)?$/i;
|
|
|
|
/**
|
|
* Ordered candidate URLs for an image: the original first, then any explicitly
|
|
* supplied fallbacks, then same-hash mirrors on the other known Blossom hosts.
|
|
*/
|
|
export function imageCandidates(
|
|
src: string | undefined | null,
|
|
extra: string[] = [],
|
|
): string[] {
|
|
const out: string[] = [];
|
|
const add = (url?: string | null) => {
|
|
if (typeof url === 'string' && url && !out.includes(url)) out.push(url);
|
|
};
|
|
|
|
add(src);
|
|
for (const url of extra) add(url);
|
|
if (!src) return out;
|
|
|
|
try {
|
|
const parsed = new URL(src);
|
|
const last = parsed.pathname.split('/').filter(Boolean).pop() ?? '';
|
|
const match = HASH_RE.exec(last);
|
|
if (match) {
|
|
for (const host of BLOSSOM_MIRROR_HOSTS) {
|
|
if (host === parsed.hostname) continue;
|
|
add(`${parsed.protocol}//${host}/${match[1]}${match[2] ?? ''}`);
|
|
}
|
|
}
|
|
} catch {
|
|
// Relative or malformed URL — nothing to mirror.
|
|
}
|
|
|
|
return out;
|
|
}
|