From fcec67645aae2e1b2b4bdb87f0c8f65fb4ef6372 Mon Sep 17 00:00:00 2001 From: Vanilagy <1696106+Vanilagy@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:10:16 +0200 Subject: [PATCH] Allow object for `tags` field in conversion --- dev/convert.html | 54 ++++++++++++++-------------- dev/demux.html | 7 +--- docs/guide/converting-media-files.md | 10 +++--- src/conversion.ts | 31 +++++++++++----- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/dev/convert.html b/dev/convert.html index 7824830..ea8de68 100644 --- a/dev/convert.html +++ b/dev/convert.html @@ -47,23 +47,6 @@ format: outputFormat, target }); - output.setMetadataTags({ - title: 'Bigggy', - artist: 'Buck Bunny', - images: [{ - data: blobData, - kind: 'coverFront', - mimeType: 'image/jpeg' - }], - trackNumber: 4, - tracksTotal: 10, - discNumber: 5, - discNumberMax: 8, - lyrics: "There's no way\nThat it's not going there", - raw: { - 'ENCODER': 'Mediabunny epic own encoder' - } - }); const conversion = await Mediabunny.Conversion.init({ input: new Mediabunny.Input({ @@ -109,16 +92,16 @@ */ video: () => ({ //discard: true, - crop: { - left: 0, - top: 0, - width: 500, - height: 500, - }, - rotate: 90, - width: 200, - height: 500, - fit: 'contain', + //crop: { + // left: 0, + // top: 0, + // width: 500, + // height: 500, + //}, + //rotate: 90, + //width: 200, + //height: 500, + //fit: 'contain', //forceTranscode: true, //codec: 'avc', //fit: 'contain', @@ -141,6 +124,23 @@ //width: 200, //height: 100, }), + tags: { + title: 'Bigggy', + artist: 'Buck Bunny', + images: [{ + data: blobData, + kind: 'coverFront', + mimeType: 'image/jpeg' + }], + trackNumber: 4, + tracksTotal: 10, + discNumber: 5, + discsTotal: 8, + lyrics: "There's no way\nThat it's not going there", + raw: { + 'AIGC': 'Mediabunny epic own encoder' + } + }, trim: { start: 10, end: 20 diff --git a/dev/demux.html b/dev/demux.html index b844f7d..7df202b 100644 --- a/dev/demux.html +++ b/dev/demux.html @@ -14,12 +14,7 @@ source: new Mediabunny.BlobSource(file), }); - const audioTrack = await input.getPrimaryAudioTrack(); - const sink = new Mediabunny.EncodedPacketSink(audioTrack); - - for await (const packet of sink.packets()) { - console.log(packet); - } + console.log(await input.getMetadataTags()) /* const sink = new Mediabunny.EncodedPacketSink(videoTrack); diff --git a/docs/guide/converting-media-files.md b/docs/guide/converting-media-files.md index 91a3aae..164963d 100644 --- a/docs/guide/converting-media-files.md +++ b/docs/guide/converting-media-files.md @@ -49,7 +49,7 @@ await conversion.execute(); That's it! A `Conversion` simply takes an instance of `Input` and `Output`, then reads the data from the input and writes it to the output. If you're unfamiliar with [`Input`](./reading-media-files) and [`Output`](./writing-media-files), check out their respective guides. ::: info -The `Output` passed to the `Conversion` must be *fresh*; that is, it must have no added tracks and be in the `'pending'` state (not started yet). +The `Output` passed to the `Conversion` must be *fresh*; that is, it must have no added tracks or metadata tags and be in the `'pending'` state (not started yet). ::: Unconfigured, the conversion process handles all the details automatically, such as: @@ -299,17 +299,17 @@ By default, any [descriptive metadata tags](../api/MetadataTags.md) of the input // Set your own metadata: const conversion = await Conversion.init({ // ... - tags: () => ({ + tags: { title: 're:Turning', artist: 'Alexander Panos', - }), + }, // ... }); // Or, augment the input's metadata: const conversion = await Conversion.init({ // ... - tags: inputTags => ({ + tags: (inputTags) => ({ ...inputTags, // Keep the existing metadata images: [{ // And add cover art data: new Uint8Array(...), @@ -324,7 +324,7 @@ const conversion = await Conversion.init({ // Or, remove all metadata const conversion = await Conversion.init({ // ... - tags: () => ({}), + tags: {}, // ... }); ``` diff --git a/src/conversion.ts b/src/conversion.ts index 10eb8f8..066a392 100644 --- a/src/conversion.ts +++ b/src/conversion.ts @@ -89,13 +89,13 @@ export type ConversionOptions = { }; /** - * A callback that returns or resolves to the descriptive metadata tags that should be written to the output file. - * As input, this function will be passed the tags of the input file, allowing you to modify, augment or extend - * them. + * An object or a callback that returns or resolves to an object containing the descriptive metadata tags that + * should be written to the output file. If a function is passed, it will be passed the tags of the input file as + * its first argument, allowing you to modify, augment or extend them. * * If no function is set, the input's metadata tags will be copied to the output. */ - tags?: (inputTags: MetadataTags) => MaybePromise; + tags?: MetadataTags | ((inputTags: MetadataTags) => MaybePromise); }; /** @@ -395,8 +395,12 @@ export class Conversion { if (!(options.output instanceof Output)) { throw new TypeError('options.output must be an Output.'); } - if (options.output._tracks.length > 0 || options.output.state !== 'pending') { - throw new TypeError('options.output must be fresh: no tracks added and not started.'); + if ( + options.output._tracks.length > 0 + || Object.keys(options.output._metadataTags).length > 0 + || options.output.state !== 'pending' + ) { + throw new TypeError('options.output must be fresh: no tracks or metadata tags added and not started.'); } if (typeof options.video !== 'function') { @@ -426,8 +430,15 @@ export class Conversion { && options.trim.start >= options.trim.end) { throw new TypeError('options.trim.start must be less than options.trim.end.'); } - if (options.tags !== undefined && typeof options.tags !== 'function') { - throw new TypeError('options.tags, when provided, must be a function.'); + if ( + options.tags !== undefined + && (typeof options.tags !== 'object' || !options.tags) + && typeof options.tags !== 'function' + ) { + throw new TypeError('options.tags, when provided, must be an object or a function.'); + } + if (typeof options.tags === 'object') { + validateMetadataTags(options.tags); } this._options = options; @@ -519,7 +530,9 @@ export class Conversion { let outputTags: MetadataTags; if (this._options.tags) { - const result = await this._options.tags(inputTags); + const result = typeof this._options.tags === 'function' + ? await this._options.tags(inputTags) + : this._options.tags; validateMetadataTags(result); outputTags = result;