feat(QMCv2): Allow extraction of songId from QMC2-wasm
(cherry picked from commit 9ca2d852ce713255caeb8424a2724cb936434f18)
This commit is contained in:
parent
0af8a0d714
commit
f6c34cd7ba
@ -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
|
||||||
|
@ -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…
Reference in New Issue
Block a user