mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 22:03:49 +02:00
Add special TXXX handling for ID3v2
This commit is contained in:
+54
-7
@@ -16,6 +16,7 @@ import {
|
||||
assertNever,
|
||||
keyValueIterator,
|
||||
toDataView,
|
||||
isRecordStringString,
|
||||
} from './misc';
|
||||
import { FileSlice, readAscii, readBytes, readU32Be, readU8 } from './reader';
|
||||
import { Writer } from './writer';
|
||||
@@ -225,7 +226,14 @@ export const parseId3V2Tag = (slice: FileSlice, header: Id3V2Header, tags: Metad
|
||||
}
|
||||
|
||||
tags.raw ??= {};
|
||||
if (frame.id[0] === 'T') {
|
||||
if (frame.id === 'TXXX') {
|
||||
const txxx = tags.raw['TXXX'] ??= {};
|
||||
const encoding = reader.readId3V2TextEncoding();
|
||||
const description = reader.readId3V2Text(encoding, frameEndPos);
|
||||
const value = reader.readId3V2Text(encoding, frameEndPos);
|
||||
|
||||
(txxx as Record<string, string>)[description] ??= value;
|
||||
} else if (frame.id[0] === 'T') {
|
||||
// It's a text frame, let's decode as text
|
||||
tags.raw[frame.id] ??= reader.readId3V2EncodingAndText(frameEndPos);
|
||||
} else {
|
||||
@@ -761,13 +769,51 @@ export class Id3V2Writer {
|
||||
|
||||
let bytes: Uint8Array;
|
||||
if (typeof value === 'string') {
|
||||
const encoded = textEncoder.encode(value);
|
||||
bytes = new Uint8Array(encoded.byteLength + 2);
|
||||
bytes[0] = Id3V2TextEncoding.UTF_8;
|
||||
bytes.set(encoded, 1);
|
||||
// Last byte is the null terminator
|
||||
const useIso88591 = isIso88591Compatible(value);
|
||||
if (useIso88591) {
|
||||
bytes = new Uint8Array(value.length + 2);
|
||||
bytes[0] = Id3V2TextEncoding.ISO_8859_1;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
bytes[i + 1] = value.charCodeAt(i);
|
||||
}
|
||||
// Last byte is the null terminator
|
||||
} else {
|
||||
const encoded = textEncoder.encode(value);
|
||||
bytes = new Uint8Array(encoded.byteLength + 2);
|
||||
bytes[0] = Id3V2TextEncoding.UTF_8;
|
||||
bytes.set(encoded, 1);
|
||||
// Last byte is the null terminator
|
||||
}
|
||||
} else if (value instanceof Uint8Array) {
|
||||
bytes = value;
|
||||
} else if (key === 'TXXX' && isRecordStringString(value)) {
|
||||
for (const description in value) {
|
||||
const frameValue = value[description]!;
|
||||
const useIso88591 = isIso88591Compatible(description) && isIso88591Compatible(frameValue);
|
||||
const descriptionDataLength = useIso88591
|
||||
? description.length
|
||||
: textEncoder.encode(description).byteLength;
|
||||
|
||||
const valueData = useIso88591 ? null : textEncoder.encode(frameValue);
|
||||
const valueDataLength = useIso88591 ? frameValue.length : valueData!.byteLength;
|
||||
const frameSize = 1 + descriptionDataLength + 1 + valueDataLength;
|
||||
|
||||
this.writeAscii('TXXX');
|
||||
this.writeSynchsafeU32(frameSize);
|
||||
this.writeU16(0x0000);
|
||||
|
||||
this.writeU8(useIso88591 ? Id3V2TextEncoding.ISO_8859_1 : Id3V2TextEncoding.UTF_8);
|
||||
if (useIso88591) {
|
||||
this.writeIsoString(description);
|
||||
for (let i = 0; i < frameValue.length; i++) {
|
||||
this.writeU8(frameValue.charCodeAt(i));
|
||||
}
|
||||
} else {
|
||||
this.writeUtf8String(description);
|
||||
this.writer.write(valueData!);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@@ -821,7 +867,8 @@ export class Id3V2Writer {
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
bytes[i] = text.charCodeAt(i);
|
||||
}
|
||||
bytes[text.length] = 0x00;
|
||||
// Last byte is the null terminator
|
||||
|
||||
this.writer.write(bytes);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user