Changeset 0d7acdf in Klonkt for src/services/AudioTranscoder.js


Ignore:
Timestamp:
06/20/2026 05:04:13 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
3ec691c
Parents:
fef781e
Message:

feat(audio): per-track owner/credit + license (+ written to mp3 ID3 tags)

New per-track metadata: credit (copyright holder) + license. Editable in the
track editor (license with datalist presets: All rights reserved, CC BY/…/CC0).

  • DB: audio_tracks.credit + .license.
  • ID3: on upload and on every metadata edit the tags are written into the mp3 itself — copyright=credit, comment=license (new retagMp3() in the transcoder, -c copy, no re-encode) → ownership travels with a download.
  • Visible: "credit · license" line below each track (post-audio-track).

busters audio.css?v=7.

Co-Authored-By: Claude <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/AudioTranscoder.js

    rfef781e r0d7acdf  
    138138
    139139/**
     140 * Herschrijf de ID3-tags van een BESTAANDE mp3 zonder her-encoden (`-c copy`).
     141 * Gebruikt bij het bewerken van track-metadata (titel/artiest/album/credit/licentie)
     142 * zodat de eigendomsinfo in het bestand zelf meereist bij een download.
     143 * ffmpeg kan niet in-place editen → schrijf naar tmp en hernoem atomisch terug.
     144 */
     145export async function retagMp3({ filePath, tags = {} }) {
     146  if (!filePath) throw new Error('retagMp3: filePath required');
     147  await stat(filePath); // throws als 't bestand mist
     148  const dir = path.dirname(filePath);
     149  const base = path.basename(filePath, path.extname(filePath));
     150  const tmpPath = path.join(dir, `${base}.retag-${process.pid}.mp3`);
     151  try {
     152    await new Promise((resolve, reject) => {
     153      const cmd = ffmpeg(filePath)
     154        .audioCodec('copy')        // geen her-encode → snel, geen kwaliteitsverlies
     155        .format('mp3')
     156        .outputOptions('-id3v2_version', '3')
     157        .outputOptions('-map_metadata', '-1')
     158        .outputOptions('-vn');
     159      if (tags.title)     cmd.outputOptions('-metadata', `title=${tags.title}`);
     160      if (tags.artist)    cmd.outputOptions('-metadata', `artist=${tags.artist}`);
     161      if (tags.album)     cmd.outputOptions('-metadata', `album=${tags.album}`);
     162      if (tags.copyright) cmd.outputOptions('-metadata', `copyright=${tags.copyright}`);
     163      if (tags.comment)   cmd.outputOptions('-metadata', `comment=${tags.comment}`);
     164      cmd.on('error', (err, so, se) => reject(new Error(((err && err.message) || 'ffmpeg') + (se ? ' | ' + se : ''))))
     165         .on('end', () => resolve())
     166         .save(tmpPath);
     167    });
     168    const s = await stat(tmpPath);
     169    if (s.size === 0) throw new Error('retag output is leeg');
     170    await rename(tmpPath, filePath);
     171    return { filePath, size: s.size };
     172  } catch (err) {
     173    try { await unlink(tmpPath); } catch { /* tmp bestaat mogelijk niet */ }
     174    throw err;
     175  }
     176}
     177
     178/**
    140179 * Run a single ffmpeg pass: input -> tmp output.
    141180 * Returns a promise that resolves when ffmpeg exits cleanly, rejects otherwise.
     
    167206    // breaks any value containing a space (e.g. "Test Artist" gets parsed
    168207    // as a separate output filename).
    169     if (tags.title)  cmd.outputOptions('-metadata', `title=${tags.title}`);
    170     if (tags.artist) cmd.outputOptions('-metadata', `artist=${tags.artist}`);
    171     if (tags.album)  cmd.outputOptions('-metadata', `album=${tags.album}`);
     208    if (tags.title)     cmd.outputOptions('-metadata', `title=${tags.title}`);
     209    if (tags.artist)    cmd.outputOptions('-metadata', `artist=${tags.artist}`);
     210    if (tags.album)     cmd.outputOptions('-metadata', `album=${tags.album}`);
     211    if (tags.copyright) cmd.outputOptions('-metadata', `copyright=${tags.copyright}`); // ID3 TCOP — eigenaar/credit
     212    if (tags.comment)   cmd.outputOptions('-metadata', `comment=${tags.comment}`);     // ID3 COMM — licentie
    172213
    173214    cmd
Note: See TracChangeset for help on using the changeset viewer.