| 1 | #!/usr/bin/env node
|
|---|
| 2 | /**
|
|---|
| 3 | * Backfill audio_tracks.duration voor bestaande tracks die nog géén duur hebben.
|
|---|
| 4 | * Leest de duur uit het mp3-bestand via ffmpeg (probeDuration — geen aparte
|
|---|
| 5 | * ffprobe-binary nodig). Idempotent: pakt alleen rijen met duration NULL of 0,
|
|---|
| 6 | * dus veilig herhaalbaar.
|
|---|
| 7 | *
|
|---|
| 8 | * npm run backfill:durations
|
|---|
| 9 | *
|
|---|
| 10 | * Respecteert AUDIO_PATH (env) net als de upload-route.
|
|---|
| 11 | */
|
|---|
| 12 | import path from 'path';
|
|---|
| 13 | import fs from 'fs';
|
|---|
| 14 | import { fileURLToPath } from 'url';
|
|---|
| 15 | import db from '../src/config/database.js';
|
|---|
| 16 | import { probeDuration } from '../src/services/AudioTranscoder.js';
|
|---|
| 17 |
|
|---|
| 18 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|---|
| 19 | const AUDIO_DIR = path.resolve(
|
|---|
| 20 | process.env.AUDIO_PATH || path.join(__dirname, '..', 'storage', 'audio')
|
|---|
| 21 | );
|
|---|
| 22 |
|
|---|
| 23 | // storage_path is absoluut (opgeslagen bij upload); val terug op AUDIO_DIR/filename.
|
|---|
| 24 | function resolveFile(t) {
|
|---|
| 25 | const candidates = [t.storage_path, t.filename ? path.join(AUDIO_DIR, t.filename) : null].filter(Boolean);
|
|---|
| 26 | for (const c of candidates) {
|
|---|
| 27 | try { if (fs.statSync(c).isFile()) return c; } catch { /* volgende kandidaat */ }
|
|---|
| 28 | }
|
|---|
| 29 | return null;
|
|---|
| 30 | }
|
|---|
| 31 |
|
|---|
| 32 | const rows = db.prepare(`
|
|---|
| 33 | SELECT t.id, m.filename, m.storage_path
|
|---|
| 34 | FROM audio_tracks t
|
|---|
| 35 | JOIN media m ON m.id = t.media_id
|
|---|
| 36 | WHERE (t.duration IS NULL OR t.duration = 0) AND m.filename IS NOT NULL
|
|---|
| 37 | `).all();
|
|---|
| 38 |
|
|---|
| 39 | console.log(`[backfill-durations] ${rows.length} track(s) zonder duur`);
|
|---|
| 40 | const update = db.prepare('UPDATE audio_tracks SET duration = ? WHERE id = ?');
|
|---|
| 41 |
|
|---|
| 42 | let ok = 0, miss = 0, fail = 0;
|
|---|
| 43 | for (const t of rows) {
|
|---|
| 44 | const file = resolveFile(t);
|
|---|
| 45 | if (!file) { console.warn(` - ${t.id}: bestand niet gevonden (${t.filename})`); miss++; continue; }
|
|---|
| 46 | try {
|
|---|
| 47 | const sec = await probeDuration(file);
|
|---|
| 48 | if (sec && sec > 0) { update.run(sec, t.id); ok++; console.log(` ✓ ${t.id}: ${sec}s`); }
|
|---|
| 49 | else { console.warn(` - ${t.id}: geen duur uit ffmpeg`); fail++; }
|
|---|
| 50 | } catch (e) { console.warn(` - ${t.id}: ${e.message}`); fail++; }
|
|---|
| 51 | }
|
|---|
| 52 | console.log(`[backfill-durations] klaar — ${ok} bijgewerkt, ${miss} bestand-mist, ${fail} mislukt`);
|
|---|
| 53 | process.exit(0);
|
|---|