forked from ORGANISATION-KA-INTERNATIONALE/FEDIVERSE-OKI
6c2df9b1cd
- scripts/fetch-podcast-cover.mjs : pochettes Castopod (flux + épisodes) téléchargées et converties en WebP 512px au prebuild (2,3 Mo → 59 Ko) - scripts/optimize-remote-images.mjs : vignettes PeerTube (640px), avatars (96px) et médias Mastodon (800px) optimisés en WebP + mapping src/lib/server/image-map.json consommé par mapImage() - a11y : liens footer soulignés dans les paragraphes, cibles tactiles ≥24px sur les liens des posts Mastodon - image-map.ts : import JSON statique (le createRequire pointait sur le bundle) - doc : étape prebuild documentée (dépendance ImageMagick) Lighthouse mobile : 97/100/100/100 — LCP 2,4s, TBT 50ms, CLS 0, poids accueil 900 Ko (budgets du playbook respectés)
52 lines
1.8 KiB
JavaScript
52 lines
1.8 KiB
JavaScript
import { writeFileSync, statSync, mkdirSync } from 'node:fs';
|
|
import { execFileSync } from 'node:child_process';
|
|
import { join, dirname, basename } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const FEED_URL = 'https://kute.o-k-i.net/@annu_kute_cedric/feed';
|
|
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const EPISODES_DIR = join(ROOT, 'static', 'images', 'episodes');
|
|
const CHANNEL_COVER = join(ROOT, 'static', 'images', 'podcast-cover.webp');
|
|
|
|
mkdirSync(EPISODES_DIR, { recursive: true });
|
|
|
|
const xml = await (await fetch(FEED_URL)).text();
|
|
|
|
const urls = new Set();
|
|
const channel = xml.split('<item')[0] ?? '';
|
|
const channelMatch =
|
|
channel.match(/<itunes:image[^>]*href="([^"]+)"/i) ?? channel.match(/<url>([^<]+)<\/url>/i);
|
|
if (channelMatch) urls.add(channelMatch[1]);
|
|
|
|
for (const item of xml.split(/<item[\s>]/i).slice(1)) {
|
|
const match = item.match(/<itunes:image[^>]*href="([^"]+)"/i);
|
|
if (match) urls.add(match[1]);
|
|
}
|
|
|
|
let total = 0;
|
|
|
|
for (const url of urls) {
|
|
const isChannel = url === channelMatch?.[1];
|
|
const out = isChannel
|
|
? CHANNEL_COVER
|
|
: join(EPISODES_DIR, basename(url).replace(/\.(png|jpe?g|gif|webp)$/i, '.webp'));
|
|
try {
|
|
const res = await fetch(url);
|
|
if (!res.ok) {
|
|
console.warn(`[covers] HTTP ${res.status} pour ${url}`);
|
|
continue;
|
|
}
|
|
const source = Buffer.from(await res.arrayBuffer());
|
|
const tmp = `/tmp/opencode/cover-${Date.now()}`;
|
|
writeFileSync(tmp, source);
|
|
execFileSync('convert', [tmp, '-resize', '512x512>', '-quality', '82', '-define', 'webp:method=6', out]);
|
|
const size = statSync(out).size;
|
|
total += size;
|
|
console.log(`[covers] ${basename(out)} : ${Math.round(source.length / 1024)} Ko → ${Math.round(size / 1024)} Ko`);
|
|
} catch (err) {
|
|
console.warn(`[covers] échec pour ${url}:`, err.message);
|
|
}
|
|
}
|
|
|
|
console.log(`[covers] total optimisé : ${Math.round(total / 1024)} Ko`);
|