diff --git a/src/decrypt-worker/client.ts b/src/decrypt-worker/client.ts index 95a52fd..b65cc05 100644 --- a/src/decrypt-worker/client.ts +++ b/src/decrypt-worker/client.ts @@ -9,7 +9,7 @@ export const workerClient = new Worker(new URL('./worker', import.meta.url), { t workerClient.onerror = (err) => console.error(err); class DecryptionQueue extends ConcurrentQueue<{ id: string; blobURI: string }> { - constructor(private workerClientBus: WorkerClientBus, maxQueue?: number) { + constructor(private workerClientBus: WorkerClientBus, maxQueue?: number) { super(maxQueue); } @@ -18,4 +18,5 @@ class DecryptionQueue extends ConcurrentQueue<{ id: string; blobURI: string }> { } } -export const decryptionQueue = new DecryptionQueue(new WorkerClientBus(workerClient)); +export const workerClientBus = new WorkerClientBus(workerClient); +export const decryptionQueue = new DecryptionQueue(workerClientBus); diff --git a/src/decrypt-worker/constants.ts b/src/decrypt-worker/constants.ts index 2751e71..4cde929 100644 --- a/src/decrypt-worker/constants.ts +++ b/src/decrypt-worker/constants.ts @@ -1,5 +1,6 @@ export enum DECRYPTION_WORKER_ACTION_NAME { DECRYPT = 'DECRYPT', + VERSION = 'VERSION', } export interface DecryptionResult { diff --git a/src/decrypt-worker/worker-handler/decrypt.ts b/src/decrypt-worker/worker-handler/decrypt.ts new file mode 100644 index 0000000..ad2ac73 --- /dev/null +++ b/src/decrypt-worker/worker-handler/decrypt.ts @@ -0,0 +1,49 @@ +import { fetchParakeet } from '@jixun/libparakeet'; +import { CryptoFactory } from '../crypto/CryptoBase'; + +import { XiamiCrypto } from '../crypto/xiami/xiami'; +import { QMC1Crypto } from '../crypto/qmc/qmc_v1'; +import { QMC2Crypto } from '../crypto/qmc/qmc_v2'; + +// Use first 4MiB of the file to perform check. +const TEST_FILE_HEADER_LEN = 1024 * 1024 * 4; + +const decryptorFactories: CryptoFactory[] = [ + // Xiami (*.xm) + () => new XiamiCrypto(), + + // QMCv1 (*.qmcflac) + () => new QMC1Crypto(), + + // QMCv2 (*.mflac) + () => new QMC2Crypto(), +]; + +export const workerDecryptHandler = async (blobURI: string) => { + const blob = await fetch(blobURI).then((r) => r.blob()); + const parakeet = await fetchParakeet(); + + for (const factory of decryptorFactories) { + const decryptor = factory(); + if (await decryptor.isSupported(blob)) { + try { + const decryptedBlob = await decryptor.decrypt(blob); + + // Check if we had a successful decryption + const header = await decryptedBlob.slice(0, TEST_FILE_HEADER_LEN).arrayBuffer(); + const audioExt = parakeet.detectAudioExtension(header); + if (!decryptor.hasSignature() && audioExt === 'bin') { + // skip this decryptor result + continue; + } + + return { decrypted: URL.createObjectURL(decryptedBlob), ext: audioExt }; + } catch (error) { + console.error('decrypt failed: ', error); + continue; + } + } + } + + throw new Error('could not decrypt file: no working decryptor found'); +}; diff --git a/src/decrypt-worker/worker.ts b/src/decrypt-worker/worker.ts index 57f90c3..fb3f1ae 100644 --- a/src/decrypt-worker/worker.ts +++ b/src/decrypt-worker/worker.ts @@ -1,55 +1,15 @@ import { WorkerServerBus } from '~/util/WorkerEventBus'; import { DECRYPTION_WORKER_ACTION_NAME } from './constants'; -import type { CryptoFactory } from './crypto/CryptoBase'; -import { fetchParakeet } from '@jixun/libparakeet'; +import { getSDKVersion } from '@jixun/libparakeet'; -import { XiamiCrypto } from './crypto/xiami/xiami'; -import { QMC1Crypto } from './crypto/qmc/qmc_v1'; -import { QMC2Crypto } from './crypto/qmc/qmc_v2'; +import { workerDecryptHandler } from './worker-handler/decrypt'; const bus = new WorkerServerBus(); onmessage = bus.onmessage; -const decryptorFactories: CryptoFactory[] = [ - // Xiami (*.xm) - () => new XiamiCrypto(), +bus.addEventHandler(DECRYPTION_WORKER_ACTION_NAME.DECRYPT, workerDecryptHandler); - // QMCv1 (*.qmcflac) - () => new QMC1Crypto(), - - // QMCv2 (*.mflac) - () => new QMC2Crypto(), -]; - -// Use first 4MiB of the file to perform check. -const TEST_FILE_HEADER_LEN = 1024 * 1024 * 4; - -bus.addEventHandler(DECRYPTION_WORKER_ACTION_NAME.DECRYPT, async (blobURI) => { - const blob = await fetch(blobURI).then((r) => r.blob()); - const parakeet = await fetchParakeet(); - - for (const factory of decryptorFactories) { - const decryptor = factory(); - if (await decryptor.isSupported(blob)) { - try { - const decryptedBlob = await decryptor.decrypt(blob); - - // Check if we had a successful decryption - const header = await decryptedBlob.slice(0, TEST_FILE_HEADER_LEN).arrayBuffer(); - const audioExt = parakeet.detectAudioExtension(header); - if (!decryptor.hasSignature() && audioExt === 'bin') { - // skip this decryptor result - continue; - } - - return { decrypted: URL.createObjectURL(decryptedBlob), ext: audioExt }; - } catch (error) { - console.error('decrypt failed: ', error); - continue; - } - } - } - - throw new Error('could not decrypt file: no working decryptor found'); +bus.addEventHandler(DECRYPTION_WORKER_ACTION_NAME.VERSION, async () => { + return getSDKVersion(); });