Compare commits

..

No commits in common. "af61d23fd4d1a3b80afa2184f189b71604eae7aa" and "c3809b48f7fa1f2d029844b5fb2e25587b547c19" have entirely different histories.

13 changed files with 35 additions and 2087 deletions

4
.env
View File

@ -1,4 +0,0 @@
# Example environment file for vite to use.
# For more information, see: https://vitejs.dev/guide/env-and-mode.html
ENABLE_PERF_LOG=0

View File

@ -4,11 +4,6 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>音乐解锁 - Unlock Music</title>
<meta name="description" content="音乐解锁 - Unlock Music" />
<link rel="icon" href="/favicon.ico" />
<link rel="apple-touch-icon" href="/pwa-512x512.png" sizes="512x512" />
<meta name="theme-color" content="#4DBA87" />
</head>
<body>
<main id="root"></main>

View File

@ -54,7 +54,6 @@
"prettier": "^2.8.8",
"typescript": "^5.0.2",
"vite": "^4.3.2",
"vite-plugin-pwa": "^0.15.0",
"vite-plugin-top-level-await": "^1.3.0",
"vite-plugin-wasm": "^3.2.2",
"vitest": "^0.31.0"

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1 +0,0 @@
export class UnsupportedSourceFile extends Error {}

View File

@ -1,6 +1,5 @@
import { Transformer, Parakeet, TransformResult, fetchParakeet } from '@jixun/libparakeet';
import { toArrayBuffer } from './buffer';
import { UnsupportedSourceFile } from './DecryptError';
export async function transformBlob(
blob: Blob | ArrayBuffer,
@ -22,9 +21,7 @@ export async function transformBlob(
cleanup.push(() => writer.delete());
const result = transformer.Transform(writer, reader);
if (result === TransformResult.ERROR_INVALID_FORMAT) {
throw new UnsupportedSourceFile(`transformer<${transformer.Name}> does not recognize this file`);
} else if (result !== TransformResult.OK) {
if (result !== TransformResult.OK) {
throw new Error(`transformer<${transformer.Name}> failed with error: ${TransformResult[result]} (${result})`);
}

View File

@ -1,9 +1,8 @@
import { Parakeet, fetchParakeet } from '@jixun/libparakeet';
import { timedLogger, withGroupedLogs as withTimeGroupedLogs } from '~/util/logUtils';
import { timedLogger } from '~/util/timedLogger';
import { allCryptoFactories } from '../../crypto/CryptoFactory';
import { toArrayBuffer, toBlob } from '~/decrypt-worker/util/buffer';
import { CryptoBase, CryptoFactory } from '~/decrypt-worker/crypto/CryptoBase';
import { UnsupportedSourceFile } from '~/decrypt-worker/util/DecryptError';
// Use first 4MiB of the file to perform check.
const TEST_FILE_HEADER_LEN = 4 * 1024 * 1024;
@ -30,11 +29,8 @@ class DecryptCommandHandler {
}
return result;
} catch (error) {
if (error instanceof UnsupportedSourceFile) {
console.debug('WARN: decryptor does not recognize source file, wrong crypto?', error);
} else {
console.error('decrypt failed with unknown error: ', error);
}
console.error('decrypt failed: ', error);
continue;
}
}
@ -87,12 +83,18 @@ class DecryptCommandHandler {
export const workerDecryptHandler = async ({ id, blobURI }: { id: string; blobURI: string }) => {
const label = `decrypt( ${id} )`;
return withTimeGroupedLogs(label, async () => {
const parakeet = await timedLogger(`${label}/init`, fetchParakeet);
const blob = await timedLogger(`${label}/fetch-src`, async () => fetch(blobURI).then((r) => r.blob()));
const buffer = await timedLogger(`${label}/read-src`, async () => blob.arrayBuffer());
console.group(label);
const handler = new DecryptCommandHandler(id, parakeet, blob, buffer);
return handler.decrypt(allCryptoFactories);
});
try {
return await timedLogger(`${label}/total`, async () => {
const parakeet = await timedLogger(`${label}/init`, fetchParakeet);
const blob = await timedLogger(`${label}/fetch-src`, async () => fetch(blobURI).then((r) => r.blob()));
const buffer = await timedLogger(`${label}/read-src`, async () => blob.arrayBuffer());
const handler = new DecryptCommandHandler(id, parakeet, blob, buffer);
return handler.decrypt(allCryptoFactories);
});
} finally {
(console.groupEnd as (label: string) => void)(label);
}
};

View File

@ -1,25 +0,0 @@
import { wrapFunctionCall } from './fnWrapper';
export function timedLogger<R = unknown>(label: string, fn: () => R): R {
if (import.meta.env.ENABLE_PERF_LOG !== '1') {
return fn();
} else {
return wrapFunctionCall(
() => console.time(label),
() => console.timeEnd(label),
fn
);
}
}
export function withGroupedLogs<R = unknown>(label: string, fn: () => R): R {
if (import.meta.env.ENABLE_PERF_LOG !== '1') {
return fn();
} else {
return wrapFunctionCall(
() => console.group(label),
() => (console.groupEnd as (label: string) => void)(label),
() => timedLogger(`${label}/total`, fn)
);
}
}

View File

@ -2,19 +2,21 @@ function isPromise<T = unknown>(p: unknown): p is Promise<T> {
return !!p && typeof p === 'object' && 'then' in p && 'catch' in p && 'finally' in p;
}
export function wrapFunctionCall<R = unknown>(pre: () => void, post: () => void, fn: () => R): R {
pre();
export function timedLogger<R = unknown>(label: string, fn: () => R): R {
console.time(label);
try {
const result = fn();
if (isPromise(result)) {
result.finally(post);
result.finally(() => {
console.timeEnd(label);
});
}
return result;
} catch (e) {
post();
console.timeEnd(label);
throw e;
}
}

View File

@ -8,7 +8,6 @@ import react from '@vitejs/plugin-react';
import wasm from 'vite-plugin-wasm';
import replace from '@rollup/plugin-replace';
import topLevelAwait from 'vite-plugin-top-level-await';
import { VitePWA } from 'vite-plugin-pwa';
const gitRoot = url.fileURLToPath(new URL('.', import.meta.url));
const pkg = JSON.parse(fs.readFileSync(gitRoot + '/package.json', 'utf-8'));
@ -53,34 +52,6 @@ export default defineConfig({
react(),
wasm(),
topLevelAwait(),
VitePWA({
registerType: 'prompt',
workbox: {
// Cache everything from dist
globPatterns: ['**/*.{js,css,html,ico,png,svg,wasm}'],
},
manifest: {
display: 'standalone',
name: '音乐解锁 (Unlock Music)',
short_name: '音乐解锁',
lang: 'zh-cmn-Hans-CN',
description: '在现代浏览器解锁已购的加密音乐!',
theme_color: '#ffffff',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'maskable',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
],
},
}),
],
resolve: {
alias: {