From f0875ad1753b5d96d1e17303cdddcbaa1ba42bf6 Mon Sep 17 00:00:00 2001 From: Emmm Monster <58943012+emmmx@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:47:06 +0800 Subject: [PATCH] fix: decrypt/qmc-cache adapt: decrypt/qmc for qmc-cache --- src/decrypt/qmc.ts | 6 ++--- src/decrypt/qmccache.ts | 57 +++++++++++++++++++++++------------------ src/decrypt/utils.ts | 8 ++++++ 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/decrypt/qmc.ts b/src/decrypt/qmc.ts index 2aeb71d..8c70b76 100644 --- a/src/decrypt/qmc.ts +++ b/src/decrypt/qmc.ts @@ -22,7 +22,7 @@ interface Handler { handler(data?: Uint8Array): QmcMask | undefined } -const HandlerMap: { [key: string]: Handler } = { +export const HandlerMap: { [key: string]: Handler } = { "mgg": {handler: QmcMaskDetectMgg, ext: "ogg", detect: true}, "mflac": {handler: QmcMaskDetectMflac, ext: "flac", detect: true}, "mgg.cache": {handler: QmcMaskDetectMgg, ext: "ogg", detect: false}, @@ -42,8 +42,8 @@ const HandlerMap: { [key: string]: Handler } = { "776176": {handler: QmcMaskGetDefault, ext: "wav", detect: false} }; -export async function Decrypt(file: File, raw_filename: string, raw_ext: string): Promise { - if (!(raw_ext in HandlerMap)) throw "File type is incorrect!"; +export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string): Promise { + if (!(raw_ext in HandlerMap)) throw `Qmc cannot handle type: ${raw_ext}`; const handler = HandlerMap[raw_ext]; const fileData = new Uint8Array(await GetArrayBuffer(file)); diff --git a/src/decrypt/qmccache.ts b/src/decrypt/qmccache.ts index 34e7165..adb3fda 100644 --- a/src/decrypt/qmccache.ts +++ b/src/decrypt/qmccache.ts @@ -1,34 +1,41 @@ -import {AudioMimeType, GetArrayBuffer, GetCoverFromFile, GetMetaFromFile, SniffAudioExt} from "@/decrypt/utils.ts"; +import { + AudioMimeType, + GetArrayBuffer, + GetCoverFromFile, + GetMetaFromFile, + SniffAudioExt, + SplitFilename +} from "@/decrypt/utils.ts"; -import {Decrypt as QmcDecrypt} from "@/decrypt/qmc"; +import {Decrypt as QmcDecrypt, HandlerMap} from "@/decrypt/qmc"; import {DecryptResult} from "@/decrypt/entity"; import {parseBlob as metaParseBlob} from "music-metadata-browser"; -export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string, detect: boolean = true) +export async function Decrypt(file: Blob, raw_filename: string, _: string) : Promise { - let ext = raw_ext; - if (detect) { - const buffer = new Uint8Array(await GetArrayBuffer(file)); - let length = buffer.length - for (let i = 0; i < length; i++) { - buffer[i] ^= 0xf4 - if(buffer[i] <= 0x3f)buffer[i] = buffer[i] * 4; - else if(buffer[i] <= 0x7f)buffer[i] = (buffer[i] - 0x40) * 4 + 1; - else if(buffer[i] <= 0xbf)buffer[i] = (buffer[i] - 0x80) * 4 + 2; - else buffer[i] = (buffer[i] - 0xc0) * 4 + 3; - } - ext = SniffAudioExt(buffer, raw_ext); - if (ext !== raw_ext) file = new Blob([buffer], {type: AudioMimeType[ext]}) - else { - file = new Blob([buffer], {type: "application/octet-stream"}) - let ext = raw_filename.substring(file.name.lastIndexOf(".") + 1, file.name.length).toLowerCase(); - if (ext !== "mgg" && ext !== "mflac") throw "不支持的QQ音乐缓存格式:" + raw_filename + ".cache"; - return QmcDecrypt(file, raw_filename, ext+".cache"); - } + const buffer = new Uint8Array(await GetArrayBuffer(file)); + let length = buffer.length + for (let i = 0; i < length; i++) { + buffer[i] ^= 0xf4 + if (buffer[i] <= 0x3f) buffer[i] = buffer[i] * 4; + else if (buffer[i] <= 0x7f) buffer[i] = (buffer[i] - 0x40) * 4 + 1; + else if (buffer[i] <= 0xbf) buffer[i] = (buffer[i] - 0x80) * 4 + 2; + else buffer[i] = (buffer[i] - 0xc0) * 4 + 3; } - const tag = await metaParseBlob(file); + let ext = SniffAudioExt(buffer, ""); + const newName = SplitFilename(raw_filename) + let audioBlob: Blob + if (ext !== "" || newName.ext === "mp3") { + audioBlob = new Blob([buffer], {type: AudioMimeType[ext]}) + } else if (newName.ext in HandlerMap) { + audioBlob = new Blob([buffer], {type: "application/octet-stream"}) + return QmcDecrypt(audioBlob, newName.name, newName.ext); + } else { + throw "不支持的QQ音乐缓存格式" + } + const tag = await metaParseBlob(audioBlob); const {title, artist} = GetMetaFromFile(raw_filename, tag.common.title, tag.common.artist) return { @@ -37,8 +44,8 @@ export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string, ext, album: tag.common.album, picture: GetCoverFromFile(tag), - file: URL.createObjectURL(file), - blob: file, + file: URL.createObjectURL(audioBlob), + blob: audioBlob, mime: AudioMimeType[ext] } } diff --git a/src/decrypt/utils.ts b/src/decrypt/utils.ts index f10753a..cef54f6 100644 --- a/src/decrypt/utils.ts +++ b/src/decrypt/utils.ts @@ -160,3 +160,11 @@ export function WriteMetaToFlac(audioData: Buffer, info: IMusicMeta, original: I } return writer.save() } + +export function SplitFilename(n: string): { name: string; ext: string } { + const pos = n.lastIndexOf(".") + return { + ext: n.substring(pos + 1).toLowerCase(), + name: n.substring(0, pos) + } +}