Merge pull request #252 from DanTheMan827/explicit-rating-metadata
feat(downloads): add explicit content rating support
This commit is contained in:
commit
bebb530d2c
1 changed files with 48 additions and 0 deletions
|
|
@ -161,6 +161,7 @@ async function readFlacMetadata(file, metadata) {
|
||||||
if (upperKey === 'ALBUM') metadata.album.title = value;
|
if (upperKey === 'ALBUM') metadata.album.title = value;
|
||||||
if (upperKey === 'ISRC') metadata.isrc = value;
|
if (upperKey === 'ISRC') metadata.isrc = value;
|
||||||
if (upperKey === 'COPYRIGHT') metadata.copyright = value;
|
if (upperKey === 'COPYRIGHT') metadata.copyright = value;
|
||||||
|
if (upperKey === 'ITUNESADVISORY') metadata.explicit = value === '1';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -262,6 +263,9 @@ async function readM4aMetadata(file, metadata) {
|
||||||
const mime = getMimeType(pictureData);
|
const mime = getMimeType(pictureData);
|
||||||
const blob = new Blob([pictureData], { type: mime });
|
const blob = new Blob([pictureData], { type: mime });
|
||||||
metadata.album.cover = URL.createObjectURL(blob);
|
metadata.album.cover = URL.createObjectURL(blob);
|
||||||
|
} else if (item.type === 'rtng') {
|
||||||
|
metadata.explicit =
|
||||||
|
contentLen > 0 && new Uint8Array(view.buffer, contentOffset, contentLen)[0] === 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -603,6 +607,9 @@ function createVorbisCommentBlock(track) {
|
||||||
if (track.isrc) {
|
if (track.isrc) {
|
||||||
comments.push(['ISRC', track.isrc]);
|
comments.push(['ISRC', track.isrc]);
|
||||||
}
|
}
|
||||||
|
if (track.explicit) {
|
||||||
|
comments.push(['ITUNESADVISORY', '1']);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate total size
|
// Calculate total size
|
||||||
const vendor = VENDOR_STRING;
|
const vendor = VENDOR_STRING;
|
||||||
|
|
@ -943,6 +950,9 @@ function createMp4MetadataAtoms(track) {
|
||||||
total: track.album?.numberOfTracks,
|
total: track.album?.numberOfTracks,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (track.explicit) {
|
||||||
|
tags['rtng'] = 1; // 1 = Explicit, 2 = Clean, 0 = Unknown
|
||||||
|
}
|
||||||
|
|
||||||
const discNumber = track.volumeNumber ?? track.discNumber;
|
const discNumber = track.volumeNumber ?? track.discNumber;
|
||||||
if (discNumber) {
|
if (discNumber) {
|
||||||
|
|
@ -1086,6 +1096,8 @@ function createMetadataBlock(metadataAtoms) {
|
||||||
for (const [key, value] of Object.entries(tags)) {
|
for (const [key, value] of Object.entries(tags)) {
|
||||||
if (key === 'trkn' || key === 'disk') {
|
if (key === 'trkn' || key === 'disk') {
|
||||||
ilstChildren.push(createIntAtom(key, value));
|
ilstChildren.push(createIntAtom(key, value));
|
||||||
|
} else if (key === 'rtng') {
|
||||||
|
ilstChildren.push(createRatingAtom(value));
|
||||||
} else {
|
} else {
|
||||||
ilstChildren.push(createStringAtom(key, value));
|
ilstChildren.push(createStringAtom(key, value));
|
||||||
}
|
}
|
||||||
|
|
@ -1218,6 +1230,42 @@ function createStringAtom(type, value) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an MP4 `rtng` metadata atom that encodes an explicit-content rating.
|
||||||
|
*
|
||||||
|
* @param {number} value - The rating to embed (0 = Unrated, 1 = Explicit, 2 = Clean).
|
||||||
|
* @returns {Uint8Array} The serialized atom buffer ready to be inserted into metadata.
|
||||||
|
*/
|
||||||
|
function createRatingAtom(value) {
|
||||||
|
const dataSize = 17; // 8 (data atom header) + 8 (flags/null) + Rating
|
||||||
|
const atomSize = 8 + dataSize;
|
||||||
|
|
||||||
|
const buf = new Uint8Array(atomSize);
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
// Wrapper atom (e.g., ©nam)
|
||||||
|
writeAtomHeader(buf, offset, atomSize, 'rtng');
|
||||||
|
offset += 8;
|
||||||
|
|
||||||
|
// Data atom
|
||||||
|
writeAtomHeader(buf, offset, dataSize, 'data');
|
||||||
|
offset += 8;
|
||||||
|
|
||||||
|
// Data Type ((21 = Rating) + Locale (0))
|
||||||
|
buf[offset++] = 0;
|
||||||
|
buf[offset++] = 0;
|
||||||
|
buf[offset++] = 0;
|
||||||
|
buf[offset++] = 21; // Type 21
|
||||||
|
buf[offset++] = 0;
|
||||||
|
buf[offset++] = 0;
|
||||||
|
buf[offset++] = 0;
|
||||||
|
buf[offset++] = 0;
|
||||||
|
buf[offset++] = value;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
function createIntAtom(type, value) {
|
function createIntAtom(type, value) {
|
||||||
// trkn/disk are special: data is 8 bytes.
|
// trkn/disk are special: data is 8 bytes.
|
||||||
// reserved(2) + track(2) + total(2) + reserved(2)
|
// reserved(2) + track(2) + total(2) + reserved(2)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue