34 changed files with 1656 additions and 1709 deletions
			
			
		@ -1,26 +1,25 @@ | 
				
			|||||
export interface DecryptResult { | 
					export interface DecryptResult { | 
				
			||||
    title: string | 
					  title: string; | 
				
			||||
    album?: string | 
					  album?: string; | 
				
			||||
    artist?: string | 
					  artist?: string; | 
				
			||||
 | 
					
 | 
				
			||||
    mime: string | 
					  mime: string; | 
				
			||||
    ext: string | 
					  ext: string; | 
				
			||||
 | 
					
 | 
				
			||||
    file: string | 
					  file: string; | 
				
			||||
    blob: Blob | 
					  blob: Blob; | 
				
			||||
    picture?: string | 
					  picture?: string; | 
				
			||||
 | 
					 | 
				
			||||
    message?: string | 
					 | 
				
			||||
    rawExt?: string | 
					 | 
				
			||||
    rawFilename?: string | 
					 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  message?: string; | 
				
			||||
 | 
					  rawExt?: string; | 
				
			||||
 | 
					  rawFilename?: string; | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
export interface FileInfo { | 
					export interface FileInfo { | 
				
			||||
    status: string | 
					  status: string; | 
				
			||||
    name: string, | 
					  name: string; | 
				
			||||
    size: number, | 
					  size: number; | 
				
			||||
    percentage: number, | 
					  percentage: number; | 
				
			||||
    uid: number, | 
					  uid: number; | 
				
			||||
    raw: File | 
					  raw: File; | 
				
			||||
} | 
					} | 
				
			||||
 | 
				
			|||||
@ -1,115 +1,117 @@ | 
				
			|||||
import {QmcMapCipher, QmcRC4Cipher, QmcStaticCipher} from "@/decrypt/qmc_cipher"; | 
					import { QmcMapCipher, QmcRC4Cipher, QmcStaticCipher } from '@/decrypt/qmc_cipher'; | 
				
			||||
import fs from 'fs' | 
					import fs from 'fs'; | 
				
			||||
 | 
					
 | 
				
			||||
test("static cipher [0x7ff8,0x8000) ", () => { | 
					test('static cipher [0x7ff8,0x8000) ', () => { | 
				
			||||
 | 
					  //prettier-ignore
 | 
				
			||||
  const expected = new Uint8Array([ | 
					  const expected = new Uint8Array([ | 
				
			||||
    0xD8, 0x52, 0xF7, 0x67, 0x90, 0xCA, 0xD6, 0x4A, | 
					    0xD8, 0x52, 0xF7, 0x67, 0x90, 0xCA, 0xD6, 0x4A, | 
				
			||||
    0x4A, 0xD6, 0xCA, 0x90, 0x67, 0xF7, 0x52, 0xD8, | 
					    0x4A, 0xD6, 0xCA, 0x90, 0x67, 0xF7, 0x52, 0xD8, | 
				
			||||
  ]) | 
					  ]) | 
				
			||||
 | 
					
 | 
				
			||||
  const c = new QmcStaticCipher() | 
					  const c = new QmcStaticCipher(); | 
				
			||||
  const buf = new Uint8Array(16) | 
					  const buf = new Uint8Array(16); | 
				
			||||
  c.decrypt(buf, 0x7ff8) | 
					  c.decrypt(buf, 0x7ff8); | 
				
			||||
 | 
					
 | 
				
			||||
  expect(buf).toStrictEqual(expected) | 
					  expect(buf).toStrictEqual(expected); | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
					
 | 
				
			||||
test("static cipher [0,0x10) ", () => { | 
					test('static cipher [0,0x10) ', () => { | 
				
			||||
 | 
					  //prettier-ignore
 | 
				
			||||
  const expected = new Uint8Array([ | 
					  const expected = new Uint8Array([ | 
				
			||||
    0xC3, 0x4A, 0xD6, 0xCA, 0x90, 0x67, 0xF7, 0x52, | 
					    0xC3, 0x4A, 0xD6, 0xCA, 0x90, 0x67, 0xF7, 0x52, | 
				
			||||
    0xD8, 0xA1, 0x66, 0x62, 0x9F, 0x5B, 0x09, 0x00, | 
					    0xD8, 0xA1, 0x66, 0x62, 0x9F, 0x5B, 0x09, 0x00, | 
				
			||||
  ]) | 
					  ]) | 
				
			||||
 | 
					
 | 
				
			||||
  const c = new QmcStaticCipher() | 
					  const c = new QmcStaticCipher(); | 
				
			||||
  const buf = new Uint8Array(16) | 
					  const buf = new Uint8Array(16); | 
				
			||||
  c.decrypt(buf, 0) | 
					  c.decrypt(buf, 0); | 
				
			||||
 | 
					
 | 
				
			||||
  expect(buf).toStrictEqual(expected) | 
					  expect(buf).toStrictEqual(expected); | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					test('map cipher: get mask', () => { | 
				
			||||
test("map cipher: get mask", () => { | 
					  //prettier-ignore
 | 
				
			||||
  const expected = new Uint8Array([ | 
					  const expected = new Uint8Array([ | 
				
			||||
    0xBB, 0x7D, 0x80, 0xBE, 0xFF, 0x38, 0x81, 0xFB, | 
					    0xBB, 0x7D, 0x80, 0xBE, 0xFF, 0x38, 0x81, 0xFB, | 
				
			||||
    0xBB, 0xFF, 0x82, 0x3C, 0xFF, 0xBA, 0x83, 0x79, | 
					    0xBB, 0xFF, 0x82, 0x3C, 0xFF, 0xBA, 0x83, 0x79, | 
				
			||||
  ]) | 
					  ]) | 
				
			||||
  const key = new Uint8Array(256) | 
					  const key = new Uint8Array(256); | 
				
			||||
  for (let i = 0; i < 256; i++) key[i] = i | 
					  for (let i = 0; i < 256; i++) key[i] = i; | 
				
			||||
  const buf = new Uint8Array(16) | 
					  const buf = new Uint8Array(16); | 
				
			||||
 | 
					
 | 
				
			||||
  const c = new QmcMapCipher(key) | 
					  const c = new QmcMapCipher(key); | 
				
			||||
  c.decrypt(buf, 0) | 
					  c.decrypt(buf, 0); | 
				
			||||
  expect(buf).toStrictEqual(expected) | 
					  expect(buf).toStrictEqual(expected); | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
					
 | 
				
			||||
function loadTestDataCipher(name: string): { | 
					function loadTestDataCipher(name: string): { | 
				
			||||
  key: Uint8Array, | 
					  key: Uint8Array; | 
				
			||||
  cipherText: Uint8Array, | 
					  cipherText: Uint8Array; | 
				
			||||
  clearText: Uint8Array | 
					  clearText: Uint8Array; | 
				
			||||
} { | 
					} { | 
				
			||||
  return { | 
					  return { | 
				
			||||
    key: fs.readFileSync(`testdata/${name}_key.bin`), | 
					    key: fs.readFileSync(`testdata/${name}_key.bin`), | 
				
			||||
    cipherText: fs.readFileSync(`testdata/${name}_raw.bin`), | 
					    cipherText: fs.readFileSync(`testdata/${name}_raw.bin`), | 
				
			||||
    clearText: fs.readFileSync(`testdata/${name}_target.bin`) | 
					    clearText: fs.readFileSync(`testdata/${name}_target.bin`), | 
				
			||||
  } | 
					  }; | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
test("map cipher: real file", async () => { | 
					test('map cipher: real file', async () => { | 
				
			||||
  const cases = ["mflac_map", "mgg_map"] | 
					  const cases = ['mflac_map', 'mgg_map']; | 
				
			||||
  for (const name of cases) { | 
					  for (const name of cases) { | 
				
			||||
    const {key, clearText, cipherText} = loadTestDataCipher(name) | 
					    const { key, clearText, cipherText } = loadTestDataCipher(name); | 
				
			||||
    const c = new QmcMapCipher(key) | 
					    const c = new QmcMapCipher(key); | 
				
			||||
 | 
					
 | 
				
			||||
    c.decrypt(cipherText, 0) | 
					    c.decrypt(cipherText, 0); | 
				
			||||
 | 
					
 | 
				
			||||
    expect(cipherText).toStrictEqual(clearText) | 
					    expect(cipherText).toStrictEqual(clearText); | 
				
			||||
  } | 
					  } | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
					
 | 
				
			||||
test("rc4 cipher: real file", async () => { | 
					test('rc4 cipher: real file', async () => { | 
				
			||||
  const cases = ["mflac0_rc4"] | 
					  const cases = ['mflac0_rc4']; | 
				
			||||
  for (const name of cases) { | 
					  for (const name of cases) { | 
				
			||||
    const {key, clearText, cipherText} = loadTestDataCipher(name) | 
					    const { key, clearText, cipherText } = loadTestDataCipher(name); | 
				
			||||
    const c = new QmcRC4Cipher(key) | 
					    const c = new QmcRC4Cipher(key); | 
				
			||||
 | 
					
 | 
				
			||||
    c.decrypt(cipherText, 0) | 
					    c.decrypt(cipherText, 0); | 
				
			||||
 | 
					
 | 
				
			||||
    expect(cipherText).toStrictEqual(clearText) | 
					    expect(cipherText).toStrictEqual(clearText); | 
				
			||||
  } | 
					  } | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
					
 | 
				
			||||
test("rc4 cipher: first segment", async () => { | 
					test('rc4 cipher: first segment', async () => { | 
				
			||||
  const cases = ["mflac0_rc4"] | 
					  const cases = ['mflac0_rc4']; | 
				
			||||
  for (const name of cases) { | 
					  for (const name of cases) { | 
				
			||||
    const {key, clearText, cipherText} = loadTestDataCipher(name) | 
					    const { key, clearText, cipherText } = loadTestDataCipher(name); | 
				
			||||
    const c = new QmcRC4Cipher(key) | 
					    const c = new QmcRC4Cipher(key); | 
				
			||||
 | 
					
 | 
				
			||||
    const buf = cipherText.slice(0, 128) | 
					    const buf = cipherText.slice(0, 128); | 
				
			||||
    c.decrypt(buf, 0) | 
					    c.decrypt(buf, 0); | 
				
			||||
    expect(buf).toStrictEqual(clearText.slice(0, 128)) | 
					    expect(buf).toStrictEqual(clearText.slice(0, 128)); | 
				
			||||
  } | 
					  } | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
					
 | 
				
			||||
test("rc4 cipher: align block (128~5120)", async () => { | 
					test('rc4 cipher: align block (128~5120)', async () => { | 
				
			||||
  const cases = ["mflac0_rc4"] | 
					  const cases = ['mflac0_rc4']; | 
				
			||||
  for (const name of cases) { | 
					  for (const name of cases) { | 
				
			||||
    const {key, clearText, cipherText} = loadTestDataCipher(name) | 
					    const { key, clearText, cipherText } = loadTestDataCipher(name); | 
				
			||||
    const c = new QmcRC4Cipher(key) | 
					    const c = new QmcRC4Cipher(key); | 
				
			||||
 | 
					
 | 
				
			||||
    const buf = cipherText.slice(128, 5120) | 
					    const buf = cipherText.slice(128, 5120); | 
				
			||||
    c.decrypt(buf, 128) | 
					    c.decrypt(buf, 128); | 
				
			||||
    expect(buf).toStrictEqual(clearText.slice(128, 5120)) | 
					    expect(buf).toStrictEqual(clearText.slice(128, 5120)); | 
				
			||||
  } | 
					  } | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
					
 | 
				
			||||
test("rc4 cipher: simple block (5120~10240)", async () => { | 
					test('rc4 cipher: simple block (5120~10240)', async () => { | 
				
			||||
  const cases = ["mflac0_rc4"] | 
					  const cases = ['mflac0_rc4']; | 
				
			||||
  for (const name of cases) { | 
					  for (const name of cases) { | 
				
			||||
    const {key, clearText, cipherText} = loadTestDataCipher(name) | 
					    const { key, clearText, cipherText } = loadTestDataCipher(name); | 
				
			||||
    const c = new QmcRC4Cipher(key) | 
					    const c = new QmcRC4Cipher(key); | 
				
			||||
 | 
					
 | 
				
			||||
    const buf = cipherText.slice(5120, 10240) | 
					    const buf = cipherText.slice(5120, 10240); | 
				
			||||
    c.decrypt(buf, 5120) | 
					    c.decrypt(buf, 5120); | 
				
			||||
    expect(buf).toStrictEqual(clearText.slice(5120, 10240)) | 
					    expect(buf).toStrictEqual(clearText.slice(5120, 10240)); | 
				
			||||
  } | 
					  } | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
				
			|||||
@ -1,30 +1,26 @@ | 
				
			|||||
import {QmcDeriveKey, simpleMakeKey} from "@/decrypt/qmc_key"; | 
					import { QmcDeriveKey, simpleMakeKey } from '@/decrypt/qmc_key'; | 
				
			||||
import fs from "fs"; | 
					import fs from 'fs'; | 
				
			||||
 | 
					
 | 
				
			||||
test("key dec: make simple key", () => { | 
					test('key dec: make simple key', () => { | 
				
			||||
  expect( | 
					  expect(simpleMakeKey(106, 8)).toStrictEqual([0x69, 0x56, 0x46, 0x38, 0x2b, 0x20, 0x15, 0x0b]); | 
				
			||||
    simpleMakeKey(106, 8) | 
					}); | 
				
			||||
  ).toStrictEqual( | 
					 | 
				
			||||
    [0x69, 0x56, 0x46, 0x38, 0x2b, 0x20, 0x15, 0x0b] | 
					 | 
				
			||||
  ) | 
					 | 
				
			||||
}) | 
					 | 
				
			||||
 | 
					
 | 
				
			||||
function loadTestDataKeyDecrypt(name: string): { | 
					function loadTestDataKeyDecrypt(name: string): { | 
				
			||||
  cipherText: Uint8Array, | 
					  cipherText: Uint8Array; | 
				
			||||
  clearText: Uint8Array | 
					  clearText: Uint8Array; | 
				
			||||
} { | 
					} { | 
				
			||||
  return { | 
					  return { | 
				
			||||
    cipherText: fs.readFileSync(`testdata/${name}_key_raw.bin`), | 
					    cipherText: fs.readFileSync(`testdata/${name}_key_raw.bin`), | 
				
			||||
    clearText: fs.readFileSync(`testdata/${name}_key.bin`) | 
					    clearText: fs.readFileSync(`testdata/${name}_key.bin`), | 
				
			||||
  } | 
					  }; | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
test("key dec: real file", async () => { | 
					test('key dec: real file', async () => { | 
				
			||||
  const cases = ["mflac_map", "mgg_map", "mflac0_rc4"] | 
					  const cases = ['mflac_map', 'mgg_map', 'mflac0_rc4']; | 
				
			||||
  for (const name of cases) { | 
					  for (const name of cases) { | 
				
			||||
    const {clearText, cipherText} = loadTestDataKeyDecrypt(name) | 
					    const { clearText, cipherText } = loadTestDataKeyDecrypt(name); | 
				
			||||
    const buf = QmcDeriveKey(cipherText) | 
					    const buf = QmcDeriveKey(cipherText); | 
				
			||||
 | 
					
 | 
				
			||||
    expect(buf).toStrictEqual(clearText) | 
					    expect(buf).toStrictEqual(clearText); | 
				
			||||
  } | 
					  } | 
				
			||||
}) | 
					}); | 
				
			||||
 | 
				
			|||||
@ -1,5 +1,2 @@ | 
				
			|||||
const bs = chrome || browser | 
					const bs = chrome || browser; | 
				
			||||
bs.tabs.create({ | 
					bs.tabs.create({ url: bs.runtime.getURL('./index.html') }, (tab) => console.log(tab)); | 
				
			||||
    url: bs.runtime.getURL('./index.html') | 
					 | 
				
			||||
}, tab => console.log(tab)) | 
					 | 
				
			||||
 | 
					 | 
				
			||||
 | 
				
			|||||
@ -1,31 +1,30 @@ | 
				
			|||||
/* eslint-disable no-console */ | 
					/* eslint-disable no-console */ | 
				
			||||
 | 
					
 | 
				
			||||
import {register} from 'register-service-worker' | 
					import { register } from 'register-service-worker'; | 
				
			||||
 | 
					 | 
				
			||||
if (process.env.NODE_ENV === 'production' && window.location.protocol === "https:") { | 
					 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					if (process.env.NODE_ENV === 'production' && window.location.protocol === 'https:') { | 
				
			||||
  register(`${process.env.BASE_URL}service-worker.js`, { | 
					  register(`${process.env.BASE_URL}service-worker.js`, { | 
				
			||||
    ready() { | 
					    ready() { | 
				
			||||
            console.log('App is being served from cache by a service worker.') | 
					      console.log('App is being served from cache by a service worker.'); | 
				
			||||
    }, | 
					    }, | 
				
			||||
    registered() { | 
					    registered() { | 
				
			||||
            console.log('Service worker has been registered.') | 
					      console.log('Service worker has been registered.'); | 
				
			||||
    }, | 
					    }, | 
				
			||||
    cached() { | 
					    cached() { | 
				
			||||
            console.log('Content has been cached for offline use.') | 
					      console.log('Content has been cached for offline use.'); | 
				
			||||
    }, | 
					    }, | 
				
			||||
    updatefound() { | 
					    updatefound() { | 
				
			||||
            console.log('New content is downloading.') | 
					      console.log('New content is downloading.'); | 
				
			||||
    }, | 
					    }, | 
				
			||||
    updated() { | 
					    updated() { | 
				
			||||
      console.log('New content is available.'); | 
					      console.log('New content is available.'); | 
				
			||||
      window.location.reload(); | 
					      window.location.reload(); | 
				
			||||
    }, | 
					    }, | 
				
			||||
    offline() { | 
					    offline() { | 
				
			||||
            console.log('No internet connection found. App is running in offline mode.') | 
					      console.log('No internet connection found. App is running in offline mode.'); | 
				
			||||
    }, | 
					    }, | 
				
			||||
    error(error) { | 
					    error(error) { | 
				
			||||
            console.error('Error during service worker registration:', error) | 
					      console.error('Error during service worker registration:', error); | 
				
			||||
        } | 
					    }, | 
				
			||||
    }) | 
					  }); | 
				
			||||
} | 
					} | 
				
			||||
 | 
				
			|||||
@ -1,17 +1,15 @@ | 
				
			|||||
import Vue, {VNode} from 'vue' | 
					import Vue, { VNode } from 'vue'; | 
				
			||||
 | 
					
 | 
				
			||||
declare global { | 
					declare global { | 
				
			||||
  namespace JSX { | 
					  namespace JSX { | 
				
			||||
    // tslint:disable no-empty-interface
 | 
					    // tslint:disable no-empty-interface
 | 
				
			||||
    interface Element extends VNode { | 
					    interface Element extends VNode {} | 
				
			||||
    } | 
					 | 
				
			||||
 | 
					
 | 
				
			||||
    // tslint:disable no-empty-interface
 | 
					    // tslint:disable no-empty-interface
 | 
				
			||||
    interface ElementClass extends Vue { | 
					    interface ElementClass extends Vue {} | 
				
			||||
    } | 
					 | 
				
			||||
 | 
					
 | 
				
			||||
    interface IntrinsicElements { | 
					    interface IntrinsicElements { | 
				
			||||
      [elem: string]: any | 
					      [elem: string]: any; | 
				
			||||
    } | 
					    } | 
				
			||||
  } | 
					  } | 
				
			||||
} | 
					} | 
				
			||||
 | 
				
			|||||
@ -1,4 +1,4 @@ | 
				
			|||||
declare module '*.vue' { | 
					declare module '*.vue' { | 
				
			||||
  import Vue from 'vue' | 
					  import Vue from 'vue'; | 
				
			||||
  export default Vue | 
					  export default Vue; | 
				
			||||
} | 
					} | 
				
			||||
 | 
				
			|||||
@ -1,56 +1,73 @@ | 
				
			|||||
import {fromByteArray as Base64Encode} from "base64-js"; | 
					import { fromByteArray as Base64Encode } from 'base64-js'; | 
				
			||||
 | 
					
 | 
				
			||||
export const IXAREA_API_ENDPOINT = "https://um-api.ixarea.com" | 
					export const IXAREA_API_ENDPOINT = 'https://um-api.ixarea.com'; | 
				
			||||
 | 
					
 | 
				
			||||
export interface UpdateInfo { | 
					export interface UpdateInfo { | 
				
			||||
    Found: boolean | 
					  Found: boolean; | 
				
			||||
    HttpsFound: boolean | 
					  HttpsFound: boolean; | 
				
			||||
    Version: string | 
					  Version: string; | 
				
			||||
    URL: string | 
					  URL: string; | 
				
			||||
    Detail: string | 
					  Detail: string; | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
export async function checkUpdate(version: string): Promise<UpdateInfo> { | 
					export async function checkUpdate(version: string): Promise<UpdateInfo> { | 
				
			||||
    const resp = await fetch(IXAREA_API_ENDPOINT + "/music/app-version", { | 
					  const resp = await fetch(IXAREA_API_ENDPOINT + '/music/app-version', { | 
				
			||||
        method: "POST", | 
					    method: 'POST', | 
				
			||||
        headers: {"Content-Type": "application/json"}, | 
					    headers: { 'Content-Type': 'application/json' }, | 
				
			||||
        body: JSON.stringify({"Version": version}) | 
					    body: JSON.stringify({ Version: version }), | 
				
			||||
  }); | 
					  }); | 
				
			||||
  return await resp.json(); | 
					  return await resp.json(); | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
export function reportKeyUsage(keyData: Uint8Array, maskData: number[], filename: string, format: string, title: string, artist?: string, album?: string) { | 
					export function reportKeyUsage( | 
				
			||||
    return fetch(IXAREA_API_ENDPOINT + "/qmcmask/usage", { | 
					  keyData: Uint8Array, | 
				
			||||
        method: "POST", | 
					  maskData: number[], | 
				
			||||
        headers: {"Content-Type": "application/json"}, | 
					  filename: string, | 
				
			||||
 | 
					  format: string, | 
				
			||||
 | 
					  title: string, | 
				
			||||
 | 
					  artist?: string, | 
				
			||||
 | 
					  album?: string, | 
				
			||||
 | 
					) { | 
				
			||||
 | 
					  return fetch(IXAREA_API_ENDPOINT + '/qmcmask/usage', { | 
				
			||||
 | 
					    method: 'POST', | 
				
			||||
 | 
					    headers: { 'Content-Type': 'application/json' }, | 
				
			||||
    body: JSON.stringify({ | 
					    body: JSON.stringify({ | 
				
			||||
            Mask: Base64Encode(new Uint8Array(maskData)), Key: Base64Encode(keyData), | 
					      Mask: Base64Encode(new Uint8Array(maskData)), | 
				
			||||
            Artist: artist, Title: title, Album: album, Filename: filename, Format: format | 
					      Key: Base64Encode(keyData), | 
				
			||||
 | 
					      Artist: artist, | 
				
			||||
 | 
					      Title: title, | 
				
			||||
 | 
					      Album: album, | 
				
			||||
 | 
					      Filename: filename, | 
				
			||||
 | 
					      Format: format, | 
				
			||||
    }), | 
					    }), | 
				
			||||
    }) | 
					  }); | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
interface KeyInfo { | 
					interface KeyInfo { | 
				
			||||
    Matrix44: string | 
					  Matrix44: string; | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
export async function queryKeyInfo(keyData: Uint8Array, filename: string, format: string): Promise<KeyInfo> { | 
					export async function queryKeyInfo(keyData: Uint8Array, filename: string, format: string): Promise<KeyInfo> { | 
				
			||||
    const resp = await fetch(IXAREA_API_ENDPOINT + "/qmcmask/query", { | 
					  const resp = await fetch(IXAREA_API_ENDPOINT + '/qmcmask/query', { | 
				
			||||
        method: "POST", | 
					    method: 'POST', | 
				
			||||
        headers: {"Content-Type": "application/json"}, | 
					    headers: { 'Content-Type': 'application/json' }, | 
				
			||||
        body: JSON.stringify({Format: format, Key: Base64Encode(keyData), Filename: filename, Type: 44}), | 
					    body: JSON.stringify({ Format: format, Key: Base64Encode(keyData), Filename: filename, Type: 44 }), | 
				
			||||
  }); | 
					  }); | 
				
			||||
  return await resp.json(); | 
					  return await resp.json(); | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
export interface CoverInfo { | 
					export interface CoverInfo { | 
				
			||||
    Id: string | 
					  Id: string; | 
				
			||||
    Type: number | 
					  Type: number; | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
export async function queryAlbumCover(title: string, artist?: string, album?: string): Promise<CoverInfo> { | 
					export async function queryAlbumCover(title: string, artist?: string, album?: string): Promise<CoverInfo> { | 
				
			||||
    const endpoint = IXAREA_API_ENDPOINT + "/music/qq-cover" | 
					  const endpoint = IXAREA_API_ENDPOINT + '/music/qq-cover'; | 
				
			||||
    const params = new URLSearchParams([["Title", title], ["Artist", artist ?? ""], ["Album", album ?? ""]]) | 
					  const params = new URLSearchParams([ | 
				
			||||
    const resp = await fetch(`${endpoint}?${params.toString()}`) | 
					    ['Title', title], | 
				
			||||
    return await resp.json() | 
					    ['Artist', artist ?? ''], | 
				
			||||
 | 
					    ['Album', album ?? ''], | 
				
			||||
 | 
					  ]); | 
				
			||||
 | 
					  const resp = await fetch(`${endpoint}?${params.toString()}`); | 
				
			||||
 | 
					  return await resp.json(); | 
				
			||||
} | 
					} | 
				
			||||
 | 
				
			|||||
@ -1,4 +1,4 @@ | 
				
			|||||
import {expose} from "threads/worker"; | 
					import { expose } from 'threads/worker'; | 
				
			||||
import {CommonDecrypt} from "@/decrypt/common"; | 
					import { CommonDecrypt } from '@/decrypt/common'; | 
				
			||||
 | 
					
 | 
				
			||||
expose(CommonDecrypt) | 
					expose(CommonDecrypt); | 
				
			||||
 | 
				
			|||||
					Loading…
					
					
				
		Reference in new issue