Merge branch 'dev'

pull/495/head
lyswhut 2021-04-24 15:53:37 +08:00
commit 6dd6741237
68 changed files with 3933 additions and 3755 deletions

View File

@ -36,14 +36,37 @@ jobs:
- name: Build src code
run: npm run build:src
- name: Release package
run: |
npm run publish:win:setup
npm run publish:win:7z:x64
npm run publish:win:7z:x86
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BT_TOKEN: ${{ secrets.BT_TOKEN }}
- name: Build Package Setup x86_64
run: npm run pack:win:setup:x86_64
- name: Upload Artifact Setup x86_64
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-x86_64-Setup
path: build/*x86_64 Setup.exe
- name: Build Package 7z x64
run: npm run pack:win:7z:x64
- name: Upload Artifact 7z x64
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-win_x64-green
path: build/*win_x64 green.7z
- name: Build Package 7z x86
run: npm run pack:win:7z:x86
- name: Upload Artifact 7z x86
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-win_x86-green
path: build/*win_x86 green.7z
- name: Build Package 7z arm64
run: npm run pack:win:7z:arm64
- name: Upload Artifact 7z arm64
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-win_arm64-green
path: build/*win_arm64 green.7z
Mac:
name: Mac
@ -75,13 +98,17 @@ jobs:
- name: Build src code
run: npm run build:src
- name: Release package
run: npm run publish:mac:dmg
- name: Build Package dmg
run: npm run pack:mac:dmg
env:
ELECTRON_CACHE: $HOME/.cache/electron
ELECTRON_BUILDERCACHE: $HOME/.cache/electron-builder
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BT_TOKEN: ${{ secrets.BT_TOKEN }}
- name: Upload Artifact dmg
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-mac_dmg
path: build/*.dmg
Linux:
name: Linux
@ -116,15 +143,58 @@ jobs:
- name: Build src code
run: npm run build:src
- name: Release package
run: |
npm run publish:linux:deb:x64
npm run publish:linux:deb:x86
npm run publish:linux:deb:arm64
npm run publish:linux:deb:armv7l
npm run publish:linux:appImage
npm run publish:linux:rpm
npm run publish:linux:pacman
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BT_TOKEN: ${{ secrets.BT_TOKEN }}
- name: Build Package deb x64
run: npm run pack:linux:deb:x64
- name: Upload Artifact deb x64
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-deb-x64
path: build/* x64.deb
- name: Build Package deb x86
run: npm run pack:linux:deb:x86
- name: Upload Artifact deb x86
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-deb-x86
path: build/* x86.deb
- name: Build Package deb arm64
run: npm run pack:linux:deb:arm64
- name: Upload Artifact deb arm64
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-deb-arm64
path: build/* arm64.deb
- name: Build Package deb armv7l
run: npm run pack:linux:deb:armv7l
- name: Upload Artifact deb armv7l
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-deb-armv7l
path: build/* armv7l.deb
- name: Build Package x64 appImage
run: npm run pack:linux:appImage
- name: Upload Artifact x64 appImage
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-x64-appImage
path: build/* x64.AppImage
- name: Build Package x64 rpm
run: npm run pack:linux:rpm
- name: Upload Artifact x64 rpm
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-x64-rpm
path: build/* x64.rpm
- name: Build Package x64 pacman
run: npm run pack:linux:pacman
- name: Upload Artifact x64 pacman
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-x64-pacman
path: build/* x64.pacman

View File

@ -41,6 +41,7 @@ jobs:
npm run publish:win:setup:always
npm run publish:win:7z:x64
npm run publish:win:7z:x86
npm run publish:win:7z:arm64
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BT_TOKEN: ${{ secrets.BT_TOKEN }}

9
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
"path-intellisense.mappings": {
"@main/*": "${workspaceFolder}/src/main/*",
"@renderer/*": "${workspaceFolder}/src/renderer/*",
"@lyric/*": "${workspaceFolder}/src/renderer-lyric/*",
"@static/*": "${workspaceFolder}/src/static/*",
"@common/*": "${workspaceFolder}/src/common/*",
}
}

10
FAQ.md
View File

@ -123,6 +123,12 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看下面的
尝试更换网络,如切换到移动网络。
## 使用软件时导致耳机意外关机
据反馈,漫步者部分型号的耳机与本软件一起使用时将会导致耳机意外关机,
详情看:<https://github.com/lyswhut/lx-music-desktop/issues/457>
若出现该问题可尝试添加`-dhmkh`启动参数解决启动参数添加方法请自行百度“windows给应用程序加启动参数的方法”。
### 其他错误
按照前面的 "歌曲无法试听与下载" 方案解决。
@ -164,7 +170,7 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看下面的
## 杀毒软件提示有病毒或恶意行为
本人只能保证我写的代码不包含任何**恶意代码**、**收集用户信息**的行为并且软件代码已开源请自行查阅软件安装包也是由CI拉取源代码构建构建日志[GitHub Actions](https://github.com/lyswhut/lx-music-desktop/actions)。v1.8.2之前的版本构建日志:[windows包](https://ci.appveyor.com/project/lyswhut/lx-music-desktop)、[Mac/Linux包](https://travis-ci.com/github/lyswhut/lx-music-desktop)<br>
本人只能保证我写的代码不包含任何**恶意代码**、**收集用户信息**的行为并且软件代码已开源请自行查阅软件安装包也是由CI拉取源代码构建构建日志[GitHub Actions](https://github.com/lyswhut/lx-music-desktop/actions)<br>
尽管如此但这不意味着软件是100%安全的,由于软件使用了第三方依赖,当这些依赖存在恶意行为时([供应链攻击](https://docs.microsoft.com/zh-cn/windows/security/threat-protection/intelligence/supply-chain-malware)),软件也将会受到牵连,所以我只能尽量选择使用较多人用、信任度较高的依赖。<br>
当然,以上说明建立的前提是在你所用的安装包是从**本项目主页上写的链接**下载的,或者有相关能力者还可以下载源代码自己构建安装包。
@ -278,7 +284,7 @@ send(EVENT_NAMES.inited, {
| 事件名 | 描述
| --- | ---
| `inited` | 脚本初始化完成后发送给应用的事件名,发送该事件时需要传入以下信息:`{status, sources, openDevTools}`<br>`status`:初始化结果(`true`成功,`false`失败)<br>`openDevTools`是否打开DevTools此选项可用于开发脚本时的调试<br>`sources`:支持的源信息对象,<br>`sources[kw/kg/tx/wy/mg].name`:源的名字(目前非必须)<br>`sources[kw/kg/tx/wy/mg].type`:源类型,目前固定值需为`music`<br>`sources[kw/kg/tx/wy/mg].actions`支持的actions由于目前只支持`musicUrl`,所以固定传`['musicUrl']`即可<br>`sources[kw/kg/tx/wy/mg].qualitys`:该源支持的音质列表,支持的值`['128k', '320k', 'flac']`,该字段用于控制应用可用的音质类型
| `inited` | 脚本初始化完成后发送给应用的事件名,发送该事件时需要传入以下信息:`{status, sources, openDevTools}`<br>`status`:初始化结果(`true`成功,`false`失败)<br>`openDevTools`是否打开DevTools此选项可用于开发脚本时的调试<br>`sources`:支持的源信息对象,<br>`sources[kw/kg/tx/wy/mg].name`:源的名字(目前非必须)<br>`sources[kw/kg/tx/wy/mg].type`:源类型,目前固定值需为`music`<br>`sources[kw/kg/tx/wy/mg].actions`支持的actions由于目前只支持`musicUrl`,所以固定传`['musicUrl']`即可<br>`sources[kw/kg/tx/wy/mg].qualitys`:该源支持的音质列表,有效的值为`['128k', '320k', 'flac']`,该字段用于控制应用可用的音质类型
| `request` | 应用API请求事件名回调入参`handler({ source, action, info})`,回调必须返回`Promise`对象<br>`source`:音乐源,可能的值取决于初始化时传入的`sources`对象的源key值<br>`info`:请求附加信息,内容根据`action`变化<br>`action`:请求操作类型,目前只有`musicUrl`即获取音乐URL链接需要在 Promise 返回歌曲 url`info`的结构:`{type, musicInfo}``info.type`:音乐质量,可能的值有`128k` / `320k` / `flac`(取决于初始化时对应源传入的`qualitys`值中的一个),`info.musicInfo`音乐信息对象里面有音乐ID、名字等信息

View File

@ -47,7 +47,7 @@
软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)<br>
软件下载请转到:[发布页面](https://github.com/lyswhut/lx-music-desktop/releases)<br>
或者到网盘下载网盘内有MAC、windows版`https://www.lanzoux.com/b0bf2cfa/` 密码:`glqw`(若链接无法打开请百度:蓝奏云链接打不开)<br>
或者到网盘下载网盘内有MAC、windows版`https://www.lanzous.com/b0bf2cfa/` 密码:`glqw`(若链接无法打开请百度:蓝奏云链接打不开)<br>
使用常见问题请转至:[常见问题](https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md)
### 源码使用方法
@ -83,6 +83,7 @@ npm run pack:linux
- `-search` 启动软件时自动在搜索框搜索指定的内容,例如:`-search="突然的自我 - 伍佰"`
- `-dha` 禁用硬件加速启动Disable Hardware Acceleration窗口显示有问题时可以尝试添加此参数启动v1.6.0起新增)
- `-dt` 以非透明模式启动Disable Transparent对于未开启AERO效果的win7系统可加此参数启动以确保界面正常显示该参数对桌面歌词无效原来的`-nt`参数已重命名为`-dt`v1.6.0起重命名)
- `-dhmkh` 禁用硬件媒体密钥处理Disable Hardware Media Key Handling此选项将禁用Chromium的Hardware Media Key Handling特性v1.8.1起新增)
- `-play` 启动时播放指定列表的音乐,参数说明:
- `type`:播放类型,目前固定为`songList`
- `source`:播放源,可用值为`kw/kg/tx/wy/mg/myList`,其中`kw/kg/tx/wy/mg`对应各源的在线列表,`myList`为本地列表
@ -90,6 +91,7 @@ npm run pack:linux
- `name`要播放的本地列表歌单名字source为`myList`时必传,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表"`
- `index`:从列表的哪个位置开始播放,选传,若不传默认播放第一首歌曲,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表&index=2"`
### 常见问题
常见问题已移至:<https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md>

View File

@ -2,6 +2,7 @@ const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HTMLPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CleanCSSPlugin = require('less-plugin-clean-css')
const vueLoaderConfig = require('../vue-loader.config')
const { mergeCSSLoader } = require('../utils')
@ -37,6 +38,7 @@ module.exports = {
loader: 'eslint-loader',
options: {
formatter: require('eslint-formatter-friendly'),
emitWarning: isDev,
},
},
exclude: /node_modules/,
@ -62,6 +64,11 @@ module.exports = {
loader: 'less-loader',
options: {
sourceMap: true,
lessOptions: {
plugins: [
new CleanCSSPlugin({ advanced: true }),
],
},
},
}),
},
@ -123,6 +130,7 @@ module.exports = {
template: path.join(__dirname, '../../src/renderer-lyric/index.pug'),
isProd: process.env.NODE_ENV == 'production',
browser: process.browser,
scriptLoading: 'blocking',
__dirname,
}),
new VueLoaderPlugin(),

View File

@ -34,7 +34,6 @@ module.exports = merge(baseConfig, {
}),
],
optimization: {
chunkIds: 'named',
minimizer: [
new TerserPlugin(),
new OptimizeCSSAssetsPlugin({}),

View File

@ -2,6 +2,7 @@ const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HTMLPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CleanCSSPlugin = require('less-plugin-clean-css')
const vueLoaderConfig = require('../vue-loader.config')
const { mergeCSSLoader } = require('../utils')
@ -37,6 +38,7 @@ module.exports = {
loader: 'eslint-loader',
options: {
formatter: require('eslint-formatter-friendly'),
emitWarning: isDev,
},
},
exclude: /node_modules/,
@ -62,6 +64,11 @@ module.exports = {
loader: 'less-loader',
options: {
sourceMap: true,
lessOptions: {
plugins: [
new CleanCSSPlugin({ advanced: true }),
],
},
},
}),
},
@ -123,6 +130,7 @@ module.exports = {
template: path.join(__dirname, '../../src/renderer/index.pug'),
isProd: process.env.NODE_ENV == 'production',
browser: process.browser,
scriptLoading: 'blocking',
__dirname,
}),
new VueLoaderPlugin(),

View File

@ -34,7 +34,6 @@ module.exports = merge(baseConfig, {
}),
],
optimization: {
chunkIds: 'named',
minimizer: [
new TerserPlugin(),
new OptimizeCSSAssetsPlugin({}),

View File

@ -2,8 +2,6 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const cssLoaderConfig = require('./css-loader.config')
const chalk = require('chalk')
const isDev = process.env.NODE_ENV === 'development'
// merge css-loader
exports.mergeCSSLoader = beforeLoader => {
const loader = [
@ -14,7 +12,7 @@ exports.mergeCSSLoader = beforeLoader => {
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: isDev,
esModule: false,
},
},
{
@ -30,7 +28,7 @@ exports.mergeCSSLoader = beforeLoader => {
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: isDev,
esModule: false,
},
},
'css-loader',

View File

@ -1,19 +1,13 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
// This is the line you want to add
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"baseUrl": "./",
"paths": {
"@main": ["src/main"],
"@renderer": ["src/renderer"],
"@lyric": ["src/renderer-lyric"],
"@static": ["src/static"],
"@common": ["src/common"],
"@main/*": ["src/main/*"],
"@renderer/*": ["src/renderer/*"],
"@lyric/*": ["src/renderer-lyric/*"],
"@static/*": ["src/static/*"],
"@common/*": ["src/common/*"],
}
},
"include": ["src/**/*"],
"exclude": ["node_modules/**/*"]
"exclude": ["node_modules", "build", "dist"]
}

6334
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,34 @@
{
"name": "lx-music-desktop",
"version": "1.8.2",
"version": "1.9.0-beta",
"description": "一个免费的音乐查找助手",
"main": "./dist/electron/main.js",
"productName": "lx-music-desktop",
"scripts": {
"pack": "node build-config/pack.js && npm run pack:win:setup:x64",
"pack:win": "node build-config/pack.js && npm run pack:win:setup:x86_64 && npm run pack:win:7z",
"pack:win:setup:x86_64": "cross-env TARGET=win_安装版 ARCH=x86_64 electron-builder -w=nsis --x64 --ia32",
"pack:win:setup:x64": "cross-env TARGET=win_安装版 ARCH=x64 electron-builder -w=nsis --x64",
"pack:win:setup:x86": "cross-env TARGET=win_安装版 ARCH=x86 electron-builder -w=nsis --ia32",
"pack:win:setup:x86_64": "cross-env TARGET=Setup ARCH=x86_64 electron-builder -w=nsis --x64 --ia32 -p never",
"pack:win:setup:x64": "cross-env TARGET=Setup ARCH=x64 electron-builder -w=nsis --x64 -p never",
"pack:win:setup:x86": "cross-env TARGET=Setup ARCH=x86 electron-builder -w=nsis --ia32 -p never",
"pack:win:portable": "npm run pack:win:portable:x86_64 && npm run pack:win:portable:x64 && npm run pack:win:portable:x86",
"pack:win:portable:x86_64": "cross-env TARGET=便携版 ARCH=x86_64 electron-builder -w=portable --x64 --ia32",
"pack:win:portable:x64": "cross-env TARGET=便携版 ARCH=x64 electron-builder -w=portable --x64",
"pack:win:portable:x86": "cross-env TARGET=便携版 ARCH=x86 electron-builder -w=portable --ia32",
"pack:win:portable:x86_64": "cross-env TARGET=portable ARCH=x86_64 electron-builder -w=portable --x64 --ia32 -p never",
"pack:win:portable:x64": "cross-env TARGET=portable ARCH=x64 electron-builder -w=portable --x64 -p never",
"pack:win:portable:x86": "cross-env TARGET=portable ARCH=x86 electron-builder -w=portable --ia32 -p never",
"pack:win:7z": "npm run pack:win:7z:x64 && npm run pack:win:7z:x86",
"pack:win:7z:x64": "cross-env TARGET=win_绿色版 ARCH=x64 electron-builder -w=7z --x64",
"pack:win:7z:x86": "cross-env TARGET=win_绿色版 ARCH=x86 electron-builder -w=7z --ia32",
"pack:win:7z:x64": "cross-env TARGET=green ARCH=win_x64 electron-builder -w=7z --x64 -p never",
"pack:win:7z:x86": "cross-env TARGET=green ARCH=win_x86 electron-builder -w=7z --ia32 -p never",
"pack:win:7z:arm64": "cross-env TARGET=green ARCH=win_arm64 electron-builder -w=7z --arm64 -p never",
"pack:linux": "node build-config/pack.js && npm run pack:linux:deb && npm run pack:linux:appImage && npm run pack:linux:rpm && npm run pack:linux:pacman",
"pack:linux:appImage": "cross-env ARCH=x64 electron-builder -l=AppImage",
"pack:linux:appImage": "cross-env ARCH=x64 electron-builder -l=AppImage -p never",
"pack:linux:deb": "npm run pack:linux:deb:x64 && npm run pack:linux:deb:x86 && npm run pack:linux:deb:arm64 && npm run pack:linux:deb:armv7l",
"pack:linux:deb:x64": "cross-env ARCH=x64 electron-builder -l=deb --x64",
"pack:linux:deb:x86": "cross-env ARCH=x86 electron-builder -l=deb --ia32",
"pack:linux:deb:arm64": "cross-env ARCH=arm64 electron-builder -l=deb --arm64",
"pack:linux:deb:armv7l": "cross-env ARCH=armv7l electron-builder -l=deb --armv7l",
"pack:linux:rpm": "cross-env ARCH=x64 electron-builder -l=rpm --x64",
"pack:linux:pacman": "cross-env ARCH=x64 electron-builder -l=pacman --x64",
"pack:mac": "node build-config/pack.js && electron-builder -m=dmg",
"pack:linux:deb:x64": "cross-env ARCH=x64 electron-builder -l=deb --x64 -p never",
"pack:linux:deb:x86": "cross-env ARCH=x86 electron-builder -l=deb --ia32 -p never",
"pack:linux:deb:arm64": "cross-env ARCH=arm64 electron-builder -l=deb --arm64 -p never",
"pack:linux:deb:armv7l": "cross-env ARCH=armv7l electron-builder -l=deb --armv7l -p never",
"pack:linux:rpm": "cross-env ARCH=x64 electron-builder -l=rpm --x64 -p never",
"pack:linux:pacman": "cross-env ARCH=x64 electron-builder -l=pacman --x64 -p never",
"pack:mac": "node build-config/pack.js && npm run pack:mac:dmg",
"pack:mac:dmg": "cross-env electron-builder -m=dmg -p never",
"pack:dir": "node build-config/pack.js && electron-builder --dir",
"publish": "node publish",
"publish:win:setup:always": "cross-env TARGET=Setup ARCH=x86_64 electron-builder -w=nsis --x64 --ia32 -p always",
@ -37,6 +39,7 @@
"publish:win:portable:x86": "cross-env TARGET=portable ARCH=x86 electron-builder -w=portable --ia32 -p onTagOrDraft",
"publish:win:7z:x64": "cross-env TARGET=green ARCH=win_x64 electron-builder -w=7z --x64 -p onTagOrDraft",
"publish:win:7z:x86": "cross-env TARGET=green ARCH=win_x86 electron-builder -w=7z --ia32 -p onTagOrDraft",
"publish:win:7z:arm64": "cross-env TARGET=green ARCH=win_arm64 electron-builder -w=7z --arm64 -p onTagOrDraft",
"publish:mac:dmg:always": "electron-builder -m=dmg -p always",
"publish:mac:dmg": "electron-builder -m=dmg -p onTagOrDraft",
"publish:linux:deb:x64:always": "cross-env ARCH=x64 electron-builder -l=deb --x64 -p always",
@ -51,9 +54,9 @@
"clean:electron": "rimraf dist/electron",
"clean": "rimraf dist && rimraf build",
"build:src": "node build-config/pack.js",
"build:main": "cross-env NODE_ENV=production webpack --config build-config/main/webpack.config.prod.js --progress --hide-modules",
"build:renderer": "cross-env NODE_ENV=production webpack --config build-config/renderer/webpack.config.prod.js --progress --hide-modules",
"build:renderer-lyric": "cross-env NODE_ENV=production webpack --config build-config/renderer-lyric/webpack.config.prod.js --progress --hide-modules",
"build:main": "cross-env NODE_ENV=production webpack --config build-config/main/webpack.config.prod.js --progress",
"build:renderer": "cross-env NODE_ENV=production webpack --config build-config/renderer/webpack.config.prod.js --progress",
"build:renderer-lyric": "cross-env NODE_ENV=production webpack --config build-config/renderer-lyric/webpack.config.prod.js --progress",
"build": "npm run clean:electron && npm run build:main && npm run build:renderer && npm run build:renderer-lyric",
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-formatter-friendly src",
"lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-formatter-friendly --fix src",
@ -131,12 +134,6 @@
"provider": "github",
"owner": "lyswhut",
"repo": "lx-music-desktop"
},
{
"package": "lx-music-desktop",
"repo": "lx-music-desktop",
"user": "lyswhut",
"provider": "bintray"
}
]
},
@ -159,48 +156,50 @@
},
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
"devDependencies": {
"@babel/core": "^7.13.10",
"@babel/core": "^7.13.16",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-modules-umd": "^7.13.0",
"@babel/plugin-transform-runtime": "^7.13.10",
"@babel/plugin-transform-runtime": "^7.13.15",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.13.10",
"@babel/preset-env": "^7.13.15",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"babel-minify-webpack-plugin": "^0.3.1",
"babel-preset-minify": "^0.5.1",
"cfonts": "^2.9.1",
"chalk": "^4.1.0",
"chalk": "^4.1.1",
"changelog-parser": "^2.8.0",
"copy-webpack-plugin": "^6.4.1",
"core-js": "^3.9.1",
"copy-webpack-plugin": "^8.1.1",
"core-js": "^3.11.0",
"cross-env": "^7.0.3",
"css-loader": "^4.3.0",
"css-loader": "^5.2.4",
"del": "^6.0.0",
"electron": "^9.4.4",
"electron-builder": "^22.10.5",
"electron-debug": "^3.2.0",
"electron-devtools-installer": "^3.1.1",
"eslint": "^7.21.0",
"electron-devtools-installer": "^3.2.0",
"eslint": "^7.25.0",
"eslint-config-standard": "^14.1.1",
"eslint-formatter-friendly": "^7.0.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-html": "^6.1.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.3.1",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^4.1.0",
"file-loader": "^6.2.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"html-webpack-plugin": "^4.5.2",
"less": "^3.13.1",
"less-loader": "^7.3.0",
"markdown-it": "^12.0.4",
"mini-css-extract-plugin": "^0.12.0",
"html-webpack-plugin": "^5.3.1",
"less": "^4.1.1",
"less-loader": "^8.1.1",
"less-plugin-clean-css": "^1.5.1",
"markdown-it": "^12.0.6",
"mini-css-extract-plugin": "^1.5.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^4.2.0",
"postcss-pxtorem": "^5.1.1",
"postcss": "^8.2.12",
"postcss-loader": "^5.2.0",
"postcss-pxtorem": "^6.0.0",
"pug": "^3.0.2",
"pug-loader": "^2.4.0",
"pug-plain-loader": "^1.1.0",
@ -208,13 +207,13 @@
"rimraf": "^3.0.2",
"spinnies": "^0.5.1",
"stylus": "^0.54.8",
"stylus-loader": "^4.3.3",
"terser-webpack-plugin": "^4.2.3",
"stylus-loader": "^5.0.0",
"terser-webpack-plugin": "^5.1.1",
"url-loader": "^4.1.1",
"vue-loader": "^15.9.6",
"vue-template-compiler": "^2.6.12",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack": "^5.35.1",
"webpack-cli": "^4.6.0",
"webpack-dev-server": "^3.11.2",
"webpack-hot-middleware": "^2.25.0",
"webpack-merge": "^5.7.3"
@ -222,18 +221,18 @@
"dependencies": {
"crypto-js": "^4.0.0",
"dnscache": "^1.0.2",
"electron-log": "^4.3.2",
"electron-log": "^4.3.4",
"electron-store": "^6.0.1",
"electron-updater": "^4.3.8",
"iconv-lite": "^0.6.2",
"image-size": "^0.9.4",
"image-size": "^1.0.0",
"js-htmlencode": "^0.3.0",
"lrc-file-parser": "^1.0.7",
"needle": "^2.6.0",
"node-id3": "^0.2.2",
"request": "^2.88.2",
"vue": "^2.6.12",
"vue-i18n": "^8.24.0",
"vue-i18n": "^8.24.3",
"vue-router": "^3.5.1",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0"

View File

@ -1,4 +1,20 @@
### 新增
- 新增启动参数`-dhmkh`此参数将禁用Chromium的Hardware Media Key Handling特性用于解决漫步者部分型号耳机与本程序冲突导致耳机意外关机的问题
- 新增Windows arm64位免安装版的构建
- 新增黑色皮肤“黑灯瞎火”,有关于皮肤配色的建议欢迎反馈
- 新增自动换源下载功能默认关闭当无法从歌曲的原始源下载时将尝试切换到其他源下载此功能不100%保证换源后的歌曲版本与原版一致
### 优化
- 程序启动时对数据文件做读取校验数据出现损坏时自动备份损坏的数据若出现数据读取错误的弹窗并出现我的列表丢失时可到GitHub或加群反馈
- 当设置-代理启用,但主机地址为空的时,将不再使用代理配置进行网络连接,并且在离开设置界面时自动禁用代理
- 优化歌曲自动换源匹配
- 分离歌词与歌曲列表信息的保存,以减小列表列表文件损坏的几率
- 兼容打开咪咕移动端分享的歌单链接,添加打开歌单的信息显示
### 修复
- 修复歌曲ID存储变更导致酷狗图片获取失败的问题
- 修复收藏的在线列表id迁移保存出错的问题
- 修复备份与恢复功能在恢复数据时某些设置不立即生效的问题
- 修正设置页“搜索设置”部分内容的缩进显示问题
- 修复正在播放“稍后播放”的歌曲时,对“稍后播放”前播放的列表进行添加、删除操作会导致切歌的问题

View File

@ -2,7 +2,7 @@ const path = require('path')
const os = require('os')
const defaultSetting = {
version: '1.0.40',
version: '1.0.41',
player: {
togglePlayMethod: 'listLoop',
highQuality: false,
@ -11,7 +11,7 @@ const defaultSetting = {
isMute: false,
mediaDeviceId: 'default',
isMediaDeviceRemovedStopPlay: false,
isShowLyricTransition: false,
isShowLyricTranslation: false,
isPlayLxlrc: true,
isSavePlayTime: false,
},
@ -45,6 +45,7 @@ const defaultSetting = {
isDownloadLrc: false,
isEmbedPic: true,
isEmbedLyric: false,
isUseOtherSource: false,
},
leaderboard: {
source: 'kw',

View File

@ -59,6 +59,13 @@ const names = {
request_user_api_cancel: 'request_user_api_cancel',
get_user_api_status: 'get_user_api_status',
user_api_status: 'user_api_status',
get_lyric: 'get_lyric',
save_lyric: 'save_lyric',
clear_lyric: 'clear_lyric',
get_music_url: 'get_music_url',
save_music_url: 'save_music_url',
clear_music_url: 'clear_music_url',
},
winLyric: {
close: 'close',

42
src/common/store.js Normal file
View File

@ -0,0 +1,42 @@
const Store = require('electron-store')
const { dialog, app, shell } = require('electron')
const path = require('path')
const fs = require('fs')
const log = require('electron-log')
const stores = {}
/**
* 获取 Store 对象
* @param {*} name store
* @param {*} isIgnoredError 是否忽略错误
* @param {*} isShowErrorAlert 是否显示错误弹窗
* @returns Store
*/
module.exports = (name, isIgnoredError = true, isShowErrorAlert = true) => {
if (stores[name]) return stores[name]
let store
try {
store = stores[name] = new Store({ name, clearInvalidConfig: false })
} catch (error) {
log.error(error)
if (!isIgnoredError) throw error
const backPath = path.join(app.getPath('userData'), name + '.json.bak')
fs.copyFileSync(path.join(app.getPath('userData'), name + '.json'), backPath)
if (isShowErrorAlert) {
dialog.showMessageBoxSync({
type: 'error',
message: name + ' data load error',
detail: `We have helped you back up the old ${name} file to: ${backPath}\nYou can try to repair and restore it manually\n\nError detail: ${error.message}`,
})
shell.showItemInFolder(backPath)
}
store = new Store({ name, clearInvalidConfig: true })
}
return store
}

View File

@ -1,11 +1,8 @@
const log = require('electron-log')
const Store = require('electron-store')
const { defaultSetting, overwriteSetting } = require('./defaultSetting')
// const apiSource = require('../renderer/utils/music/api-source-info')
const getStore = require('./store')
const defaultHotKey = require('./defaultHotKey')
const { dialog, app } = require('electron')
const path = require('path')
const fs = require('fs')
exports.isLinux = process.platform == 'linux'
exports.isWin = process.platform == 'win32'
@ -126,33 +123,13 @@ exports.mergeSetting = (setting, version) => {
/**
* 初始化设置
* @param {*} setting
* @param {*} isShowErrorAlert
*/
exports.initSetting = () => {
let electronStore_list
try {
electronStore_list = new Store({
name: 'playList',
clearInvalidConfig: false,
})
} catch (error) {
log.error(error)
const backPath = path.join(app.getPath('userData'), 'playList.json.bak')
fs.copyFileSync(path.join(app.getPath('userData'), 'playList.json'), backPath)
dialog.showMessageBoxSync({
type: 'error',
message: 'Playlist data loading error',
detail: `We have helped you back up the old list file to ${backPath}\nYou can try to repair and restore it manually\n\nError detail: ${error.message}`,
})
electronStore_list = new Store({
name: 'playList',
})
}
const electronStore_config = new Store({
name: 'config',
})
const electronStore_downloadList = new Store({
name: 'downloadList',
})
exports.initSetting = isShowErrorAlert => {
const electronStore_list = getStore('playList', true, isShowErrorAlert)
const electronStore_config = getStore('config')
const electronStore_downloadList = getStore('downloadList')
let setting = electronStore_config.get('setting')
if (setting) {
let version = electronStore_config.get('version')
@ -182,6 +159,11 @@ exports.initSetting = () => {
electronStore_config.set('setting.list.isSaveScrollLocation', scroll.enable)
delete setting.list.scroll
}
if (setting.player.isShowLyricTransition != null) { // 修正拼写问题 v1.8.2 及以前
setting.player.isShowLyricTranslation = setting.player.isShowLyricTransition
delete setting.player.isShowLyricTransition
}
}
// 从我的列表分离下载列表 v1.7.0 后
@ -197,8 +179,7 @@ exports.initSetting = () => {
if (!newSetting.leaderboard.tabId.includes('__')) newSetting.leaderboard.tabId = 'kw__16'
// newSetting.controlBtnPosition = 'right'
electronStore_config.set('version', settingVersion)
electronStore_config.set('setting', newSetting)
electronStore_config.set({ version: settingVersion, setting: newSetting })
return { version: settingVersion, setting: newSetting }
}
@ -206,9 +187,7 @@ exports.initSetting = () => {
* 初始化快捷键设置
*/
exports.initHotKey = () => {
const electronStore_hotKey = new Store({
name: 'hotKey',
})
const electronStore_hotKey = getStore('hotKey')
let localConfig = electronStore_hotKey.get('local')
if (!localConfig) {

View File

@ -2,7 +2,7 @@ const { common: COMMON_EVENT_NAME, mainWindow: MAIN_WINDOW_EVENT_NAME } = requir
const { mainSend, NAMES: { mainWindow: ipcMainWindowNames } } = require('./../common/ipc')
const { getAppHotKeyConfig } = require('./utils')
global.lx_event.common.on(COMMON_EVENT_NAME.config, name => {
global.lx_event.common.on(COMMON_EVENT_NAME.configStatus, name => {
if (MAIN_WINDOW_EVENT_NAME.name === name) return
if (global.modules.mainWindow) mainSend(global.modules.mainWindow, ipcMainWindowNames.set_config, global.appSetting)
})

View File

@ -1,16 +1,14 @@
const { EventEmitter } = require('events')
const { common: COMMON_EVENT_NAME } = require('./_name')
const { updateSetting } = require('../utils')
class Common extends EventEmitter {
initSetting() {
this.emit(COMMON_EVENT_NAME.initConfig)
this.emit(COMMON_EVENT_NAME.config, null)
this.configStatus(null)
}
setAppConfig(config, name) {
if (config) updateSetting(config)
this.emit(COMMON_EVENT_NAME.config, name)
configStatus(name) {
this.emit(COMMON_EVENT_NAME.configStatus, name)
}
}

View File

@ -1,6 +1,6 @@
exports.common = {
initConfig: 'initConfig',
config: 'config',
configStatus: 'config',
}
exports.mainWindow = {

View File

@ -4,7 +4,7 @@ const path = require('path')
// 单例应用程序
if (!app.requestSingleInstanceLock()) {
app.quit()
return
process.exit(0)
}
if (!global.modules) global.modules = {}
app.on('second-instance', (event, argv, cwd) => {
@ -29,13 +29,15 @@ require('./env')
// Is disable hardware acceleration
if (global.envParams.cmdParams.dha) app.disableHardwareAcceleration()
if (global.envParams.cmdParams.dt == null && global.envParams.cmdParams.nt != null) global.envParams.cmdParams.dt = global.envParams.cmdParams.nt
if (global.envParams.cmdParams.dhmkh) app.commandLine.appendSwitch('disable-features', 'HardwareMediaKeyHandling')
// https://github.com/electron/electron/issues/22691
app.commandLine.appendSwitch('wm-window-animations-disabled')
const { navigationUrlWhiteList } = require('../common/config')
const { getWindowSizeInfo } = require('./utils')
const { isMac, isLinux, initSetting, initHotKey } = require('../common/utils')
const { getWindowSizeInfo, initSetting, updateSetting } = require('./utils')
const { isMac, isLinux, initHotKey } = require('../common/utils')
// https://github.com/electron/electron/issues/18397
@ -130,11 +132,16 @@ global.appHotKey = {
state: null,
}
global.lx_core = {
setAppConfig(setting, name) {
updateSetting(setting)
global.lx_event.common.configStatus(name)
},
}
function init() {
console.log('init')
const info = initSetting()
global.appSetting = info.setting
global.appSettingVersion = info.version
initSetting()
global.appHotKey.config = initHotKey()
global.lx_event.common.initSetting()
global.lx_event.hotKey.init()

View File

@ -16,7 +16,7 @@ const themeList = [
isNative: false,
},
]
global.lx_event.common.on(COMMON_EVENT_NAME.config, sourceName => {
global.lx_event.common.on(COMMON_EVENT_NAME.configStatus, sourceName => {
if (sourceName === TRAY_EVENT_NAME.name) return
if (themeId !== global.appSetting.tray.themeId) {
themeId = global.appSetting.tray.themeId
@ -89,34 +89,34 @@ const createMenu = tray => {
menu.push(global.appSetting.desktopLyric.enable ? {
label: '关闭桌面歌词',
click() {
global.lx_event.common.setAppConfig({ desktopLyric: { enable: false } }, TRAY_EVENT_NAME.name)
global.lx_core.setAppConfig({ desktopLyric: { enable: false } }, TRAY_EVENT_NAME.name)
},
} : {
label: '开启桌面歌词',
click() {
global.lx_event.common.setAppConfig({ desktopLyric: { enable: true } }, TRAY_EVENT_NAME.name)
global.lx_core.setAppConfig({ desktopLyric: { enable: true } }, TRAY_EVENT_NAME.name)
},
})
menu.push(global.appSetting.desktopLyric.isLock ? {
label: '解锁桌面歌词',
click() {
global.lx_event.common.setAppConfig({ desktopLyric: { isLock: false } }, TRAY_EVENT_NAME.name)
global.lx_core.setAppConfig({ desktopLyric: { isLock: false } }, TRAY_EVENT_NAME.name)
},
} : {
label: '锁定桌面歌词',
click() {
global.lx_event.common.setAppConfig({ desktopLyric: { isLock: true } }, TRAY_EVENT_NAME.name)
global.lx_core.setAppConfig({ desktopLyric: { isLock: true } }, TRAY_EVENT_NAME.name)
},
})
menu.push(global.appSetting.desktopLyric.isAlwaysOnTop ? {
label: '取消置顶',
click() {
global.lx_event.common.setAppConfig({ desktopLyric: { isAlwaysOnTop: false } }, TRAY_EVENT_NAME.name)
global.lx_core.setAppConfig({ desktopLyric: { isAlwaysOnTop: false } }, TRAY_EVENT_NAME.name)
},
} : {
label: '置顶歌词',
click() {
global.lx_event.common.setAppConfig({ desktopLyric: { isAlwaysOnTop: true } }, TRAY_EVENT_NAME.name)
global.lx_core.setAppConfig({ desktopLyric: { isAlwaysOnTop: true } }, TRAY_EVENT_NAME.name)
},
})
menu.push({

View File

@ -1,12 +1,10 @@
const { userApis: defaultUserApis } = require('../config')
const Store = require('electron-store')
const getStore = require('@common/store')
let userApis
const electronStore_userApi = new Store({
name: 'userApi',
})
exports.getUserApis = () => {
const electronStore_userApi = getStore('userApi')
if (userApis) return userApis
userApis = electronStore_userApi.get('userApis')
if (!userApis) {
@ -31,7 +29,7 @@ exports.importApi = script => {
script,
}
userApis.push(apiInfo)
electronStore_userApi.set('userApis', userApis)
getStore('userApi').set('userApis', userApis)
return apiInfo
}
@ -42,5 +40,5 @@ exports.removeApi = ids => {
ids.splice(index, 1)
}
}
electronStore_userApi.set('userApis', userApis)
getStore('userApi').set('userApis', userApis)
}

View File

@ -2,6 +2,7 @@ const { common: COMMON_EVENT_NAME, winLyric: WIN_LYRIC_EVENT_NAME, hotKey: HOT_K
const { mainSend, NAMES: { winLyric: ipcWinLyricNames } } = require('../../../common/ipc')
const { desktop_lyric } = require('../../../common/hotKey')
const { getLyricWindowBounds } = require('./utils')
const { updateSetting } = require('../../utils')
let isLock = null
let isEnable = null
@ -13,7 +14,7 @@ const setLrcConfig = () => {
mainSend(global.modules.lyricWindow, ipcWinLyricNames.set_lyric_config, {
config: desktopLyric,
languageId: global.appSetting.langId,
isShowLyricTransition: global.appSetting.player.isShowLyricTransition,
isShowLyricTranslation: global.appSetting.player.isShowLyricTranslation,
isPlayLxlrc: global.appSetting.player.isPlayLxlrc,
})
if (isLock != desktopLyric.isLock) {
@ -49,7 +50,7 @@ const setLrcConfig = () => {
}
}
}
global.lx_event.common.on(COMMON_EVENT_NAME.config, name => {
global.lx_event.common.on(COMMON_EVENT_NAME.configStatus, name => {
if (WIN_LYRIC_EVENT_NAME.name === name) return
setLrcConfig()
})
@ -77,5 +78,5 @@ global.lx_event.hotKey.on(HOT_KEY_EVENT_NAME.keyDown, ({ type, key }) => {
}
desktopLyricSetting[settingKey] = !desktopLyricSetting[settingKey]
global.lx_event.common.setAppConfig({ desktopLyric: desktopLyricSetting }, null)
updateSetting({ desktopLyric: desktopLyricSetting }, null)
})

View File

@ -21,7 +21,7 @@ const setLyricsConfig = debounce(config => {
// if (y != null) bounds.y = y
// if (width != null) bounds.width = width
// if (height != null) bounds.height = height
global.lx_event.common.setAppConfig({ desktopLyric: config }, WIN_LYRIC_EVENT_NAME.name)
global.lx_core.setAppConfig({ desktopLyric: config }, WIN_LYRIC_EVENT_NAME.name)
}, 500)
const winEvent = lyricWindow => {

View File

@ -20,14 +20,14 @@ mainOn(ipcWinLyricNames.get_lyric_info, (event, action) => {
})
mainOn(ipcWinLyricNames.set_lyric_config, (event, config) => {
global.lx_event.common.setAppConfig({ desktopLyric: config }, WIN_LYRIC_EVENT_NAME.name)
global.lx_core.setAppConfig({ desktopLyric: config }, WIN_LYRIC_EVENT_NAME.name)
})
mainHandle(ipcWinLyricNames.get_lyric_config, async() => {
return {
config: global.appSetting.desktopLyric,
languageId: global.appSetting.langId,
isShowLyricTransition: global.appSetting.player.isShowLyricTransition,
isShowLyricTranslation: global.appSetting.player.isShowLyricTranslation,
isPlayLxlrc: global.appSetting.player.isPlayLxlrc,
}
})

View File

@ -1,9 +1,11 @@
const { mainWindow: MAIN_WINDOW_EVENT_NAME } = require('../events/_name')
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
const { NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
mainOn(ipcMainWindowNames.set_app_setting, (event, config) => {
mainHandle(ipcMainWindowNames.set_app_setting, (event, config) => {
if (!config) return
global.lx_event.common.setAppConfig(config, MAIN_WINDOW_EVENT_NAME.name)
global.lx_core.setAppConfig(config, MAIN_WINDOW_EVENT_NAME.name)
return global.appSetting
})
mainHandle(ipcMainWindowNames.get_setting, async() => ({ setting: global.appSetting, version: global.appSettingVersion }))

View File

@ -1,12 +1,8 @@
const Store = require('electron-store')
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
const getStore = require('@common/store')
const electronStore_data = new Store({
name: 'data',
})
mainHandle(ipcMainWindowNames.get_data, async(event, path) => electronStore_data.get(path))
mainHandle(ipcMainWindowNames.get_data, async(event, path) => getStore('data').get(path))
mainOn(ipcMainWindowNames.save_data, (event, { path, data }) => electronStore_data.set(path, data))
mainOn(ipcMainWindowNames.save_data, (event, { path, data }) => getStore('data').set(path, data))

View File

@ -1,10 +1,8 @@
const Store = require('electron-store')
const { mainSend, NAMES: { mainWindow: ipcMainWindowNames }, mainOn, mainHandle } = require('../../common/ipc')
const { mainWindow: MAIN_WINDOW_EVENT_NAME, hotKey: HOT_KEY_EVENT_NAME } = require('../events/_name')
const getStore = require('@common/store')
const electronStore_hotKey = new Store({
name: 'hotKey',
})
// const { registerHotkey, unRegisterHotkey } = require('../modules/hotKey/utils')
// mainHandle(ipcMainWindowNames.set_hot_key_config, async(event, { action, data }) => {
@ -19,10 +17,13 @@ const electronStore_hotKey = new Store({
// }
// })
mainHandle(ipcMainWindowNames.get_hot_key, async() => ({
local: electronStore_hotKey.get('local'),
global: electronStore_hotKey.get('global'),
}))
mainHandle(ipcMainWindowNames.get_hot_key, async() => {
const electronStore_hotKey = getStore('hotKey')
return {
local: electronStore_hotKey.get('local'),
global: electronStore_hotKey.get('global'),
}
})
mainOn(ipcMainWindowNames.quit, () => global.lx_event.mainWindow.quit())
mainOn(ipcMainWindowNames.min_toggle, () => global.lx_event.mainWindow.toggleMinimize())

View File

@ -17,6 +17,8 @@ require('./getDataPath')
require('./showDialog')
require('./playList')
require('./data')
require('./lyric')
require('./musicUrl')
require('./kw_decodeLyric')

View File

@ -0,0 +1,10 @@
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
const getStore = require('@common/store')
mainHandle(ipcMainWindowNames.get_lyric, async(event, id) => getStore('lyrics', true, false).get(id) || {})
mainOn(ipcMainWindowNames.save_lyric, (event, { id, lyrics }) => getStore('lyrics', true, false).set(id, lyrics))
mainOn(ipcMainWindowNames.clear_lyric, () => getStore('lyrics', true, false).clear())

View File

@ -0,0 +1,10 @@
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
const getStore = require('@common/store')
mainHandle(ipcMainWindowNames.get_music_url, async(event, id) => getStore('musicUrls', true, false).get(id) || '')
mainOn(ipcMainWindowNames.save_music_url, (event, { id, url }) => getStore('musicUrls', true, false).set(id, url))
mainOn(ipcMainWindowNames.clear_music_url, () => getStore('musicUrls', true, false).clear())

View File

@ -1,38 +1,24 @@
const Store = require('electron-store')
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
const getStore = require('@common/store')
let electronStore_list
let electronStore_downloadList
mainHandle(ipcMainWindowNames.get_playlist, async(event, isIgnoredError = false) => {
if (!electronStore_list) {
electronStore_list = new Store({
name: 'playList',
clearInvalidConfig: !isIgnoredError,
})
}
if (!electronStore_downloadList) {
electronStore_downloadList = new Store({
name: 'downloadList',
})
}
const electronStore_list = getStore('playList', isIgnoredError, false)
return {
defaultList: electronStore_list.get('defaultList'),
loveList: electronStore_list.get('loveList'),
userList: electronStore_list.get('userList'),
downloadList: electronStore_downloadList.get('list'),
downloadList: getStore('downloadList').get('list'),
}
})
const handleSaveList = ({ defaultList, loveList, userList }) => {
if (!electronStore_list) return
let data = {}
if (defaultList != null) data.defaultList = defaultList
if (loveList != null) data.loveList = loveList
if (userList != null) data.userList = userList
electronStore_list.set(data)
getStore('playList').set(data)
}
mainOn(ipcMainWindowNames.save_playlist, (event, { type, data }) => {
switch (type) {
@ -40,7 +26,7 @@ mainOn(ipcMainWindowNames.save_playlist, (event, { type, data }) => {
handleSaveList(data)
break
case 'downloadList':
electronStore_downloadList && electronStore_downloadList.set('list', data)
getStore('downloadList').set('list', data)
break
}
})

View File

@ -1,22 +1,18 @@
const Store = require('electron-store')
const { windowSizeList } = require('../../common/config')
const { objectDeepMerge, throttle } = require('../../common/utils')
const { objectDeepMerge, throttle, initSetting } = require('../../common/utils')
const getStore = require('@common/store')
exports.getWindowSizeInfo = ({ windowSizeId = 1 } = {}) => {
return windowSizeList.find(i => i.id === windowSizeId) || windowSizeList[0]
}
const electronStore_config = new Store({
name: 'config',
})
exports.getAppSetting = () => {
return electronStore_config.get('setting')
return getStore('config').get('setting')
}
const electronStore_hotKey = new Store({
name: 'hotKey',
})
exports.getAppHotKeyConfig = () => {
const electronStore_hotKey = getStore('hotKey')
return {
global: electronStore_hotKey.get('global'),
local: electronStore_hotKey.get('local'),
@ -25,17 +21,23 @@ exports.getAppHotKeyConfig = () => {
const saveHotKeyConfig = throttle(config => {
for (const key of Object.keys(config)) {
global.appHotKey.config[key] = config[key]
electronStore_hotKey.set(key, config[key])
getStore('hotKey').set(key, config[key])
}
})
exports.saveAppHotKeyConfig = config => {
saveHotKeyConfig(config)
}
const saveSetting = throttle(n => {
electronStore_config.set('setting', n)
})
exports.updateSetting = settings => {
// const saveSetting = throttle(n => {
// electronStore_config.set('setting', n)
// })
exports.updateSetting = (settings) => {
objectDeepMerge(global.appSetting, settings)
saveSetting(global.appSetting)
getStore('config').set('setting', global.appSetting)
exports.initSetting(false)
}
exports.initSetting = (isShowErrorAlert = true) => {
const info = initSetting(isShowErrorAlert)
global.appSetting = info.setting
global.appSettingVersion = info.version
}

View File

@ -4,7 +4,7 @@
transition(enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut")
.control-bar(v-show="!lrcConfig.isLock")
core-control-bar(:lrcConfig="lrcConfig" :themes="themeList")
core-lyric(:lrcConfig="lrcConfig" :isPlayLxlrc="isPlayLxlrc" :isShowLyricTransition="isShowLyricTransition")
core-lyric(:lrcConfig="lrcConfig" :isPlayLxlrc="isPlayLxlrc" :isShowLyricTranslation="isShowLyricTranslation")
div.resize-left(@mousedown.self="handleMouseDown('left', $event)")
div.resize-top(@mousedown.self="handleMouseDown('top', $event)")
div.resize-right(@mousedown.self="handleMouseDown('right', $event)")
@ -44,57 +44,47 @@ export default {
isZoomActiveLrc: true,
},
},
isShowLyricTransition: true,
isShowLyricTranslation: true,
isPlayLxlrc: true,
themeList: [
{
id: 0,
name: '绿意盎然',
className: 'green',
},
{
id: 1,
name: '绿意盎然',
className: 'yellow',
},
{
id: 2,
name: '绿意盎然',
className: 'blue',
},
{
id: 3,
name: '绿意盎然',
className: 'red',
},
{
id: 4,
name: '绿意盎然',
className: 'pink',
},
{
id: 5,
name: '绿意盎然',
className: 'purple',
},
{
id: 6,
name: '绿意盎然',
className: 'orange',
},
{
id: 7,
name: '绿意盎然',
className: 'grey',
},
{
id: 8,
name: '绿意盎然',
className: 'ming',
},
{
id: 9,
name: '绿意盎然',
className: 'blue2',
},
],
@ -119,9 +109,9 @@ export default {
document.removeEventListener('mouseup', this.handleMouseUp)
},
methods: {
handleUpdateConfig({ config, languageId, isShowLyricTransition, isPlayLxlrc }) {
handleUpdateConfig({ config, languageId, isShowLyricTranslation, isPlayLxlrc }) {
this.lrcConfig = config
this.isShowLyricTransition = isShowLyricTransition
this.isShowLyricTranslation = isShowLyricTranslation
this.isPlayLxlrc = isPlayLxlrc
if (this.$i18n.locale !== languageId && languageId != null) this.$i18n.locale = languageId
},

View File

@ -174,6 +174,7 @@ export default {
@import '../../assets/styles/layout.less';
@bar-height: 38px;
@bar-height-padding: 7px;
.container {
position: relative;
@ -221,20 +222,19 @@ export default {
display: flex;
flex-flow: row wrap;
min-height: @bar-height;
padding-top: (@bar-height - 24px) / 2;
padding-left: (@bar-height - 24px) / 2;
padding-top: @bar-height-padding;
padding-left: @bar-height-padding;
box-sizing: border-box;
}
.btnBack {
margin-top: -(@bar-height - 24px) / 2;
margin-left: -(@bar-height - 24px) / 2;
margin-top: -@bar-height-padding;
margin-left: -@bar-height-padding;
}
.theme-item {
display: block;
margin-bottom: (@bar-height - 24px) / 2;
margin-right: (@bar-height - 24px) / 2;
margin-right: @bar-height-padding;
width: 24px;
height: 24px;
border-radius: @radius-border;

View File

@ -32,7 +32,7 @@ export default {
type: Boolean,
default: true,
},
isShowLyricTransition: {
isShowLyricTranslation: {
type: Boolean,
default: true,
},
@ -126,7 +126,7 @@ export default {
},
immediate: true,
},
isShowLyricTransition() {
isShowLyricTranslation() {
this.setLyric()
rendererSend(NAMES.winLyric.get_lyric_info, 'status')
},
@ -306,8 +306,8 @@ export default {
setLyric() {
window.lrc.setLyric(
this.isPlayLxlrc && this.lyrics.lxlyric ? this.lyrics.lxlyric : this.lyrics.lyric,
this.isShowLyricTransition && this.lyrics.tlyric ? this.lyrics.tlyric : '',
// (this.isShowLyricTransition && this.lyrics.tlyric ? (this.lyrics.tlyric + '\n') : '') + (this.lyrics.lyric || ''),
this.isShowLyricTranslation && this.lyrics.tlyric ? this.lyrics.tlyric : '',
// (this.isShowLyricTranslation && this.lyrics.tlyric ? (this.lyrics.tlyric + '\n') : '') + (this.lyrics.lyric || ''),
)
},
},

View File

@ -25,7 +25,7 @@ import { mapMutations, mapGetters, mapActions } from 'vuex'
import { rendererOn, rendererSend, rendererInvoke, NAMES } from '../common/ipc'
import { isLinux } from '../common/utils'
import music from './utils/music'
import { throttle, openUrl, compareVer, getPlayList, parseUrlParams } from './utils'
import { throttle, openUrl, compareVer, getPlayList, parseUrlParams, saveSetting } from './utils'
import { base as eventBaseName } from './event/names'
import apiSourceInfo from './utils/music/api-source-info'
@ -113,7 +113,7 @@ export default {
watch: {
setting: {
handler(n, o) {
rendererSend(NAMES.mainWindow.set_app_setting, n)
saveSetting(n)
},
deep: true,
},
@ -164,6 +164,20 @@ export default {
}))
}
},
'globalObj.proxy.enable'(n, o) {
if (n != this.setting.network.proxy.enable) {
this.setSetting({
...this.setting,
network: {
...this.setting.network,
proxy: {
...this.setting.network.proxy,
enable: n,
},
},
})
}
},
'windowSizeActive.fontSize'(n) {
document.documentElement.style.fontSize = n
},
@ -246,7 +260,7 @@ export default {
})
rendererOn(NAMES.mainWindow.set_config, (event, config) => {
// console.log(config)
console.log(config)
// this.setDesktopLyricConfig(config)
// console.log('set_config', JSON.stringify(this.setting) === JSON.stringify(config))
this.setSetting(Object.assign({}, this.setting, config))
@ -355,7 +369,7 @@ export default {
if (info.listId) {
const list = window.allList[info.listId]
// console.log(list)
if (!list) return
if (!list || !list.list[info.index]) return
info.list = list.list
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,6 +1,6 @@
@import './colors.less';
@themes: green, yellow, blue, red, pink, purple, orange, grey, ming, blue2, mid_autumn, naruto, happy_new_year;
@themes: green, yellow, blue, red, pink, purple, orange, grey, ming, blue2, black, mid_autumn, naruto, happy_new_year;
// Colors
@ -8,7 +8,7 @@
@color-theme: #4daf7c;
@color-theme-bgimg: none;
@color-theme-bgposition: center;
@color-theme-bgsize: auto auto;
@color-theme-bgsize: cover;
@color-theme-hover: fadeout(lighten(@color-theme, 10%), 30%);
@color-theme-active: fadeout(darken(@color-theme, 20%), 60%);
@color-theme-font: #fff;
@ -51,6 +51,8 @@
@color-player-progress-bar1: darken(@color-theme_2, 12%);
@color-player-progress-bar2: lighten(@color-theme, 12%);
@color-player-status-text: lighten(@color-theme_2-font, 32%);
@color-player-detail-lyric: fadeout(@color-theme_2-font, 40%);
@color-player-detail-lyric-active: darken(@color-theme, 2%);
@color-player-detail-play-btn: lighten(@color-theme, 7%);
@color-tab-btn-background: fadeout(lighten(@color-theme, 10%), 80%);
@ -78,7 +80,7 @@
@color-green-theme: #4daf7c;
@color-green-theme-bgimg: none;
@color-green-theme-bgposition: center;
@color-green-theme-bgsize: auto auto;
@color-green-theme-bgsize: cover;
@color-green-theme-hover: fadeout(lighten(@color-green-theme, 10%), 30%);
@color-green-theme-active: fadeout(darken(@color-green-theme, 20%), 60%);
@color-green-theme-font: #fff;
@ -114,6 +116,8 @@
@color-green-player-progress-bar1: darken(@color-green-theme_2, 12%);
@color-green-player-progress-bar2: lighten(@color-green-theme, 12%);
@color-green-player-status-text: lighten(@color-green-theme_2-font, 32%);
@color-green-player-detail-lyric: fadeout(@color-green-theme_2-font, 40%);
@color-green-player-detail-lyric-active: darken(@color-green-theme, 2%);
@color-green-player-detail-play-btn: lighten(@color-green-theme, 7%);
@color-green-tab-btn-background: fadeout(lighten(@color-green-theme, 10%), 80%);
@color-green-tab-btn-background-hover: @color-green-theme_2-hover;
@ -136,7 +140,7 @@
@color-yellow-theme: #e9d460;
@color-yellow-theme-bgimg: none;
@color-yellow-theme-bgposition: center;
@color-yellow-theme-bgsize: auto auto;
@color-yellow-theme-bgsize: cover;
@color-yellow-theme-hover: fadeout(lighten(@color-yellow-theme, 10%), 30%);
@color-yellow-theme-active: fadeout(darken(@color-yellow-theme, 20%), 60%);
@color-yellow-theme-font: #fff;
@ -172,6 +176,8 @@
@color-yellow-player-progress-bar1: darken(@color-yellow-theme_2, 12%);
@color-yellow-player-progress-bar2: lighten(@color-yellow-theme, 2%);
@color-yellow-player-status-text: lighten(@color-yellow-theme_2-font, 32%);
@color-yellow-player-detail-lyric: fadeout(@color-yellow-theme_2-font, 40%);
@color-yellow-player-detail-lyric-active: darken(@color-yellow-theme, 7%);
@color-yellow-player-detail-play-btn: lighten(@color-yellow-theme, 7%);
@color-yellow-tab-btn-background: fadeout(lighten(@color-yellow-theme, 10%), 70%);
@color-yellow-tab-btn-background-hover: @color-yellow-theme_2-hover;
@ -193,7 +199,7 @@
@color-orange-theme: #f5ab35;
@color-orange-theme-bgimg: none;
@color-orange-theme-bgposition: center;
@color-orange-theme-bgsize: auto auto;
@color-orange-theme-bgsize: cover;
@color-orange-theme-hover: fadeout(lighten(@color-orange-theme, 10%), 30%);
@color-orange-theme-active: fadeout(darken(@color-orange-theme, 20%), 60%);
@color-orange-theme-font: #fff;
@ -229,6 +235,8 @@
@color-orange-player-progress-bar1: darken(@color-orange-theme_2, 12%);
@color-orange-player-progress-bar2: lighten(@color-orange-theme, 12%);
@color-orange-player-status-text: lighten(@color-orange-theme_2-font, 32%);
@color-orange-player-detail-lyric: fadeout(@color-orange-theme_2-font, 40%);
@color-orange-player-detail-lyric-active: darken(@color-orange-theme, 7%);
@color-orange-player-detail-play-btn: lighten(@color-orange-theme, 7%);
@color-orange-tab-btn-background: fadeout(lighten(@color-orange-theme, 10%), 80%);
@color-orange-tab-btn-background-hover: @color-orange-theme_2-hover;
@ -250,7 +258,7 @@
@color-blue-theme: #3498db;
@color-blue-theme-bgimg: none;
@color-blue-theme-bgposition: center;
@color-blue-theme-bgsize: auto auto;
@color-blue-theme-bgsize: cover;
@color-blue-theme-hover: fadeout(lighten(@color-blue-theme, 10%), 30%);
@color-blue-theme-active: fadeout(darken(@color-blue-theme, 20%), 60%);
@color-blue-theme-font: #fff;
@ -286,6 +294,8 @@
@color-blue-player-progress-bar1: darken(@color-blue-theme_2, 12%);
@color-blue-player-progress-bar2: lighten(@color-blue-theme, 12%);
@color-blue-player-status-text: lighten(@color-blue-theme_2-font, 32%);
@color-blue-player-detail-lyric: fadeout(@color-blue-theme_2-font, 40%);
@color-blue-player-detail-lyric-active: darken(@color-blue-theme, 2%);
@color-blue-player-detail-play-btn: lighten(@color-blue-theme, 7%);
@color-blue-tab-btn-background: fadeout(lighten(@color-blue-theme, 10%), 80%);
@color-blue-tab-btn-background-hover: @color-blue-theme_2-hover;
@ -307,7 +317,7 @@
@color-red-theme: #d64541;
@color-red-theme-bgimg: none;
@color-red-theme-bgposition: center;
@color-red-theme-bgsize: auto auto;
@color-red-theme-bgsize: cover;
@color-red-theme-hover: fadeout(lighten(@color-red-theme, 10%), 30%);
@color-red-theme-active: fadeout(darken(@color-red-theme, 20%), 60%);
@color-red-theme-font: #fff;
@ -343,6 +353,8 @@
@color-red-player-progress-bar1: darken(@color-red-theme_2, 12%);
@color-red-player-progress-bar2: lighten(@color-red-theme, 12%);
@color-red-player-status-text: lighten(@color-red-theme_2-font, 32%);
@color-red-player-detail-lyric: fadeout(@color-red-theme_2-font, 40%);
@color-red-player-detail-lyric-active: lighten(@color-red-theme, 2%);
@color-red-player-detail-play-btn: lighten(@color-red-theme, 7%);
@color-red-tab-border-top: fadeout(lighten(@color-red-theme, 25%), 70%);
@color-red-tab-border-bottom: lighten(@color-red-theme, 35%);
@ -366,7 +378,7 @@
@color-pink-theme: #f1828d;
@color-pink-theme-bgimg: none;
@color-pink-theme-bgposition: center;
@color-pink-theme-bgsize: auto auto;
@color-pink-theme-bgsize: cover;
@color-pink-theme-hover: fadeout(lighten(@color-pink-theme, 10%), 30%);
@color-pink-theme-active: fadeout(darken(@color-pink-theme, 20%), 60%);
@color-pink-theme-font: #fff;
@ -402,6 +414,8 @@
@color-pink-player-progress-bar1: darken(@color-pink-theme_2, 12%);
@color-pink-player-progress-bar2: lighten(@color-pink-theme, 2%);
@color-pink-player-status-text: lighten(@color-pink-theme_2-font, 32%);
@color-pink-player-detail-lyric: fadeout(@color-pink-theme_2-font, 40%);
@color-pink-player-detail-lyric-active: darken(@color-pink-theme, 2%);
@color-pink-player-detail-play-btn: lighten(@color-pink-theme, 7%);
@color-pink-tab-btn-background: fadeout(lighten(@color-pink-theme, 10%), 70%);
@color-pink-tab-btn-background-hover: @color-pink-theme_2-hover;
@ -423,7 +437,7 @@
@color-purple-theme: #9b59b6;
@color-purple-theme-bgimg: none;
@color-purple-theme-bgposition: center;
@color-purple-theme-bgsize: auto auto;
@color-purple-theme-bgsize: cover;
@color-purple-theme-hover: fadeout(lighten(@color-purple-theme, 10%), 30%);
@color-purple-theme-active: fadeout(darken(@color-purple-theme, 20%), 60%);
@color-purple-theme-font: #fff;
@ -459,6 +473,8 @@
@color-purple-player-progress-bar1: darken(@color-purple-theme_2, 12%);
@color-purple-player-progress-bar2: lighten(@color-purple-theme, 12%);
@color-purple-player-status-text: lighten(@color-purple-theme_2-font, 32%);
@color-purple-player-detail-lyric: fadeout(@color-purple-theme_2-font, 40%);
@color-purple-player-detail-lyric-active: darken(@color-purple-theme, 2%);
@color-purple-player-detail-play-btn: lighten(@color-purple-theme, 7%);
@color-purple-tab-btn-background: fadeout(lighten(@color-purple-theme, 10%), 80%);
@color-purple-tab-btn-background-hover: @color-purple-theme_2-hover;
@ -480,7 +496,7 @@
@color-grey-theme: #6c7a89;
@color-grey-theme-bgimg: none;
@color-grey-theme-bgposition: center;
@color-grey-theme-bgsize: auto auto;
@color-grey-theme-bgsize: cover;
@color-grey-theme-hover: fadeout(lighten(@color-grey-theme, 10%), 30%);
@color-grey-theme-active: fadeout(darken(@color-grey-theme, 20%), 60%);
@color-grey-theme-font: #fff;
@ -516,6 +532,8 @@
@color-grey-player-progress-bar1: darken(@color-grey-theme_2, 12%);
@color-grey-player-progress-bar2: lighten(@color-grey-theme, 12%);
@color-grey-player-status-text: lighten(@color-grey-theme_2-font, 32%);
@color-grey-player-detail-lyric: fadeout(@color-grey-theme_2-font, 55%);
@color-grey-player-detail-lyric-active: darken(@color-grey-theme, 3%);
@color-grey-player-detail-play-btn: lighten(@color-grey-theme, 7%);
@color-grey-tab-btn-background: fadeout(lighten(@color-grey-theme, 10%), 80%);
@color-grey-tab-btn-background-hover: @color-grey-theme_2-hover;
@ -538,7 +556,7 @@
@color-ming-theme: #336e7b;
@color-ming-theme-bgimg: none;
@color-ming-theme-bgposition: center;
@color-ming-theme-bgsize: auto auto;
@color-ming-theme-bgsize: cover;
@color-ming-theme-hover: fadeout(lighten(@color-ming-theme, 7%), 30%);
@color-ming-theme-active: fadeout(darken(@color-ming-theme, 20%), 60%);
@color-ming-theme-font: #fff;
@ -574,6 +592,8 @@
@color-ming-player-progress-bar1: darken(@color-ming-theme_2, 12%);
@color-ming-player-progress-bar2: lighten(@color-ming-theme, 12%);
@color-ming-player-status-text: lighten(@color-ming-theme_2-font, 32%);
@color-ming-player-detail-lyric: fadeout(@color-ming-theme_2-font, 50%);
@color-ming-player-detail-lyric-active: lighten(@color-ming-theme, 2%);
@color-ming-player-detail-play-btn: lighten(@color-ming-theme, 10%);
@color-ming-tab-border-top: fadeout(lighten(@color-ming-theme, 25%), 70%);
@color-ming-tab-border-bottom: lighten(@color-ming-theme, 35%);
@ -598,7 +618,7 @@
@color-blue2-theme: #4f62d0;
@color-blue2-theme-bgimg: none;
@color-blue2-theme-bgposition: center;
@color-blue2-theme-bgsize: auto auto;
@color-blue2-theme-bgsize: cover;
@color-blue2-theme-hover: fadeout(lighten(@color-blue2-theme, 10%), 30%);
@color-blue2-theme-active: fadeout(darken(@color-blue2-theme, 20%), 60%);
@color-blue2-theme-font: #fff;
@ -634,6 +654,8 @@
@color-blue2-player-progress-bar1: darken(@color-blue2-theme_2, 12%);
@color-blue2-player-progress-bar2: lighten(@color-blue2-theme, 12%);
@color-blue2-player-status-text: lighten(@color-blue2-theme_2-font, 32%);
@color-blue2-player-detail-lyric: fadeout(@color-blue2-theme_2-font, 50%);
@color-blue2-player-detail-lyric-active: darken(@color-blue2-theme, 2%);
@color-blue2-player-detail-play-btn: lighten(@color-blue2-theme, 7%);
@color-blue2-tab-btn-background: fadeout(lighten(@color-blue2-theme, 10%), 80%);
@color-blue2-tab-btn-background-hover: @color-blue2-theme_2-hover;
@ -653,6 +675,66 @@
@color-blue2-badge-info-font: #fff;
@color-black-theme: #272727;
@color-black-theme-bgimg: url(../images/landingMoon.png);
@color-black-theme-bgposition: center;
@color-black-theme-bgsize: cover;
@color-black-theme-hover: fadeout(lighten(@color-black-theme, 13%), 30%);
@color-black-theme-active: fadeout(lighten(@color-black-theme, 8%), 30%);
@color-black-theme-font: lighten(@color-black-theme, 55%);
@color-black-theme-font-label: lighten(@color-black-theme, 35%);
@color-black-theme_2: rgba(19, 19, 19, 0.82);
@color-black-theme_2-background_1: #080808;
@color-black-theme_2-background_2: #1f1f1f;
@color-black-theme_2-hover: fadeout(lighten(@color-black-theme, 10%), 80%);
@color-black-theme_2-active: fadeout(lighten(@color-black-theme, 10%), 70%);
@color-black-theme_2-font: lighten(@color-black-theme_2, 73%);
@color-black-theme_2-font-label: darken(@color-black-theme_2-font, 30%);
// @color-black-theme_2-line: transparent;
@color-black-theme_2-line: lighten(@color-black-theme_2, 3.2%);
@color-black-reply-floor: fadeout(lighten(@color-black-theme, 60%), 95%);
@color-black-theme-sidebar: @color-black-theme;
@color-black-btn: lighten(@color-black-theme, 40%);
@color-black-btn-background: fadeout(lighten(@color-black-theme, 30%), 70%);
@color-black-btn-hover: fadeout(lighten(@color-black-theme, 40%), 70%);
@color-black-btn-active: fadeout(lighten(@color-black-theme, 20%), 70%);
@color-black-btn-select: fadeout(lighten(@color-black-theme, 25%), 70%);
@color-black-pagination-background: fadeout(darken(@color-black-theme, 15%), 50%);
@color-black-pagination-hover: fadeout(lighten(@color-black-theme, 1%), 70%);
@color-black-pagination-active: fadeout(darken(@color-black-theme, 5%), 60%);
@color-black-pagination-select: fadeout(darken(@color-black-theme, 3%), 60%);
@color-black-search-form-background: fadeout(lighten(@color-black-theme, 8%), 6%);
@color-black-search-list-hover: fadeout(darken(@color-black-theme, 10%), 70%);
@color-black-scrollbar-track: fadeout(lighten(@color-black-theme, 10%), 75%);
@color-black-scrollbar-thumb: fadeout(lighten(@color-black-theme, 10%), 50%);
@color-black-scrollbar-thumb-hover: fadeout(lighten(@color-black-theme, 10%), 35%);
@color-black-player-pic-c1: fadeout(@color-black-theme_2, 50%);
@color-black-player-pic-c2: lighten(@color-black-theme_2, 30%);
@color-black-player-progress: lighten(@color-black-theme_2, 6%);
@color-black-player-progress-bar1: lighten(@color-black-theme_2, 12%);
@color-black-player-progress-bar2: lighten(@color-black-theme, 12%);
@color-black-player-status-text: darken(@color-black-theme_2-font, 20%);
@color-black-player-detail-lyric: fadeout(darken(@color-black-theme_2-font, 30%), 10%);
@color-black-player-detail-lyric-active: lighten(@color-black-theme, 50%);
@color-black-player-detail-play-btn: lighten(@color-black-theme, 30%);
@color-black-tab-btn-background: fadeout(lighten(@color-black-theme, 10%), 80%);
@color-black-tab-btn-background-hover: @color-black-theme_2-hover;
@color-black-tab-border-top: fadeout(lighten(@color-black-theme, 5%), 50%);
@color-black-tab-border-bottom: lighten(@color-black-theme, 5%);
@color-black-hideBtn: #4e4e4e;
@color-black-minBtn: #5e5e5e;
@color-black-maxBtn: #535353;
@color-black-closeBtn: #6e6e6e;
@color-black-hideBtn-hover: fadeout(@color-hideBtn, 10%);
@color-black-minBtn-hover: fadeout(@color-black-minBtn, 10%);
@color-black-maxBtn-hover: fadeout(@color-black-maxBtn, 10%);
@color-black-closeBtn-hover: fadeout(@color-black-closeBtn, 10%);
@color-black-badge-success: lighten(@color-black-theme, 10%);
@color-black-badge-success-font: #fff;
@color-black-badge-info: lighten(@color-black-theme, 25%);
@color-black-badge-info-font: #fff;
@color-mid_autumn-theme: rgba(74, 55, 82, 1);
@color-mid_autumn-theme-bgimg: url(../images/jqbg.jpg);
@color-mid_autumn-theme-bgposition: center;
@ -692,6 +774,8 @@
@color-mid_autumn-player-progress-bar1: darken(@color-mid_autumn-theme_2, 12%);
@color-mid_autumn-player-progress-bar2: lighten(@color-mid_autumn-theme, 12%);
@color-mid_autumn-player-status-text: lighten(@color-mid_autumn-theme_2-font, 32%);
@color-mid_autumn-player-detail-lyric: fadeout(@color-mid_autumn-theme_2-font, 40%);
@color-mid_autumn-player-detail-lyric-active: lighten(@color-mid_autumn-theme, 7%);
@color-mid_autumn-player-detail-play-btn: lighten(@color-mid_autumn-theme, 7%);
@color-mid_autumn-tab-btn-background: fadeout(lighten(@color-mid_autumn-theme, 10%), 80%);
@color-mid_autumn-tab-btn-background-hover: @color-mid_autumn-theme_2-hover;
@ -750,6 +834,8 @@
@color-mid_autumn-player-progress-bar1: darken(@color-mid_autumn-theme_2, 12%);
@color-mid_autumn-player-progress-bar2: lighten(@color-mid_autumn-theme, 12%);
@color-mid_autumn-player-status-text: lighten(@color-mid_autumn-theme_2-font, 32%);
@color-mid_autumn-player-detail-lyric: lighten(@color-mid_autumn-theme, 7%);
@color-mid_autumn-player-detail-lyric-active: lighten(@color-mid_autumn-theme, 7%);
@color-mid_autumn-player-detail-play-btn: lighten(@color-mid_autumn-theme, 7%);
@color-mid_autumn-tab-btn-background: fadeout(lighten(@color-mid_autumn-theme, 10%), 80%);
@color-mid_autumn-tab-btn-background-hover: @color-mid_autumn-theme_2-hover;
@ -807,6 +893,8 @@
@color-naruto-player-progress-bar1: darken(@color-naruto-theme_2, 12%);
@color-naruto-player-progress-bar2: lighten(@color-naruto-theme, 12%);
@color-naruto-player-status-text: lighten(@color-naruto-theme_2-font, 32%);
@color-naruto-player-detail-lyric: fadeout(@color-naruto-theme_2-font, 36%);
@color-naruto-player-detail-lyric-active: darken(@color-naruto-theme, 7%);
@color-naruto-player-detail-play-btn: lighten(@color-naruto-theme, 7%);
@color-naruto-tab-btn-background: fadeout(lighten(@color-naruto-theme, 10%), 80%);
@color-naruto-tab-btn-background-hover: @color-naruto-theme_2-hover;
@ -864,6 +952,8 @@
@color-happy_new_year-player-progress-bar1: darken(@color-happy_new_year-theme_2, 12%);
@color-happy_new_year-player-progress-bar2: lighten(@color-happy_new_year-theme, 9%);
@color-happy_new_year-player-status-text: lighten(@color-happy_new_year-theme_2-font, 32%);
@color-happy_new_year-player-detail-lyric: fadeout(@color-happy_new_year-theme_2-font, 40%);
@color-happy_new_year-player-detail-lyric-active: darken(@color-happy_new_year-theme, 2%);
@color-happy_new_year-player-detail-play-btn: lighten(@color-happy_new_year-theme, 7%);
@color-happy_new_year-tab-btn-background: fadeout(lighten(@color-happy_new_year-theme, 10%), 80%);
@color-happy_new_year-tab-btn-background-hover: @color-happy_new_year-theme_2-hover;

View File

@ -272,13 +272,14 @@ export default {
'setting.player.mediaDeviceId'(n) {
this.setMediaDevice()
},
'setting.player.isShowLyricTransition'() {
'setting.player.isShowLyricTranslation'() {
this.setLyric()
},
'setting.player.isPlayLxlrc'() {
this.setLyric()
},
async list(n, o) {
if (this.playInfo.isTempPlay) return
if (n === o && this.musicInfo.songmid) {
let index = this.listId == 'download'
? n.findIndex(s => s.musicInfo.songmid === this.musicInfo.songmid)
@ -607,7 +608,7 @@ export default {
if (!retryedSource.includes(targetSong.source)) retryedSource.push(targetSong.source)
let type = this.getPlayType(this.setting.player.highQuality, targetSong)
this.musicInfo.url = targetSong.typeUrl[type]
// this.musicInfo.url = await getMusicUrl(targetSong, type)
this.status = this.statusText = this.$t('core.player.geting_url')
return this.getUrl({ musicInfo: targetSong, originMusic, type, isRefresh }).then(url => {
@ -646,10 +647,10 @@ export default {
}
},
setLrc(targetSong) {
this.getLrc(targetSong).then(() => {
this.musicInfo.lrc = targetSong.lrc
this.musicInfo.tlrc = targetSong.tlrc
this.musicInfo.lxlrc = targetSong.lxlrc
this.getLrc(targetSong).then(({ lyric, tlyric, lxlyric }) => {
this.musicInfo.lrc = lyric
this.musicInfo.tlrc = tlyric
this.musicInfo.lxlrc = lxlyric
}).catch(() => {
this.status = this.statusText = this.$t('core.player.lyric_error')
}).finally(() => {
@ -860,9 +861,9 @@ export default {
setLyric() {
window.lrc.setLyric(
this.setting.player.isPlayLxlrc && this.musicInfo.lxlrc ? this.musicInfo.lxlrc : this.musicInfo.lrc,
this.setting.player.isShowLyricTransition && this.musicInfo.tlrc ? this.musicInfo.tlrc : '',
this.setting.player.isShowLyricTranslation && this.musicInfo.tlrc ? this.musicInfo.tlrc : '',
// (
// this.setting.player.isShowLyricTransition && this.musicInfo.tlrc
// this.setting.player.isShowLyricTranslation && this.musicInfo.tlrc
// ? (this.musicInfo.tlrc + '\n')
// : ''
// ) + (this.musicInfo.lrc || ''),
@ -1057,7 +1058,7 @@ export default {
height: 100%;
border-radius: @radius-progress-border;
transition-duration: 0.2s;
background-color: @color-theme;
background-color: @color-btn;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
}
@ -1075,14 +1076,14 @@ export default {
margin-left: 5px;
height: 100%;
width: 20px;
color: @color-theme;
color: @color-btn;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
transition: opacity 0.2s ease;
opacity: .5;
opacity: .6;
cursor: pointer;
svg {
@ -1226,10 +1227,10 @@ each(@themes, {
// }
}
.titleBtn {
color: ~'@{color-@{value}-theme}';
color: ~'@{color-@{value}-btn}';
}
.play-btn {
color: ~'@{color-@{value}-theme}';
color: ~'@{color-@{value}-btn}';
svg {
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.3));
}
@ -1239,7 +1240,7 @@ each(@themes, {
}
.volume-bar {
background-color: ~'@{color-@{value}-theme}';
background-color: ~'@{color-@{value}-btn}';
}

View File

@ -579,7 +579,6 @@ export default {
overflow: hidden;
font-size: 16px;
cursor: grab;
color: @color-theme_2-font;
&.draging {
cursor: grabbing;
}
@ -588,11 +587,12 @@ export default {
line-height: 1.2;
margin: 16px 0;
overflow-wrap: break-word;
color: @color-player-detail-lyric;
.translation {
transition: @transition-theme !important;
transition-property: font-size, color;
font-size: 1em;
font-size: .9em;
margin-top: 5px;
}
.line {
@ -606,7 +606,7 @@ export default {
color: @color-theme;
}
.translation {
font-size: 1.2em;
font-size: 1em;
color: @color-theme;
}
span {
@ -833,17 +833,19 @@ each(@themes, {
.lyric {
:global {
.lrc-content {
color: ~'@{color-@{value}-player-detail-lyric}';
&.active {
.translation {
color: ~'@{color-@{value}-theme}';
color: ~'@{color-@{value}-player-detail-lyric-active}';
}
.line {
color: ~'@{color-@{value}-theme}';
color: ~'@{color-@{value}-player-detail-lyric-active}';
}
}
span {
// background-color: ~'@{color-@{value}-theme_2-font}';
background-image: -webkit-linear-gradient(top, ~'@{color-@{value}-theme}', ~'@{color-@{value}-theme}');
background-color: ~'@{color-@{value}-player-detail-lyric}';
background-image: -webkit-linear-gradient(top, ~'@{color-@{value}-player-detail-lyric-active}', ~'@{color-@{value}-player-detail-lyric-active}');
}
}
}

View File

@ -80,7 +80,7 @@ export default {
watch: {
'setting.isAgreePact'(n) {
if (n) return
this.time = 10
this.time = 5
this.startTimeout()
},
},

View File

@ -155,7 +155,7 @@ export default {
background-color: @color-theme_2-background_2;
opacity: 0;
transform: scaleY(0) translateY(0);
transform-origin: 0 @selection-height / 2 0;
transform-origin: 0 (@selection-height / 2) 0;
transition: .25s ease;
transition-property: transform, opacity;
z-index: 10;

View File

@ -46,7 +46,7 @@ material-modal(:show="version.showModal" @close="handleClose" v-if="version.newV
| 你可以去&nbsp;
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
| &nbsp;&nbsp;
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoux.com/b0bf2cfa/')" tips="点击打开") 网盘
strong.hover.underline(@click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')" tips="点击打开") 网盘
| (密码
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
| )&nbsp;下载新版本
@ -63,7 +63,7 @@ material-modal(:show="version.showModal" @close="handleClose" v-if="version.newV
| 你可以去
material-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
material-btn(min @click="handleOpenUrl('https://www.lanzoux.com/b0bf2cfa/')" tips="点击打开") 网盘
material-btn(min @click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')" tips="点击打开") 网盘
| (密码
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
| )下载新版本
@ -84,7 +84,7 @@ material-modal(:show="version.showModal" @close="handleClose" v-if="version.newV
| 检查方法打开
material-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
material-btn(min @click="handleOpenUrl('https://www.lanzoux.com/b0bf2cfa/')" tips="点击打开") 网盘
material-btn(min @click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')" tips="点击打开") 网盘
| (密码
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
| )查看它们的
@ -117,7 +117,7 @@ material-modal(:show="version.showModal" @close="handleClose" v-if="version.newV
| 手动更新可以去&nbsp;
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
| &nbsp;&nbsp;
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoux.com/b0bf2cfa/')" tips="点击打开") 网盘
strong.hover.underline(@click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')" tips="点击打开") 网盘
| (密码
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
| )&nbsp;下载

View File

@ -9,6 +9,7 @@
"theme_grey": "Grey",
"theme_ming": "Ming",
"theme_blue2": "Purple Blue",
"theme_black": "Black",
"theme_mid_autumn": "Mid-Autumn",
"theme_naruto": "Naruto",
"theme_happy_new_year": "New Year",

View File

@ -73,6 +73,7 @@
"download_name1": "Title - Artist",
"download_name2": "Artist - Title",
"download_name3": "Title only",
"download_use_other_source": "Automatically change the source to download (when the song cannot be downloaded from the original source, try to switch to another source to download. Note: this function does not 100% guarantee that the version of the song after the source is changed is the same as the original version)",
"download_select_save_path": "Select the save path",
"hot_key": "Shortcut Key Settings",

View File

@ -9,6 +9,7 @@
"theme_grey": "灰常美丽",
"theme_ming": "青出于黑",
"theme_blue2": "清热版蓝",
"theme_black": "黑灯瞎火",
"theme_mid_autumn": "月里嫦娥",
"theme_naruto": "木叶之村",
"theme_happy_new_year": "新年快乐",
@ -33,6 +34,6 @@
"source_alias_all": "聚合大会",
"load_list_file_error_title": "播放列表数据加载错误",
"load_list_file_error_title": "播放列表数据加载错误建议到GitHub或加群反馈",
"load_list_file_error_detail": "我们已经帮你把旧的列表文件备份到{path}\n它以 JSON 格式存储,你可以尝试手动修复并恢复它\n\n错误详情{detail}"
}

View File

@ -73,6 +73,7 @@
"download_name1": "歌名 - 歌手",
"download_name2": "歌手 - 歌名",
"download_name3": "歌名",
"download_use_other_source": "自动换源下载当无法从歌曲的原始源下载时尝试切换到其他源下载此功能不100%保证换源后的歌曲版本与原版一致)",
"download_select_save_path": "选择歌曲保存路径",
"hot_key": "快捷键设置",

View File

@ -9,6 +9,7 @@
"theme_grey": "灰常美麗",
"theme_ming": "青出於黑",
"theme_blue2": "清熱版藍",
"theme_black": "黑燈瞎火",
"theme_mid_autumn": "月裡嫦娥",
"theme_naruto": "木葉之村",
"theme_happy_new_year": "新年快樂",

View File

@ -73,6 +73,7 @@
"download_name1": "歌名 - 歌手",
"download_name2": "歌手 - 歌名",
"download_name3": "歌名",
"download_use_other_source": "自動換源下載當無法從歌曲的原始源下載時嘗試切換到其他源下載此功能不100%保證換源後的歌曲版本與原版一致)",
"download_select_save_path": "選擇歌曲保存路徑",
"hot_key": "快捷鍵設置",

View File

@ -23,7 +23,7 @@ import { rendererSend, NAMES } from '../common/ipc'
sync(store, router)
Vue.config.productionTip = false
Vue.config.devtools = process.env.NODE_ENV === 'development'
getSetting().then(({ setting, version }) => {
// Set language automatically
@ -56,5 +56,7 @@ getSetting().then(({ setting, version }) => {
el: '#root',
render: h => h(App),
})
// window.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue = app.constructor
})

View File

@ -3,7 +3,15 @@ import fs from 'fs'
import path from 'path'
import music from '../../utils/music'
import { getMusicType } from '../../utils/music/utils'
import { setMeta, saveLrc } from '../../utils'
import {
setMeta,
saveLrc,
getLyric as getLyricFromStorage,
setLyric,
getMusicUrl as getMusicUrlFormStorage,
setMusicUrl,
assertApiSupport,
} from '../../utils'
// state
const state = {
@ -147,15 +155,96 @@ const pauseTasks = async(store, list, runs = []) => {
await pauseTasks(store, list, runs)
}
const getUrl = (downloadInfo, isRefresh) => {
const url = downloadInfo.musicInfo.typeUrl[downloadInfo.type]
const handleGetMusicUrl = function(musicInfo, type, retryedSource = [], originMusic) {
// console.log(musicInfo.source)
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getMusicUrl(musicInfo, type).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source) || !assertApiSupport(musicInfo.source)) retryedSource.push(musicInfo.source)
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return handleGetMusicUrl.call(this, item, type, retryedSource, originMusic)
}
}
return Promise.reject(err)
})
})
}
const getMusicUrl = async function(downloadInfo, isUseOtherSource, isRefresh) {
const cachedUrl = await getMusicUrlFormStorage(downloadInfo.musicInfo, downloadInfo.type)
if (!downloadInfo.musicInfo._types[downloadInfo.type]) {
// 兼容旧版酷我源搜索列表过滤128k音质的bug
if (!(downloadInfo.musicInfo.source == 'kw' && downloadInfo.type == '128k')) return Promise.reject(new Error('该歌曲没有可下载的音频'))
if (!(downloadInfo.musicInfo.source == 'kw' && downloadInfo.type == '128k')) throw new Error('该歌曲没有可下载的音频')
// return Promise.reject(new Error('该歌曲没有可下载的音频'))
}
return url && !isRefresh ? Promise.resolve({ url }) : music[downloadInfo.musicInfo.source].getMusicUrl(downloadInfo.musicInfo, downloadInfo.type).promise
return cachedUrl && !isRefresh
? cachedUrl
: (
isUseOtherSource
? handleGetMusicUrl.call(this, downloadInfo.musicInfo, downloadInfo.type)
: music[downloadInfo.musicInfo.source].getMusicUrl(downloadInfo.musicInfo, downloadInfo.type).promise
).then(({ url }) => {
setMusicUrl(downloadInfo.musicInfo, downloadInfo.type, url)
return url
})
}
const getPic = function(musicInfo, retryedSource = [], originMusic) {
// console.log(musicInfo.source)
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getPic(musicInfo).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return getPic.call(this, item, retryedSource, originMusic)
}
}
return Promise.reject(err)
})
})
}
const getLyric = function(musicInfo, retryedSource = [], originMusic) {
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getLyric(musicInfo).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return getLyric.call(this, item, retryedSource, originMusic)
}
}
return Promise.reject(err)
})
})
}
// 修复 1.1.x版本 酷狗源歌词格式
@ -167,24 +256,37 @@ const fixKgLyric = lrc => /\[00:\d\d:\d\d.\d+\]/.test(lrc) ? lrc.replace(/(?:\[0
* @param {*} filePath
* @param {*} isEmbedPic // 是否嵌入图片
*/
const saveMeta = (downloadInfo, filePath, isEmbedPic, isEmbedLyric) => {
const saveMeta = function(downloadInfo, filePath, isUseOtherSource, isEmbedPic, isEmbedLyric) {
if (downloadInfo.type === 'ape') return
const tasks = [
isEmbedPic
? downloadInfo.musicInfo.img
? Promise.resolve(downloadInfo.musicInfo.img)
: music[downloadInfo.musicInfo.source].getPic(downloadInfo.musicInfo).promise.catch(err => {
: (
isUseOtherSource
? getPic.call(this, downloadInfo.musicInfo)
: music[downloadInfo.musicInfo.source].getPic(downloadInfo.musicInfo).promise
).catch(err => {
console.log(err)
return null
})
: Promise.resolve(),
isEmbedLyric
? downloadInfo.musicInfo.lrc
? Promise.resolve({ lyric: downloadInfo.musicInfo.lrc, tlyric: downloadInfo.musicInfo.tlrc || '' })
: music[downloadInfo.musicInfo.source].getLyric(downloadInfo.musicInfo).promise.catch(err => {
console.log(err)
return null
})
? getLyricFromStorage(downloadInfo.musicInfo).then(lrcInfo => {
return lrcInfo.lyric
? Promise.resolve({ lyric: lrcInfo.lyric, tlyric: lrcInfo.tlyric || '' })
: (
isUseOtherSource
? getLyric.call(this, downloadInfo.musicInfo)
: music[downloadInfo.musicInfo.source].getLyric(downloadInfo.musicInfo).promise
).then(({ lyric, tlyric, lxlyric }) => {
setLyric(downloadInfo.musicInfo, { lyric, tlyric, lxlyric })
return { lyric, tlyric, lxlyric }
}).catch(err => {
console.log(err)
return null
})
})
: Promise.resolve(),
]
Promise.all(tasks).then(([imgUrl, lyrics = {}]) => {
@ -205,9 +307,14 @@ const saveMeta = (downloadInfo, filePath, isEmbedPic, isEmbedLyric) => {
* @param {*} filePath
*/
const downloadLyric = (downloadInfo, filePath) => {
const promise = downloadInfo.musicInfo.lrc
? Promise.resolve({ lyric: downloadInfo.musicInfo.lrc, tlyric: downloadInfo.musicInfo.tlrc || '' })
: music[downloadInfo.musicInfo.source].getLyric(downloadInfo.musicInfo).promise
const promise = getLyric(downloadInfo.musicInfo).then(lrcInfo => {
return lrcInfo.lyric
? Promise.resolve({ lyric: lrcInfo.lyric, tlyric: lrcInfo.tlyric || '' })
: music[downloadInfo.musicInfo.source].getLyric(downloadInfo.musicInfo).promise.then(({ lyric, tlyric, lxlyric }) => {
setLyric(downloadInfo.musicInfo, { lyric, tlyric, lxlyric })
return { lyric, tlyric, lxlyric }
})
})
promise.then(lrcs => {
if (lrcs.lyric) {
lrcs.lyric = fixKgLyric(lrcs.lyric)
@ -216,14 +323,14 @@ const downloadLyric = (downloadInfo, filePath) => {
})
}
const refreshUrl = function(commit, downloadInfo) {
const refreshUrl = function(commit, downloadInfo, isUseOtherSource) {
commit('setStatusText', { downloadInfo, text: '链接失效,正在刷新链接' })
getUrl(downloadInfo, true).then(result => {
commit('updateUrl', { downloadInfo, url: result.url })
getMusicUrl.call(this, downloadInfo, isUseOtherSource, true).then(url => {
commit('updateUrl', { downloadInfo, url })
commit('setStatusText', { downloadInfo, text: '链接刷新成功' })
const dl = dls[downloadInfo.key]
if (!dl) return
dl.refreshUrl(result.url)
dl.refreshUrl(url)
dl.start().catch(err => {
commit('onError', { downloadInfo, errorMsg: err.message })
commit('setStatusText', { downloadInfo, text: err.message })
@ -326,7 +433,7 @@ const actions = {
commit('onCompleted', downloadInfo)
dispatch('startTask')
saveMeta(downloadInfo, downloadInfo.filePath, rootState.setting.download.isEmbedPic, rootState.setting.download.isEmbedLyric)
saveMeta.call(_this, downloadInfo, downloadInfo.filePath, rootState.setting.download.isUseOtherSource, rootState.setting.download.isEmbedPic, rootState.setting.download.isEmbedLyric)
if (rootState.setting.download.isDownloadLrc) downloadLyric(downloadInfo, downloadInfo.filePath)
console.log('on complate')
},
@ -343,7 +450,8 @@ const actions = {
return
}
if (err.code == 'ENOTFOUND') {
refreshUrl.call(_this, commit, downloadInfo)
commit('onError', { downloadInfo, errorMsg: '链接失效' })
refreshUrl.call(_this, commit, downloadInfo, rootState.setting.download.isUseOtherSource)
} else {
console.log('Download failed, Attempting Retry')
dls[downloadInfo.key].start()
@ -360,7 +468,13 @@ const actions = {
case 401:
case 403:
case 410:
refreshUrl.call(_this, commit, downloadInfo)
commit('onError', { downloadInfo, errorMsg: '链接失效' })
refreshUrl.call(_this, commit, downloadInfo, rootState.setting.download.isUseOtherSource)
break
default:
dls[downloadInfo.key].start()
commit('setStatusText', { downloadInfo, text: '正在重试' })
break
}
},
onStart() {
@ -379,10 +493,10 @@ const actions = {
commit('setStatusText', { downloadInfo, text: '获取URL中...' })
let p = options.url
? Promise.resolve()
: getUrl(downloadInfo).then(result => {
commit('updateUrl', { downloadInfo, url: result.url })
if (!result.url) return Promise.reject(new Error('获取URL失败'))
options.url = result.url
: getMusicUrl.call(this, downloadInfo, rootState.setting.download.isUseOtherSource).then(url => {
commit('updateUrl', { downloadInfo, url })
if (!url) return Promise.reject(new Error('获取URL失败'))
options.url = url
})
p.then(() => {
tryNum[downloadInfo.key] = 0

View File

@ -1,4 +1,5 @@
import musicSdk from '../../utils/music'
import { clearLyric, clearMusicUrl } from '../../utils'
let allList = {}
window.allList = allList
@ -207,9 +208,15 @@ const mutations = {
if (item.typeUrl['320k']) delete item.typeUrl['320k']
if (item.typeUrl.flac) delete item.typeUrl.flac
if (item.typeUrl.wav) delete item.typeUrl.wav
// if (item.lxlrc == '') item.lxlrc = null
// v1.8.2以前的Lyric
if (item.lxlrc) delete item.lxlrc
if (item.lrc) delete item.lrc
if (item.tlrc) delete item.tlrc
}
}
clearMusicUrl()
clearLyric()
},
setOtherSource(state, { musicInfo, otherSource }) {
musicInfo.otherSource = otherSource

View File

@ -1,6 +1,13 @@
import path from 'path'
import music from '../../utils/music'
import { getRandom, checkPath } from '../../utils'
import {
getRandom,
checkPath,
getLyric as getStoreLyric,
setLyric,
setMusicUrl,
getMusicUrl,
} from '../../utils'
// state
const state = {
@ -17,9 +24,6 @@ const state = {
tempPlayList: [],
}
let urlRequest
// let picRequest
// let lrcRequest
const filterList = async({ playedList, listInfo, savePath, commit }) => {
// if (this.list.listName === null) return
@ -64,10 +68,16 @@ const filterList = async({ playedList, listInfo, savePath, commit }) => {
const getPic = function(musicInfo, retryedSource = [], originMusic) {
// console.log(musicInfo.source)
return music[musicInfo.source].getPic(musicInfo).promise.catch(err => {
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getPic(musicInfo).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
return this.dispatch('list/getOtherSource', musicInfo).then(otherSource => {
if (!originMusic) originMusic = musicInfo
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
@ -81,10 +91,16 @@ const getPic = function(musicInfo, retryedSource = [], originMusic) {
})
}
const getLyric = function(musicInfo, retryedSource = [], originMusic) {
return music[musicInfo.source].getLyric(musicInfo).promise.catch(err => {
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getLyric(musicInfo).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
return this.dispatch('list/getOtherSource', musicInfo).then(otherSource => {
if (!originMusic) originMusic = musicInfo
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
@ -147,27 +163,27 @@ const getters = {
// actions
const actions = {
getUrl({ commit, state }, { musicInfo, originMusic, type, isRefresh }) {
async getUrl({ commit, state }, { musicInfo, originMusic, type, isRefresh }) {
if (!musicInfo._types[type]) {
// 兼容旧版酷我源搜索列表过滤128k音质的bug
if (!(musicInfo.source == 'kw' && type == '128k')) return Promise.reject(new Error('该歌曲没有可播放的音频'))
if (!(musicInfo.source == 'kw' && type == '128k')) throw new Error('该歌曲没有可播放的音频')
// return Promise.reject(new Error('该歌曲没有可播放的音频'))
}
if (urlRequest && urlRequest.cancelHttp) urlRequest.cancelHttp()
if (musicInfo.typeUrl[type] && !isRefresh) return Promise.resolve(musicInfo.typeUrl[type])
const cachedUrl = await getMusicUrl(musicInfo, type)
if (cachedUrl && !isRefresh) return cachedUrl
let reqPromise
try {
urlRequest = music[musicInfo.source].getMusicUrl(musicInfo, type)
reqPromise = music[musicInfo.source].getMusicUrl(musicInfo, type).promise
} catch (err) {
return Promise.reject(err)
reqPromise = Promise.reject(err)
}
return urlRequest.promise.then(({ url }) => {
return reqPromise.then(({ url }) => {
if (originMusic) commit('setUrl', { musicInfo: originMusic, url, type })
commit('setUrl', { musicInfo, url, type })
urlRequest = null
return url
}).catch(err => {
urlRequest = null
return Promise.reject(err)
})
},
@ -182,26 +198,26 @@ const actions = {
return Promise.reject(err)
})
},
getLrc({ commit, state }, musicInfo) {
async getLrc({ commit, state }, musicInfo) {
const lrcInfo = await getStoreLyric(musicInfo)
// if (lrcRequest && lrcRequest.cancelHttp) lrcRequest.cancelHttp()
if (musicInfo.lrc && musicInfo.tlrc != null) {
if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) {
let str = musicInfo.lrc.replace('\ufeff[id:$00000000]\n', '')
commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
} else if (musicInfo.lrc.startsWith('[id:$00000000]')) {
let str = musicInfo.lrc.replace('[id:$00000000]\n', '')
commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
}
if (lrcInfo.lyric && lrcInfo.tlyric != null) {
// if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) {
// let str = musicInfo.lrc.replace('\ufeff[id:$00000000]\n', '')
// commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
// } else if (musicInfo.lrc.startsWith('[id:$00000000]')) {
// let str = musicInfo.lrc.replace('[id:$00000000]\n', '')
// commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
// }
if ((musicInfo.lxlrc == null && musicInfo.source != 'kg') || musicInfo.lxlrc != null) {
return Promise.resolve()
}
if ((lrcInfo.lxlyric == null && musicInfo.source != 'kg') || lrcInfo.lxlyric != null) return lrcInfo
}
// lrcRequest = music[musicInfo.source].getLyric(musicInfo)
return getLyric.call(this, musicInfo).then(({ lyric, tlyric, lxlyric }) => {
// lrcRequest = null
commit('setLrc', { musicInfo, lyric, tlyric, lxlyric })
return { lyric, tlyric, lxlyric }
}).catch(err => {
// lrcRequest = null
return Promise.reject(err)
@ -328,16 +344,21 @@ const actions = {
// mitations
const mutations = {
setUrl(state, datas) {
datas.musicInfo.typeUrl = Object.assign({}, datas.musicInfo.typeUrl, { [datas.type]: datas.url })
setUrl(state, { musicInfo, type, url }) {
setMusicUrl(musicInfo, type, url)
},
getPic(state, datas) {
datas.musicInfo.img = datas.url
},
setLrc(state, datas) {
datas.musicInfo.lrc = datas.lyric
datas.musicInfo.tlrc = datas.tlyric
datas.musicInfo.lxlrc = datas.lxlyric
// datas.musicInfo.lrc = datas.lyric
// datas.musicInfo.tlrc = datas.tlyric
// datas.musicInfo.lxlrc = datas.lxlyric
setLyric(datas.musicInfo, {
lyric: datas.lyric,
tlyric: datas.tlyric,
lxlyric: datas.lxlyric,
})
},
setList(state, { list, index }) {
state.playMusicInfo = {
@ -391,7 +412,7 @@ const mutations = {
playIndex = -1
} else {
let listId = playMusicInfo.listId
if (listId != '__temp__' && listId === state.listInfo.id) playIndex = state.listInfo.list.indexOf(state.playMusicInfo.musicInfo)
if (listId != '__temp__' && listId === state.listInfo.id) playIndex = state.listInfo.list.indexOf(playMusicInfo.musicInfo)
}
state.playMusicInfo = playMusicInfo

View File

@ -167,7 +167,7 @@ const mutations = {
list.push(...source.list)
pages.push(source.allPage)
total += source.total
limit += source.limit
// limit = Math.max(source.limit, limit)
}
state.allPage = Math.max(...pages)
state.total = total

View File

@ -57,6 +57,11 @@ export default {
name: '青出于黑',
class: 'blue2',
},
{
id: 13,
name: '黑纸白字',
class: 'black',
},
{
id: 7,
name: '月里嫦娥',

View File

@ -371,7 +371,7 @@ export const clearCache = () => rendererInvoke(NAMES.mainWindow.clear_cache)
export const setWindowSize = (width, height) => rendererSend(NAMES.mainWindow.set_window_size, { width, height })
export const getProxyInfo = () => window.globalObj.proxy.enable
export const getProxyInfo = () => window.globalObj.proxy.enable && window.globalObj.proxy.host
? `http://${window.globalObj.proxy.username}:${window.globalObj.proxy.password}@${window.globalObj.proxy.host}:${window.globalObj.proxy.port};`
: undefined
@ -379,7 +379,7 @@ export const getProxyInfo = () => window.globalObj.proxy.enable
export const assertApiSupport = source => window.globalObj.qualityList[source] != undefined
export const getSetting = () => rendererInvoke(NAMES.mainWindow.get_setting)
export const saveSetting = () => rendererInvoke(NAMES.mainWindow.set_app_setting)
export const saveSetting = setting => rendererInvoke(NAMES.mainWindow.set_app_setting, setting)
export const getPlayList = () => rendererInvoke(NAMES.mainWindow.get_playlist).catch(error => {
rendererInvoke(NAMES.mainWindow.get_data_path).then(dataPath => {
@ -407,3 +407,17 @@ export const parseUrlParams = str => {
}
return params
}
export const getLyric = musicInfo => rendererInvoke(NAMES.mainWindow.get_lyric, `${musicInfo.source}_${musicInfo.songmid}`)
export const setLyric = (musicInfo, { lyric, tlyric, lxlyric }) => rendererSend(NAMES.mainWindow.save_lyric, {
id: `${musicInfo.source}_${musicInfo.songmid}`,
lyrics: { lyric, tlyric, lxlyric },
})
export const clearLyric = () => rendererSend(NAMES.mainWindow.clear_lyric)
export const getMusicUrl = (musicInfo, type) => rendererInvoke(NAMES.mainWindow.get_music_url, `${musicInfo.source}_${musicInfo.songmid}_${type}`)
export const setMusicUrl = (musicInfo, type, url) => rendererSend(NAMES.mainWindow.save_music_url, {
id: `${musicInfo.source}_${musicInfo.songmid}_${type}`,
url,
})
export const clearMusicUrl = () => rendererSend(NAMES.mainWindow.clear_music_url)

View File

@ -139,6 +139,7 @@ module.exports = class Lyric {
return {
text: line.text.replace(fontTimeExp, ''),
time: line.time,
translation: line.translation,
dom_line: fontPlayer.lineContent,
}
})

View File

@ -92,8 +92,7 @@ export default {
// console.log(lowerCaseName, item.lowerCaseName)
if (
(
item.sortedSinger === sortedSinger &&
(item.lowerCaseName === lowerCaseName || item.interval === musicInfo.interval)
item.sortedSinger === sortedSinger && item.lowerCaseName === lowerCaseName
) ||
(
item.interval === musicInfo.interval && item.lowerCaseName === lowerCaseName &&
@ -107,6 +106,18 @@ export default {
return item
}
}
for (const item of res.list) {
item.sortedSinger = String(sortSingle(item.singer)).toLowerCase()
item.name = trimStr(item.name)
item.lowerCaseName = String(item.name).toLowerCase()
item.lowerCaseAlbumName = String(item.albumName).toLowerCase()
// console.log(lowerCaseName, item.lowerCaseName)
if (
item.sortedSinger === sortedSinger && item.interval === musicInfo.interval
) {
return item
}
}
return null
}).catch(_ => null))
}
@ -114,9 +125,9 @@ export default {
const newResult = []
if (result.length) {
newResult.push(...sortMusic(result, item => item.sortedSinger === sortedSinger && item.lowerCaseName === lowerCaseName && item.interval === musicInfo.interval))
newResult.push(...sortMusic(result, item => item.sortedSinger === sortedSinger && item.interval === musicInfo.interval))
newResult.push(...sortMusic(result, item => item.lowerCaseName === lowerCaseName && item.sortedSinger === sortedSinger && item.lowerCaseAlbumName === lowerCaseAlbumName))
newResult.push(...sortMusic(result, item => item.sortedSinger === sortedSinger && item.lowerCaseName === lowerCaseName))
newResult.push(...sortMusic(result, item => item.sortedSinger === sortedSinger && item.interval === musicInfo.interval))
for (const item of result) {
delete item.sortedSinger
delete item.lowerCaseName

View File

@ -16,7 +16,7 @@ export default {
if (!info) info = list.find(s => s.songId == songmid)
return info ? info.songId : null
},
async getComment(musicInfo, page = 1, limit = 20) {
async getComment(musicInfo, page = 1, limit = 10) {
if (this._requestObj) this._requestObj.cancelHttp()
if (!musicInfo.songId) {
let id = await this.getSongId(musicInfo)
@ -35,7 +35,7 @@ export default {
if (statusCode != 200 || body.returnCode !== '000000') throw new Error('获取评论失败')
return { source: 'mg', comments: this.filterComment(body.data.items), total: body.data.itemTotal, page, limit, maxPage: Math.ceil(body.data.itemTotal / limit) || 1 }
},
async getHotComment(musicInfo, page = 1, limit = 100) {
async getHotComment(musicInfo, page = 1, limit = 5) {
if (this._requestObj2) this._requestObj2.cancelHttp()
if (!musicInfo.songId) {
@ -55,7 +55,7 @@ export default {
if (statusCode != 200 || body.returnCode !== '000000') throw new Error('获取热门评论失败')
return { source: 'mg', comments: this.filterComment(body.data.items) }
},
async getReplyComment(musicInfo, replyId, page = 1, limit = 100) {
async getReplyComment(musicInfo, replyId, page = 1, limit = 10) {
if (this._requestObj2) this._requestObj2.cancelHttp()
const _requestObj2 = httpFetch(`https://music.migu.cn/v3/api/comment/listCommentsById?commentId=${replyId}&pageSize=${limit}&pageNo=${page}`, {
@ -75,7 +75,7 @@ export default {
time: item.createTime,
timeStr: dateFormat2(new Date(item.createTime).getTime()),
userName: item.author.name,
avatar: item.author.avatar,
avatar: item.author.avatar && item.author.avatar.startsWith('//') ? `http:${item.author.avatar}` : item.author.avatar,
userId: item.author.id,
likedCount: item.praiseCount,
replyNum: item.replyTotal,

View File

@ -5,9 +5,11 @@ export default {
_requestObj_tags: null,
_requestObj_list: null,
_requestObj_listDetail: null,
_requestObj_listDetailInfo: null,
limit_list: 10,
limit_song: 10000,
successCode: '000000',
cachedDetailInfo: {},
sortList: [
{
name: '推荐',
@ -66,11 +68,14 @@ export default {
return num
},
getListDetail(id, page, tryNum = 0) { // 获取歌曲列表内的音乐
getListDetailList(id, page, tryNum = 0) {
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
if (tryNum > 2) return Promise.reject(new Error('try max num'))
// https://h5.nf.migu.cn/app/v4/p/share/playlist/index.html?id=184187437&channel=0146921
if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
if (/playlist\/index\.html\?/.test(id)) {
id = id.replace(/.*(?:\?|&)id=(\d+)(?:&.*|$)/, '$1')
} else if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
this._requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id, page), { headers: this.defaultHeaders })
return this._requestObj_listDetail.promise.then(({ body }) => {
@ -83,16 +88,47 @@ export default {
limit: this.limit_song,
total: body.totalCount,
source: 'mg',
// info: {
// // name: body.result.info.list_title,
// // img: body.result.info.list_pic,
// // desc: body.result.info.list_desc,
// // author: body.result.info.userinfo.username,
// // play_count: this.formatPlayCount(body.result.listen_num),
// },
}
})
},
getListDetailInfo(id, tryNum = 0) {
if (this._requestObj_listDetailInfo) this._requestObj_listDetailInfo.cancelHttp()
if (tryNum > 2) return Promise.reject(new Error('try max num'))
if (this.cachedDetailInfo[id]) return Promise.resolve(this.cachedDetailInfo[id])
this._requestObj_listDetailInfo = httpFetch(`https://c.musicapp.migu.cn/MIGUM3.0/resource/playlist/v2.0?playlistId=${id}`, {
headers: this.defaultHeaders,
})
return this._requestObj_listDetailInfo.promise.then(({ body }) => {
if (body.code !== this.successCode) return this.getListDetail(id, ++tryNum)
// console.log(JSON.stringify(body))
// console.log(body)
const cachedDetailInfo = this.cachedDetailInfo[id] = {
name: body.data.title,
img: body.data.imgItem.img,
desc: body.data.summary,
author: body.data.ownerName,
play_count: this.formatPlayCount(body.data.opNumItem.playNum),
}
return cachedDetailInfo
})
},
getListDetail(id, page) { // 获取歌曲列表内的音乐
// https://h5.nf.migu.cn/app/v4/p/share/playlist/index.html?id=184187437&channel=0146921
if (/playlist\/index\.html\?/.test(id)) {
id = id.replace(/.*(?:\?|&)id=(\d+)(?:&.*|$)/, '$1')
} else if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
return Promise.all([
this.getListDetailList(id, page),
this.getListDetailInfo(id),
]).then(([listData, info]) => {
listData.info = info
return listData
})
},
filterListDetail(rawList) {
// console.log(rawList)
let ids = new Set()

View File

@ -1,5 +1,38 @@
import { httpFetch } from '../../request'
import { linuxapi } from './utils/crypto'
// import { decodeName } from '../..'
// const parseLyric = (str, lrc) => {
// if (!str) return ''
// str = str.replace(/\r/g, '')
// let lxlyric = str.replace(/\[((\d+),\d+)\].*/g, str => {
// let result = str.match(/\[((\d+),\d+)\].*/)
// let time = parseInt(result[2])
// let ms = time % 1000
// time /= 1000
// let m = parseInt(time / 60).toString().padStart(2, '0')
// time %= 60
// let s = parseInt(time).toString().padStart(2, '0')
// time = `${m}:${s}.${ms}`
// str = str.replace(result[1], time)
// let startTime = 0
// str = str.replace(/\(0,1\) /g, ' ').replace(/\(\d+,\d+\)/g, time => {
// const [start, end] = time.replace(/^\((\d+,\d+)\)$/, '$1').split(',')
// time = `<${parseInt(startTime + parseInt(start))},${end}>`
// startTime = parseInt(startTime + parseInt(end))
// return time
// })
// return str
// })
// lxlyric = decodeName(lxlyric)
// return lxlyric.trim()
// }
export default songmid => {
const requestObj = httpFetch('https://music.163.com/api/linux/forward', {
@ -21,6 +54,7 @@ export default songmid => {
return {
lyric: body.lrc.lyric,
tlyric: body.tlyric.lyric,
// lxlyric: parseLyric(body.klyric.lyric),
}
})
return requestObj

View File

@ -63,34 +63,34 @@ div(:class="$style.main")
material-checkbox(v-for="item in controlBtnPositionList" :key="item.id" :class="$style.gapLeft" :id="`setting_basic_control_btn_position_${item.id}`"
name="setting_basic_control_btn_position" need v-model="current_setting.controlBtnPosition" :value="item.id" :label="item.name")
dt#play {{$t('view.setting.play')}}
dd
div(:class="$style.gapTop")
material-checkbox(id="setting_player_save_play_time" v-model="current_setting.player.isSavePlayTime" :label="$t('view.setting.play_save_play_time')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_lyric_transition" v-model="current_setting.player.isShowLyricTransition" :label="$t('view.setting.play_lyric_transition')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_lyric_play_lxlrc" v-model="current_setting.player.isPlayLxlrc" :label="$t('view.setting.play_lyric_lxlrc')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_highQuality" v-model="current_setting.player.highQuality" :label="$t('view.setting.play_quality')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_showTaskProgess" v-model="current_setting.player.isShowTaskProgess" :label="$t('view.setting.play_task_bar')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_isMediaDeviceRemovedStopPlay" v-model="current_setting.player.isMediaDeviceRemovedStopPlay" :label="$t('view.setting.play_mediaDevice_remove_stop_play')")
dd(:tips="$t('view.setting.play_mediaDevice_title')")
h3#play_mediaDevice {{$t('view.setting.play_mediaDevice')}}
div
material-selection(:list="mediaDevices" :class="$style.gapLeft" v-model="current_setting.player.mediaDeviceId" item-key="deviceId" item-name="label")
dt#desktop_lyric {{$t('view.setting.desktop_lyric')}}
dd
div(:class="$style.gapTop")
material-checkbox(id="setting_desktop_lyric_enable" v-model="current_setting.desktopLyric.enable" :label="$t('view.setting.desktop_lyric_enable')")
div(:class="$style.gapTop")
material-checkbox(id="setting_desktop_lyric_lock" v-model="current_setting.desktopLyric.isLock" :label="$t('view.setting.desktop_lyric_lock')")
div(:class="$style.gapTop")
material-checkbox(id="setting_desktop_lyric_alwaysOnTop" v-model="current_setting.desktopLyric.isAlwaysOnTop" :label="$t('view.setting.desktop_lyric_always_on_top')")
div(:class="$style.gapTop")
material-checkbox(id="setting_desktop_lyric_lockScreen" v-model="current_setting.desktopLyric.isLockScreen" :label="$t('view.setting.desktop_lyric_lock_screen')")
dt#play {{$t('view.setting.play')}}
dd
div(:class="$style.gapTop")
material-checkbox(id="setting_player_save_play_time" v-model="current_setting.player.isSavePlayTime" :label="$t('view.setting.play_save_play_time')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_lyric_transition" v-model="current_setting.player.isShowLyricTranslation" :label="$t('view.setting.play_lyric_transition')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_lyric_play_lxlrc" v-model="current_setting.player.isPlayLxlrc" :label="$t('view.setting.play_lyric_lxlrc')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_highQuality" v-model="current_setting.player.highQuality" :label="$t('view.setting.play_quality')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_showTaskProgess" v-model="current_setting.player.isShowTaskProgess" :label="$t('view.setting.play_task_bar')")
div(:class="$style.gapTop")
material-checkbox(id="setting_player_isMediaDeviceRemovedStopPlay" v-model="current_setting.player.isMediaDeviceRemovedStopPlay" :label="$t('view.setting.play_mediaDevice_remove_stop_play')")
dd(:tips="$t('view.setting.play_mediaDevice_title')")
h3#play_mediaDevice {{$t('view.setting.play_mediaDevice')}}
div
material-selection(:list="mediaDevices" :class="$style.gapLeft" v-model="current_setting.player.mediaDeviceId" item-key="deviceId" item-name="label")
dt#desktop_lyric {{$t('view.setting.desktop_lyric')}}
dd
div(:class="$style.gapTop")
material-checkbox(id="setting_desktop_lyric_enable" v-model="current_setting.desktopLyric.enable" :label="$t('view.setting.desktop_lyric_enable')")
div(:class="$style.gapTop")
material-checkbox(id="setting_desktop_lyric_lock" v-model="current_setting.desktopLyric.isLock" :label="$t('view.setting.desktop_lyric_lock')")
div(:class="$style.gapTop")
material-checkbox(id="setting_desktop_lyric_alwaysOnTop" v-model="current_setting.desktopLyric.isAlwaysOnTop" :label="$t('view.setting.desktop_lyric_always_on_top')")
div(:class="$style.gapTop")
material-checkbox(id="setting_desktop_lyric_lockScreen" v-model="current_setting.desktopLyric.isLockScreen" :label="$t('view.setting.desktop_lyric_lock_screen')")
dt#search {{$t('view.setting.search')}}
dd
@ -122,6 +122,11 @@ div(:class="$style.main")
span.auto-hidden.hover(:tips="$t('view.setting.download_path_open_label')" :class="$style.savePath" @click="handleOpenDir(current_setting.download.savePath)") {{current_setting.download.savePath}}
p
material-btn(:class="$style.btn" min @click="handleChangeSavePath") {{$t('view.setting.download_path_change_btn')}}
dd
h3#download_name {{$t('view.setting.download_use_other_source')}}
div
material-checkbox(id="setting_download_isUseOtherSource" v-model="current_setting.download.isUseOtherSource" :label="$t('view.setting.is_enable')")
div
dd(:tips="$t('view.setting.download_name_title')")
h3#download_name {{$t('view.setting.download_name')}}
div
@ -169,11 +174,11 @@ div(:class="$style.main")
p
material-checkbox(id="setting_network_proxy_enable" v-model="current_setting.network.proxy.enable" @change="handleProxyChange('enable')" :label="$t('view.setting.is_enable')")
p
material-input(:class="$style.gapLeft" v-model="current_setting.network.proxy.host" @change="handleProxyChange('host')" :placeholder="$t('view.setting.network_proxy_host')")
material-input(:class="$style.gapLeft" v-model="current_setting.network.proxy.port" @change="handleProxyChange('port')" :placeholder="$t('view.setting.network_proxy_port')")
material-input(:class="$style.gapLeft" v-model.trim="current_setting.network.proxy.host" @change="handleProxyChange('host')" :placeholder="$t('view.setting.network_proxy_host')")
material-input(:class="$style.gapLeft" v-model.trim="current_setting.network.proxy.port" @change="handleProxyChange('port')" :placeholder="$t('view.setting.network_proxy_port')")
p
material-input(:class="$style.gapLeft" v-model="current_setting.network.proxy.username" @change="handleProxyChange('username')" :placeholder="$t('view.setting.network_proxy_username')")
material-input(:class="$style.gapLeft" v-model="current_setting.network.proxy.password" @change="handleProxyChange('password')" type="password" :placeholder="$t('view.setting.network_proxy_password')")
material-input(:class="$style.gapLeft" v-model.trim="current_setting.network.proxy.username" @change="handleProxyChange('username')" :placeholder="$t('view.setting.network_proxy_username')")
material-input(:class="$style.gapLeft" v-model.trim="current_setting.network.proxy.password" @change="handleProxyChange('password')" type="password" :placeholder="$t('view.setting.network_proxy_password')")
dt#odc {{$t('view.setting.odc')}}
dd
div(:class="$style.gapTop")
@ -232,7 +237,7 @@ div(:class="$style.main")
span.hover.underline(:tips="$t('view.setting.click_open')" @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop#readme')") https://github.com/lyswhut/lx-music-desktop
p.small
| 最新版网盘下载地址网盘内有WindowsMAC版
span.hover.underline(:tips="$t('view.setting.click_open')" @click="handleOpenUrl('https://www.lanzoux.com/b0bf2cfa/')") 网盘地址
span.hover.underline(:tips="$t('view.setting.click_open')" @click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')") 网盘地址
| &nbsp;&nbsp;密码
span.hover(:tips="$t('view.setting.click_copy')" @click="clipboardWriteText('glqw')") glqw
p.small
@ -279,6 +284,8 @@ import {
clearCache,
sizeFormate,
setWindowSize,
getSetting,
saveSetting,
} from '../utils'
import { rendererSend, rendererInvoke, NAMES } from '@common/ipc'
import { mergeSetting, isMac } from '../../common/utils'
@ -289,6 +296,7 @@ import { base as eventBaseName } from '../event/names'
import * as hotKeys from '../../common/hotKey'
import { mainWindow as eventsNameMainWindow, winLyric as eventsNameWinLyric } from '../../main/events/_name'
import { gzip, gunzip } from 'zlib'
import music from '../utils/music'
let hotKeyTargetInput
let newHotKey
@ -649,6 +657,8 @@ export default {
window.eventHub.$off(eventBaseName.set_config, this.handleUpdateSetting)
window.eventHub.$off(eventBaseName.key_down, this.handleKeyDown)
window.eventHub.$off(eventBaseName.set_hot_key_config, this.handleUpdateHotKeyConfig)
if (this.current_setting.network.proxy.enable && !this.current_setting.network.proxy.host) window.globalObj.proxy.enable = false
},
methods: {
...mapMutations(['setSetting', 'setSettingVersion', 'setVersionModalVisible']),
@ -748,8 +758,10 @@ export default {
if (list.location == null) list.location = 0
this.setList(list)
}
await this.refreshSetting(this.setting, this.settingVersion)
},
exportPlayList(path) {
async exportPlayList(path) {
const data = JSON.parse(JSON.stringify({
type: 'playList',
data: [
@ -758,8 +770,8 @@ export default {
...this.userList,
],
}))
for (const list of data.data) {
for (const item of list.list) {
for await (const list of data.data) {
for await (const item of list.list) {
if (item.otherSource) delete item.otherSource
}
}
@ -773,9 +785,6 @@ export default {
return
}
if (allData.type !== 'allData') return
const { version: settingVersion, setting } = mergeSetting(allData.setting)
setting.isAgreePact = false
this.refreshSetting(setting, settingVersion)
// 0.6.2
if (allData.defaultList) return this.setList({ id: 'default', list: allData.defaultList.list, name: '试听列表', location: 0 })
@ -784,6 +793,11 @@ export default {
if (list.location == null) list.location = 0
this.setList(list)
}
const { version: settingVersion, setting } = mergeSetting(allData.setting)
setting.isAgreePact = false
await this.refreshSetting(setting, settingVersion)
},
async exportAllData(path) {
let allData = JSON.parse(JSON.stringify({
@ -795,8 +809,8 @@ export default {
...this.userList,
],
}))
for (const list of allData.playList) {
for (const item of list.list) {
for await (const list of allData.playList) {
for await (const item of list.list) {
if (item.otherSource) delete item.otherSource
}
}
@ -906,10 +920,18 @@ export default {
let info = index == null ? this.windowSizeList[2] : this.windowSizeList[index]
setWindowSize(info.width, info.height)
},
refreshSetting(setting, version) {
async refreshSetting(newSetting, newVersion) {
await saveSetting(newSetting)
const { setting, version } = await getSetting()
this.setSetting(setting)
this.setSettingVersion(version)
if (setting.windowSizeId != null) this.handleWindowSizeChange(null, setting.windowSizeId)
window.globalObj.apiSource = setting.apiSource
if (/^user_api/.test(setting.apiSource)) {
rendererInvoke(NAMES.mainWindow.set_user_api, setting.apiSource)
} else {
window.globalObj.qualityList = music.supportQuality[setting.apiSource]
}
for (let key of Object.keys(setting.network.proxy)) {
window.globalObj.proxy[key] = setting.network.proxy[key]
}

View File

@ -419,10 +419,11 @@ export default {
})
},
async addSongListDetail() {
if (!this.listDetail.info.name) return
// console.log(this.listDetail.info)
// if (!this.listDetail.info.name) return
const list = await this.fetchList()
this.createUserList({
name: this.listDetail.info.name,
name: this.listDetail.info.name || `${this.listDetail.source}-list`,
id: `${this.listDetail.source}__${this.listDetail.id}`,
list,
source: this.listDetail.source,