refactor: component/*.vue

remotes/origin/HEAD
Emmm Monster 4 years ago
parent ca4ed149b2
commit c7e5dfb4c4
No known key found for this signature in database
GPG Key ID: C98279C83FB50DB9

94
package-lock.json generated

@ -5820,6 +5820,12 @@
"estraverse": "^4.1.1" "estraverse": "^4.1.1"
} }
}, },
"esm": {
"version": "3.2.25",
"resolved": "http://mirrors.cloud.tencent.com/npm/esm/-/esm-3.2.25.tgz",
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
"optional": true
},
"esprima": { "esprima": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@ -7822,6 +7828,11 @@
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
"dev": true "dev": true
}, },
"is-observable": {
"version": "2.1.0",
"resolved": "http://mirrors.cloud.tencent.com/npm/is-observable/-/is-observable-2.1.0.tgz",
"integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw=="
},
"is-path-cwd": { "is-path-cwd": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
@ -9305,6 +9316,11 @@
"has": "^1.0.3" "has": "^1.0.3"
} }
}, },
"observable-fns": {
"version": "0.5.1",
"resolved": "http://mirrors.cloud.tencent.com/npm/observable-fns/-/observable-fns-0.5.1.tgz",
"integrity": "sha512-wf7g4Jpo1Wt2KIqZKLGeiuLOEMqpaOZ5gJn7DmSdqXgTdxRwSdBhWegQQpPteQ2gZvzCKqNNpwb853wcpA0j7A=="
},
"obuf": { "obuf": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
@ -12243,6 +12259,56 @@
} }
} }
}, },
"threads": {
"version": "1.6.4",
"resolved": "http://mirrors.cloud.tencent.com/npm/threads/-/threads-1.6.4.tgz",
"integrity": "sha512-A+9MQFAUha9W8MjIPmrvETy98qVmZFr5Unox9D95y7kvz3fBpGiFS7JOZs07B2KvTHoRNI5MrGudRVeCmv4Alw==",
"requires": {
"callsites": "^3.1.0",
"debug": "^4.2.0",
"is-observable": "^2.1.0",
"observable-fns": "^0.5.1",
"tiny-worker": ">= 2"
},
"dependencies": {
"callsites": {
"version": "3.1.0",
"resolved": "https://mirrors.tencent.com/npm/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
}
}
},
"threads-plugin": {
"version": "1.4.0",
"resolved": "http://mirrors.cloud.tencent.com/npm/threads-plugin/-/threads-plugin-1.4.0.tgz",
"integrity": "sha512-lQENPueZLsD+6Cvxvj/QaQyUskwnFZO+2ZGDMnPIvtytSeywWvYzete8paZ9L+5IR4v8jnSYNZPlIQrEhSK1EA==",
"dev": true,
"requires": {
"loader-utils": "^1.1.0"
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "http://mirrors.cloud.tencent.com/npm/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.4.0",
"resolved": "http://mirrors.cloud.tencent.com/npm/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
}
}
},
"throttle-debounce": { "throttle-debounce": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz",
@ -12284,6 +12350,15 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true "dev": true
}, },
"tiny-worker": {
"version": "2.3.0",
"resolved": "http://mirrors.cloud.tencent.com/npm/tiny-worker/-/tiny-worker-2.3.0.tgz",
"integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==",
"optional": true,
"requires": {
"esm": "^3.2.25"
}
},
"tinycolor2": { "tinycolor2": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz",
@ -13009,11 +13084,6 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz", "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz",
"integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==" "integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg=="
}, },
"vue-class-component": {
"version": "7.2.6",
"resolved": "http://mirrors.cloud.tencent.com/npm/vue-class-component/-/vue-class-component-7.2.6.tgz",
"integrity": "sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w=="
},
"vue-cli-plugin-element": { "vue-cli-plugin-element": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/vue-cli-plugin-element/-/vue-cli-plugin-element-1.0.1.tgz", "resolved": "https://registry.npmjs.org/vue-cli-plugin-element/-/vue-cli-plugin-element-1.0.1.tgz",
@ -13136,11 +13206,6 @@
} }
} }
}, },
"vue-property-decorator": {
"version": "9.1.2",
"resolved": "http://mirrors.cloud.tencent.com/npm/vue-property-decorator/-/vue-property-decorator-9.1.2.tgz",
"integrity": "sha512-xYA8MkZynPBGd/w5QFJ2d/NM0z/YeegMqYTphy7NJQXbZcuU6FC6AOdUAcy4SXP+YnkerC6AfH+ldg7PDk9ESQ=="
},
"vue-style-loader": { "vue-style-loader": {
"version": "4.1.3", "version": "4.1.3",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
@ -13957,15 +14022,6 @@
"microevent.ts": "~0.1.1" "microevent.ts": "~0.1.1"
} }
}, },
"workerize-loader": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/workerize-loader/-/workerize-loader-1.3.0.tgz",
"integrity": "sha512-utWDc8K6embcICmRBUUkzanPgKBb8yM1OHfh6siZfiMsswE8wLCa9CWS+L7AARz0+Th4KH4ZySrqer/OJ9WuWw==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0"
}
},
"wrap-ansi": { "wrap-ansi": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",

@ -26,9 +26,8 @@
"metaflac-js": "^1.0.5", "metaflac-js": "^1.0.5",
"music-metadata-browser": "^2.2.6", "music-metadata-browser": "^2.2.6",
"register-service-worker": "^1.7.2", "register-service-worker": "^1.7.2",
"vue": "^2.6.12", "threads": "^1.6.4",
"vue-class-component": "^7.2.3", "vue": "^2.6.12"
"vue-property-decorator": "^9.1.2"
}, },
"devDependencies": { "devDependencies": {
"@types/crypto-js": "^4.0.1", "@types/crypto-js": "^4.0.1",
@ -40,9 +39,9 @@
"node-sass": "^5.0.0", "node-sass": "^5.0.0",
"sass-loader": "^10.2.0", "sass-loader": "^10.2.0",
"semver": "^7.3.5", "semver": "^7.3.5",
"threads-plugin": "^1.4.0",
"typescript": "~4.1.5", "typescript": "~4.1.5",
"vue-cli-plugin-element": "^1.0.1", "vue-cli-plugin-element": "^1.0.1",
"vue-template-compiler": "^2.6.12", "vue-template-compiler": "^2.6.12"
"workerize-loader": "^1.3.0"
} }
} }

@ -2,7 +2,7 @@
<el-container id="app"> <el-container id="app">
<el-main> <el-main>
<x-upload v-on:handle_error="showFail" v-on:handle_finish="showSuccess"></x-upload> <file-selector @error="showFail" @success="showSuccess"/>
<div id="app-control"> <div id="app-control">
<el-row class="mb-3"> <el-row class="mb-3">
@ -28,14 +28,14 @@
<audio :autoplay="playing_auto" :src="playing_url" controls/> <audio :autoplay="playing_auto" :src="playing_url" controls/>
<x-preview :download_format="download_format" :table-data="tableData" <PreviewTable :filename_format="download_format" :table-data="tableData"
v-on:music_changed="changePlaying"></x-preview> @music_changed="changePlaying"></PreviewTable>
</el-main> </el-main>
<el-footer id="app-footer"> <el-footer id="app-footer">
<el-row> <el-row>
<a href="https://github.com/ix64/unlock-music" target="_blank">音乐解锁</a>(v<span <a href="https://github.com/ix64/unlock-music" target="_blank">音乐解锁</a>
v-text="version"></span>)移除已购音乐的加密保护 (v{{ version }})移除已购音乐的加密保护
<a href="https://github.com/ix64/unlock-music/wiki/使用提示" target="_blank">使用提示</a> <a href="https://github.com/ix64/unlock-music/wiki/使用提示" target="_blank">使用提示</a>
</el-row> </el-row>
<el-row> <el-row>
@ -44,7 +44,7 @@
</el-row> </el-row>
<el-row> <el-row>
<!--如果进行二次开发此行版权信息不得移除且应明显地标注于页面上--> <!--如果进行二次开发此行版权信息不得移除且应明显地标注于页面上-->
<span>Copyright &copy; 2019-</span><span v-text="(new Date()).getFullYear()"></span> MengYX <span>Copyright &copy; 2019 - {{ (new Date()).getFullYear() }} MengYX</span>
音乐解锁使用 音乐解锁使用
<a href="https://github.com/ix64/unlock-music/blob/master/LICENSE" target="_blank">MIT许可协议</a> <a href="https://github.com/ix64/unlock-music/blob/master/LICENSE" target="_blank">MIT许可协议</a>
开放源代码 开放源代码
@ -56,50 +56,50 @@
<script> <script>
import upload from "./component/upload" import FileSelector from "./component/FileSelector"
import preview from "./component/preview" import PreviewTable from "./component/PreviewTable"
import {DownloadBlobMusic, RemoveBlobMusic} from "./component/util" import {DownloadBlobMusic, RemoveBlobMusic} from "./component/utils"
import config from "../package" import config from "../package"
import {IXAREA_API_ENDPOINT} from "@/decrypt/utils"; import {IXAREA_API_ENDPOINT} from "@/decrypt/utils";
export default { export default {
name: 'app', name: 'app',
components: { components: {
xUpload: upload, FileSelector,
xPreview: preview PreviewTable
}, },
data() { data() {
return { return {
version: config.version, version: config.version,
activeIndex: '1', activeIndex: '1',
tableData: [], tableData: [],
playing_url: "", playing_url: "",
playing_auto: false, playing_auto: false,
download_format: '1', download_format: '1',
instant_download: false, instant_download: false,
}
},
created() {
this.$nextTick(function () {
this.finishLoad();
});
},
methods: {
async finishLoad() {
const mask = document.getElementById("loader-mask");
if (!!mask) mask.remove();
let updateInfo;
try {
const resp = await fetch(IXAREA_API_ENDPOINT + "/music/app-version", {
method: "POST", headers: {"Content-Type": "application/json"},
body: JSON.stringify({"Version": this.version})
});
updateInfo = await resp.json();
} catch (e) {
} }
}, if ((!!updateInfo && process.env.NODE_ENV === 'production') && (!!updateInfo.HttpsFound ||
created() { (!!updateInfo.Found && window.location.protocol !== "https:"))) {
this.$nextTick(function () { this.$notify.warning({
this.finishLoad();
});
},
methods: {
async finishLoad() {
const mask = document.getElementById("loader-mask");
if (!!mask) mask.remove();
let updateInfo;
try {
const resp = await fetch(IXAREA_API_ENDPOINT + "/music/app-version", {
method: "POST", headers: {"Content-Type": "application/json"},
body: JSON.stringify({"Version": this.version})
});
updateInfo = await resp.json();
} catch (e) {
}
if ((!!updateInfo && process.env.NODE_ENV === 'production') && (!!updateInfo.HttpsFound ||
(!!updateInfo.Found && window.location.protocol !== "https:"))) {
this.$notify.warning({
title: '发现更新', title: '发现更新',
message: '发现新版本 v' + updateInfo.Version + message: '发现新版本 v' + updateInfo.Version +
'<br/>更新详情:' + updateInfo.Detail + '<br/>更新详情:' + updateInfo.Detail +
@ -107,78 +107,74 @@
dangerouslyUseHTMLString: true, dangerouslyUseHTMLString: true,
duration: 15000, duration: 15000,
position: 'top-left' position: 'top-left'
}); });
} else { } else {
this.$notify.info({ this.$notify.info({
title: '离线使用', title: '离线使用',
message: '我们使用PWA技术无网络也能使用' + message: '我们使用PWA技术无网络也能使用' +
'<br/>最近更新:' + config.updateInfo + '<br/>最近更新:' + config.updateInfo +
'<br/><a target="_blank" href="https://github.com/ix64/unlock-music/wiki/使用提示">使用提示</a>', '<br/><a target="_blank" href="https://github.com/ix64/unlock-music/wiki/使用提示">使用提示</a>',
dangerouslyUseHTMLString: true,
duration: 10000,
position: 'top-left'
});
}
},
showSuccess(data) {
if (data.status) {
if (this.instant_download) {
DownloadBlobMusic(data, this.download_format);
RemoveBlobMusic(data);
} else {
this.tableData.push(data);
this.$notify.success({
title: '解锁成功',
message: '成功解锁 ' + data.title,
duration: 3000
});
}
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)]);
}
} else {
this.showFail(data.message, data.rawFilename + "." + data.rawExt)
}
},
showFail(errInfo, filename) {
this.$notify.error({
title: '出现问题',
message: errInfo + "" + filename +
',参考<a target="_blank" href="https://github.com/ix64/unlock-music/wiki/使用提示">使用提示</a>',
dangerouslyUseHTMLString: true, dangerouslyUseHTMLString: true,
duration: 6000 duration: 10000,
position: 'top-left'
}); });
if (process.env.NODE_ENV === 'production') { }
window._paq.push(["trackEvent", "Error", errInfo, filename]); },
} showSuccess(data) {
console.error(errInfo, filename); if (this.instant_download) {
}, DownloadBlobMusic(data, this.download_format);
changePlaying(url) { RemoveBlobMusic(data);
this.playing_url = url; } else {
this.playing_auto = true; this.tableData.push(data);
}, this.$notify.success({
handleDeleteAll() { title: '解锁成功',
this.tableData.forEach(value => { message: '成功解锁 ' + data.title,
RemoveBlobMusic(value); duration: 3000
}); });
this.tableData = [];
},
handleDownloadAll() {
let index = 0;
let c = setInterval(() => {
if (index < this.tableData.length) {
DownloadBlobMusic(this.tableData[index], this.download_format);
index++;
} else {
clearInterval(c);
}
}, 300);
} }
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)]);
}
},
showFail(errInfo, filename) {
this.$notify.error({
title: '出现问题',
message: errInfo + "" + filename +
',参考<a target="_blank" href="https://github.com/ix64/unlock-music/wiki/使用提示">使用提示</a>',
dangerouslyUseHTMLString: true,
duration: 6000
});
if (process.env.NODE_ENV === 'production') {
window._paq.push(["trackEvent", "Error", errInfo, filename]);
}
console.error(errInfo, filename);
},
changePlaying(url) {
this.playing_url = url;
this.playing_auto = true;
},
handleDeleteAll() {
this.tableData.forEach(value => {
RemoveBlobMusic(value);
});
this.tableData = [];
}, },
} handleDownloadAll() {
let index = 0;
let c = setInterval(() => {
if (index < this.tableData.length) {
DownloadBlobMusic(this.tableData[index], this.download_format);
index++;
} else {
clearInterval(c);
}
}, 300);
}
},
}
</script> </script>
<style lang="scss"> <style lang="scss">
@import "scss/unlock-music"; @import "scss/unlock-music";
</style> </style>

@ -0,0 +1,77 @@
<template>
<el-upload
:auto-upload="false"
:on-change="addFile"
:show-file-list="false"
action=""
drag
multiple>
<i class="el-icon-upload"/>
<div class="el-upload__text">将文件拖到此处<em>点击选择</em></div>
<div slot="tip" class="el-upload__tip">本工具仅在浏览器内对文件进行解锁无需消耗流量</div>
<transition name="el-fade-in"><!--todo: add delay to animation-->
<el-progress
v-show="progress_show" :format="progress_string" :percentage="progress_value"
:stroke-width="16" :text-inside="true"
style="margin: 16px 6px 0 6px"
></el-progress>
</transition>
</el-upload>
</template>
<script>
import {spawn, Worker, Pool} from "threads"
import {CommonDecrypt} from "@/decrypt/common.ts";
import {DecryptQueue} from "@/component/utils";
export default {
name: "FileSelector",
data() {
return {
task_all: 0,
task_finished: 0,
queue: new DecryptQueue() // for http or file protocol
}
},
computed: {
progress_value() {
return this.task_all ? this.task_finished / this.task_all * 100 : 0
},
progress_show() {
return this.task_all !== this.task_finished
}
},
mounted() {
if (window.Worker) {
console.log("Using Worker Pool")
this.queue = Pool(
() => spawn(new Worker('@/component/worker.ts')),
navigator.hardwareConcurrency || 1
)
} else {
console.log("Using Queue in Main Thread")
}
},
methods: {
progress_string() {
return `${this.task_finished} / ${this.task_all}`
},
async addFile(file) {
this.task_all++
this.queue.queue(async (dec = CommonDecrypt) => {
console.log("start handling", file.name)
try {
this.$emit("success", await dec(file));
} catch (e) {
console.error(e)
this.$emit("error", file)
} finally {
this.task_finished++
}
})
},
}
}
</script>

@ -4,7 +4,7 @@
<el-table-column label="封面"> <el-table-column label="封面">
<template slot-scope="scope"> <template slot-scope="scope">
<el-image :src="scope.row.picture" style="width: 100px; height: 100px"> <el-image :src="scope.row.picture" style="width: 100px; height: 100px">
<div class="image-slot el-image__error" slot="error"> <div slot="error" class="image-slot el-image__error">
暂无封面 暂无封面
</div> </div>
</el-image> </el-image>
@ -27,14 +27,14 @@
</el-table-column> </el-table-column>
<el-table-column label="操作"> <el-table-column label="操作">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button @click="handlePlay(scope.$index, scope.row)" <el-button circle
circle icon="el-icon-video-play" type="success"> icon="el-icon-video-play" type="success" @click="handlePlay(scope.$index, scope.row)">
</el-button> </el-button>
<el-button @click="handleDownload(scope.row)" <el-button circle
circle icon="el-icon-download"> icon="el-icon-download" @click="handleDownload(scope.row)">
</el-button> </el-button>
<el-button @click="handleDelete(scope.$index, scope.row)" <el-button circle
circle icon="el-icon-delete" type="danger"> icon="el-icon-delete" type="danger" @click="handleDelete(scope.$index, scope.row)">
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
@ -42,28 +42,28 @@
</template> </template>
<script> <script>
import {DownloadBlobMusic, RemoveBlobMusic} from './util' import {DownloadBlobMusic, RemoveBlobMusic} from '@/component/utils'
export default { export default {
name: "preview", name: "PreviewTable",
props: { props: {
tableData: {type: Array, required: true}, tableData: {type: Array, required: true},
download_format: {type: String, required: true} filename_format: {type: String, required: true}
}, },
methods: { methods: {
handlePlay(index, row) { handlePlay(index, row) {
this.$emit("music_changed", row.file); this.$emit("music_changed", row.file);
}, },
handleDelete(index, row) { handleDelete(index, row) {
RemoveBlobMusic(row); RemoveBlobMusic(row);
this.tableData.splice(index, 1); this.tableData.splice(index, 1);
}, },
handleDownload(row) { handleDownload(row) {
DownloadBlobMusic(row, this.download_format) DownloadBlobMusic(row, this.download_format)
}, },
}
} }
}
</script> </script>
<style scoped> <style scoped>

@ -1,120 +0,0 @@
<template>
<el-upload
:auto-upload="false"
:on-change="handleFile"
:show-file-list="false"
action=""
drag
multiple>
<i class="el-icon-upload"/>
<div class="el-upload__text">将文件拖到此处<em>点击选择</em></div>
<div class="el-upload__tip" slot="tip">本工具仅在浏览器内对文件进行解锁无需消耗流量</div>
<transition name="el-fade-in">
<el-progress
:format="progressFormat" :percentage="progress_percent" :stroke-width="16"
:text-inside="true" style="margin: 16px 6px 0 6px"
v-show="progress_show"
></el-progress>
</transition>
</el-upload>
</template>
<script>
"use strict";//
export default {
name: "upload",
data() {
return {
cacheQueue: [],
workers: [],
idle_workers: [],
thread_num: 1,
progress_show: false,
progress_finished: 0,
progress_all: 0,
progress_percent: 0,
}
},
mounted() {
if (document.location.host !== "" && process.env.NODE_ENV === 'production') {
this.thread_num = navigator.hardwareConcurrency || 1;
const worker = require("workerize-loader!../decrypt/common");
// noinspection JSValidateTypes,JSUnresolvedVariable
this.workers.push(worker().CommonDecrypt);
this.idle_workers.push(0);
// delay to optimize for first loading
setTimeout(() => {
for (let i = 1; i < this.thread_num; i++) {
// noinspection JSValidateTypes,JSUnresolvedVariable
this.workers.push(worker().CommonDecrypt);
this.idle_workers.push(i);
}
}, 5000);
} else {
const dec = require('../decrypt/common');
this.workers.push(dec.CommonDecrypt);
this.idle_workers.push(0)
}
},
methods: {
progressFormat() {
return this.progress_finished + "/" + (this.progress_all)
},
progressChange(finish, all) {
this.progress_all += all;
this.progress_finished += finish;
this.progress_percent = Math.round(this.progress_finished / this.progress_all * 100);
if (this.progress_finished === this.progress_all) {
setTimeout(() => {
this.progress_show = false;
this.progress_finished = 0;
this.progress_all = 0;
}, 3000);
} else {
this.progress_show = true;
}
},
handleFile(file) {
this.progressChange(0, +1);
// worker
if (this.idle_workers.length > 0) {
this.handleDoFile(file, this.idle_workers.shift());
}
// worker
else {
this.cacheQueue.push(file);
}
},
handleCacheQueue(worker_id) {
//
if (this.cacheQueue.length === 0) {
this.idle_workers.push(worker_id);
return
}
this.handleDoFile(this.cacheQueue.shift(), worker_id);
},
handleDoFile(file, worker_id) {
this.workers[worker_id](file).then(data => {
this.$emit("handle_finish", data);
// todo: call stack
this.handleCacheQueue(worker_id);
this.progressChange(+1, 0);
}).catch(err => {
this.$emit("handle_error", err, file.name);
this.handleCacheQueue(worker_id);
this.progressChange(+1, 0);
})
},
}
}
</script>
<style scoped>
/*noinspection CssUnusedSymbol*/
.el-upload-dragger {
width: 80vw !important;
}
</style>

@ -1,4 +1,6 @@
export function DownloadBlobMusic(data, format) { import {DecryptResult} from "@/decrypt/entity";
export function DownloadBlobMusic(data: DecryptResult, format: string) {//todo: use enum
const a = document.createElement('a'); const a = document.createElement('a');
a.href = data.file; a.href = data.file;
switch (format) { switch (format) {
@ -21,10 +23,27 @@ export function DownloadBlobMusic(data, format) {
a.remove(); a.remove();
} }
export function RemoveBlobMusic(data) { export function RemoveBlobMusic(data: DecryptResult) {
URL.revokeObjectURL(data.file); URL.revokeObjectURL(data.file);
if (data.picture.startsWith("blob:")) { if (data.picture?.startsWith("blob:")) {
URL.revokeObjectURL(data.picture); URL.revokeObjectURL(data.picture);
} }
}
export class DecryptQueue {
private readonly pending: (() => Promise<void>)[];
constructor() {
this.pending = []
}
queue(fn: () => Promise<void>) {
this.pending.push(fn)
this.consume()
}
private consume() {
const fn = this.pending.shift()
if (fn) fn().then(() => this.consume).catch(console.error)
}
} }

@ -0,0 +1,4 @@
import {expose} from "threads/worker";
import {CommonDecrypt} from "@/decrypt/common";
expose(CommonDecrypt)

@ -1,21 +1,11 @@
import {Decrypt as NcmDecrypt} from "./ncm"; import {Decrypt as NcmDecrypt} from "@/decrypt/ncm";
import {Decrypt as XmDecrypt} from "./xm"; import {Decrypt as XmDecrypt} from "@/decrypt/xm";
import {Decrypt as QmcDecrypt} from "./qmc"; import {Decrypt as QmcDecrypt} from "@/decrypt/qmc";
import {Decrypt as KgmDecrypt} from "./kgm"; import {Decrypt as KgmDecrypt} from "@/decrypt/kgm";
import {Decrypt as KwmDecrypt} from "@/decrypt/kwm"; import {Decrypt as KwmDecrypt} from "@/decrypt/kwm";
import {Decrypt as RawDecrypt} from "@/decrypt/raw"; import {Decrypt as RawDecrypt} from "@/decrypt/raw";
import {Decrypt as TmDecrypt} from "@/decrypt/tm"; import {Decrypt as TmDecrypt} from "@/decrypt/tm";
import {DecryptResult} from "@/decrypt/entity"; import {DecryptResult, FileInfo} from "@/decrypt/entity";
interface FileInfo {
status: string
name: string,
size: number,
percentage: number,
uid: number,
raw: File
}
export async function CommonDecrypt(file: FileInfo): Promise<DecryptResult> { export async function CommonDecrypt(file: FileInfo): Promise<DecryptResult> {
@ -78,3 +68,4 @@ export async function CommonDecrypt(file: FileInfo): Promise<DecryptResult> {
console.log(rt_data); console.log(rt_data);
return rt_data; return rt_data;
} }

@ -14,3 +14,12 @@ export interface DecryptResult {
rawFilename?: string rawFilename?: string
} }
export interface FileInfo {
status: string
name: string,
size: number,
percentage: number,
uid: number,
raw: File
}

@ -136,7 +136,7 @@ async function queryKeyInfo(keyData: Uint8Array, filename: string, format: strin
let data = await resp.json(); let data = await resp.json();
return new QmcMask(Base64Decode(data.Matrix44)); return new QmcMask(Base64Decode(data.Matrix44));
} catch (e) { } catch (e) {
console.log(e); console.warn(e);
} }
} }
@ -150,7 +150,7 @@ async function queryAlbumCoverImage(title: string, artist?: string, album?: stri
return song_query_url + "/" + data.Type + "/" + data.Id return song_query_url + "/" + data.Type + "/" + data.Id
} }
} catch (e) { } catch (e) {
console.log(e); console.warn(e);
} }
return ""; return "";
} }

@ -177,7 +177,6 @@ export function QmcMaskDetectMgg(data: Uint8Array) {
function calcMaskFromConfidence(confidence: { [key: number]: number }) { function calcMaskFromConfidence(confidence: { [key: number]: number }) {
console.log(confidence)
const count = Object.keys(confidence).length const count = Object.keys(confidence).length
if (count === 0) throw "can not match at least one key"; if (count === 0) throw "can not match at least one key";
if (count > 1) console.warn("There are 2 potential value for the mask!") if (count > 1) console.warn("There are 2 potential value for the mask!")

@ -42,7 +42,7 @@ export async function Decrypt(file: File, raw_filename: string, raw_ext: string)
const musicMeta = await metaParseBlob(musicBlob); const musicMeta = await metaParseBlob(musicBlob);
if (ext === "wav") { if (ext === "wav") {
//todo:未知的编码方式 //todo:未知的编码方式
console.log(musicMeta.common) console.info(musicMeta.common)
musicMeta.common.album = ""; musicMeta.common.album = "";
musicMeta.common.artist = ""; musicMeta.common.artist = "";
musicMeta.common.title = ""; musicMeta.common.title = "";

@ -1,6 +1,6 @@
import Vue from 'vue' import Vue from 'vue'
import App from './App.vue' import App from '@/App.vue'
import './registerServiceWorker' import '@/registerServiceWorker'
import { import {
Button, Button,
Checkbox, Checkbox,

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "esnext", "target": "es5",
"module": "esnext", "module": "esnext",
"strict": true, "strict": true,
"jsx": "preserve", "jsx": "preserve",

@ -1,3 +1,4 @@
const ThreadsPlugin = require('threads-plugin');
module.exports = { module.exports = {
publicPath: '', publicPath: '',
productionSourceMap: false, productionSourceMap: false,
@ -35,5 +36,8 @@ module.exports = {
workboxOptions: { workboxOptions: {
skipWaiting: true skipWaiting: true
} }
},
configureWebpack: {
plugins: [new ThreadsPlugin()]
} }
}; };

Loading…
Cancel
Save