feat(QMCv2): Allow extraction of songId from QMC2-wasm

(cherry picked from commit 9ca2d852ce713255caeb8424a2724cb936434f18)
remotes/origin/HEAD
鲁树人 3 years ago
parent 0af8a0d714
commit f6c34cd7ba

@ -3,6 +3,7 @@ import { AudioMimeType, GetArrayBuffer, SniffAudioExt } from '@/decrypt/utils';
import { DecryptResult } from '@/decrypt/entity';
import { QmcDeriveKey } from '@/decrypt/qmc_key';
import { DecryptQMCWasm } from '@/decrypt/qmc_wasm';
import { extractQQMusicMeta } from '@/utils/qm_meta';
interface Handler {
@ -41,17 +42,20 @@ export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string)
const fileBuffer = await GetArrayBuffer(file);
let musicDecoded: Uint8Array | undefined;
let musicID: number | undefined;
// todo: wasm decoder doesn't support extract the song id for .mgg1/.mflac0 currently
// if (version === 2 && globalThis.WebAssembly) {
// console.log('qmc: using wasm decoder');
// const v2Decrypted = await DecryptQMCWasm(fileBuffer);
// // 如果 v2 检测失败,降级到 v1 再尝试一次
// if (v2Decrypted) {
// musicDecoded = v2Decrypted;
// }
// }
let musicID: number | string | undefined;
if (version === 2 && globalThis.WebAssembly) {
console.log('qmc: using wasm decoder');
const v2Decrypted = await DecryptQMCWasm(fileBuffer);
// 若 v2 检测失败,降级到 v1 再尝试一次
if (v2Decrypted.success) {
musicDecoded = v2Decrypted.data;
musicID = v2Decrypted.songId;
} else {
console.warn('qmc2-wasm failed with error %s', v2Decrypted.error || '(no error)');
}
}
if (!musicDecoded) {
// may throw error

@ -1,5 +1,6 @@
import QMCCryptoModule from '@jixun/qmc2-crypto/QMC2-wasm-bundle';
import { MergeUint8Array } from '@/utils/MergeUint8Array';
import { QMCCrypto } from '@jixun/qmc2-crypto/QMCCrypto';
// 检测文件末端使用的缓冲区大小
const DETECTION_SIZE = 40;
@ -7,14 +8,22 @@ const DETECTION_SIZE = 40;
// 每次处理 2M 的数据
const DECRYPTION_BUF_SIZE = 2 * 1024 * 1024;
export interface QMC2DecryptionResult {
success: boolean;
data: Uint8Array;
songId: string | number;
error: string;
}
/**
* QMC2
*
* Uint8Array
* @param {ArrayBuffer} mggBlob Blob
* @return {Promise<Uint8Array|false>}
*/
export async function DecryptQMCWasm(mggBlob: ArrayBuffer) {
export async function DecryptQMCWasm(mggBlob: ArrayBuffer): Promise<QMC2DecryptionResult> {
const result: QMC2DecryptionResult = { success: false, data: new Uint8Array(), songId: 0, error: '' };
// 初始化模组
const QMCCrypto = await QMCCryptoModule();
@ -34,12 +43,26 @@ export async function DecryptQMCWasm(mggBlob: ArrayBuffer) {
const position = QMCCrypto.getValue(pDetectionResult, 'i32');
const len = QMCCrypto.getValue(pDetectionResult + 4, 'i32');
result.success = detectOK;
result.error = QMCCrypto.UTF8ToString(
pDetectionResult + QMCCrypto.offsetof_error_msg(),
QMCCrypto.sizeof_error_msg(),
);
const songId = QMCCrypto.UTF8ToString(pDetectionResult + QMCCrypto.offsetof_song_id(), QMCCrypto.sizeof_song_id());
if (!songId) {
console.debug('qmc2-wasm: songId not found');
} else if (/^\d+$/.test(songId)) {
result.songId = songId;
} else {
console.warn('qmc2-wasm: Invalid songId: %s', songId);
}
// 释放内存
QMCCrypto._free(pDetectionBuf);
QMCCrypto._free(pDetectionResult);
if (!detectOK) {
return false;
return result;
}
// 计算解密后文件的大小。
@ -75,5 +98,7 @@ export async function DecryptQMCWasm(mggBlob: ArrayBuffer) {
QMCCrypto._free(buf);
hCrypto.delete();
return MergeUint8Array(decryptedParts);
result.data = MergeUint8Array(decryptedParts);
return result;
}

Loading…
Cancel
Save