-
- 暂无封面
-
+
+ 暂无封面
>> input {
drag
>
-
- 将新图片拖到此处,或点击选择
以替换自动匹配的图片
-
-
- 新拖到此处的图片将覆盖原始图片
-
+ 将新图片拖到此处,或点击选择
以替换自动匹配的图片
+ 新拖到此处的图片将覆盖原始图片
>> input {
标题:
{{ title }}
-
艺术家:
{{ artist }}
-
专辑:
{{ album }}
-
专辑艺术家:
{{ albumartist }}
@@ -110,10 +85,7 @@ form >>> input {
风格:
{{ genre }}
-
diff --git a/src/component/FileSelector.vue b/src/component/FileSelector.vue
index aeef540..2ba5cf3 100644
--- a/src/component/FileSelector.vue
+++ b/src/component/FileSelector.vue
@@ -1,21 +1,12 @@
-
+
将文件拖到此处,或 点击选择
仅在浏览器内对文件进行解锁,无需消耗流量
-
- 算法在源代码中已经提供,所有运算都发生在本地
-
+ 算法在源代码中已经提供,所有运算都发生在本地
@@ -73,16 +64,9 @@ export default {
},
},
mounted() {
- if (
- window.Worker &&
- window.location.protocol !== 'file:' &&
- process.env.NODE_ENV === 'production'
- ) {
+ if (window.Worker && window.location.protocol !== 'file:' && process.env.NODE_ENV === 'production') {
console.log('Using Worker Pool');
- this.queue = Pool(
- () => spawn(new Worker('@/utils/worker.ts')),
- navigator.hardwareConcurrency || 1
- );
+ this.queue = Pool(() => spawn(new Worker('@/utils/worker.ts')), navigator.hardwareConcurrency || 1);
this.parallel = true;
} else {
console.log('Using Queue in Main Thread');
diff --git a/src/component/PreviewTable.vue b/src/component/PreviewTable.vue
index 42db682..e2cee72 100644
--- a/src/component/PreviewTable.vue
+++ b/src/component/PreviewTable.vue
@@ -3,9 +3,7 @@
-
- 暂无封面
-
+ 暂无封面
@@ -26,11 +24,7 @@
-
+
@@ -43,11 +37,7 @@
-
+
diff --git a/src/decrypt/kgm.ts b/src/decrypt/kgm.ts
index ca3afa6..d58c73c 100644
--- a/src/decrypt/kgm.ts
+++ b/src/decrypt/kgm.ts
@@ -63,7 +63,11 @@ export async function Decrypt(file: File, raw_filename: string, raw_ext: string)
const mime = AudioMimeType[ext];
let musicBlob = new Blob([musicDecoded], { type: mime });
const musicMeta = await metaParseBlob(musicBlob);
- const { title, artist } = GetMetaFromFile(raw_filename, musicMeta.common.title, String(musicMeta.common.artists || musicMeta.common.artist || ""));
+ const { title, artist } = GetMetaFromFile(
+ raw_filename,
+ musicMeta.common.title,
+ String(musicMeta.common.artists || musicMeta.common.artist || ''),
+ );
return {
album: musicMeta.common.album,
picture: GetCoverFromFile(musicMeta),
diff --git a/src/decrypt/kgm_wasm.ts b/src/decrypt/kgm_wasm.ts
index db2f18d..f8ab4bb 100644
--- a/src/decrypt/kgm_wasm.ts
+++ b/src/decrypt/kgm_wasm.ts
@@ -16,10 +16,7 @@ export interface KGMDecryptionResult {
* 如果检测并解密成功,返回解密后的 Uint8Array 数据。
* @param {ArrayBuffer} kgmBlob 读入的文件 Blob
*/
-export async function DecryptKgmWasm(
- kgmBlob: ArrayBuffer,
- ext: string
-): Promise {
+export async function DecryptKgmWasm(kgmBlob: ArrayBuffer, ext: string): Promise {
const result: KGMDecryptionResult = {
success: false,
data: new Uint8Array(),
diff --git a/src/decrypt/kwm.ts b/src/decrypt/kwm.ts
index a72b202..59895ae 100644
--- a/src/decrypt/kwm.ts
+++ b/src/decrypt/kwm.ts
@@ -38,7 +38,11 @@ export async function Decrypt(file: File, raw_filename: string, _: string): Prom
let musicBlob = new Blob([audioData], { type: mime });
const musicMeta = await metaParseBlob(musicBlob);
- const { title, artist } = GetMetaFromFile(raw_filename, musicMeta.common.title, String(musicMeta.common.artists || musicMeta.common.artist || ""));
+ const { title, artist } = GetMetaFromFile(
+ raw_filename,
+ musicMeta.common.title,
+ String(musicMeta.common.artists || musicMeta.common.artist || ''),
+ );
return {
album: musicMeta.common.album,
picture: GetCoverFromFile(musicMeta),
diff --git a/src/decrypt/mg3d.ts b/src/decrypt/mg3d.ts
index 8ddc845..18d3a24 100644
--- a/src/decrypt/mg3d.ts
+++ b/src/decrypt/mg3d.ts
@@ -5,24 +5,24 @@ import { DecryptResult } from '@/decrypt/entity';
const segmentSize = 0x20;
function isPrintableAsciiChar(ch: number) {
- return ch >= 0x20 && ch <= 0x7E;
+ return ch >= 0x20 && ch <= 0x7e;
}
function isUpperHexChar(ch: number) {
- return (ch >= 0x30 && ch <= 0x39) || (ch >= 0x41 && ch <= 0x46);
+ return (ch >= 0x30 && ch <= 0x39) || (ch >= 0x41 && ch <= 0x46);
}
/**
- * @param {Buffer} data
- * @param {Buffer} key
- * @param {boolean} copy
+ * @param {Buffer} data
+ * @param {Buffer} key
+ * @param {boolean} copy
* @returns Buffer
*/
function decryptSegment(data: Uint8Array, key: Uint8Array) {
- for (let i = 0; i < data.byteLength; i++) {
- data[i] -= key[i % segmentSize];
- }
- return Buffer.from(data);
+ for (let i = 0; i < data.byteLength; i++) {
+ data[i] -= key[i % segmentSize];
+ }
+ return Buffer.from(data);
}
export async function Decrypt(file: File, raw_filename: string): Promise {
@@ -33,37 +33,37 @@ export async function Decrypt(file: File, raw_filename: string): Promise {
+export async function Decrypt(file: File, raw_filename: string, _: string): Promise {
return new NcmDecrypt(await GetArrayBuffer(file), raw_filename).decrypt();
}
@@ -72,16 +68,14 @@ class NcmDecrypt {
_getKeyData(): Uint8Array {
const keyLen = this.view.getUint32(this.offset, true);
this.offset += 4;
- const cipherText = new Uint8Array(this.raw, this.offset, keyLen).map(
- (uint8) => uint8 ^ 0x64
- );
+ const cipherText = new Uint8Array(this.raw, this.offset, keyLen).map((uint8) => uint8 ^ 0x64);
this.offset += keyLen;
const plainText = AES.decrypt(
// @ts-ignore
{ ciphertext: WordArray.create(cipherText) },
CORE_KEY,
- { mode: ModeECB, padding: PKCS7 }
+ { mode: ModeECB, padding: PKCS7 },
);
const result = new Uint8Array(plainText.sigBytes);
@@ -121,9 +115,7 @@ class NcmDecrypt {
this.offset += 4;
if (metaDataLen === 0) return {};
- const cipherText = new Uint8Array(this.raw, this.offset, metaDataLen).map(
- (data) => data ^ 0x63
- );
+ const cipherText = new Uint8Array(this.raw, this.offset, metaDataLen).map((data) => data ^ 0x63);
this.offset += metaDataLen;
WordArray.create();
@@ -132,11 +124,11 @@ class NcmDecrypt {
{
ciphertext: Base64.parse(
// @ts-ignore
- WordArray.create(cipherText.slice(22)).toString(EncUTF8)
+ WordArray.create(cipherText.slice(22)).toString(EncUTF8),
),
},
META_KEY,
- { mode: ModeECB, padding: PKCS7 }
+ { mode: ModeECB, padding: PKCS7 },
).toString(EncUTF8);
const labelIndex = plainText.indexOf(':');
@@ -148,8 +140,7 @@ class NcmDecrypt {
result = JSON.parse(plainText.slice(labelIndex + 1));
}
if (!!result.albumPic) {
- result.albumPic =
- result.albumPic.replace('http://', 'https://') + '?param=500y500';
+ result.albumPic = result.albumPic.replace('http://', 'https://') + '?param=500y500';
}
return result;
}
@@ -158,8 +149,7 @@ class NcmDecrypt {
this.offset += this.view.getUint32(this.offset + 5, true) + 13;
const audioData = new Uint8Array(this.raw, this.offset);
let lenAudioData = audioData.length;
- for (let cur = 0; cur < lenAudioData; ++cur)
- audioData[cur] ^= keyBox[cur & 0xff];
+ for (let cur = 0; cur < lenAudioData; ++cur) audioData[cur] ^= keyBox[cur & 0xff];
return audioData;
}
@@ -207,21 +197,14 @@ class NcmDecrypt {
if (!this.blob) this.blob = new Blob([this.audio], { type: this.mime });
const ori = await metaParseBlob(this.blob);
- let shouldWrite =
- !ori.common.album && !ori.common.artists && !ori.common.title;
+ let shouldWrite = !ori.common.album && !ori.common.artists && !ori.common.title;
if (shouldWrite || this.newMeta.picture) {
if (this.format === 'mp3') {
this.audio = WriteMetaToMp3(Buffer.from(this.audio), this.newMeta, ori);
} else if (this.format === 'flac') {
- this.audio = WriteMetaToFlac(
- Buffer.from(this.audio),
- this.newMeta,
- ori
- );
+ this.audio = WriteMetaToFlac(Buffer.from(this.audio), this.newMeta, ori);
} else {
- console.info(
- `writing meta for ${this.format} is not being supported for now`
- );
+ console.info(`writing meta for ${this.format} is not being supported for now`);
return;
}
this.blob = new Blob([this.audio], { type: this.mime });
diff --git a/src/decrypt/ncmcache.ts b/src/decrypt/ncmcache.ts
index f6ef63f..d758eec 100644
--- a/src/decrypt/ncmcache.ts
+++ b/src/decrypt/ncmcache.ts
@@ -13,7 +13,11 @@ export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string)
const ext = SniffAudioExt(buffer, raw_ext);
if (ext !== raw_ext) file = new Blob([buffer], { type: AudioMimeType[ext] });
const tag = await metaParseBlob(file);
- const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, String(tag.common.artists || tag.common.artist || ""));
+ const { title, artist } = GetMetaFromFile(
+ raw_filename,
+ tag.common.title,
+ String(tag.common.artists || tag.common.artist || ''),
+ );
return {
title,
diff --git a/src/decrypt/qmc.ts b/src/decrypt/qmc.ts
index 2f5e29c..db3e2fe 100644
--- a/src/decrypt/qmc.ts
+++ b/src/decrypt/qmc.ts
@@ -1,9 +1,4 @@
-import {
- QmcMapCipher,
- QmcRC4Cipher,
- QmcStaticCipher,
- QmcStreamCipher,
-} from './qmc_cipher';
+import { QmcMapCipher, QmcRC4Cipher, QmcStaticCipher, QmcStreamCipher } from './qmc_cipher';
import { AudioMimeType, GetArrayBuffer, SniffAudioExt } from '@/decrypt/utils';
import { DecryptResult } from '@/decrypt/entity';
@@ -42,11 +37,7 @@ export const HandlerMap: { [key: string]: Handler } = {
'776176': { ext: 'wav', version: 1 },
};
-export async function Decrypt(
- file: Blob,
- raw_filename: string,
- raw_ext: string
-): Promise {
+export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string): Promise {
if (!(raw_ext in HandlerMap)) throw `Qmc cannot handle type: ${raw_ext}`;
const handler = HandlerMap[raw_ext];
let { version } = handler;
@@ -65,10 +56,7 @@ export async function Decrypt(
musicID = v2Decrypted.songId;
console.log('qmc wasm decoder suceeded');
} else {
- console.warn(
- 'QmcWasm failed with error %s',
- v2Decrypted.error || '(unknown error)'
- );
+ console.warn('QmcWasm failed with error %s', v2Decrypted.error || '(unknown error)');
}
}
@@ -87,7 +75,7 @@ export async function Decrypt(
new Blob([musicDecoded], { type: mime }),
raw_filename,
ext,
- musicID
+ musicID,
);
return {
diff --git a/src/decrypt/qmc_key.ts b/src/decrypt/qmc_key.ts
index b23b15f..576b315 100644
--- a/src/decrypt/qmc_key.ts
+++ b/src/decrypt/qmc_key.ts
@@ -34,11 +34,14 @@ export function simpleMakeKey(salt: number, length: number): number[] {
return keyBuf;
}
-const mixKey1: Uint8Array = new Uint8Array([ 0x33, 0x38, 0x36, 0x5A, 0x4A, 0x59, 0x21, 0x40, 0x23, 0x2A, 0x24, 0x25, 0x5E, 0x26, 0x29, 0x28 ])
-const mixKey2: Uint8Array = new Uint8Array([ 0x2A, 0x2A, 0x23, 0x21, 0x28, 0x23, 0x24, 0x25, 0x26, 0x5E, 0x61, 0x31, 0x63, 0x5A, 0x2C, 0x54 ])
+const mixKey1: Uint8Array = new Uint8Array([
+ 0x33, 0x38, 0x36, 0x5a, 0x4a, 0x59, 0x21, 0x40, 0x23, 0x2a, 0x24, 0x25, 0x5e, 0x26, 0x29, 0x28,
+]);
+const mixKey2: Uint8Array = new Uint8Array([
+ 0x2a, 0x2a, 0x23, 0x21, 0x28, 0x23, 0x24, 0x25, 0x26, 0x5e, 0x61, 0x31, 0x63, 0x5a, 0x2c, 0x54,
+]);
-function decryptV2Key(key: Buffer): Buffer
-{
+function decryptV2Key(key: Buffer): Buffer {
const textEnc = new TextDecoder();
if (key.length < 18 || textEnc.decode(key.slice(0, 18)) !== 'QQMusic EncV2,Key:') {
return key;
diff --git a/src/decrypt/qmc_wasm.ts b/src/decrypt/qmc_wasm.ts
index b627d46..a1b801d 100644
--- a/src/decrypt/qmc_wasm.ts
+++ b/src/decrypt/qmc_wasm.ts
@@ -17,10 +17,7 @@ export interface QMCDecryptionResult {
* 如果检测并解密成功,返回解密后的 Uint8Array 数据。
* @param {ArrayBuffer} qmcBlob 读入的文件 Blob
*/
-export async function DecryptQmcWasm(
- qmcBlob: ArrayBuffer,
- ext: string
-): Promise {
+export async function DecryptQmcWasm(qmcBlob: ArrayBuffer, ext: string): Promise {
const result: QMCDecryptionResult = {
success: false,
data: new Uint8Array(),
@@ -67,12 +64,7 @@ export async function DecryptQmcWasm(
// 解密一些片段
const blockData = new Uint8Array(qmcBuf.slice(offset, offset + blockSize));
QmcCrypto.writeArrayToMemory(blockData, pQmcBuf);
- decryptedParts.push(
- QmcCrypto.HEAPU8.slice(
- pQmcBuf,
- pQmcBuf + QmcCrypto.decBlob(pQmcBuf, blockSize, offset)
- )
- );
+ decryptedParts.push(QmcCrypto.HEAPU8.slice(pQmcBuf, pQmcBuf + QmcCrypto.decBlob(pQmcBuf, blockSize, offset)));
offset += blockSize;
bytesToDecrypt -= blockSize;
diff --git a/src/decrypt/qmccache.ts b/src/decrypt/qmccache.ts
index 6a57a94..d346e94 100644
--- a/src/decrypt/qmccache.ts
+++ b/src/decrypt/qmccache.ts
@@ -52,7 +52,11 @@ export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string)
throw '不支持的QQ音乐缓存格式';
}
const tag = await metaParseBlob(audioBlob);
- const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, String(tag.common.artists || tag.common.artist || ""));
+ const { title, artist } = GetMetaFromFile(
+ raw_filename,
+ tag.common.title,
+ String(tag.common.artists || tag.common.artist || ''),
+ );
return {
title,
diff --git a/src/decrypt/raw.ts b/src/decrypt/raw.ts
index 4d2427d..b1c19c2 100644
--- a/src/decrypt/raw.ts
+++ b/src/decrypt/raw.ts
@@ -17,7 +17,11 @@ export async function Decrypt(
if (ext !== raw_ext) file = new Blob([buffer], { type: AudioMimeType[ext] });
}
const tag = await metaParseBlob(file);
- const { title, artist } = GetMetaFromFile(raw_filename, tag.common.title, String(tag.common.artists || tag.common.artist || ''));
+ const { title, artist } = GetMetaFromFile(
+ raw_filename,
+ tag.common.title,
+ String(tag.common.artists || tag.common.artist || ''),
+ );
return {
title,
diff --git a/src/decrypt/utils.ts b/src/decrypt/utils.ts
index 94b7593..85a74bc 100644
--- a/src/decrypt/utils.ts
+++ b/src/decrypt/utils.ts
@@ -94,7 +94,8 @@ export function GetMetaFromFile(
const items = filename.split(separator);
if (items.length > 1) {
//由文件名和原metadata共同决定歌手tag(有时从文件名看有多个歌手,而metadata只有一个)
- if (!meta.artist || meta.artist.split(split_regex).length < items[0].trim().split(split_regex).length) meta.artist = items[0].trim();
+ if (!meta.artist || meta.artist.split(split_regex).length < items[0].trim().split(split_regex).length)
+ meta.artist = items[0].trim();
if (!meta.title) meta.title = items[1].trim();
} else if (items.length === 1) {
if (!meta.title) meta.title = items[0].trim();
@@ -182,11 +183,12 @@ export function RewriteMetaToMp3(audioData: Buffer, info: IMusicMeta, original:
// preserve original data
const frames = original.native['ID3v2.4'] || original.native['ID3v2.3'] || original.native['ID3v2.2'] || [];
frames.forEach((frame) => {
- if (frame.id !== 'TPE1'
- && frame.id !== 'TIT2'
- && frame.id !== 'TALB'
- && frame.id !== 'TPE2'
- && frame.id !== 'TCON'
+ if (
+ frame.id !== 'TPE1' &&
+ frame.id !== 'TIT2' &&
+ frame.id !== 'TALB' &&
+ frame.id !== 'TPE2' &&
+ frame.id !== 'TCON'
) {
try {
writer.setFrame(frame.id, frame.value);
diff --git a/src/decrypt/xm.ts b/src/decrypt/xm.ts
index afa9841..a8007a6 100644
--- a/src/decrypt/xm.ts
+++ b/src/decrypt/xm.ts
@@ -49,7 +49,7 @@ export async function Decrypt(file: File, raw_filename: string, raw_ext: string)
const { title, artist } = GetMetaFromFile(
raw_filename,
musicMeta.common.title,
- String(musicMeta.common.artists || musicMeta.common.artist || ""),
+ String(musicMeta.common.artists || musicMeta.common.artist || ''),
raw_filename.indexOf('_') === -1 ? '-' : '_',
);
diff --git a/src/extension/popup.html b/src/extension/popup.html
index b57bb19..44dc63c 100644
--- a/src/extension/popup.html
+++ b/src/extension/popup.html
@@ -1,13 +1,12 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
diff --git a/src/ixarea-stats.js b/src/ixarea-stats.js
index 5cb9f71..355d75a 100644
--- a/src/ixarea-stats.js
+++ b/src/ixarea-stats.js
@@ -1,6 +1,11 @@
var _paq = window._paq || [];
-_paq.push(["setRequestMethod", "POST"], ["trackPageView"], ["enableLinkTracking"],
- ["setSiteId", "2"], ["setTrackerUrl", "https://stats.ixarea.com/ixarea-stats/report"]);
+_paq.push(
+ ['setRequestMethod', 'POST'],
+ ['trackPageView'],
+ ['enableLinkTracking'],
+ ['setSiteId', '2'],
+ ['setTrackerUrl', 'https://stats.ixarea.com/ixarea-stats/report'],
+);
var tag = document.createElement('script');
tag.type = 'text/javascript';
diff --git a/src/scss/_dark-mode.scss b/src/scss/_dark-mode.scss
index e90af2f..673a3e9 100644
--- a/src/scss/_dark-mode.scss
+++ b/src/scss/_dark-mode.scss
@@ -3,85 +3,83 @@
*/
@media (prefers-color-scheme: dark) {
- #app{
+ #app {
color: $dark-text-info;
}
- body{
+ body {
background-color: $dark-bg;
}
// FORM
- .el-radio{
- &__label{
+ .el-radio {
+ &__label {
color: $dark-text-main;
}
- &__input{
+ &__input {
color: $dark-text-info;
- .el-radio__inner{
+ .el-radio__inner {
border-color: $dark-border;
background-color: $dark-btn-bg;
}
}
- &.is-checked{
- .el-radio__inner{
+ &.is-checked {
+ .el-radio__inner {
background-color: $blue;
}
- .el-radio__label{
+ .el-radio__label {
font-weight: bold;
}
}
}
- .el-checkbox.is-bordered{
+ .el-checkbox.is-bordered {
border-color: $dark-border;
color: $dark-text-main;
background-color: $dark-btn-bg;
- .el-checkbox__inner{
+ .el-checkbox__inner {
background-color: $dark-btn-bg-highlight;
border-color: $dark-border-highlight;
}
- &:hover{
+ &:hover {
border-color: $dark-border-highlight;
- .el-checkbox__inner{
+ .el-checkbox__inner {
background-color: $dark-btn-bg-highlight;
border-color: $dark-border-highlight;
}
- .el-checkbox__label{
+ .el-checkbox__label {
color: $dark-text-info;
}
}
- &.is-checked{
+ &.is-checked {
background-color: $blue;
- .el-checkbox__inner{
+ .el-checkbox__inner {
border-color: white;
}
- .el-checkbox__label{
+ .el-checkbox__label {
color: white;
font-weight: bold;
}
- &:hover{
+ &:hover {
border-color: $blue;
- .el-checkbox__inner{
+ .el-checkbox__inner {
background-color: white;
}
}
}
}
-
-
// BUTTON
- .el-button{
+ .el-button {
background-color: $dark-btn-bg;
border-color: $dark-border;
color: $dark-text-main;
- &:active{
+ &:active {
transform: translateY(2px);
}
- &--default{
+ &--default {
&.is-plain {
background-color: $dark-btn-bg;
&:hover {
@@ -101,7 +99,7 @@
}
}
- &--success{
+ &--success {
&.is-plain {
background-color: $dark-btn-bg;
&:hover {
@@ -120,11 +118,11 @@
}
}
}
- &--danger{
- &.is-plain{
+ &--danger {
+ &.is-plain {
border-color: $dark-border;
background-color: $dark-btn-bg;
- &:hover{
+ &:hover {
background-color: $red;
border-color: $red;
}
@@ -142,44 +140,45 @@
}
// 文件拖放区
- .el-upload__tip{
+ .el-upload__tip {
color: $dark-text-info;
}
- .el-upload-dragger{
+ .el-upload-dragger {
background-color: $dark-uploader-bg;
border-color: $dark-border;
- .el-upload__text{
+ .el-upload__text {
color: $dark-text-info;
}
- &:hover{
+ &:hover {
background: $dark-uploader-bg-highlight;
border-color: $dark-border-highlight;
}
}
// TABLE
- .el-table{
+ .el-table {
background-color: $dark-bg-td;
- &:before{ // 去除表格末尾的横线
+ &:before {
+ // 去除表格末尾的横线
content: none;
}
- &__header{
- th{
+ &__header {
+ th {
border-bottom-color: $dark-border !important;
}
}
- th.el-table__cell{
+ th.el-table__cell {
background-color: $dark-bg-th;
color: $dark-text-info;
}
- td{
+ td {
border-bottom-color: $dark-border !important;
}
- tr{
+ tr {
background-color: $dark-bg-td;
color: $dark-text-main;
- &:hover{
- td{
+ &:hover {
+ td {
background-color: $dark-bg-th !important;
}
}
@@ -187,68 +186,66 @@
}
// LINKS
- a{
+ a {
text-decoration: none;
color: darken($dark-color-link, 15%);
- &:hover{
+ &:hover {
color: $dark-color-link;
}
}
// ALERT
- .el-notification{
+ .el-notification {
background-color: $dark-btn-bg-highlight;
border-color: $dark-border;
- &__title{
+ &__title {
color: white;
}
- &__content{
+ &__content {
color: $dark-text-info;
}
}
// DIALOG
- .el-dialog{
+ .el-dialog {
background-color: $dark-dialog-bg;
- .el-dialog__header{
- .el-dialog__title{
+ .el-dialog__header {
+ .el-dialog__title {
color: $dark-text-main;
}
}
- .el-dialog__body{
+ .el-dialog__body {
color: $dark-text-main;
- .el-input{
- .el-input__inner{
+ .el-input {
+ .el-input__inner {
color: $dark-text-main;
background-color: $dark-btn-bg;
}
- .el-input__suffix{
- .el-input__suffix-inner{
+ .el-input__suffix {
+ .el-input__suffix-inner {
}
}
- .el-input__count{
- .el-input__count-inner{
+ .el-input__count {
+ .el-input__count-inner {
background-color: transparent;
}
}
}
}
- .item-desc{
+ .item-desc {
color: $dark-text-info;
}
}
-
-
// 自定义样式
// 首页弹窗提示信息的 更新信息 面板
- .update-info{
+ .update-info {
border: 1px solid $dark-btn-bg !important;
- .update-title{
+ .update-title {
color: $dark-text-main;
background-color: $dark-btn-bg !important;
}
- .update-content{
+ .update-content {
color: $dark-text-info;
padding: 10px;
}
diff --git a/src/scss/_element-ui-overrite.scss b/src/scss/_element-ui-overrite.scss
index b452fd0..e13414c 100644
--- a/src/scss/_element-ui-overrite.scss
+++ b/src/scss/_element-ui-overrite.scss
@@ -1,32 +1,32 @@
$color-checkbox: $blue;
-$color-border-el: #DCDFE6;
+$color-border-el: #dcdfe6;
$btn-radius: 6px;
/* FORM */
// checkbox
-.el-checkbox.is-bordered{
- @include border-radius($btn-radius) ;
- &:hover{
+.el-checkbox.is-bordered {
+ @include border-radius($btn-radius);
+ &:hover {
border-color: $color-checkbox;
- .el-checkbox__label{
+ .el-checkbox__label {
color: $color-checkbox;
}
}
- .el-checkbox__input.is-focus{
- .el-checkbox__inner{
+ .el-checkbox__input.is-focus {
+ .el-checkbox__inner {
border-color: $color-border-el;
}
}
- &.is-checked{
+ &.is-checked {
background-color: $color-checkbox;
- .el-checkbox__label{
+ .el-checkbox__label {
color: white;
}
- .el-checkbox__inner{
+ .el-checkbox__inner {
border-color: white;
background-color: white;
- &:after{
+ &:after {
border-color: $color-checkbox;
}
}
@@ -34,6 +34,6 @@ $btn-radius: 6px;
}
// el-button
-.el-button{
- @include border-radius($btn-radius) ;
+.el-button {
+ @include border-radius($btn-radius);
}
diff --git a/src/scss/_gaps.scss b/src/scss/_gaps.scss
index f9cad59..ef30cce 100644
--- a/src/scss/_gaps.scss
+++ b/src/scss/_gaps.scss
@@ -4,15 +4,35 @@
$gap: 5px;
@for $item from 0 through 8 {
- .mt-#{$item} { margin-top : $gap * $item !important;}
- .mb-#{$item} { margin-bottom : $gap * $item !important;}
- .ml-#{$item} { margin-left : $gap * $item !important;}
- .mr-#{$item} { margin-right : $gap * $item !important;}
- .m-#{$item} { margin : $gap * $item !important;}
+ .mt-#{$item} {
+ margin-top: $gap * $item !important;
+ }
+ .mb-#{$item} {
+ margin-bottom: $gap * $item !important;
+ }
+ .ml-#{$item} {
+ margin-left: $gap * $item !important;
+ }
+ .mr-#{$item} {
+ margin-right: $gap * $item !important;
+ }
+ .m-#{$item} {
+ margin: $gap * $item !important;
+ }
- .pt-#{$item} { padding-top : $gap * $item !important;}
- .pb-#{$item} { padding-bottom : $gap * $item !important;}
- .pl-#{$item} { padding-left : $gap * $item !important;}
- .pr-#{$item} { padding-right : $gap * $item !important;}
- .p-#{$item} { padding : $gap * $item !important;}
+ .pt-#{$item} {
+ padding-top: $gap * $item !important;
+ }
+ .pb-#{$item} {
+ padding-bottom: $gap * $item !important;
+ }
+ .pl-#{$item} {
+ padding-left: $gap * $item !important;
+ }
+ .pr-#{$item} {
+ padding-right: $gap * $item !important;
+ }
+ .p-#{$item} {
+ padding: $gap * $item !important;
+ }
}
diff --git a/src/scss/_normal.scss b/src/scss/_normal.scss
index 69ace39..2d2dfd3 100644
--- a/src/scss/_normal.scss
+++ b/src/scss/_normal.scss
@@ -1,4 +1,4 @@
-body{
+body {
font-family: $font-family;
font-size: $fz-main;
-webkit-font-smoothing: antialiased;
@@ -26,13 +26,13 @@ body{
padding-bottom: 1em;
}
-audio{
+audio {
margin-bottom: 15px; // 播放控件与表格间隔
}
-a{
+a {
color: darken($color-link, 15%);
- &:hover{
+ &:hover {
color: $color-link;
}
-}
\ No newline at end of file
+}
diff --git a/src/scss/_utility.scss b/src/scss/_utility.scss
index 141fedb..a968010 100644
--- a/src/scss/_utility.scss
+++ b/src/scss/_utility.scss
@@ -1,19 +1,19 @@
// box-shadow
-@mixin box-shadow($value...){
- -webkit-box-shadow: $value;
- -moz-box-shadow: $value;
- box-shadow: $value;
+@mixin box-shadow($value...) {
+ -webkit-box-shadow: $value;
+ -moz-box-shadow: $value;
+ box-shadow: $value;
}
// border-radius
-@mixin border-radius($corner...){
+@mixin border-radius($corner...) {
-webkit-border-radius: $corner;
-moz-border-radius: $corner;
border-radius: $corner;
}
-@mixin clearfix(){
- &:after{
+@mixin clearfix() {
+ &:after {
content: '';
display: block;
clear: both;
@@ -21,7 +21,7 @@
}
}
-@mixin transform($value){
+@mixin transform($value) {
-webkit-transform: $value;
-moz-transform: $value;
-ms-transform: $value;
@@ -29,7 +29,7 @@
transform: $value;
}
-@mixin transition($value...){
+@mixin transition($value...) {
-webkit-transition: $value;
-moz-transition: $value;
-ms-transition: $value;
@@ -37,23 +37,22 @@
transition: $value;
}
-@mixin animation($value){
+@mixin animation($value) {
animation: $value;
-webkit-animation: $value;
}
-@mixin linear-gradient($direct, $colors){
+@mixin linear-gradient($direct, $colors) {
background: linear-gradient($direct, $colors);
background: -webkit-linear-gradient($direct, $colors);
background: -moz-linear-gradient($direct, $colors);
}
-@mixin backdrop-filter($value){
- backdrop-filter: $value ;
+@mixin backdrop-filter($value) {
+ backdrop-filter: $value;
-webkit-backdrop-filter: $value;
}
-
/*
Extension
*/
@@ -65,8 +64,8 @@
user-select: none;
}
-.btn-like{
- &:active{
- @include transform(translateY(2px))
+.btn-like {
+ &:active {
+ @include transform(translateY(2px));
}
}
diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss
index 51cd555..0d8ff1c 100644
--- a/src/scss/_variables.scss
+++ b/src/scss/_variables.scss
@@ -1,35 +1,34 @@
// COLORS
-$blue : #409EFF;
-$red : #F56C6C;
-$green : #85ce61;
+$blue: #409eff;
+$red: #f56c6c;
+$green: #85ce61;
// TEXT
-$text-main : #2C3E50;
+$text-main: #2c3e50;
$color-link: $blue;
$fz-main: 14px;
$fz-mini-title: 13px;
$fz-mini-content: 12px;
-$font-family: "Helvetica Neue", Helvetica, "PingFang SC",
-"Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
-
+$font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial,
+ sans-serif;
// DARK MODE
-$dark-border : lighten(black, 25%);
-$dark-border-highlight : lighten(black, 55%);
-$dark-bg : lighten(black, 10%);
-$dark-text-main : lighten(black, 90%);
-$dark-text-info : lighten(black, 60%);
-$dark-uploader-bg : lighten(black, 13%);
-$dark-dialog-bg : lighten(black, 15%);
-$dark-uploader-bg-highlight : lighten(black, 18%);
-$dark-btn-bg : lighten(black, 20%);
-$dark-btn-bg-highlight : lighten(black, 30%);
-$dark-bg-th : lighten(black, 18%);
-$dark-bg-td : lighten(black, 13%);
-$dark-color-link : $green;
+$dark-border: lighten(black, 25%);
+$dark-border-highlight: lighten(black, 55%);
+$dark-bg: lighten(black, 10%);
+$dark-text-main: lighten(black, 90%);
+$dark-text-info: lighten(black, 60%);
+$dark-uploader-bg: lighten(black, 13%);
+$dark-dialog-bg: lighten(black, 15%);
+$dark-uploader-bg-highlight: lighten(black, 18%);
+$dark-btn-bg: lighten(black, 20%);
+$dark-btn-bg-highlight: lighten(black, 30%);
+$dark-bg-th: lighten(black, 18%);
+$dark-bg-td: lighten(black, 13%);
+$dark-color-link: $green;
-$dark-blue : darken(desaturate($blue, 40%), 30%);
-$dark-red : darken(desaturate($red, 50%), 30%);
-$dark-green : darken(desaturate($green, 30%), 30%);
+$dark-blue: darken(desaturate($blue, 40%), 30%);
+$dark-red: darken(desaturate($red, 50%), 30%);
+$dark-green: darken(desaturate($green, 30%), 30%);
diff --git a/src/scss/unlock-music.scss b/src/scss/unlock-music.scss
index 178f28c..0138555 100644
--- a/src/scss/unlock-music.scss
+++ b/src/scss/unlock-music.scss
@@ -1,24 +1,23 @@
-@import "variables";
-@import "utility";
-@import "gaps";
-@import "element-ui-overrite";
-
-@import "normal";
-@import "dark-mode"; // dark-mode 放在 normal 后面,以获得更高优先级
+@import 'variables';
+@import 'utility';
+@import 'gaps';
+@import 'element-ui-overrite';
+@import 'normal';
+@import 'dark-mode'; // dark-mode 放在 normal 后面,以获得更高优先级
// 首页弹窗提示信息的 更新信息 面板
-.update-info{
+.update-info {
@include border-radius(8px);
overflow: hidden;
border: 1px solid $color-border-el;
margin: 10px 0;
- .update-title{
+ .update-title {
font-size: $fz-mini-title;
padding: 5px 10px;
background-color: $color-border-el;
}
- .update-content{
+ .update-content {
font-size: $fz-mini-content;
line-height: 1.5;
padding: 10px;
diff --git a/src/utils/qm_meta.ts b/src/utils/qm_meta.ts
index d93d44f..2148bbb 100644
--- a/src/utils/qm_meta.ts
+++ b/src/utils/qm_meta.ts
@@ -44,8 +44,7 @@ export async function extractQQMusicMeta(
musicMeta.common.artist = '';
if (!musicMeta.common.artists) {
musicMeta.common.artist = fromGBK(musicMeta.common.artist);
- }
- else {
+ } else {
musicMeta.common.artist = musicMeta.common.artists.map(fromGBK).join();
}
musicMeta.common.title = fromGBK(musicMeta.common.title);
diff --git a/src/view/Home.vue b/src/view/Home.vue
index 17aea99..3cc0442 100644
--- a/src/view/Home.vue
+++ b/src/view/Home.vue
@@ -5,12 +5,7 @@
歌曲命名格式:
-
+
{{ k.text }}
@@ -26,10 +21,7 @@
@cancel="showEditDialog = false"
@ok="handleEdit"
>
-
+
部分解密方案需要设定解密参数。
@@ -47,22 +39,13 @@
-
- 工作模式: {{ dir ? '写入本地文件系统' : '调用浏览器下载' }}
-
+ 工作模式: {{ dir ? '写入本地文件系统' : '调用浏览器下载' }}
当您使用此工具进行大量文件解锁的时候,建议开启此选项。
开启后,解锁结果将不会存留于浏览器中,防止内存不足。
-
- 立即保存
-
+ 立即保存
@@ -86,20 +69,8 @@ import PreviewTable from '@/component/PreviewTable';
import ConfigDialog from '@/component/ConfigDialog';
import EditDialog from '@/component/EditDialog';
-import {
- DownloadBlobMusic,
- FilenamePolicy,
- FilenamePolicies,
- RemoveBlobMusic,
- DirectlyWriteFile,
-} from '@/utils/utils';
-import {
- GetImageFromURL,
- RewriteMetaToMp3,
- RewriteMetaToFlac,
- AudioMimeType,
- split_regex,
-} from '@/decrypt/utils';
+import { DownloadBlobMusic, FilenamePolicy, FilenamePolicies, RemoveBlobMusic, DirectlyWriteFile } from '@/utils/utils';
+import { GetImageFromURL, RewriteMetaToMp3, RewriteMetaToFlac, AudioMimeType, split_regex } from '@/decrypt/utils';
import { parseBlob as metaParseBlob } from 'music-metadata-browser';
export default {
@@ -152,12 +123,7 @@ export default {
}
if (process.env.NODE_ENV === 'production') {
let _rp_data = [data.title, data.artist, data.album];
- window._paq.push([
- 'trackEvent',
- 'Unlock',
- data.rawExt + ',' + data.mime,
- JSON.stringify(_rp_data),
- ]);
+ window._paq.push(['trackEvent', 'Unlock', data.rawExt + ',' + data.mime, JSON.stringify(_rp_data)]);
}
},
showFail(errInfo, filename) {
@@ -214,9 +180,7 @@ export default {
let writeSuccess = true;
let notifyMsg = '成功修改 ' + this.editing_data.title;
try {
- const musicMeta = await metaParseBlob(
- new Blob([this.editing_data.blob], { type: mime })
- );
+ const musicMeta = await metaParseBlob(new Blob([this.editing_data.blob], { type: mime }));
let imageInfo = undefined;
if (this.editing_data.picture !== '') {
imageInfo = await GetImageFromURL(this.editing_data.picture);
@@ -235,26 +199,16 @@ export default {
const buffer = Buffer.from(await this.editing_data.blob.arrayBuffer());
const mime = AudioMimeType[this.editing_data.ext] || AudioMimeType.mp3;
if (this.editing_data.ext === 'mp3') {
- this.editing_data.blob = new Blob(
- [RewriteMetaToMp3(buffer, newMeta, musicMeta)],
- { type: mime }
- );
+ this.editing_data.blob = new Blob([RewriteMetaToMp3(buffer, newMeta, musicMeta)], { type: mime });
} else if (this.editing_data.ext === 'flac') {
- this.editing_data.blob = new Blob(
- [RewriteMetaToFlac(buffer, newMeta, musicMeta)],
- { type: mime }
- );
+ this.editing_data.blob = new Blob([RewriteMetaToFlac(buffer, newMeta, musicMeta)], { type: mime });
} else {
writeSuccess = undefined;
notifyMsg = this.editing_data.ext + '类型文件暂时不支持修改音乐标签';
}
} catch (e) {
writeSuccess = false;
- notifyMsg =
- '修改' +
- this.editing_data.title +
- '未能完成。在写入新的元数据时发生错误:' +
- e;
+ notifyMsg = '修改' + this.editing_data.title + '未能完成。在写入新的元数据时发生错误:' + e;
}
this.editing_data.file = URL.createObjectURL(this.editing_data.blob);
if (writeSuccess === true) {
@@ -305,16 +259,12 @@ export default {
async showDirectlySave() {
if (!window.showDirectoryPicker) return;
try {
- await ElMessageBox.confirm(
- '您的浏览器支持文件直接保存到磁盘,是否使用?',
- '新特性提示',
- {
- confirmButtonText: '使用',
- cancelButtonText: '不使用',
- type: 'warning',
- center: true,
- }
- );
+ await ElMessageBox.confirm('您的浏览器支持文件直接保存到磁盘,是否使用?', '新特性提示', {
+ confirmButtonText: '使用',
+ cancelButtonText: '不使用',
+ type: 'warning',
+ center: true,
+ });
} catch (e) {
console.log(e);
return;
diff --git a/tsconfig.json b/tsconfig.json
index b8e44f8..2bd2753 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,31 +13,13 @@
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
- "types": [
- "webpack-env",
- "jest"
- ],
+ "types": ["webpack-env", "jest"],
"paths": {
- "@/*": [
- "src/*"
- ]
+ "@/*": ["src/*"]
},
- "lib": [
- "esnext",
- "dom",
- "dom.iterable",
- "scripthost"
- ],
+ "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
"resolveJsonModule": true
},
- "include": [
- "src/**/*.ts",
- "src/**/*.tsx",
- "src/**/*.vue",
- "tests/**/*.ts",
- "tests/**/*.tsx"
- ],
- "exclude": [
- "node_modules"
- ]
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx"],
+ "exclude": ["node_modules"]
}
diff --git a/vue.config.js b/vue.config.js
index b8c37c1..5ca58ee 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -1,43 +1,43 @@
const ThreadsPlugin = require('threads-plugin');
module.exports = {
- publicPath: '',
- productionSourceMap: false,
- pwa: {
- manifestPath: "web-manifest.json",
- name: "音乐解锁",
- themeColor: "#4DBA87",
- msTileColor: "#000000",
- manifestOptions: {
- start_url: "./index.html",
- description: "在任何设备上解锁已购的加密音乐!",
- icons: [
- {
- 'src': './img/icons/android-chrome-192x192.png',
- 'sizes': '192x192',
- 'type': 'image/png'
- },
- {
- 'src': './img/icons/android-chrome-512x512.png',
- 'sizes': '512x512',
- 'type': 'image/png'
- }
- ]
+ publicPath: '',
+ productionSourceMap: false,
+ pwa: {
+ manifestPath: 'web-manifest.json',
+ name: '音乐解锁',
+ themeColor: '#4DBA87',
+ msTileColor: '#000000',
+ manifestOptions: {
+ start_url: './index.html',
+ description: '在任何设备上解锁已购的加密音乐!',
+ icons: [
+ {
+ src: './img/icons/android-chrome-192x192.png',
+ sizes: '192x192',
+ type: 'image/png',
},
- appleMobileWebAppCapable: 'yes',
- iconPaths: {
- faviconSVG: './img/icons/safari-pinned-tab.svg',
- favicon32: './img/icons/favicon-32x32.png',
- favicon16: './img/icons/favicon-16x16.png',
- appleTouchIcon: './img/icons/apple-touch-icon-152x152.png',
- maskIcon: './img/icons/safari-pinned-tab.svg',
- msTileImage: './img/icons/msapplication-icon-144x144.png'
+ {
+ src: './img/icons/android-chrome-512x512.png',
+ sizes: '512x512',
+ type: 'image/png',
},
- workboxPluginMode: "GenerateSW",
- workboxOptions: {
- skipWaiting: true
- }
+ ],
},
- configureWebpack: {
- plugins: [new ThreadsPlugin()]
- }
+ appleMobileWebAppCapable: 'yes',
+ iconPaths: {
+ faviconSVG: './img/icons/safari-pinned-tab.svg',
+ favicon32: './img/icons/favicon-32x32.png',
+ favicon16: './img/icons/favicon-16x16.png',
+ appleTouchIcon: './img/icons/apple-touch-icon-152x152.png',
+ maskIcon: './img/icons/safari-pinned-tab.svg',
+ msTileImage: './img/icons/msapplication-icon-144x144.png',
+ },
+ workboxPluginMode: 'GenerateSW',
+ workboxOptions: {
+ skipWaiting: true,
+ },
+ },
+ configureWebpack: {
+ plugins: [new ThreadsPlugin()],
+ },
};