Browse Source

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

(cherry picked from commit 9ca2d852ce713255caeb8424a2724cb936434f18)
20230320
Jixun Wu 3 years ago
committed by MengYX
parent
commit
55772dec31
No known key found for this signature in database GPG Key ID: E63F9C7303E8F604
  1. 26
      src/decrypt/qmc.ts
  2. 33
      src/decrypt/qmc_wasm.ts

26
src/decrypt/qmc.ts

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

33
src/decrypt/qmc_wasm.ts

@ -1,5 +1,6 @@
import QMCCryptoModule from '@jixun/qmc2-crypto/QMC2-wasm-bundle'; import QMCCryptoModule from '@jixun/qmc2-crypto/QMC2-wasm-bundle';
import { MergeUint8Array } from '@/utils/MergeUint8Array'; import { MergeUint8Array } from '@/utils/MergeUint8Array';
import { QMCCrypto } from '@jixun/qmc2-crypto/QMCCrypto';
// 检测文件末端使用的缓冲区大小 // 检测文件末端使用的缓冲区大小
const DETECTION_SIZE = 40; const DETECTION_SIZE = 40;
@ -7,14 +8,22 @@ const DETECTION_SIZE = 40;
// 每次处理 2M 的数据 // 每次处理 2M 的数据
const DECRYPTION_BUF_SIZE = 2 * 1024 * 1024; const DECRYPTION_BUF_SIZE = 2 * 1024 * 1024;
export interface QMC2DecryptionResult {
success: boolean;
data: Uint8Array;
songId: string | number;
error: string;
}
/** /**
* QMC2 * QMC2
* *
* Uint8Array * Uint8Array
* @param {ArrayBuffer} mggBlob Blob * @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(); const QMCCrypto = await QMCCryptoModule();
@ -34,12 +43,26 @@ export async function DecryptQMCWasm(mggBlob: ArrayBuffer) {
const position = QMCCrypto.getValue(pDetectionResult, 'i32'); const position = QMCCrypto.getValue(pDetectionResult, 'i32');
const len = QMCCrypto.getValue(pDetectionResult + 4, '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(pDetectionBuf);
QMCCrypto._free(pDetectionResult); QMCCrypto._free(pDetectionResult);
if (!detectOK) { if (!detectOK) {
return false; return result;
} }
// 计算解密后文件的大小。 // 计算解密后文件的大小。
@ -75,5 +98,7 @@ export async function DecryptQMCWasm(mggBlob: ArrayBuffer) {
QMCCrypto._free(buf); QMCCrypto._free(buf);
hCrypto.delete(); hCrypto.delete();
return MergeUint8Array(decryptedParts); result.data = MergeUint8Array(decryptedParts);
return result;
} }

Loading…
Cancel
Save