Compare commits

...

91 Commits

Author SHA1 Message Date
lyswhut
144941d991 Merge branch 'dev' 2021-04-24 15:55:49 +08:00
lyswhut
f203517ce8 发布1.9.0版本 2021-04-24 15:55:40 +08:00
lyswhut
6dd6741237 Merge branch 'dev' 2021-04-24 15:53:37 +08:00
lyswhut
066e9c2fd5 修复上传包名匹配 2021-04-24 15:38:02 +08:00
lyswhut
f500b9b2d5 优化beta打包流程 2021-04-24 15:13:10 +08:00
lyswhut
c80e35872e 修改打包名 2021-04-24 14:34:52 +08:00
lyswhut
05eda6e406 修复打包失败 2021-04-24 14:13:13 +08:00
lyswhut
1686182616 更新版本号 2021-04-24 13:50:34 +08:00
lyswhut
fd5720451e 更新依赖 2021-04-24 13:48:27 +08:00
lyswhut
5b9adc8daa 修复属性计算 2021-04-23 10:57:47 +08:00
lyswhut
3efd6867d8 新增自动换源下载功能 2021-04-22 16:01:47 +08:00
lyswhut
cd1a55652f 修复换源错误的处理 2021-04-18 15:06:21 +08:00
lyswhut
47d0a4a343 修复正在播放“稍后播放”的歌曲时,对“稍后播放”前播放的列表进行添加、删除操作会导致切歌的问题 2021-04-16 16:58:20 +08:00
lyswhut
fe76d103f0 更新依赖 2021-04-16 14:18:53 +08:00
lyswhut
789a9bfe1a 更新依赖 2021-04-15 09:21:35 +08:00
lyswhut
391f97d3bb 修复js加载顺序问题 2021-04-14 16:11:57 +08:00
lyswhut
d077a03e60 优化配色 2021-04-14 15:38:59 +08:00
lyswhut
3317b6a9e5 优化配色 2021-04-14 15:01:55 +08:00
lyswhut
0b0f0e4649 新增黑色皮肤“黑纸白字” 2021-04-14 14:46:57 +08:00
lyswhut
f75e416479 添加黑色皮肤 2021-04-14 13:33:36 +08:00
lyswhut
d83db6bdf5 Merge branch 'dev' into 黑色主题 2021-04-14 08:35:00 +08:00
lyswhut
92ec461a77 修正设置页“搜索设置”部分内容的缩进显示问题 2021-04-13 15:57:25 +08:00
lyswhut
144fe3b8ac 更新依赖 2021-04-10 20:43:20 +08:00
lyswhut
af2e650538 兼容打开咪咕移动端分享的歌单链接,添加打开歌单的信息显示 2021-04-06 15:39:16 +08:00
lyswhut
1c585dc479 分离歌曲URL的缓存 2021-04-05 19:31:07 +08:00
lyswhut
c6853b197c 修复列表清除Bug 2021-04-03 21:31:19 +08:00
lyswhut
ef591c883a 移除列表lrc存储 2021-04-03 21:17:27 +08:00
lyswhut
4918db9cb1 分离歌词与歌曲列表信息的保存 2021-04-03 20:26:28 +08:00
lyswhut
b8250b67c9 升级到 webpack 5 2021-04-03 13:58:10 +08:00
lyswhut
d6f87894aa 更新依赖 2021-04-03 13:12:11 +08:00
lyswhut
c808500083 新增Windows arm64位免安装版的构建 2021-03-31 08:54:47 +08:00
lyswhut
3a6c2be48a 更新依赖 2021-03-29 08:54:55 +08:00
lyswhut
a28d01704a 更新faq 2021-03-27 19:34:45 +08:00
lyswhut
8bed654756 修复聚合搜索总页计算问题 2021-03-24 11:06:18 +08:00
lyswhut
8845884b24 更新发布流程 2021-03-21 13:23:13 +08:00
lyswhut
ea5de9a289 优化歌曲自动换源匹配 2021-03-20 20:55:44 +08:00
lyswhut
7922920f51 修改默认每页条数 2021-03-20 20:19:04 +08:00
lyswhut
dcf6ab0792 清理列表缓存将同时清理歌词 2021-03-20 19:52:02 +08:00
lyswhut
57fe510138 更新网盘链接 2021-03-20 00:10:36 +08:00
lyswhut
b4c7a6e448 自动禁用空代理 2021-03-18 17:30:44 +08:00
lyswhut
1d8702e95f 添加路径提示支持 2021-03-16 11:01:57 +08:00
lyswhut
8171fcd346 序启动时对数据文件做读取校验,数据出现损坏时自动备份损坏的数据 2021-03-14 02:06:35 +08:00
lyswhut
b1ccdeb0d3 修正错误 2021-03-13 16:49:05 +08:00
lyswhut
969b03b364 略微减小翻译字体大小 2021-03-13 15:25:35 +08:00
lyswhut
5ed81132fb 优化错误处理 2021-03-13 14:35:20 +08:00
lyswhut
c663cdbe0d 分离store逻辑 2021-03-13 14:10:36 +08:00
lyswhut
a4d46fd501 修正描述 2021-03-12 22:49:27 +08:00
lyswhut
c3e1ead90a Merge branch 'dhmkh' into dev 2021-03-12 22:42:17 +08:00
lyswhut
92c10eb534 修改协议阅读时间 2021-03-12 16:30:27 +08:00
lyswhut
08d0758616 修复备份与恢复功能在恢复数据时某些设置不立即生效的问题 2021-03-12 16:22:22 +08:00
lyswhut
68d8369a8b 修正单词拼写错误 2021-03-12 09:02:40 +08:00
lyswhut
af59a4472a 调整翻译字体大小 2021-03-11 17:34:29 +08:00
lyswhut
269546add1 Merge branch 'dev' 2021-03-10 10:23:50 +08:00
lyswhut
65246f8856 修正beta打包规则 2021-03-10 10:22:19 +08:00
lyswhut
ab35fe793d Merge branch 'dev' 2021-03-10 10:20:34 +08:00
lyswhut
e7b897e67c 优化打包命令 2021-03-10 10:19:49 +08:00
lyswhut
0b5dbb464d Merge branch 'dev' 2021-03-10 09:36:04 +08:00
lyswhut
60419f4319 修正徽章地址 2021-03-10 09:35:48 +08:00
lyswhut
1ddf0db18d 重命名beta打包工作流文件名 2021-03-10 09:34:43 +08:00
lyswhut
0732ca37b8 优化打包规则 2021-03-10 09:33:04 +08:00
lyswhut
801ea899e6 迁移到GitHub Actions 2021-03-10 09:21:43 +08:00
lyswhut
ba5159d2ad 修复Linux构建错误 2021-03-10 01:39:08 +08:00
lyswhut
ab2cf5a50f 修正错误,添加dev构建 2021-03-10 01:34:58 +08:00
lyswhut
d533c12315 修复Linux配置 2021-03-10 01:24:28 +08:00
lyswhut
1d90719053 Merge branch 'dev' 2021-03-10 01:18:49 +08:00
lyswhut
127d279266 修正语法错误 2021-03-10 01:15:30 +08:00
lyswhut
a484f66e69 修正语法错误 2021-03-10 01:02:30 +08:00
lyswhut
b34924e264 Merge branch 'dev' 2021-03-10 00:59:36 +08:00
lyswhut
4d5494c256 更新文件夹名 2021-03-10 00:59:06 +08:00
lyswhut
46b094a57a Merge branch 'dev' 2021-03-10 00:51:44 +08:00
lyswhut
0ef89c30e3 更新更新日志 2021-03-10 00:50:55 +08:00
lyswhut
dc2a89ce3f Merge branch 'dev' 2021-03-10 00:47:42 +08:00
lyswhut
47adcfec30 添加缓存 2021-03-10 00:42:27 +08:00
lyswhut
25e848702f 更新依赖 2021-03-10 00:42:15 +08:00
lyswhut
756a285978 修复收藏的在线列表id迁移保存出错的问题 2021-03-10 00:41:38 +08:00
lyswhut
fcf79bda03 Merge branch 'dev' 2021-03-09 22:55:20 +08:00
lyswhut
6b170f3116 尝试迁移到GitHub Actions 2021-03-09 22:50:08 +08:00
lyswhut
ea6bc245ff Merge branch 'dev' 2021-03-09 20:50:50 +08:00
lyswhut
61dc344d89 发布v1.8.2 2021-03-09 20:49:49 +08:00
lyswhut
fa6b7eacaa 修复歌曲ID存储变更导致酷狗图片获取失败的问题 2021-03-09 17:40:33 +08:00
lyswhut
23dafe539d 修正错误 2021-03-08 19:20:49 +08:00
lyswhut
0a654efda0 修改api窗口名 2021-03-07 21:43:00 +08:00
lyswhut
bec10ebe34 Merge branch 'dev' 2021-03-07 17:56:13 +08:00
lyswhut
0e03ca5d48 发布v1.8.1 2021-03-07 17:55:04 +08:00
lyswhut
4b1bf29ea0 新增启动参数-dhmkh 2021-03-07 17:54:02 +08:00
lyswhut
b391b2c16d 添加链接锚点 2021-03-07 17:53:24 +08:00
lyswhut
7b9cf93b40 修复歌词翻译的主题颜色适配问题 2021-03-07 15:07:22 +08:00
lyswhut
dd55e5e086 修改api窗口名 2021-03-07 13:30:47 +08:00
lyswhut
7b7711d410 Merge branch 'dev' into 黑色主题 2021-01-09 20:32:55 +08:00
lyswhut
3b00efdeae Merge branch 'dev' into 黑色主题 2020-12-24 17:22:30 +08:00
lyswhut
0a0d6969ec 初始提交 2020-11-14 11:48:51 +08:00
77 changed files with 4294 additions and 3904 deletions

View File

@@ -1,21 +0,0 @@
platform:
- x64
cache:
- node_modules
- '%APPDATA%\npm-cache'
- '%LOCALAPPDATA%\electron\Cache'
- '%LOCALAPPDATA%\electron-builder\Cache'
install:
- ps: Install-Product node 12 x64
- npm install
build_script:
- npm run publish:gh
test: off
branches:
only:
- master

200
.github/workflows/beta-pack.yml vendored Normal file
View File

@@ -0,0 +1,200 @@
name: Build Beta
on:
push:
branches:
- beta
jobs:
Windows:
name: Windows
runs-on: windows-latest
steps:
- name: Check out git repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '12.x'
- name: Cache file
uses: actions/cache@v2
with:
path: |
node_modules
%APPDATA%\npm-cache
%LOCALAPPDATA%\electron\Cache
%LOCALAPPDATA%\electron-builder\Cache
key: ${{ runner.os }}-build-caches-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-
- name: Install Dependencies
run: npm install
- name: Build src code
run: npm run build:src
- 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
runs-on: macos-latest
steps:
- name: Check out git repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '12.x'
- name: Cache file
uses: actions/cache@v2
with:
path: |
node_modules
$HOME/.cache/electron
$HOME/.cache/electron-builder
$HOME/.npm/_prebuilds
key: ${{ runner.os }}-build-caches-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-
- name: Install Dependencies
run: npm install
- name: Build src code
run: npm run build:src
- name: Build Package dmg
run: npm run pack:mac:dmg
env:
ELECTRON_CACHE: $HOME/.cache/electron
ELECTRON_BUILDERCACHE: $HOME/.cache/electron-builder
- name: Upload Artifact dmg
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-mac_dmg
path: build/*.dmg
Linux:
name: Linux
runs-on: ubuntu-latest
steps:
- name: Install package
run: sudo apt-get install -y rpm libarchive-tools
- name: Check out git repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '12.x'
- name: Cache file
uses: actions/cache@v2
with:
path: |
node_modules
$HOME/.cache/electron
$HOME/.cache/electron-builder
$HOME/.npm/_prebuilds
key: ${{ runner.os }}-build-caches-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-
- name: Install Dependencies
run: npm install
- name: Build src code
run: npm run build:src
- 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

131
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,131 @@
name: Build
on:
push:
branches:
- master
jobs:
Windows:
name: Windows
runs-on: windows-latest
steps:
- name: Check out git repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '12.x'
- name: Cache file
uses: actions/cache@v2
with:
path: |
node_modules
%APPDATA%\npm-cache
%LOCALAPPDATA%\electron\Cache
%LOCALAPPDATA%\electron-builder\Cache
key: ${{ runner.os }}-build-caches-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-
- name: Install Dependencies
run: npm install
- name: Build src code
run: npm run build:src
- name: Release package
run: |
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 }}
Mac:
name: Mac
runs-on: macos-latest
steps:
- name: Check out git repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '12.x'
- name: Cache file
uses: actions/cache@v2
with:
path: |
node_modules
$HOME/.cache/electron
$HOME/.cache/electron-builder
$HOME/.npm/_prebuilds
key: ${{ runner.os }}-build-caches-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-
- name: Install Dependencies
run: npm install
- name: Build src code
run: npm run build:src
- name: Release package
run: npm run publish:mac:dmg:always
env:
ELECTRON_CACHE: $HOME/.cache/electron
ELECTRON_BUILDERCACHE: $HOME/.cache/electron-builder
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BT_TOKEN: ${{ secrets.BT_TOKEN }}
Linux:
name: Linux
runs-on: ubuntu-latest
steps:
- name: Install package
run: sudo apt-get install -y rpm libarchive-tools
- name: Check out git repository
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '12.x'
- name: Cache file
uses: actions/cache@v2
with:
path: |
node_modules
$HOME/.cache/electron
$HOME/.cache/electron-builder
$HOME/.npm/_prebuilds
key: ${{ runner.os }}-build-caches-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-
- name: Install Dependencies
run: npm install
- name: Build src code
run: npm run build:src
- name: Release package
run: |
npm run publish:linux:deb:x64:always
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 }}

View File

@@ -1,49 +0,0 @@
language: node_js
node_js: 12
matrix:
include:
- os: osx
osx_image: xcode10.2
env:
- ELECTRON_CACHE=$HOME/.cache/electron
- ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
- os: linux
dist: trusty
sudo: required
addons:
apt:
packages:
- rpm
- bsdtar
cache:
directories:
- node_modules
- $HOME/.cache/electron
- $HOME/.cache/electron-builder
- $HOME/.npm/_prebuilds
notifications:
email: false
script:
- node --version
- npm --version
- |
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
npm install && npm run publish:gh:linux
else
npm run publish:gh:mac
fi
before_cache:
- rm -rf $HOME/.cache/electron-builder/wine
# only run this script on pull requests and merges into
# the 'master' and 'prod' branches
branches:
only:
- master
- dev

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/*",
}
}

View File

@@ -6,6 +6,42 @@ Project versioning adheres to [Semantic Versioning](http://semver.org/).
Commit convention is based on [Conventional Commits](http://conventionalcommits.org).
Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
## [1.9.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.8.2...v1.9.0) - 2021-04-24
### 新增
- 新增启动参数`-dhmkh`此参数将禁用Chromium的Hardware Media Key Handling特性用于解决漫步者部分型号耳机与本程序冲突导致耳机意外关机的问题
- 新增Windows arm64位免安装版的构建
- 新增黑色皮肤“黑灯瞎火”,有关于皮肤配色的建议欢迎反馈
- 新增自动换源下载功能默认关闭当无法从歌曲的原始源下载时将尝试切换到其他源下载此功能不100%保证换源后的歌曲版本与原版一致
### 优化
- 程序启动时对数据文件做读取校验数据出现损坏时自动备份损坏的数据若出现数据读取错误的弹窗并出现我的列表丢失时可到GitHub或加群反馈
- 当设置-代理启用,但主机地址为空的时,将不再使用代理配置进行网络连接,并且在离开设置界面时自动禁用代理
- 优化歌曲自动换源匹配
- 分离歌词与歌曲列表信息的保存,以减小列表列表文件损坏的几率
- 兼容打开咪咕移动端分享的歌单链接,添加打开歌单的信息显示
### 修复
- 修复备份与恢复功能在恢复数据时某些设置不立即生效的问题
- 修正设置页“搜索设置”部分内容的缩进显示问题
- 修复正在播放“稍后播放”的歌曲时,对“稍后播放”前播放的列表进行添加、删除操作会导致切歌的问题
## [1.8.2](https://github.com/lyswhut/lx-music-desktop/compare/v1.8.1...v1.8.2) - 2021-03-09
### 修复
- 修复歌曲ID存储变更导致酷狗图片获取失败的问题
- 修复收藏的在线列表id迁移保存出错的问题
## [1.8.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.8.0...v1.8.1) - 2021-03-07
### 修复
- 修复歌词翻译的主题颜色适配问题
## [1.8.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.7.1...v1.8.0) - 2021-03-07
### 新增

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拉取源代码构建构建日志[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

@@ -2,8 +2,8 @@
<p align="center">
<a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/release/lyswhut/lx-music-desktop" alt="Release version"></a>
<a href="https://ci.appveyor.com/project/lyswhut/lx-music-desktop"><img src="https://ci.appveyor.com/api/projects/status/flrsqd5ymp8fnte5?svg=true" alt="Build status"></a>
<a href="https://travis-ci.com/lyswhut/lx-music-desktop"><img src="https://travis-ci.com/lyswhut/lx-music-desktop.svg?branch=master" alt="Build status"></a>
<a href="https://github.com/lyswhut/lx-music-desktop/actions/workflows/release.yml"><img src="https://github.com/lyswhut/lx-music-desktop/workflows/Build/badge.svg" alt="Build status"></a>
<a href="https://github.com/lyswhut/lx-music-desktop/actions/workflows/beta-pack.yml"><img src="https://github.com/lyswhut/lx-music-desktop/workflows/Build%20Beta/badge.svg" alt="Build status"></a>
<a href="https://electronjs.org/releases/stable"><img src="https://img.shields.io/github/package-json/dependency-version/lyswhut/lx-music-desktop/dev/electron/master" alt="Electron version"></a>
<!-- <a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/latest/total" alt="Downloads"></a> -->
<a href="https://github.com/lyswhut/lx-music-desktop/tree/dev"><img src="https://img.shields.io/github/package-json/v/lyswhut/lx-music-desktop/dev" alt="Dev branch version"></a>
@@ -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,12 +83,14 @@ 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`为本地列表
- `link`要播放的在线列表歌单链接、或IDsource为`kw/kg/tx/wy/mg`之一(在线列表)时必传,举例:`./lx-music-desktop -play="type=songList&source=kw&link=歌单URL or ID"注意如果传入URL时必须对URL进行编码后再传入
- `name`要播放的本地列表歌单名字source为`myList`时必传,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表"
- `index`:从列表的哪个位置开始播放,选传,若不传默认播放第一首歌曲,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表&index=2"
- `link`要播放的在线列表歌单链接、或IDsource为`kw/kg/tx/wy/mg`之一(在线列表)时必传,举例:`./lx-music-desktop -play="type=songList&source=kw&link=歌单URL or ID"`注意如果传入URL时必须对URL进行编码后再传入
- `name`要播放的本地列表歌单名字source为`myList`时必传,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表"`
- `index`:从列表的哪个位置开始播放,选传,若不传默认播放第一首歌曲,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表&index=2"`
### 常见问题

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"]
}

6448
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,63 +1,62 @@
{
"name": "lx-music-desktop",
"version": "1.8.0",
"version": "1.9.0",
"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 -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 -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:gh": "node build-config/pack.js && npm run publish:win",
"publish:win": "npm run publish:win:7z && npm run publish:win:setup",
"publish:win:setup:always": "cross-env TARGET=Setup ARCH=x86_64 electron-builder -w=nsis --x64 --ia32 -p always",
"publish:win:setup": "cross-env TARGET=Setup ARCH=x86_64 electron-builder -w=nsis --x64 --ia32 -p onTagOrDraft",
"publish:win:portable": "npm run publish:win:portable:x86_64 && npm run publish:win:portable:x64 && npm run publish:win:portable:x86",
"publish:win:portable:x86_64": "cross-env TARGET=portable ARCH=x86_64 electron-builder -w=portable --x64 --ia32 -p onTagOrDraft",
"publish:win:portable:x64": "cross-env TARGET=portable ARCH=x64 electron-builder -w=portable --x64 -p onTagOrDraft",
"publish:win:portable:x86": "cross-env TARGET=portable ARCH=x86 electron-builder -w=portable --ia32 -p onTagOrDraft",
"publish:win:7z": "npm run publish:win:7z:x64 && npm run publish:win:7z:x86",
"publish:win:7z:x64": "cross-env TARGET=green ARCH=win_x64 electron-builder -w=7z --x64 -p always",
"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:gh:mac": "node build-config/pack.js && npm run publish:mac",
"publish:mac": "npm run publish:mac:dmg",
"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:gh:linux": "node build-config/pack.js && npm run publish:linux",
"publish:linux": "npm run publish:linux:deb && npm run publish:linux:appImage && npm run publish:linux:rpm && npm run publish:linux:pacman",
"publish:linux:appImage": "cross-env ARCH=x64 electron-builder -l=AppImage -p onTagOrDraft",
"publish:linux:deb": "npm run publish:linux:deb:x64 && npm run publish:linux:deb:x86 && npm run publish:linux:deb:arm64 && npm run publish:linux:deb:armv7l",
"publish:linux:deb:x64:always": "cross-env ARCH=x64 electron-builder -l=deb --x64 -p always",
"publish:linux:deb:x64": "cross-env ARCH=x64 electron-builder -l=deb --x64 -p onTagOrDraft",
"publish:linux:deb:x86": "cross-env ARCH=x86 electron-builder -l=deb --ia32 -p onTagOrDraft",
"publish:linux:deb:arm64": "cross-env ARCH=arm64 electron-builder -l=deb --arm64 -p onTagOrDraft",
"publish:linux:deb:armv7l": "cross-env ARCH=armv7l electron-builder -l=deb --armv7l -p onTagOrDraft",
"publish:linux:appImage": "cross-env ARCH=x64 electron-builder -l=AppImage -p onTagOrDraft",
"publish:linux:rpm": "cross-env ARCH=x64 electron-builder -l=rpm --x64 -p onTagOrDraft",
"publish:linux:pacman": "cross-env ARCH=x64 electron-builder -l=pacman --x64 -p onTagOrDraft",
"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: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:dir": "node build-config/pack.js && electron-builder --dir",
"dev": "node build-config/runner-dev.js",
"clean:electron": "rimraf dist/electron",
"clean": "rimraf dist && rimraf build",
"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:src": "node build-config/pack.js",
"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",
@@ -135,12 +134,6 @@
"provider": "github",
"owner": "lyswhut",
"repo": "lx-music-desktop"
},
{
"package": "lx-music-desktop",
"repo": "lx-music-desktop",
"user": "lyswhut",
"provider": "bintray"
}
]
},
@@ -163,48 +156,50 @@
},
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
"devDependencies": {
"@babel/core": "^7.13.8",
"@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.9",
"@babel/plugin-transform-runtime": "^7.13.15",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.13.9",
"@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.1",
"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",
@@ -212,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"
@@ -226,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.23.0",
"vue-i18n": "^8.24.3",
"vue-router": "^3.5.1",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0"

View File

@@ -1,34 +1,20 @@
### 新增
- 新增设置-其他-列表缓存信息清理功能,注:此功能一般情况下不要使用
- 新增启动参数`-play`可以在启动软件时播放指定歌单使用方法看Readme.md的"启动参数"部分
- 新增逐字歌词播放,默认开启,可到设置界面关闭,注:本功能目前仅对酷狗源的歌曲有效
- 新增自定义源功能,源编写规则可以去常见问题查看
- 新增启动参数`-dhmkh`此参数将禁用Chromium的Hardware Media Key Handling特性用于解决漫步者部分型号耳机与本程序冲突导致耳机意外关机的问题
- 新增Windows arm64位免安装版的构建
- 新增黑色皮肤“黑灯瞎火”,有关于皮肤配色的建议欢迎反馈
- 新增自动换源下载功能默认关闭当无法从歌曲的原始源下载时将尝试切换到其他源下载此功能不100%保证换源后的歌曲版本与原版一致
### 优化
- 允许播放除了搜索列表以外的所有歌曲,即原来没有播放按钮或者灰色的歌曲都可以去尝试点击播放。注:该功能的原理是尝试自动切换到其他源播放,所以不一定会播放成功,特别是对于那些独家的资源
- 优化单首歌曲的“添加到列表”弹窗歌曲列表状态的显示;现在在收藏单首歌曲时,若列表存在本歌曲则列表名字将变成灰色不可点击状态。总的来说,在添加单首歌曲时若列表名是灰色,则证明当前歌曲已在那个列表中
- 将歌词翻译放到原文的下方,同时新增当前播放翻译的高亮功能
### 移除
- 移除虾米源。注:虽然已移除该源,但仍可尝试去播放之前添加的歌曲,虽然不一定会成功
- 程序启动时对数据文件做读取校验数据出现损坏时自动备份损坏的数据若出现数据读取错误的弹窗并出现我的列表丢失时可到GitHub或加群反馈
- 当设置-代理启用,但主机地址为空的时,将不再使用代理配置进行网络连接,并且在离开设置界面时自动禁用代理
- 优化歌曲自动换源匹配
- 分离歌词与歌曲列表信息的保存,以减小列表列表文件损坏的几率
- 兼容打开咪咕移动端分享的歌单链接,添加打开歌单的信息显示
### 修复
- 修复音乐搜索列表的稍后播放功能无效的问题
-复搜索列表双击不支持播放的源时会导致切歌的问题
- 修复歌单列表加载失败时无法进入歌单打开界面的问题
- 修复mg源歌单列表无法加载的问题
- 修复kg跳转到官方歌曲详情页的歌曲无法播放的问题
- 修复我的列表的歌曲添加到其他列表时不排除当前列表的问题
- 修复在下载列表右击未下载完成的歌曲弹出的右击菜单中没有开始下载选项的问题
### 变更
- 歌词翻译显示功能修改为默认关闭,注:此变更仅影响首次安装软件的用户
### 其他
- 更新electron到v9.4.4
- 修复备份与恢复功能在恢复数据时某些设置不立即生效的问题
-正设置页“搜索设置”部分内容的缩进显示问题
- 修复正在播放“稍后播放”的歌曲时,对“稍后播放”前播放的列表进行添加、删除操作会导致切歌的问题

File diff suppressed because one or more lines are too long

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

@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<title>User api</title>
</head>
<body>

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 || ''),
)
},
},
@@ -468,6 +468,9 @@ each(@themes, {
:global {
.lrc-content {
&.active {
.translation {
color: ~'@{color-@{value}-theme}';
}
.line {
color: ~'@{color-@{value}-theme}';
}

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))
@@ -313,7 +327,7 @@ export default {
l.sourceListId = id
if (!needSave) needSave = true
})
if (needSave) this.saveUserList(userList)
if (needSave) this.saveMyList({ userList })
} else {
userList = this.userList
}
@@ -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,14 +833,19 @@ each(@themes, {
.lyric {
:global {
.lrc-content {
color: ~'@{color-@{value}-player-detail-lyric}';
&.active {
.translation {
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

@@ -15,7 +15,7 @@ material-modal(:show="visible" bg-close @close="handleClose")
div(:class="$style.note")
p(:class="[$style.ruleLink]")
| {{$t('material.user_api_modal.readme')}}
span.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md')" tips="https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md") FAQ.md
span.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%BA%90%E8%84%9A%E6%9C%AC%E7%BC%96%E5%86%99%E8%AF%B4%E6%98%8E')" tips="https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md") FAQ.md
p {{$t('material.user_api_modal.note')}}
div(:class="$style.footer")
material-btn(:class="$style.footerBtn" @click="handleImport") {{$t('material.user_api_modal.btn_import')}}

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

@@ -31,9 +31,13 @@ export default {
if (statusCode != 200 || body.err_code !== 0) throw new Error('获取热门评论失败')
return { source: 'kg', comments: this.filterComment(body.weightList || []) }
},
async getReplyComment({ songmid }, replyId, page = 1, limit = 100) {
async getReplyComment({ songmid, audioId }, replyId, page = 1, limit = 100) {
if (this._requestObj2) this._requestObj2.cancelHttp()
songmid = songmid.length == 32 // 修复歌曲ID存储变更导致图片获取失败的问题
? audioId.split('_')[0]
: songmid
const _requestObj2 = httpFetch(`http://comment.service.kugou.com/index.php?r=commentsv2/getReplyWithLike&code=fc4be23b4e972707f36b8a828a93ba8a&p=${page}&pagesize=${limit}&ver=1.01&clientver=8373&kugouid=687373022&appid=1001&childrenid=${songmid}&tid=${replyId}`, {
headers: {
'User-Agent': 'Android712-AndroidPhone-8983-18-0-COMMENT-wifi',

View File

@@ -48,7 +48,7 @@ export default {
name: decodeName(rawData.songname),
albumName: decodeName(rawData.album_name),
albumId: rawData.album_id,
songmid: rawData.hash,
songmid: rawData.audio_id,
source: 'kg',
interval: formatPlayTime(rawData.duration),
_interval: rawData.duration,
@@ -58,7 +58,6 @@ export default {
hash: rawData.hash,
types,
_types,
audioId: rawData.audio_id + '_' + rawData.hash,
typeUrl: {},
}
},

View File

@@ -20,7 +20,10 @@ export default {
relate: 1,
resource: [
{
album_audio_id: songInfo.songmid,
album_audio_id:
songInfo.songmid.length == 32 // 修复歌曲ID存储变更导致图片获取失败的问题
? songInfo.audioId.split('_')[0]
: songInfo.songmid,
album_id: songInfo.albumId,
hash: songInfo.hash,
id: 0,

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,