mirror of
https://git.unlock-music.dev/um/web.git
synced 2024-12-29 08:05:04 +08:00
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 { 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;
|
||||
let musicID: number | string | 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;
|
||||
// }
|
||||
// }
|
||||
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…
Reference in New Issue
Block a user