Add player functionality with HLS support and API integration
- Implemented a new Player class in player.js to handle audio playback, including HLS support using hls.js. - Created a shared API module in api.js for making HTTP requests with proper error handling. - Added DOM utility functions in dom.js for creating and clearing elements. - Introduced WebSocket connection handling in ws.js for real-time updates. - Developed a comprehensive CSS stylesheet for styling the application, including a high-contrast theme.
This commit is contained in:
48
server/scripts/restore-images-from-seed.js
Normal file
48
server/scripts/restore-images-from-seed.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// Restore image_url from seed JSON files for any station where it is currently NULL.
|
||||
// Match priority: explicit uuid → uuidFromSlug(slug) → exact name.
|
||||
import 'dotenv/config';
|
||||
import Database from 'better-sqlite3';
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { resolve, dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createHash } from 'node:crypto';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const SEED_DIR = resolve(__dirname, '../../data/seed');
|
||||
|
||||
function uuidFromSlug(slug) {
|
||||
const h = createHash('sha1').update('oradio:' + slug).digest('hex');
|
||||
return [h.slice(0, 8), h.slice(8, 12), '5' + h.slice(13, 16), '8' + h.slice(17, 20), h.slice(20, 32)].join('-');
|
||||
}
|
||||
|
||||
const db = new Database(process.env.DB_PATH || './data/db/oradio.sqlite');
|
||||
const apply = process.argv.includes('--apply');
|
||||
|
||||
const entries = [];
|
||||
for (const f of readdirSync(SEED_DIR).filter((x) => x.startsWith('stations') && x.endsWith('.json'))) {
|
||||
try {
|
||||
const data = JSON.parse(readFileSync(join(SEED_DIR, f), 'utf8'));
|
||||
if (Array.isArray(data)) entries.push(...data);
|
||||
} catch { }
|
||||
}
|
||||
|
||||
const byUuid = new Map();
|
||||
const byName = new Map();
|
||||
for (const e of entries) {
|
||||
if (!e.image_url) continue;
|
||||
const u = e.uuid || (e.slug ? uuidFromSlug(e.slug) : null);
|
||||
if (u) byUuid.set(u, e.image_url);
|
||||
if (e.name) byName.set(e.name.toLowerCase(), e.image_url);
|
||||
}
|
||||
|
||||
const rows = db.prepare(`SELECT id, uuid, name FROM stations WHERE image_url IS NULL OR image_url = ''`).all();
|
||||
const upd = db.prepare('UPDATE stations SET image_url = ? WHERE id = ?');
|
||||
let restored = 0;
|
||||
for (const r of rows) {
|
||||
const url = (r.uuid && byUuid.get(r.uuid)) || byName.get(r.name?.toLowerCase());
|
||||
if (!url) continue;
|
||||
console.log(`restore ${r.name} -> ${url}`);
|
||||
if (apply) upd.run(url, r.id);
|
||||
restored++;
|
||||
}
|
||||
console.log(`Done. restored=${restored}${apply ? '' : ' (dry run; pass --apply to write)'}`);
|
||||
Reference in New Issue
Block a user