mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 19:03:46 +02:00
Add lyrics field to metadata
This commit is contained in:
+2
-1
@@ -54,7 +54,8 @@
|
|||||||
data: blobData,
|
data: blobData,
|
||||||
kind: 'coverFront',
|
kind: 'coverFront',
|
||||||
mimeType: 'image/jpeg'
|
mimeType: 'image/jpeg'
|
||||||
}]
|
}],
|
||||||
|
lyrics: "There's no way\nThat it's not going there"
|
||||||
});
|
});
|
||||||
|
|
||||||
const conversion = await Mediabunny.Conversion.init({
|
const conversion = await Mediabunny.Conversion.init({
|
||||||
|
|||||||
+14
-9
@@ -9,6 +9,7 @@ export type MediaMetadata = {
|
|||||||
discNumber?: number;
|
discNumber?: number;
|
||||||
genre?: string;
|
genre?: string;
|
||||||
releasedAt?: Date;
|
releasedAt?: Date;
|
||||||
|
lyrics?: string;
|
||||||
images?: {
|
images?: {
|
||||||
data: Uint8Array;
|
data: Uint8Array;
|
||||||
mimeType: string;
|
mimeType: string;
|
||||||
@@ -47,6 +48,9 @@ export const validateMediaMetadata = (metadata: MediaMetadata) => {
|
|||||||
if (metadata.releasedAt !== undefined && !(metadata.releasedAt instanceof Date)) {
|
if (metadata.releasedAt !== undefined && !(metadata.releasedAt instanceof Date)) {
|
||||||
throw new TypeError('metadata.releasedAt, when provided, must be a Date.');
|
throw new TypeError('metadata.releasedAt, when provided, must be a Date.');
|
||||||
}
|
}
|
||||||
|
if (metadata.lyrics !== undefined && typeof metadata.lyrics !== 'string') {
|
||||||
|
throw new TypeError('metadata.lyrics, when provided, must be a string.');
|
||||||
|
}
|
||||||
if (metadata.comment !== undefined && typeof metadata.comment !== 'string') {
|
if (metadata.comment !== undefined && typeof metadata.comment !== 'string') {
|
||||||
throw new TypeError('metadata.comment, when provided, must be a string.');
|
throw new TypeError('metadata.comment, when provided, must be a string.');
|
||||||
}
|
}
|
||||||
@@ -72,14 +76,15 @@ export const validateMediaMetadata = (metadata: MediaMetadata) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const mediaMetadataIsEmpty = (metadata: MediaMetadata) => {
|
export const mediaMetadataIsEmpty = (metadata: MediaMetadata) => {
|
||||||
return !metadata.title
|
return metadata.title === undefined
|
||||||
&& !metadata.artist
|
&& metadata.artist === undefined
|
||||||
&& !metadata.album
|
&& metadata.album === undefined
|
||||||
&& !metadata.albumArtist
|
&& metadata.albumArtist === undefined
|
||||||
&& !metadata.trackNumber
|
&& metadata.trackNumber === undefined
|
||||||
&& !metadata.discNumber
|
&& metadata.discNumber === undefined
|
||||||
&& !metadata.genre
|
&& metadata.genre === undefined
|
||||||
&& !metadata.releasedAt
|
&& metadata.releasedAt === undefined
|
||||||
&& !metadata.comment
|
&& metadata.lyrics === undefined
|
||||||
|
&& metadata.comment === undefined
|
||||||
&& (!metadata.images || metadata.images.length === 0);
|
&& (!metadata.images || metadata.images.length === 0);
|
||||||
};
|
};
|
||||||
|
|||||||
+13
-10
@@ -130,38 +130,41 @@ export class Mp3Muxer extends Muxer {
|
|||||||
|
|
||||||
const startPos = this.writer.getPos();
|
const startPos = this.writer.getPos();
|
||||||
|
|
||||||
if (metadata.title) {
|
if (metadata.title !== undefined) {
|
||||||
this.mp3Writer.writeId3V2TextFrame('TIT2', metadata.title);
|
this.mp3Writer.writeId3V2TextFrame('TIT2', metadata.title);
|
||||||
}
|
}
|
||||||
if (metadata.artist) {
|
if (metadata.artist !== undefined) {
|
||||||
this.mp3Writer.writeId3V2TextFrame('TPE1', metadata.artist);
|
this.mp3Writer.writeId3V2TextFrame('TPE1', metadata.artist);
|
||||||
}
|
}
|
||||||
if (metadata.album) {
|
if (metadata.album !== undefined) {
|
||||||
this.mp3Writer.writeId3V2TextFrame('TALB', metadata.album);
|
this.mp3Writer.writeId3V2TextFrame('TALB', metadata.album);
|
||||||
}
|
}
|
||||||
if (metadata.albumArtist) {
|
if (metadata.albumArtist !== undefined) {
|
||||||
this.mp3Writer.writeId3V2TextFrame('TPE2', metadata.albumArtist);
|
this.mp3Writer.writeId3V2TextFrame('TPE2', metadata.albumArtist);
|
||||||
}
|
}
|
||||||
if (metadata.trackNumber) {
|
if (metadata.trackNumber !== undefined) {
|
||||||
this.mp3Writer.writeId3V2TextFrame('TRCK', metadata.trackNumber.toString());
|
this.mp3Writer.writeId3V2TextFrame('TRCK', metadata.trackNumber.toString());
|
||||||
}
|
}
|
||||||
if (metadata.discNumber) {
|
if (metadata.discNumber !== undefined) {
|
||||||
this.mp3Writer.writeId3V2TextFrame('TPOS', metadata.discNumber.toString());
|
this.mp3Writer.writeId3V2TextFrame('TPOS', metadata.discNumber.toString());
|
||||||
}
|
}
|
||||||
if (metadata.genre) {
|
if (metadata.genre !== undefined) {
|
||||||
this.mp3Writer.writeId3V2TextFrame('TCON', metadata.genre);
|
this.mp3Writer.writeId3V2TextFrame('TCON', metadata.genre);
|
||||||
}
|
}
|
||||||
if (metadata.releasedAt) {
|
if (metadata.releasedAt !== undefined) {
|
||||||
this.mp3Writer.writeId3V2TextFrame('TDRC', metadata.releasedAt.toISOString().split('.')[0]!);
|
this.mp3Writer.writeId3V2TextFrame('TDRC', metadata.releasedAt.toISOString().split('.')[0]!);
|
||||||
}
|
}
|
||||||
if (metadata.comment) {
|
if (metadata.lyrics !== undefined) {
|
||||||
|
this.mp3Writer.writeId3V2LyricsFrame(metadata.lyrics);
|
||||||
|
}
|
||||||
|
if (metadata.comment !== undefined) {
|
||||||
this.mp3Writer.writeId3V2CommentFrame(metadata.comment);
|
this.mp3Writer.writeId3V2CommentFrame(metadata.comment);
|
||||||
}
|
}
|
||||||
if (metadata.images) {
|
if (metadata.images) {
|
||||||
const pictureTypeMap = { coverFront: 0x03, coverBack: 0x04, unknown: 0x00 };
|
const pictureTypeMap = { coverFront: 0x03, coverBack: 0x04, unknown: 0x00 };
|
||||||
for (const image of metadata.images) {
|
for (const image of metadata.images) {
|
||||||
const pictureType = pictureTypeMap[image.kind];
|
const pictureType = pictureTypeMap[image.kind];
|
||||||
const description = image.description || '';
|
const description = image.description ?? '';
|
||||||
this.mp3Writer.writeId3V2ApicFrame(image.mimeType, pictureType, description, image.data);
|
this.mp3Writer.writeId3V2ApicFrame(image.mimeType, pictureType, description, image.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -350,6 +350,14 @@ export class Mp3Reader {
|
|||||||
}
|
}
|
||||||
}; break;
|
}; break;
|
||||||
|
|
||||||
|
case 'USLT':
|
||||||
|
case 'ULT': {
|
||||||
|
const encoding = reader.readU8();
|
||||||
|
reader.pos += 3; // Skip language
|
||||||
|
reader.readId3V2Text(encoding, frameEndPos); // Short content description
|
||||||
|
metadata.lyrics ??= reader.readId3V2Text(encoding, frameEndPos);
|
||||||
|
}; break;
|
||||||
|
|
||||||
case 'COMM':
|
case 'COMM':
|
||||||
case 'COM': {
|
case 'COM': {
|
||||||
const encoding = reader.readU8();
|
const encoding = reader.readU8();
|
||||||
|
|||||||
+26
-4
@@ -17,6 +17,7 @@ import {
|
|||||||
SAMPLING_RATES,
|
SAMPLING_RATES,
|
||||||
XING,
|
XING,
|
||||||
} from '../../shared/mp3-misc';
|
} from '../../shared/mp3-misc';
|
||||||
|
import { Id3V2TextEncoding } from './mp3-reader';
|
||||||
|
|
||||||
export type XingFrameData = {
|
export type XingFrameData = {
|
||||||
mpegVersionId: number;
|
mpegVersionId: number;
|
||||||
@@ -89,7 +90,7 @@ export class Mp3Writer {
|
|||||||
this.writeSynchsafeU32(frameSize);
|
this.writeSynchsafeU32(frameSize);
|
||||||
this.writeU16(0x0000);
|
this.writeU16(0x0000);
|
||||||
|
|
||||||
this.writeU8(useIso88591 ? 0x00 : 0x03);
|
this.writeU8(useIso88591 ? Id3V2TextEncoding.ISO_8859_1 : Id3V2TextEncoding.UTF_8);
|
||||||
if (useIso88591) {
|
if (useIso88591) {
|
||||||
this.writeIsoString(text);
|
this.writeIsoString(text);
|
||||||
} else {
|
} else {
|
||||||
@@ -97,17 +98,38 @@ export class Mp3Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeId3V2LyricsFrame(lyrics: string) {
|
||||||
|
const useIso88591 = isIso88591Compatible(lyrics);
|
||||||
|
const shortDescription = '';
|
||||||
|
const frameSize = 1 + 3 + shortDescription.length + 1 + lyrics.length + 1;
|
||||||
|
|
||||||
|
this.writeAscii('USLT');
|
||||||
|
this.writeSynchsafeU32(frameSize);
|
||||||
|
this.writeU16(0x0000);
|
||||||
|
|
||||||
|
this.writeU8(useIso88591 ? Id3V2TextEncoding.ISO_8859_1 : Id3V2TextEncoding.UTF_8);
|
||||||
|
this.writeAscii('und');
|
||||||
|
|
||||||
|
if (useIso88591) {
|
||||||
|
this.writeIsoString(shortDescription);
|
||||||
|
this.writeIsoString(lyrics);
|
||||||
|
} else {
|
||||||
|
this.writeUtf8String(shortDescription);
|
||||||
|
this.writeUtf8String(lyrics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
writeId3V2CommentFrame(comment: string) {
|
writeId3V2CommentFrame(comment: string) {
|
||||||
const useIso88591 = isIso88591Compatible(comment);
|
const useIso88591 = isIso88591Compatible(comment);
|
||||||
const textDataLength = useIso88591 ? comment.length : textEncoder.encode(comment).byteLength;
|
const textDataLength = useIso88591 ? comment.length : textEncoder.encode(comment).byteLength;
|
||||||
const frameSize = 1 + 3 + 1 + textDataLength + 1;
|
|
||||||
const shortDescription = '';
|
const shortDescription = '';
|
||||||
|
const frameSize = 1 + 3 + shortDescription.length + 1 + textDataLength + 1;
|
||||||
|
|
||||||
this.writeAscii('COMM');
|
this.writeAscii('COMM');
|
||||||
this.writeSynchsafeU32(frameSize);
|
this.writeSynchsafeU32(frameSize);
|
||||||
this.writeU16(0x0000);
|
this.writeU16(0x0000);
|
||||||
|
|
||||||
this.writeU8(useIso88591 ? 0x00 : 0x03);
|
this.writeU8(useIso88591 ? Id3V2TextEncoding.ISO_8859_1 : Id3V2TextEncoding.UTF_8);
|
||||||
this.writeU8(0x75); // 'u'
|
this.writeU8(0x75); // 'u'
|
||||||
this.writeU8(0x6E); // 'n'
|
this.writeU8(0x6E); // 'n'
|
||||||
this.writeU8(0x64); // 'd'
|
this.writeU8(0x64); // 'd'
|
||||||
@@ -130,7 +152,7 @@ export class Mp3Writer {
|
|||||||
this.writeSynchsafeU32(frameSize);
|
this.writeSynchsafeU32(frameSize);
|
||||||
this.writeU16(0x0000);
|
this.writeU16(0x0000);
|
||||||
|
|
||||||
this.writeU8(useIso88591 ? 0x00 : 0x03);
|
this.writeU8(useIso88591 ? Id3V2TextEncoding.ISO_8859_1 : Id3V2TextEncoding.UTF_8);
|
||||||
|
|
||||||
if (useIso88591) {
|
if (useIso88591) {
|
||||||
this.writeIsoString(mimeType);
|
this.writeIsoString(mimeType);
|
||||||
|
|||||||
Reference in New Issue
Block a user