Browse Source

Move ID3 Writer to Util

20230320
MengYX 5 years ago
parent
commit
2415db67be
No known key found for this signature in database GPG Key ID: E63F9C7303E8F604
  1. 31
      src/decrypt/ncm.js
  2. 4
      src/decrypt/raw.js
  3. 55
      src/decrypt/util.js

31
src/decrypt/ncm.js

@ -1,8 +1,7 @@
const CryptoJS = require("crypto-js"); const CryptoJS = require("crypto-js");
const ID3Writer = require("browser-id3-writer");
const CORE_KEY = CryptoJS.enc.Hex.parse("687a4852416d736f356b496e62617857"); const CORE_KEY = CryptoJS.enc.Hex.parse("687a4852416d736f356b496e62617857");
const META_KEY = CryptoJS.enc.Hex.parse("2331346C6A6B5F215C5D2630553C2728"); const META_KEY = CryptoJS.enc.Hex.parse("2331346C6A6B5F215C5D2630553C2728");
import {AudioMimeType, DetectAudioExt, GetArrayBuffer, GetFileInfo} from "./util" import {AudioMimeType, DetectAudioExt, GetArrayBuffer, GetFileInfo, GetWebImage, WriteMp3Meta} from "./util"
export async function Decrypt(file, raw_filename, raw_ext) { export async function Decrypt(file, raw_filename, raw_ext) {
const fileBuffer = await GetArrayBuffer(file); const fileBuffer = await GetArrayBuffer(file);
@ -31,8 +30,10 @@ export async function Decrypt(file, raw_filename, raw_ext) {
if (artists.length === 0) artists.push(info.artist); if (artists.length === 0) artists.push(info.artist);
if (musicMeta.format === undefined) musicMeta.format = DetectAudioExt(audioData, "mp3"); if (musicMeta.format === undefined) musicMeta.format = DetectAudioExt(audioData, "mp3");
if (musicMeta.format === "mp3")
audioData = await writeID3(audioData, artists, info.title, musicMeta.album, musicMeta.albumPic); const imageInfo = await GetWebImage(musicMeta.albumPic);
if (musicMeta.format === "mp3") audioData = await WriteMp3Meta(
audioData, artists, info.title, musicMeta.album, imageInfo.buffer, musicMeta.albumPic);
const mime = AudioMimeType[musicMeta.format]; const mime = AudioMimeType[musicMeta.format];
const musicData = new Blob([audioData], {type: mime}); const musicData = new Blob([audioData], {type: mime});
@ -42,32 +43,12 @@ export async function Decrypt(file, raw_filename, raw_ext) {
artist: info.artist, artist: info.artist,
ext: musicMeta.format, ext: musicMeta.format,
album: musicMeta.album, album: musicMeta.album,
picture: musicMeta.albumPic, picture: imageInfo.url,
file: URL.createObjectURL(musicData), file: URL.createObjectURL(musicData),
mime: mime mime: mime
}; };
} }
async function writeID3(audioData, artistList, title, album, picture) {
const writer = new ID3Writer(audioData);
writer.setFrame("TPE1", artistList)
.setFrame("TIT2", title)
.setFrame("TALB", album);
if (picture !== "") {
try {
const img = await (await fetch(picture)).arrayBuffer();
writer.setFrame('APIC', {
type: 3,
data: img,
description: 'Cover'
})
} catch (e) {
console.log("Fail to write cover image!");
}
}
writer.addTag();
return writer.arrayBuffer;
}
function getKeyData(dataView, fileBuffer, offset) { function getKeyData(dataView, fileBuffer, offset) {
const keyLen = dataView.getUint32(offset, true); const keyLen = dataView.getUint32(offset, true);

4
src/decrypt/raw.js

@ -1,5 +1,5 @@
const musicMetadata = require("music-metadata-browser"); const musicMetadata = require("music-metadata-browser");
import {AudioMimeType, DetectAudioExt, GetArrayBuffer, GetCoverURL, GetFileInfo} from "./util"; import {AudioMimeType, DetectAudioExt, GetArrayBuffer, GetMetaCoverURL, GetFileInfo} from "./util";
export async function Decrypt(file, raw_filename, raw_ext, detect = true) { export async function Decrypt(file, raw_filename, raw_ext, detect = true) {
let ext = raw_ext; let ext = raw_ext;
@ -16,7 +16,7 @@ export async function Decrypt(file, raw_filename, raw_ext, detect = true) {
artist: info.artist, artist: info.artist,
ext: ext, ext: ext,
album: tag.common.album, album: tag.common.album,
picture: GetCoverURL(tag), picture: GetMetaCoverURL(tag),
file: URL.createObjectURL(file), file: URL.createObjectURL(file),
mime: AudioMimeType[ext] mime: AudioMimeType[ext]
} }

55
src/decrypt/util.js

@ -1,3 +1,4 @@
const ID3Writer = require("browser-id3-writer");
export const FLAC_HEADER = [0x66, 0x4C, 0x61, 0x43]; export const FLAC_HEADER = [0x66, 0x4C, 0x61, 0x43];
export const MP3_HEADER = [0x49, 0x44, 0x33]; export const MP3_HEADER = [0x49, 0x44, 0x33];
export const OGG_HEADER = [0x4F, 0x67, 0x67, 0x53]; export const OGG_HEADER = [0x4F, 0x67, 0x67, 0x53];
@ -38,7 +39,7 @@ export function GetFileInfo(artist, title, filenameNoExt) {
/** /**
* @return {string} * @return {string}
*/ */
export function GetCoverURL(metadata) { export function GetMetaCoverURL(metadata) {
let pic_url = ""; let pic_url = "";
if (metadata.common.picture !== undefined && metadata.common.picture.length > 0) { if (metadata.common.picture !== undefined && metadata.common.picture.length > 0) {
let pic = new Blob([metadata.common.picture[0].data], {type: metadata.common.picture[0].format}); let pic = new Blob([metadata.common.picture[0].data], {type: metadata.common.picture[0].format});
@ -61,6 +62,56 @@ export function DetectAudioExt(data, fallbackExt) {
if (IsBytesEqual(MP3_HEADER, data.slice(0, MP3_HEADER.length))) return "mp3"; if (IsBytesEqual(MP3_HEADER, data.slice(0, MP3_HEADER.length))) return "mp3";
if (IsBytesEqual(FLAC_HEADER, data.slice(0, FLAC_HEADER.length))) return "flac"; if (IsBytesEqual(FLAC_HEADER, data.slice(0, FLAC_HEADER.length))) return "flac";
if (IsBytesEqual(OGG_HEADER, data.slice(0, OGG_HEADER.length))) return "ogg"; if (IsBytesEqual(OGG_HEADER, data.slice(0, OGG_HEADER.length))) return "ogg";
if (IsBytesEqual(M4A_HEADER, data.slice(4, 8))) return "m4a"; if (IsBytesEqual(M4A_HEADER, data.slice(4, 4 + M4A_HEADER.length))) return "m4a";
return fallbackExt; return fallbackExt;
} }
export async function GetWebImage(pic_url) {
try {
let resp = await fetch(pic_url);
let mime = resp.headers.get("Content-Type");
if (mime.startsWith("image/")) {
let buf = await resp.arrayBuffer();
let objBlob = new Blob([buf], {type: mime});
let objUrl = URL.createObjectURL(objBlob);
return {"buffer": buf, "url": objUrl, "type": mime};
}
} catch (e) {
}
return {"buffer": null, "url": "", "type": ""}
}
export async function WriteMp3Meta(audioData, artistList, title, album, pictureData = null, pictureDesc = "Cover") {
const writer = new ID3Writer(audioData);
writer.setFrame("TPE1", artistList)
.setFrame("TIT2", title)
.setFrame("TALB", album);
if (pictureData !== null) {
writer.setFrame('APIC', {
type: 3,
data: pictureData,
description: pictureDesc,
})
}
writer.addTag();
return writer.arrayBuffer;
}
export function RequestJsonp(url, callback_name = "callback") {
return new Promise((resolve, reject) => {
let node;
window[callback_name] = function (data) {
delete window[callback_name];
if (node.parentNode) node.parentNode.removeChild(node);
resolve(data)
};
node = document.createElement('script');
node.type = "text/javascript";
node.src = url;
node.addEventListener('error', msg => {
reject(msg);
});
document.head.appendChild(node);
});
}

Loading…
Cancel
Save