mirror of
https://git.unlock-music.dev/um/web.git
synced 2025-05-13 17:46:54 +00:00
Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c4f07f08dc | ||
![]() |
c9d1cbac09 | ||
![]() |
9f2a74e1d6 | ||
![]() |
abda8cc1bb | ||
![]() |
25aec6b199 | ||
![]() |
1676f9f095 | ||
![]() |
bf96544a51 | ||
![]() |
80d79d0f65 | ||
![]() |
b0ee928199 | ||
![]() |
f22b05f40d | ||
![]() |
6addbb5ecd | ||
![]() |
7f050a682d | ||
![]() |
ce45bdb8dd | ||
![]() |
1846e5c959 | ||
![]() |
c866d4909f | ||
![]() |
bded04e40f | ||
![]() |
b7cb485be2 | ||
![]() |
3dcf064b48 | ||
![]() |
437765f79f | ||
![]() |
584fb24fdd | ||
![]() |
2835ac08ec | ||
![]() |
201e44fb38 | ||
![]() |
bdb8d6da34 | ||
![]() |
1429c5786e | ||
![]() |
820b98afed | ||
![]() |
d567e9f136 |
25
.drone.yml
25
.drone.yml
@ -1,25 +0,0 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: node:16.18-bullseye
|
||||
commands:
|
||||
- apt-get update
|
||||
- apt-get install -y jq zip
|
||||
- npm ci
|
||||
- npm run test
|
||||
- ./scripts/build-and-package.sh legacy
|
||||
- ./scripts/build-and-package.sh extension
|
||||
- ./scripts/build-and-package.sh modern
|
||||
|
||||
- name: upload artifact
|
||||
image: node:16.18-bullseye
|
||||
environment:
|
||||
DRONE_GITEA_SERVER: https://git.unlock-music.dev
|
||||
GITEA_API_KEY:
|
||||
from_secret: GITEA_API_KEY
|
||||
commands:
|
||||
- ./scripts/upload-packages.sh
|
@ -9,22 +9,26 @@ labels:
|
||||
|
||||
---
|
||||
|
||||
* 请按照此模板填写,否则可能立即被关闭
|
||||
* 请按照此模板填写,否则可能立即被关闭。请将符合条件的 `[ ]` 更改为 `[x]`。
|
||||
|
||||
- [x] 我确认已经搜索过Issue不存并确认相同的Issue
|
||||
- [x] 我有证据表明这是程序导致的问题(如不确认,可以通过 Telegram 讨论组 (https://t.me/unlock_music_chat) 进行讨论)
|
||||
- [ ] 我确认已经搜索过 issue,确认没有已报告的相同 issue
|
||||
- [ ] 我有证据表明这是程序导致的问题(如不确认,可以通过 Telegram 讨论组 (https://t.me/unlock_music_chat) 进行讨论)
|
||||
|
||||
## Bug描述
|
||||
|
||||
简要地复述你遇到的Bug
|
||||
简要地复述你遇到的 Bug:
|
||||
|
||||
……
|
||||
|
||||
## 复现方法
|
||||
|
||||
描述复现方法,必要时请提供样本文件
|
||||
描述复现方法,必要时请提供样本文件:
|
||||
|
||||
……
|
||||
|
||||
## 程序截图或浏览器开发者控制台(Console)的报错信息
|
||||
|
||||
如果可以请提供二者之一
|
||||
……
|
||||
|
||||
## 环境信息
|
||||
|
||||
@ -36,5 +40,6 @@ labels:
|
||||
|
||||
## 附加信息
|
||||
|
||||
如果有,请提供其他能够帮助确认问题的信息到下方:
|
||||
如果有其他能够帮助确认问题的信息,请在下方填写:
|
||||
|
||||
……
|
@ -10,20 +10,19 @@ labels:
|
||||
---
|
||||
|
||||
<!-- ⚠ 请按照此模板填写,否则可能立即被关闭 -->
|
||||
<!-- 提交前请使用【Preview】预览提交的更改 -->
|
||||
<!-- 提交前可使用【Preview】预览提交的更改 -->
|
||||
|
||||
## 背景和说明
|
||||
|
||||
<!-- 简要说明产生此想法的背景和此想法的具体内容 -->
|
||||
|
||||
|
||||
## 实现途径
|
||||
|
||||
- 如果没有设计方案,请简要描述实现思路
|
||||
- 如果你没有任何的实现思路,请通过 Telegram 讨论组 (https://t.me/unlock_music_chat) 进行讨论
|
||||
|
||||
|
||||
## 附加信息
|
||||
|
||||
<!-- 更多你想要表达的内容 -->
|
||||
|
||||
## 额外选项
|
||||
|
||||
<!-- 请将符合条件的 `[ ]` 更改为 `[x]` -->
|
||||
|
||||
- [ ] 我可以自行实现并提交 PR。
|
||||
- [ ] 我确认已经搜索过 issue,确认没有已报告的相同 issue
|
42
.gitea/workflows/build.yml
Normal file
42
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,42 @@
|
||||
name: Build
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- "src/**/*"
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
types: [ opened, synchronize, reopened ]
|
||||
paths:
|
||||
- "src/**/*"
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Test
|
||||
run: npm test
|
||||
|
||||
- name: Build all variants
|
||||
run: npm run build:all
|
||||
|
||||
- name: Publish artifact
|
||||
uses: christopherhx/gitea-upload-artifact@v4
|
||||
with:
|
||||
name: um-web-all
|
||||
path: "um-*.zip"
|
@ -1,47 +0,0 @@
|
||||
image: node:16
|
||||
cache:
|
||||
paths:
|
||||
- node_modules/
|
||||
|
||||
stages:
|
||||
- build
|
||||
|
||||
|
||||
build-job:
|
||||
stage: build
|
||||
script: |
|
||||
sed -i 's/deb.debian.org/mirrors.cloud.tencent.com/g' /etc/apt/sources.list
|
||||
apt-get update
|
||||
apt-get -y install zip
|
||||
|
||||
npm config set registry http://mirrors.cloud.tencent.com/npm/
|
||||
npm ci
|
||||
|
||||
npm run build
|
||||
tar -czf legacy.tar.gz -C ./dist .
|
||||
cd dist
|
||||
zip -rJ9 ../legacy.zip *
|
||||
cd ..
|
||||
|
||||
npm run make-extension
|
||||
cd dist
|
||||
zip -rJ9 ../extension.zip *
|
||||
cd ..
|
||||
|
||||
npm run build -- --modern
|
||||
tar -czf modern.tar.gz -C ./dist .
|
||||
cd dist
|
||||
zip -rJ9 ../modern.zip *
|
||||
cd ..
|
||||
|
||||
sha256sum *.tar.gz *.zip > sha256sum.txt
|
||||
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME"
|
||||
paths:
|
||||
- legacy.zip
|
||||
- legacy.tar.gz
|
||||
- extension.zip
|
||||
- modern.zip
|
||||
- modern.tar.gz
|
||||
- sha256sum.txt
|
@ -1,76 +0,0 @@
|
||||
name: 解码错误报告 (填表)
|
||||
about: 遇到文件解码失败的问题请选择该项。
|
||||
title: '[Bug/Crypto] '
|
||||
labels:
|
||||
- bug
|
||||
- crypto
|
||||
body:
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: 错误描述
|
||||
description: 请描述你所遇到的问题,以及你期待的行为。
|
||||
placeholder: ''
|
||||
value: ''
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: version
|
||||
attributes:
|
||||
label: Unlock Music 版本
|
||||
description: |
|
||||
能够重现错误的版本,版本号通常在页面底部。
|
||||
如果不确定,请升级到最新版确认问题是否解决。
|
||||
multiple: true
|
||||
options:
|
||||
- 1.10.5 (仓库最新)
|
||||
- 1.10.3 (官方 DEMO)
|
||||
- 其它(请在错误描述中指定)
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: browsers
|
||||
attributes:
|
||||
label: 产生错误的浏览器
|
||||
multiple: true
|
||||
options:
|
||||
- 火狐 / Firefox
|
||||
- Chrome
|
||||
- Safari
|
||||
- 其它基于 Chromium 的浏览器 (Edge、Brave、Opera 等)
|
||||
- type: dropdown
|
||||
id: music-platform
|
||||
attributes:
|
||||
label: 音乐平台
|
||||
description: |
|
||||
如果需要报告多个平台的问题,请每个平台提交一个新的 Issue。
|
||||
请注意:播放器缓存文件不属于该项目支持的文件类型。
|
||||
multiple: false
|
||||
options:
|
||||
- 其它 (请在错误描述指定)
|
||||
- QQ 音乐
|
||||
- Joox (QQ 音乐海外版)
|
||||
- 虾米音乐
|
||||
- 网易云音乐
|
||||
- 酷我音乐
|
||||
- 酷狗音乐
|
||||
- 喜马拉雅
|
||||
- 咪咕 3D
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: 日志信息
|
||||
description: 如果有,请提供浏览器开发者控制台(Console)的错误日志:
|
||||
render: text
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: 我已经阅读并确认下述内容
|
||||
description: ''
|
||||
options:
|
||||
- label: 我已经检索过 Issue 列表,并确认这是一个为报告过的问题。
|
||||
required: true
|
||||
- label: 我有证据表明这是程序导致的问题(如不确认,可以通过 Telegram 讨论组 (https://t.me/unlock_music_chat) 进行讨论)
|
||||
required: true
|
1
.npmrc
Normal file
1
.npmrc
Normal file
@ -0,0 +1 @@
|
||||
@unlock-music:registry=https://git.unlock-music.dev/api/packages/um/npm/
|
@ -3,7 +3,7 @@ FROM --platform=$TARGETPLATFORM nginx:stable-alpine
|
||||
LABEL org.opencontainers.image.title="Unlock Music"
|
||||
LABEL org.opencontainers.image.description="Unlock encrypted music file in browser"
|
||||
LABEL org.opencontainers.image.authors="MengYX"
|
||||
LABEL org.opencontainers.image.source="https://github.com/ix64/unlock-music"
|
||||
LABEL org.opencontainers.image.source="https://git.unlock-music.dev/um/web"
|
||||
LABEL org.opencontainers.image.licenses="MIT"
|
||||
LABEL maintainer="MengYX"
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2023 MengYX
|
||||
Copyright (c) 2019-2025 MengYX
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
15
README.md
15
README.md
@ -1,17 +1,20 @@
|
||||
# Unlock Music 音乐解锁
|
||||
|
||||
[](https://ci.unlock-music.dev/um/web)
|
||||
[][ci]
|
||||
|
||||
- 在浏览器中解锁加密的音乐文件。 Unlock encrypted music file in the browser.
|
||||
- Unlock Music 项目是以学习和技术研究的初衷创建的,修改、再分发时请遵循[授权协议]。
|
||||
- Unlock Music 的 CLI 版本可以在 [unlock-music/cli] 找到,大批量转换建议使用 CLI 版本。
|
||||
- 我们新建了 Telegram 群组 [`@unlock_music_chat`] ,欢迎加入!
|
||||
- CI 自动构建已经部署,可以在 [UM-Packages] 下载
|
||||
- CI 自动构建已经部署,可以在 [Actions][ci] 下载
|
||||
|
||||
[授权协议]: https://git.unlock-music.dev/um/web/src/branch/master/LICENSE
|
||||
> **WARNING**
|
||||
> 在本站 fork 不会起到备份的作用,只会浪费服务器储存空间。如无必要请勿 fork 该仓库。
|
||||
|
||||
[授权协议]: https://git.unlock-music.dev/um/web/src/branch/main/LICENSE
|
||||
[unlock-music/cli]: https://git.unlock-music.dev/um/cli
|
||||
[`@unlock_music_chat`]: https://t.me/unlock_music_chat
|
||||
[UM-Packages]: https://git.unlock-music.dev/um/-/packages/generic/web-build/
|
||||
[ci]: https://git.unlock-music.dev/um/web/actions?workflow=build.yml
|
||||
|
||||
## 特性
|
||||
|
||||
@ -42,7 +45,7 @@
|
||||
|
||||
### 使用预构建版本
|
||||
|
||||
- 从 [Release] 或 [CI 构建][UM-Packages] 下载预构建的版本
|
||||
- 从 [Release] 或 [CI 构建][ci] 下载预构建的版本
|
||||
- :warning: 本地使用请下载`legacy版本`(`modern版本`只能通过 **http(s)协议** 访问)
|
||||
- 解压缩后即可部署或本地使用(**请勿直接运行源代码**)
|
||||
|
||||
@ -51,7 +54,7 @@
|
||||
### 自行构建
|
||||
|
||||
- 环境要求
|
||||
- nodejs (v16.x)
|
||||
- nodejs (v22.x)
|
||||
- npm
|
||||
|
||||
1. 获取项目源代码后安装相关依赖:
|
||||
|
@ -1,18 +1,29 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"manifest_version": 3,
|
||||
"content_security_policy": {
|
||||
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
|
||||
},
|
||||
"name": "音乐解锁",
|
||||
"short_name": "音乐解锁",
|
||||
"icons": {
|
||||
"128": "./img/icons/msapplication-icon-144x144.png"
|
||||
"16": "img/icons/favicon-16x16.png",
|
||||
"32": "img/icons/favicon-32x32.png",
|
||||
"192": "img/icons/android-chrome-192x192.png",
|
||||
"512": "img/icons/android-chrome-512x512.png"
|
||||
},
|
||||
"description": "在任何设备上解锁已购的加密音乐!",
|
||||
"permissions": [
|
||||
"storage"
|
||||
],
|
||||
"permissions": ["storage"],
|
||||
"offline_enabled": true,
|
||||
"options_page": "./index.html",
|
||||
"options_page": "index.html",
|
||||
"homepage_url": "https://git.unlock-music.dev/um/web",
|
||||
"browser_action": {
|
||||
"action": {
|
||||
"default_icon": "img/icons/favicon-32x32.png",
|
||||
"default_popup": "./popup.html"
|
||||
},
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "addon@unlock-music.dev",
|
||||
"strict_min_version": "128.0"
|
||||
}
|
||||
}
|
||||
}
|
61
package-lock.json
generated
61
package-lock.json
generated
@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "unlock-music",
|
||||
"version": "1.10.6",
|
||||
"version": "1.10.8",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "unlock-music",
|
||||
"version": "1.10.6",
|
||||
"version": "1.10.8",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.16.5",
|
||||
"@unlock-music/joox-crypto": "^0.0.1-R5",
|
||||
"@unlock-music/joox-crypto": "^0.0.1",
|
||||
"@xhacker/kgmwasm": "^1.0.0",
|
||||
"@xhacker/qmcwasm": "^1.0.0",
|
||||
"base64-js": "^1.5.1",
|
||||
@ -3484,11 +3484,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@unlock-music/joox-crypto": {
|
||||
"version": "0.0.1-R5",
|
||||
"resolved": "https://registry.npmjs.org/@unlock-music/joox-crypto/-/joox-crypto-0.0.1-R5.tgz",
|
||||
"integrity": "sha512-+FhGT4bjzfb1Q7dAwHps/XqbqXrRA6Qg7pkDPzyXfeRmQocAySQ/dekojxkaFBf7ZX5ToIAopwxkKZ5NFt5bFw==",
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://git.unlock-music.dev/api/packages/um/npm/%40unlock-music%2Fjoox-crypto/-/0.0.1/joox-crypto-0.0.1.tgz",
|
||||
"integrity": "sha512-bj7UcA4/KSqK07PPmoRYJ+3s4h3P45RGUVAMspptMYXobhVkDlB1ArTYNlyIlrF/P0EMy7JkfEdOgUz0nD7EAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"crypto-js": "^4.1.1"
|
||||
"crypto-js": "^4.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"joox-decrypt": "joox-decrypt"
|
||||
@ -5711,9 +5712,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001434",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
|
||||
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA=="
|
||||
"version": "1.0.30001717",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz",
|
||||
"integrity": "sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/case-sensitive-paths-webpack-plugin": {
|
||||
"version": "2.4.0",
|
||||
@ -6729,9 +6744,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
|
||||
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||
},
|
||||
"node_modules/css-color-names": {
|
||||
"version": "0.0.4",
|
||||
@ -23653,11 +23668,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"@unlock-music/joox-crypto": {
|
||||
"version": "0.0.1-R5",
|
||||
"resolved": "https://registry.npmjs.org/@unlock-music/joox-crypto/-/joox-crypto-0.0.1-R5.tgz",
|
||||
"integrity": "sha512-+FhGT4bjzfb1Q7dAwHps/XqbqXrRA6Qg7pkDPzyXfeRmQocAySQ/dekojxkaFBf7ZX5ToIAopwxkKZ5NFt5bFw==",
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://git.unlock-music.dev/api/packages/um/npm/%40unlock-music%2Fjoox-crypto/-/0.0.1/joox-crypto-0.0.1.tgz",
|
||||
"integrity": "sha512-bj7UcA4/KSqK07PPmoRYJ+3s4h3P45RGUVAMspptMYXobhVkDlB1ArTYNlyIlrF/P0EMy7JkfEdOgUz0nD7EAg==",
|
||||
"requires": {
|
||||
"crypto-js": "^4.1.1"
|
||||
"crypto-js": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"@vue/babel-helper-vue-jsx-merge-props": {
|
||||
@ -25476,9 +25491,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001434",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
|
||||
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA=="
|
||||
"version": "1.0.30001717",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz",
|
||||
"integrity": "sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw=="
|
||||
},
|
||||
"case-sensitive-paths-webpack-plugin": {
|
||||
"version": "2.4.0",
|
||||
@ -26297,9 +26312,9 @@
|
||||
}
|
||||
},
|
||||
"crypto-js": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
|
||||
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||
},
|
||||
"css-color-names": {
|
||||
"version": "0.0.4",
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "unlock-music",
|
||||
"version": "1.10.6",
|
||||
"version": "1.10.8",
|
||||
"ext_build": 0,
|
||||
"updateInfo": "修正文件过小的情况下酷狗 / QQ解密错误问题",
|
||||
"updateInfo": "修正 joox 在远程获取 API 信息出错时不能正确回退到本地元信息获取的错误。",
|
||||
"license": "MIT",
|
||||
"description": "Unlock encrypted music file in browser.",
|
||||
"repository": {
|
||||
@ -14,14 +14,15 @@
|
||||
"postinstall": "patch-package",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"build:all": "./scripts/build-and-package.sh --all",
|
||||
"test": "jest",
|
||||
"pretty": "prettier --write src/{**/*,*}.{js,ts,jsx,tsx,vue}",
|
||||
"pretty:check": "prettier --check src/{**/*,*}.{js,ts,jsx,tsx,vue}",
|
||||
"make-extension": "node ./make-extension.js"
|
||||
"make-extension": "node ./scripts/make-extension.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.16.5",
|
||||
"@unlock-music/joox-crypto": "^0.0.1-R5",
|
||||
"@unlock-music/joox-crypto": "^0.0.1",
|
||||
"@xhacker/kgmwasm": "^1.0.0",
|
||||
"@xhacker/qmcwasm": "^1.0.0",
|
||||
"base64-js": "^1.5.1",
|
||||
|
21
patches/babel-loader+8.2.3.patch
Normal file
21
patches/babel-loader+8.2.3.patch
Normal file
@ -0,0 +1,21 @@
|
||||
diff --git a/node_modules/babel-loader/lib/cache.js b/node_modules/babel-loader/lib/cache.js
|
||||
index fced210..6b0c137 100644
|
||||
--- a/node_modules/babel-loader/lib/cache.js
|
||||
+++ b/node_modules/babel-loader/lib/cache.js
|
||||
@@ -91,15 +91,7 @@ const write = /*#__PURE__*/function () {
|
||||
|
||||
|
||||
const filename = function (source, identifier, options) {
|
||||
- // md4 hashing is not supported starting with node v17.0.0
|
||||
- const majorNodeVersion = parseInt(process.versions.node.split(".")[0], 10);
|
||||
- let hashType = "md4";
|
||||
-
|
||||
- if (majorNodeVersion >= 17) {
|
||||
- hashType = "md5";
|
||||
- }
|
||||
-
|
||||
- const hash = crypto.createHash(hashType);
|
||||
+ const hash = crypto.createHash("sha256");
|
||||
const contents = JSON.stringify({
|
||||
source,
|
||||
options,
|
13
patches/copy-webpack-plugin+5.1.2.patch
Normal file
13
patches/copy-webpack-plugin+5.1.2.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/copy-webpack-plugin/dist/postProcessPattern.js b/node_modules/copy-webpack-plugin/dist/postProcessPattern.js
|
||||
index 8354f00..9bdf6ed 100644
|
||||
--- a/node_modules/copy-webpack-plugin/dist/postProcessPattern.js
|
||||
+++ b/node_modules/copy-webpack-plugin/dist/postProcessPattern.js
|
||||
@@ -69,7 +69,7 @@ function postProcessPattern(globalRef, pattern, file) {
|
||||
name: _package.name,
|
||||
version: _package.version,
|
||||
pattern,
|
||||
- hash: _crypto.default.createHash('md4').update(content).digest('hex')
|
||||
+ hash: _crypto.default.createHash('sha256').update(content).digest('hex')
|
||||
});
|
||||
return _cacache.default.get(globalRef.cacheDir, cacheKey).then(result => {
|
||||
logger.debug(`getting cached transformation for '${file.absoluteFrom}'`);
|
13
patches/terser-webpack-plugin+1.4.5.patch
Normal file
13
patches/terser-webpack-plugin+1.4.5.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/terser-webpack-plugin/dist/index.js b/node_modules/terser-webpack-plugin/dist/index.js
|
||||
index 6268f6b..1cb8f2c 100644
|
||||
--- a/node_modules/terser-webpack-plugin/dist/index.js
|
||||
+++ b/node_modules/terser-webpack-plugin/dist/index.js
|
||||
@@ -214,7 +214,7 @@ class TerserPlugin {
|
||||
// eslint-disable-next-line global-require
|
||||
'terser-webpack-plugin': require('../package.json').version,
|
||||
'terser-webpack-plugin-options': this.options,
|
||||
- hash: _crypto.default.createHash('md4').update(input).digest('hex')
|
||||
+ hash: _crypto.default.createHash('sha256').update(input).digest('hex')
|
||||
};
|
||||
task.cacheKeys = this.options.cacheKeys(defaultCacheKeys, file);
|
||||
}
|
26
patches/webpack+4.46.0.patch
Normal file
26
patches/webpack+4.46.0.patch
Normal file
@ -0,0 +1,26 @@
|
||||
diff --git a/node_modules/webpack/lib/optimize/SplitChunksPlugin.js b/node_modules/webpack/lib/optimize/SplitChunksPlugin.js
|
||||
index e7d560b..94a8401 100644
|
||||
--- a/node_modules/webpack/lib/optimize/SplitChunksPlugin.js
|
||||
+++ b/node_modules/webpack/lib/optimize/SplitChunksPlugin.js
|
||||
@@ -22,7 +22,7 @@ const deterministicGroupingForModules = /** @type {function(DeterministicGroupin
|
||||
|
||||
const hashFilename = name => {
|
||||
return crypto
|
||||
- .createHash("md4")
|
||||
+ .createHash("sha256")
|
||||
.update(name)
|
||||
.digest("hex")
|
||||
.slice(0, 8);
|
||||
diff --git a/node_modules/webpack/lib/util/createHash.js b/node_modules/webpack/lib/util/createHash.js
|
||||
index 64de510..4cc3fc9 100644
|
||||
--- a/node_modules/webpack/lib/util/createHash.js
|
||||
+++ b/node_modules/webpack/lib/util/createHash.js
|
||||
@@ -131,6 +131,8 @@ module.exports = algorithm => {
|
||||
// TODO add non-cryptographic algorithm here
|
||||
case "debug":
|
||||
return new DebugHash();
|
||||
+ case 'md4':
|
||||
+ algorithm = "sha256";
|
||||
default:
|
||||
return new BulkUpdateDecorator(require("crypto").createHash(algorithm));
|
||||
}
|
@ -11,6 +11,12 @@ case "$1" in
|
||||
"modern") npm run build -- --modern ;;
|
||||
"legacy") npm run build ;;
|
||||
"extension") npm run make-extension ;;
|
||||
"--all")
|
||||
"$0" legacy
|
||||
"$0" extension
|
||||
"$0" modern
|
||||
exit 0
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown command: $1"
|
||||
@ -18,6 +24,7 @@ case "$1" in
|
||||
;;
|
||||
esac
|
||||
|
||||
cp README.md LICENSE dist/
|
||||
mv dist "${DIST_NAME}"
|
||||
zip -rJ9 "${DIST_NAME}.zip" "${DIST_NAME}"
|
||||
|
||||
|
14
make-extension.js → scripts/make-extension.js
Normal file → Executable file
14
make-extension.js → scripts/make-extension.js
Normal file → Executable file
@ -1,7 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const src = __dirname + "/src/extension/"
|
||||
const dst = __dirname + "/dist"
|
||||
|
||||
const DIR_ROOT = path.resolve(__dirname, "..")
|
||||
const src = DIR_ROOT + "/src/extension/"
|
||||
const dst = DIR_ROOT + "/dist"
|
||||
fs.readdirSync(src).forEach(file => {
|
||||
let srcPath = path.join(src, file)
|
||||
let dstPath = path.join(dst, file)
|
||||
@ -9,10 +13,10 @@ fs.readdirSync(src).forEach(file => {
|
||||
console.log(`Copy: ${srcPath} => ${dstPath}`)
|
||||
})
|
||||
|
||||
const manifestRaw = fs.readFileSync(__dirname + "/extension-manifest.json", "utf-8")
|
||||
const manifestRaw = fs.readFileSync(DIR_ROOT + "/extension-manifest.json", "utf-8")
|
||||
const manifest = JSON.parse(manifestRaw)
|
||||
|
||||
const pkgRaw = fs.readFileSync(__dirname + "/package.json", "utf-8")
|
||||
const pkgRaw = fs.readFileSync(DIR_ROOT + "/package.json", "utf-8")
|
||||
const pkg = JSON.parse(pkgRaw)
|
||||
|
||||
verExt = pkg["version"]
|
||||
@ -21,5 +25,5 @@ if (verExt.includes("-")) verExt = verExt.split("-")[0]
|
||||
manifest["version"] = `${verExt}.${pkg["ext_build"]}`
|
||||
manifest["version_name"] = pkg["version"]
|
||||
|
||||
fs.writeFileSync(__dirname + "/dist/manifest.json", JSON.stringify(manifest), "utf-8")
|
||||
fs.writeFileSync(DIR_ROOT + "/dist/manifest.json", JSON.stringify(manifest), "utf-8")
|
||||
console.log("Write: manifest.json")
|
@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
if [ -z "$GITEA_API_KEY" ]; then
|
||||
echo "GITEA_API_KEY is empty, skip upload."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
URL_BASE="$DRONE_GITEA_SERVER/api/packages/${DRONE_REPO_NAMESPACE}/generic/${DRONE_REPO_NAME}-build"
|
||||
|
||||
for ZIP_NAME in *.zip; do
|
||||
UPLOAD_URL="${URL_BASE}/${DRONE_BUILD_NUMBER}/${ZIP_NAME}"
|
||||
sha256sum "${ZIP_NAME}"
|
||||
curl -sLifu "um-release-bot:$GITEA_API_KEY" -T "${ZIP_NAME}" "${UPLOAD_URL}"
|
||||
echo "Uploaded to: ${UPLOAD_URL}"
|
||||
done
|
16
src/App.vue
16
src/App.vue
@ -4,22 +4,22 @@
|
||||
<Home />
|
||||
</el-main>
|
||||
<el-footer id="app-footer">
|
||||
<el-row>
|
||||
<div>
|
||||
<a href="https://git.unlock-music.dev/um/web" target="_blank">音乐解锁</a>({{ version }})
|
||||
:移除已购音乐的加密保护。
|
||||
<a href="https://git.unlock-music.dev/um/web/wiki/使用提示" target="_blank">使用提示</a>
|
||||
</el-row>
|
||||
<el-row>
|
||||
</div>
|
||||
<div>
|
||||
目前支持 网易云音乐(ncm), QQ音乐(qmc, mflac, mgg), 酷狗音乐(kgm), 虾米音乐(xm), 酷我音乐(.kwm)
|
||||
<a href="https://git.unlock-music.dev/um/web/src/branch/master/README.md" target="_blank">更多</a>。
|
||||
</el-row>
|
||||
<el-row>
|
||||
<a href="https://git.unlock-music.dev/um/web/src/branch/main/README.md" target="_blank">更多</a>。
|
||||
</div>
|
||||
<div>
|
||||
<!--如果进行二次开发,此行版权信息不得移除且应明显地标注于页面上-->
|
||||
<span>Copyright © 2019 - {{ new Date().getFullYear() }} MengYX</span>
|
||||
音乐解锁使用
|
||||
<a href="https://git.unlock-music.dev/um/web/src/branch/master/LICENSE" target="_blank">MIT许可协议</a>
|
||||
<a href="https://git.unlock-music.dev/um/web/src/branch/main/LICENSE" target="_blank">MIT许可协议</a>
|
||||
开放源代码
|
||||
</el-row>
|
||||
</div>
|
||||
</el-footer>
|
||||
</el-container>
|
||||
</template>
|
||||
|
@ -4,16 +4,6 @@ label {
|
||||
line-height: 1.2;
|
||||
display: block;
|
||||
}
|
||||
.item-desc {
|
||||
color: #aaa;
|
||||
font-size: small;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
.item-desc a {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
form >>> input {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
@ -39,7 +29,7 @@ form >>> input {
|
||||
</el-form-item>
|
||||
</label>
|
||||
|
||||
<p class="item-desc">
|
||||
<p class="tip">
|
||||
下载该加密文件的 JOOX 应用所记录的设备唯一识别码。
|
||||
<br />
|
||||
参见:
|
||||
|
@ -1,24 +1,4 @@
|
||||
<style scoped>
|
||||
label {
|
||||
cursor: pointer;
|
||||
line-height: 1.2;
|
||||
display: block;
|
||||
}
|
||||
.item-desc {
|
||||
color: #aaa;
|
||||
font-size: small;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
.item-desc a {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
form >>> input {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
* >>> .um-edit-dialog {
|
||||
max-width: 90%;
|
||||
width: 30em;
|
||||
@ -29,7 +9,8 @@ form >>> input {
|
||||
<el-dialog @close="cancel()" title="音乐标签编辑" :visible="show" custom-class="um-edit-dialog" center>
|
||||
<el-form ref="form" status-icon :model="form" label-width="0">
|
||||
<section>
|
||||
<el-image v-show="!editPicture" :src="imgFile.url || picture" style="width: 100px; height: 100px">
|
||||
<div class="music-cover">
|
||||
<el-image v-show="!editPicture" :src="imgFile.url || picture">
|
||||
<div slot="error" class="image-slot el-image__error">暂无封面</div>
|
||||
</el-image>
|
||||
<el-upload v-show="editPicture" :auto-upload="false" :on-change="addFile" :on-remove="rmvFile" :show-file-list="true" :limit="1" list-type="picture" action="" drag>
|
||||
@ -39,47 +20,51 @@ form >>> input {
|
||||
新拖到此处的图片将覆盖原始图片
|
||||
</div>
|
||||
</el-upload>
|
||||
<i
|
||||
:class="{'el-icon-edit': !editPicture, 'el-icon-check': editPicture}"
|
||||
@click="changeCover"
|
||||
></i><br />
|
||||
标题:
|
||||
<span v-show="!editTitle">{{title}}</span>
|
||||
<el-input v-show="editTitle" v-model="title"></el-input>
|
||||
<i
|
||||
:class="{'el-icon-edit': !editTitle, 'el-icon-check': editTitle}"
|
||||
@click="editTitle = !editTitle"
|
||||
></i><br />
|
||||
艺术家:
|
||||
<span v-show="!editArtist">{{artist}}</span>
|
||||
<el-input v-show="editArtist" v-model="artist"></el-input>
|
||||
<i
|
||||
:class="{'el-icon-edit': !editArtist, 'el-icon-check': editArtist}"
|
||||
@click="editArtist = !editArtist"
|
||||
></i><br />
|
||||
专辑:
|
||||
<span v-show="!editAlbum">{{album}}</span>
|
||||
<el-input v-show="editAlbum" v-model="album"></el-input>
|
||||
<i
|
||||
:class="{'el-icon-edit': !editAlbum, 'el-icon-check': editAlbum}"
|
||||
@click="editAlbum = !editAlbum"
|
||||
></i><br />
|
||||
专辑艺术家:
|
||||
<span v-show="!editAlbumartist">{{albumartist}}</span>
|
||||
<el-input v-show="editAlbumartist" v-model="albumartist"></el-input>
|
||||
<i
|
||||
:class="{'el-icon-edit': !editAlbumartist, 'el-icon-check': editAlbumartist}"
|
||||
@click="editAlbumartist = !editAlbumartist"
|
||||
></i><br />
|
||||
风格:
|
||||
<span v-show="!editGenre">{{genre}}</span>
|
||||
<el-input v-show="editGenre" v-model="genre"></el-input>
|
||||
<i
|
||||
:class="{'el-icon-edit': !editGenre, 'el-icon-check': editGenre}"
|
||||
@click="editGenre = !editGenre"
|
||||
></i><br />
|
||||
<i :class="{'el-icon-edit': !editPicture, 'el-icon-check': editPicture}"
|
||||
@click="changeCover"></i>
|
||||
</div>
|
||||
|
||||
<p class="item-desc">
|
||||
<div class="edit-item">
|
||||
<div class="label">标题</div>
|
||||
<div class="value" v-show="!editTitle">{{title}}</div>
|
||||
<el-input class="input" size="small" v-show="editTitle" v-model="title"/>
|
||||
<i :class="{'el-icon-edit': !editTitle, 'el-icon-check': editTitle}"
|
||||
@click="editTitle = !editTitle"/>
|
||||
</div>
|
||||
<div class="edit-item">
|
||||
<div class="label">艺术家</div>
|
||||
<div class="value" v-show="!editArtist">{{artist}}</div>
|
||||
<el-input class="input" size="small" v-show="editArtist" v-model="artist"/>
|
||||
<i :class="{'el-icon-edit': !editArtist, 'el-icon-check': editArtist}"
|
||||
@click="editArtist = !editArtist"
|
||||
/>
|
||||
</div>
|
||||
<div class="edit-item">
|
||||
<div class="label">专辑</div>
|
||||
<div class="value" v-show="!editAlbum">{{album}}</div>
|
||||
<el-input class="input" size="small" v-show="editAlbum" v-model="album"/>
|
||||
<i :class="{'el-icon-edit': !editAlbum, 'el-icon-check': editAlbum}"
|
||||
@click="editAlbum = !editAlbum"
|
||||
/>
|
||||
</div>
|
||||
<div class="edit-item">
|
||||
<div class="label">专辑艺术家</div>
|
||||
<div class="value" v-show="!editAlbumartist">{{albumartist}}</div>
|
||||
<el-input class="input" size="small" v-show="editAlbumartist" v-model="albumartist"/>
|
||||
<i :class="{'el-icon-edit': !editAlbumartist, 'el-icon-check': editAlbumartist}"
|
||||
@click="editAlbumartist = !editAlbumartist"
|
||||
/>
|
||||
</div>
|
||||
<div class="edit-item">
|
||||
<div class="label">风格</div>
|
||||
<div class="value" v-show="!editGenre">{{genre}}</div>
|
||||
<el-input class="input" size="small" v-show="editGenre" v-model="genre"/>
|
||||
<i :class="{'el-icon-edit': !editGenre, 'el-icon-check': editGenre}"
|
||||
@click="editGenre = !editGenre"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p class="tip">
|
||||
为了节省您设备的资源,请在确定前充分检查,避免反复修改。<br />
|
||||
直接关闭此对话框不会保留所作的更改。
|
||||
</p>
|
||||
|
@ -9,7 +9,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="歌曲">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.title }}</span>
|
||||
<p>{{ scope.row.title }}</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="歌手">
|
||||
|
@ -10,235 +10,45 @@
|
||||
background-color: $dark-bg;
|
||||
}
|
||||
|
||||
// FORM
|
||||
.el-radio{
|
||||
&__label{
|
||||
color: $dark-text-main;
|
||||
}
|
||||
&__input{
|
||||
color: $dark-text-info;
|
||||
.el-radio__inner{
|
||||
border-color: $dark-border;
|
||||
background-color: $dark-btn-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-checked{
|
||||
.el-radio__inner{
|
||||
background-color: $blue;
|
||||
}
|
||||
.el-radio__label{
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-checkbox.is-bordered{
|
||||
border-color: $dark-border;
|
||||
color: $dark-text-main;
|
||||
background-color: $dark-btn-bg;
|
||||
.el-checkbox__inner{
|
||||
background-color: $dark-btn-bg-highlight;
|
||||
border-color: $dark-border-highlight;
|
||||
}
|
||||
// 编辑歌曲信息
|
||||
.music-cover{
|
||||
i{
|
||||
&:hover{
|
||||
border-color: $dark-border-highlight;
|
||||
.el-checkbox__inner{
|
||||
background-color: $dark-btn-bg-highlight;
|
||||
border-color: $dark-border-highlight;
|
||||
}
|
||||
.el-checkbox__label{
|
||||
color: $dark-text-info;
|
||||
color: $color-checkbox;
|
||||
}
|
||||
}
|
||||
&.is-checked{
|
||||
background-color: $blue;
|
||||
.el-checkbox__inner{
|
||||
border-color: white;
|
||||
.el-image{
|
||||
border: 1px solid $dark-border;
|
||||
}
|
||||
.el-checkbox__label{
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
.edit-item{
|
||||
.label{
|
||||
}
|
||||
.value{
|
||||
}
|
||||
.input{
|
||||
input{
|
||||
background-color: transparent !important;
|
||||
border-bottom: 1px solid $dark-border;
|
||||
}
|
||||
}
|
||||
i{
|
||||
&:hover{
|
||||
border-color: $blue;
|
||||
.el-checkbox__inner{
|
||||
background-color: white;
|
||||
}
|
||||
color: $color-checkbox;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// BUTTON
|
||||
.el-button{
|
||||
background-color: $dark-btn-bg;
|
||||
border-color: $dark-border;
|
||||
color: $dark-text-main;
|
||||
|
||||
&:active{
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
&--default{
|
||||
&.is-plain {
|
||||
background-color: $dark-btn-bg;
|
||||
&:hover {
|
||||
background-color: $blue;
|
||||
border-color: $blue;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
&.is-circle {
|
||||
background-color: $dark-blue;
|
||||
border-color: $dark-blue;
|
||||
&:hover {
|
||||
background-color: $blue;
|
||||
border-color: $blue;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--success{
|
||||
&.is-plain {
|
||||
background-color: $dark-btn-bg;
|
||||
&:hover {
|
||||
background-color: $green;
|
||||
border-color: $green;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
&.is-circle {
|
||||
background-color: $dark-green;
|
||||
border-color: $dark-green;
|
||||
&:hover {
|
||||
background-color: $green;
|
||||
border-color: $green;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
&--danger{
|
||||
&.is-plain{
|
||||
border-color: $dark-border;
|
||||
background-color: $dark-btn-bg;
|
||||
&:hover{
|
||||
background-color: $red;
|
||||
border-color: $red;
|
||||
}
|
||||
}
|
||||
&.is-circle {
|
||||
background-color: $dark-red;
|
||||
border-color: $dark-red;
|
||||
&:hover {
|
||||
background-color: $red;
|
||||
border-color: $red;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 文件拖放区
|
||||
.el-upload__tip{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
.el-upload-dragger{
|
||||
background-color: $dark-uploader-bg;
|
||||
border-color: $dark-border;
|
||||
.el-upload__text{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
&:hover{
|
||||
background: $dark-uploader-bg-highlight;
|
||||
border-color: $dark-border-highlight;
|
||||
}
|
||||
}
|
||||
|
||||
// TABLE
|
||||
.el-table{
|
||||
background-color: $dark-bg-td;
|
||||
&:before{ // 去除表格末尾的横线
|
||||
content: none;
|
||||
}
|
||||
&__header{
|
||||
th{
|
||||
border-bottom-color: $dark-border !important;
|
||||
}
|
||||
}
|
||||
th.el-table__cell{
|
||||
background-color: $dark-bg-th;
|
||||
color: $dark-text-info;
|
||||
}
|
||||
td{
|
||||
border-bottom-color: $dark-border !important;
|
||||
}
|
||||
tr{
|
||||
background-color: $dark-bg-td;
|
||||
color: $dark-text-main;
|
||||
&:hover{
|
||||
td{
|
||||
background-color: $dark-bg-th !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LINKS
|
||||
// footer
|
||||
#app-footer {
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: darken($dark-color-link, 15%);
|
||||
color: lighten($text-comment, 5%);
|
||||
&:hover{
|
||||
color: $dark-color-link;
|
||||
}
|
||||
}
|
||||
|
||||
// ALERT
|
||||
.el-notification{
|
||||
background-color: $dark-btn-bg-highlight;
|
||||
border-color: $dark-border;
|
||||
&__title{
|
||||
color: white;
|
||||
}
|
||||
&__content{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
}
|
||||
|
||||
// DIALOG
|
||||
.el-dialog{
|
||||
background-color: $dark-dialog-bg;
|
||||
.el-dialog__header{
|
||||
.el-dialog__title{
|
||||
color: $dark-text-main;
|
||||
}
|
||||
}
|
||||
.el-dialog__body{
|
||||
color: $dark-text-main;
|
||||
.el-input{
|
||||
.el-input__inner{
|
||||
color: $dark-text-main;
|
||||
background-color: $dark-btn-bg;
|
||||
}
|
||||
.el-input__suffix{
|
||||
.el-input__suffix-inner{
|
||||
}
|
||||
}
|
||||
.el-input__count{
|
||||
.el-input__count-inner{
|
||||
background-color: transparent;
|
||||
color: $color-link;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-desc{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 自定义样式
|
||||
// 首页弹窗提示信息的 更新信息 面板
|
||||
|
@ -1,39 +0,0 @@
|
||||
$color-checkbox: $blue;
|
||||
$color-border-el: #DCDFE6;
|
||||
|
||||
$btn-radius: 6px;
|
||||
|
||||
/* FORM */
|
||||
// checkbox
|
||||
.el-checkbox.is-bordered{
|
||||
@include border-radius($btn-radius) ;
|
||||
&:hover{
|
||||
border-color: $color-checkbox;
|
||||
.el-checkbox__label{
|
||||
color: $color-checkbox;
|
||||
}
|
||||
}
|
||||
.el-checkbox__input.is-focus{
|
||||
.el-checkbox__inner{
|
||||
border-color: $color-border-el;
|
||||
}
|
||||
}
|
||||
&.is-checked{
|
||||
background-color: $color-checkbox;
|
||||
.el-checkbox__label{
|
||||
color: white;
|
||||
}
|
||||
.el-checkbox__inner{
|
||||
border-color: white;
|
||||
background-color: white;
|
||||
&:after{
|
||||
border-color: $color-checkbox;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// el-button
|
||||
.el-button{
|
||||
@include border-radius($btn-radius) ;
|
||||
}
|
291
src/scss/_element-ui-overwrite.scss
Normal file
291
src/scss/_element-ui-overwrite.scss
Normal file
@ -0,0 +1,291 @@
|
||||
$color-checkbox: $blue;
|
||||
$color-border-el: #DCDFE6;
|
||||
|
||||
$btn-radius: 6px;
|
||||
|
||||
/* FORM */
|
||||
// checkbox
|
||||
.el-checkbox.is-bordered{
|
||||
@include border-radius($btn-radius) ;
|
||||
&:hover{
|
||||
border-color: $color-checkbox;
|
||||
.el-checkbox__label{
|
||||
color: $color-checkbox;
|
||||
}
|
||||
}
|
||||
.el-checkbox__input.is-focus{
|
||||
.el-checkbox__inner{
|
||||
border-color: $color-border-el;
|
||||
}
|
||||
}
|
||||
&.is-checked{
|
||||
background-color: $color-checkbox;
|
||||
.el-checkbox__label{
|
||||
color: white;
|
||||
}
|
||||
.el-checkbox__inner{
|
||||
border-color: white;
|
||||
background-color: white;
|
||||
&:after{
|
||||
border-color: $color-checkbox;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// el-button
|
||||
.el-button{
|
||||
@include border-radius($btn-radius) ;
|
||||
}
|
||||
|
||||
// upload
|
||||
.el-upload-dragger{
|
||||
&:hover{
|
||||
background-color: transparentize($color-checkbox, 0.9);
|
||||
}
|
||||
}
|
||||
.el-upload__tip{
|
||||
text-align: center;
|
||||
color: $text-comment;
|
||||
}
|
||||
|
||||
|
||||
// dialog
|
||||
.el-dialog{
|
||||
@include border-radius(5px);
|
||||
&.el-dialog--center{
|
||||
.el-dialog__body{
|
||||
padding: 25px 25px 15px;
|
||||
}
|
||||
.el-dialog__footer{
|
||||
padding: 10px 20px 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
// FORM
|
||||
.el-radio{
|
||||
&__label{
|
||||
color: $dark-text-main;
|
||||
}
|
||||
&__input{
|
||||
color: $dark-text-info;
|
||||
.el-radio__inner{
|
||||
border-color: $dark-border;
|
||||
background-color: $dark-btn-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-checked{
|
||||
.el-radio__inner{
|
||||
background-color: $blue;
|
||||
}
|
||||
.el-radio__label{
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-checkbox.is-bordered{
|
||||
border-color: $dark-border;
|
||||
color: $dark-text-main;
|
||||
background-color: $dark-btn-bg;
|
||||
.el-checkbox__inner{
|
||||
background-color: $dark-btn-bg-highlight;
|
||||
border-color: $dark-border-highlight;
|
||||
}
|
||||
&:hover{
|
||||
border-color: $dark-border-highlight;
|
||||
.el-checkbox__inner{
|
||||
background-color: $dark-btn-bg-highlight;
|
||||
border-color: $dark-border-highlight;
|
||||
}
|
||||
.el-checkbox__label{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
}
|
||||
&.is-checked{
|
||||
background-color: $blue;
|
||||
.el-checkbox__inner{
|
||||
border-color: white;
|
||||
}
|
||||
.el-checkbox__label{
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
&:hover{
|
||||
border-color: $blue;
|
||||
.el-checkbox__inner{
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// BUTTON
|
||||
.el-button{
|
||||
background-color: $dark-btn-bg;
|
||||
border-color: $dark-border;
|
||||
color: $dark-text-main;
|
||||
|
||||
&:active{
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
&--default{
|
||||
&.is-plain {
|
||||
background-color: $dark-btn-bg;
|
||||
&:hover {
|
||||
background-color: $blue;
|
||||
border-color: $blue;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
&.is-circle {
|
||||
background-color: $dark-blue;
|
||||
border-color: $dark-blue;
|
||||
&:hover {
|
||||
background-color: $blue;
|
||||
border-color: $blue;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--success{
|
||||
&.is-plain {
|
||||
background-color: $dark-btn-bg;
|
||||
&:hover {
|
||||
background-color: $green;
|
||||
border-color: $green;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
&.is-circle {
|
||||
background-color: $dark-green;
|
||||
border-color: $dark-green;
|
||||
&:hover {
|
||||
background-color: $green;
|
||||
border-color: $green;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
&--danger{
|
||||
&.is-plain{
|
||||
border-color: $dark-border;
|
||||
background-color: $dark-btn-bg;
|
||||
&:hover{
|
||||
background-color: $red;
|
||||
border-color: $red;
|
||||
}
|
||||
}
|
||||
&.is-circle {
|
||||
background-color: $dark-red;
|
||||
border-color: $dark-red;
|
||||
&:hover {
|
||||
background-color: $red;
|
||||
border-color: $red;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 文件拖放区
|
||||
.el-upload__tip{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
.el-upload-dragger{
|
||||
background-color: $dark-uploader-bg;
|
||||
border-color: $dark-border;
|
||||
.el-upload__text{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
&:hover{
|
||||
background: $dark-uploader-bg-highlight;
|
||||
border-color: $dark-border-highlight;
|
||||
}
|
||||
}
|
||||
|
||||
// TABLE
|
||||
.el-table{
|
||||
background-color: $dark-bg-td;
|
||||
&:before{ // 去除表格末尾的横线
|
||||
content: none;
|
||||
}
|
||||
&__header{
|
||||
th{
|
||||
border-bottom-color: $dark-border !important;
|
||||
}
|
||||
}
|
||||
th.el-table__cell{
|
||||
background-color: $dark-bg-th;
|
||||
color: $dark-text-info;
|
||||
}
|
||||
td{
|
||||
border-bottom-color: $dark-border !important;
|
||||
}
|
||||
tr{
|
||||
background-color: $dark-bg-td;
|
||||
color: $dark-text-main;
|
||||
&:hover{
|
||||
td{
|
||||
background-color: $dark-bg-th !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ALERT
|
||||
.el-notification{
|
||||
background-color: $dark-btn-bg-highlight;
|
||||
border-color: $dark-border;
|
||||
&__title{
|
||||
color: white;
|
||||
}
|
||||
&__content{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
}
|
||||
|
||||
// DIALOG
|
||||
.el-dialog{
|
||||
background-color: $dark-dialog-bg;
|
||||
.el-dialog__header{
|
||||
.el-dialog__title{
|
||||
color: $dark-text-main;
|
||||
}
|
||||
}
|
||||
.el-dialog__body{
|
||||
color: $dark-text-main;
|
||||
.el-input{
|
||||
.el-input__inner{
|
||||
border-color: $dark-border;
|
||||
color: $dark-text-main;
|
||||
background-color: $dark-btn-bg;
|
||||
}
|
||||
.el-input__suffix{
|
||||
.el-input__suffix-inner{
|
||||
}
|
||||
}
|
||||
.el-input__count{
|
||||
.el-input__count-inner{
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-desc{
|
||||
color: $dark-text-info;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
body{
|
||||
font-family: $font-family;
|
||||
font-size: $fz-main;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
#app {
|
||||
text-align: center;
|
||||
color: $text-main;
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
#app-footer a {
|
||||
padding-left: 0.2em;
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
|
||||
#app-footer {
|
||||
text-align: center;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
#app-control {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
audio{
|
||||
margin-bottom: 15px; // 播放控件与表格间隔
|
||||
}
|
||||
|
||||
a{
|
||||
color: darken($color-link, 15%);
|
||||
&:hover{
|
||||
color: $color-link;
|
||||
}
|
||||
}
|
@ -66,6 +66,7 @@
|
||||
}
|
||||
|
||||
.btn-like{
|
||||
cursor: pointer;
|
||||
&:active{
|
||||
@include transform(translateY(2px))
|
||||
}
|
||||
|
@ -3,18 +3,17 @@ $blue : #409EFF;
|
||||
$red : #F56C6C;
|
||||
$green : #85ce61;
|
||||
|
||||
// TEXT
|
||||
// TEXT COLOR
|
||||
$text-main : #2C3E50;
|
||||
$text-copyright : #777;
|
||||
$text-comment : #999;
|
||||
$color-link : $blue;
|
||||
|
||||
// FONT SIZE
|
||||
$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;
|
||||
|
||||
|
||||
// DARK MODE
|
||||
$dark-border : lighten(black, 25%);
|
||||
$dark-border-highlight : lighten(black, 55%);
|
||||
|
@ -1,11 +1,127 @@
|
||||
@import "variables";
|
||||
@import "utility";
|
||||
@import "gaps";
|
||||
@import "element-ui-overrite";
|
||||
@import "element-ui-overwrite";
|
||||
|
||||
@import "normal";
|
||||
@import "dark-mode"; // dark-mode 放在 normal 后面,以获得更高优先级
|
||||
// MAIN CONTENT
|
||||
body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: "PingFang SC", "微软雅黑", "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;
|
||||
font-size: $fz-main;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
#app {
|
||||
text-align: center;
|
||||
color: $text-main;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
// 音频文件操作
|
||||
#app-control {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
// 音频播放
|
||||
audio{
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.table-content{
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
// 编辑歌曲信息
|
||||
.music-cover{
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-flow: column nowrap;
|
||||
i{
|
||||
margin-top: 10px;
|
||||
@extend .btn-like;
|
||||
&:hover{
|
||||
color: $color-checkbox;
|
||||
}
|
||||
}
|
||||
.el-image{
|
||||
padding: 5px;
|
||||
@include border-radius(5px);
|
||||
border: 1px solid $color-border-el;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
}
|
||||
.edit-item{
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.label{
|
||||
font-weight: bold;
|
||||
width: 80px;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.value{
|
||||
padding: 5px 0;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
margin-left: 10px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.input{
|
||||
margin-left: 10px;
|
||||
input{
|
||||
font-family: inherit;
|
||||
height: 30px;
|
||||
line-height: 20px;
|
||||
@include border-radius(0);
|
||||
border: none;
|
||||
border-bottom: 1px solid $color-border-el;
|
||||
padding: 5px 5px;
|
||||
}
|
||||
}
|
||||
i{
|
||||
margin-left: 10px;
|
||||
@extend .btn-like;
|
||||
&:hover{
|
||||
color: $color-checkbox;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tip{
|
||||
margin-top: 20px;
|
||||
color: $text-comment;
|
||||
font-size: $fz-mini-content;
|
||||
a{
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
// footer
|
||||
#app-footer {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
color: $text-copyright;
|
||||
line-height: 1.3;
|
||||
font-size: $fz-mini-content;
|
||||
a {
|
||||
padding-left: 0.2rem;
|
||||
padding-right: 0.2rem;
|
||||
color: darken($text-copyright, 10%);
|
||||
&:hover{
|
||||
color: $color-link;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 首页弹窗提示信息的 更新信息 面板
|
||||
.update-info{
|
||||
@ -15,12 +131,14 @@
|
||||
margin: 10px 0;
|
||||
.update-title{
|
||||
font-size: $fz-mini-title;
|
||||
padding: 5px 10px;
|
||||
padding: 3px 10px;
|
||||
background-color: $color-border-el;
|
||||
}
|
||||
.update-content{
|
||||
font-size: $fz-mini-content;
|
||||
line-height: 1.5;
|
||||
padding: 10px;
|
||||
padding: 5px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@import "dark-mode"; // dark-mode 放在 normal 后面,以获得更高优先级
|
||||
|
@ -55,7 +55,7 @@ export async function extractQQMusicMeta(
|
||||
|
||||
if (id && id !== '0') {
|
||||
try {
|
||||
return fetchMetadataFromSongId(id, ext, musicMeta, musicBlob);
|
||||
return await fetchMetadataFromSongId(id, ext, musicMeta, musicBlob);
|
||||
} catch (e) {
|
||||
console.warn('在线获取曲目信息失败,回退到本地 meta 提取', e);
|
||||
}
|
||||
|
@ -47,12 +47,12 @@
|
||||
<audio :autoplay="playing_auto" :src="playing_url" controls />
|
||||
|
||||
<PreviewTable
|
||||
class="table-content"
|
||||
:policy="filename_policy"
|
||||
:table-data="tableData"
|
||||
@download="saveFile"
|
||||
@edit="editFile"
|
||||
@play="changePlaying"
|
||||
/>
|
||||
@play="changePlaying" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user