From 2415db67be7bc8d15c714af6c89fd03be8522d20 Mon Sep 17 00:00:00 2001 From: MengYX Date: Sun, 5 Apr 2020 17:31:16 +0800 Subject: [PATCH] Move ID3 Writer to Util --- src/decrypt/ncm.js | 31 +++++-------------------- src/decrypt/raw.js | 4 ++-- src/decrypt/util.js | 55 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/decrypt/ncm.js b/src/decrypt/ncm.js index 245d98b..d785bba 100644 --- a/src/decrypt/ncm.js +++ b/src/decrypt/ncm.js @@ -1,8 +1,7 @@ const CryptoJS = require("crypto-js"); -const ID3Writer = require("browser-id3-writer"); const CORE_KEY = CryptoJS.enc.Hex.parse("687a4852416d736f356b496e62617857"); 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) { 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 (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 musicData = new Blob([audioData], {type: mime}); @@ -42,32 +43,12 @@ export async function Decrypt(file, raw_filename, raw_ext) { artist: info.artist, ext: musicMeta.format, album: musicMeta.album, - picture: musicMeta.albumPic, + picture: imageInfo.url, file: URL.createObjectURL(musicData), 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) { const keyLen = dataView.getUint32(offset, true); diff --git a/src/decrypt/raw.js b/src/decrypt/raw.js index 01b56e9..38136d4 100644 --- a/src/decrypt/raw.js +++ b/src/decrypt/raw.js @@ -1,5 +1,5 @@ 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) { let ext = raw_ext; @@ -16,7 +16,7 @@ export async function Decrypt(file, raw_filename, raw_ext, detect = true) { artist: info.artist, ext: ext, album: tag.common.album, - picture: GetCoverURL(tag), + picture: GetMetaCoverURL(tag), file: URL.createObjectURL(file), mime: AudioMimeType[ext] } diff --git a/src/decrypt/util.js b/src/decrypt/util.js index a19348f..ab6f404 100644 --- a/src/decrypt/util.js +++ b/src/decrypt/util.js @@ -1,3 +1,4 @@ +const ID3Writer = require("browser-id3-writer"); export const FLAC_HEADER = [0x66, 0x4C, 0x61, 0x43]; export const MP3_HEADER = [0x49, 0x44, 0x33]; export const OGG_HEADER = [0x4F, 0x67, 0x67, 0x53]; @@ -38,7 +39,7 @@ export function GetFileInfo(artist, title, filenameNoExt) { /** * @return {string} */ -export function GetCoverURL(metadata) { +export function GetMetaCoverURL(metadata) { let pic_url = ""; 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}); @@ -61,6 +62,56 @@ export function DetectAudioExt(data, fallbackExt) { 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(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; } + + +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); + }); +}