Archived
fix(pipeline): dedupe+P2002; add red maple-leaf cover system; replace dead CBC feeds (Google News CN / NatPost Canada); worker dead-letter
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Generate per-category cover art used as the last-resort image fallback
|
||||
* (baked into /public/covers/*.svg, served statically).
|
||||
*
|
||||
* Design language matches the brand system: ink→brazil gradient (#161614 to
|
||||
* #45060c), maple-500 line art, Source Serif word label. 1200x630 (16:8).
|
||||
*
|
||||
* Usage: node scripts/make-covers.mjs (idempotent — overwrites)
|
||||
*/
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const outDir = join(root, 'public', 'covers');
|
||||
|
||||
const BG =
|
||||
'<defs><linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">' +
|
||||
'<stop offset="0" stop-color="#161614"/><stop offset="0.55" stop-color="#2b2b28"/>' +
|
||||
'<stop offset="1.3" stop-color="#45060c"/></linearGradient>' +
|
||||
'<pattern id="grid" width="48" height="48" patternUnits="userSpaceOnUse">' +
|
||||
'<path d="M48 0H0V48" fill="none" stroke="#f8402f" stroke-opacity="0.10" stroke-width="1"/>' +
|
||||
'</pattern></defs>';
|
||||
|
||||
const stroke = 'fill="none" stroke="#f8402f" stroke-opacity="0.38" stroke-width="10" stroke-linecap="round" stroke-linejoin="round"';
|
||||
const faint = 'fill="none" stroke="#f8402f" stroke-opacity="0.14" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"';
|
||||
|
||||
/** Simple geometric motif per category, centred at (880, 300). */
|
||||
const MOTIFS = {
|
||||
// Parliament Hill: central tower + two flanking towers with connecting wings
|
||||
national:
|
||||
`<g ${stroke}>` +
|
||||
`<path d="M760 440V300M880 440V180M1000 440V300"/>` +
|
||||
`<path d="M850 180L880 120L910 180" stroke-width="7"/>` +
|
||||
`<path d="M782 300L760 268L738 300M978 300L1000 268L1022 300" stroke-width="7"/>` +
|
||||
`<path d="M760 380H1000M820 340H940" stroke-width="7"/>` +
|
||||
`</g>` +
|
||||
`<g ${faint}>` +
|
||||
`<path d="M700 440H1060M700 160H1060"/>` +
|
||||
`</g>`,
|
||||
// maple leaf: stem + lobe outline
|
||||
canada:
|
||||
`<g ${stroke}>` +
|
||||
`<path d="M880 130L904 196L964 182L934 236L1006 250L948 296L1006 338L934 346L964 402L904 386L880 452L856 386L796 402L826 346L754 338L812 296L754 250L826 236L796 182L856 196Z"/>` +
|
||||
`<path d="M880 452V520"/>` +
|
||||
`</g>` +
|
||||
`<g ${faint}>` +
|
||||
`<path d="M700 452H1060"/>` +
|
||||
`</g>`,
|
||||
// world globe with meridian (top stories)
|
||||
'top-stories':
|
||||
`<g ${stroke}>` +
|
||||
`<circle cx="880" cy="305" r="150"/>` +
|
||||
`<ellipse cx="880" cy="305" rx="64" ry="150"/>` +
|
||||
`<path d="M736 254H1024M730 356H1030"/>` +
|
||||
`</g>` +
|
||||
`<g ${faint}>` +
|
||||
`<path d="M700 155H1060M700 455H1060"/>` +
|
||||
`</g>`,
|
||||
};
|
||||
|
||||
const LABEL = {
|
||||
national: 'National',
|
||||
canada: 'Canada',
|
||||
'top-stories': 'Top Stories',
|
||||
};
|
||||
|
||||
function cover(category, motif, label) {
|
||||
void category; // contextual only; filename is the real key
|
||||
return (
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630" role="img" aria-label="${label} — MapleBrief">` +
|
||||
BG +
|
||||
`<rect width="1200" height="630" fill="url(#bg)"/>` +
|
||||
`<rect width="1200" height="630" fill="url(#grid)"/>` +
|
||||
motif +
|
||||
`<text x="80" y="556" font-family="Georgia, 'Times New Roman', serif" font-size="44" font-weight="700" fill="#ffd9d4" fill-opacity="0.92">${label}</text>` +
|
||||
`<text x="80" y="592" font-family="Inter, 'Segoe UI', sans-serif" font-size="18" letter-spacing="4" fill="#f8402f" fill-opacity="0.55">MAPLEBRIEF</text>` +
|
||||
`</svg>`
|
||||
);
|
||||
}
|
||||
|
||||
await mkdir(outDir, { recursive: true });
|
||||
const covers = {
|
||||
'top-stories.svg': cover('top-stories', MOTIFS['top-stories'], LABEL['top-stories']),
|
||||
'national.svg': cover('national', MOTIFS.national, LABEL.national),
|
||||
'canada.svg': cover('canada', MOTIFS.canada, LABEL.canada),
|
||||
};
|
||||
for (const [name, svg] of Object.entries(covers)) {
|
||||
await writeFile(join(outDir, name), svg);
|
||||
console.log('wrote', name);
|
||||
}
|
||||
Reference in New Issue
Block a user