commit
f10c1e923e
|
@ -92,6 +92,11 @@ jobs:
|
||||||
name: lx-music-desktop-win_arm64-green
|
name: lx-music-desktop-win_arm64-green
|
||||||
path: build/*win_arm64 green.7z
|
path: build/*win_arm64 green.7z
|
||||||
|
|
||||||
|
- name: Generate file MD5
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
Get-FileHash *.exe,*.7z -Algorithm MD5 | Format-List
|
||||||
|
|
||||||
Mac:
|
Mac:
|
||||||
name: Mac
|
name: Mac
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
@ -143,6 +148,11 @@ jobs:
|
||||||
name: lx-music-desktop-mac-dmg-arm64
|
name: lx-music-desktop-mac-dmg-arm64
|
||||||
path: build/*-arm64.dmg
|
path: build/*-arm64.dmg
|
||||||
|
|
||||||
|
- name: Generate file MD5
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
md5 *.dmg
|
||||||
|
|
||||||
Linux:
|
Linux:
|
||||||
name: Linux
|
name: Linux
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -231,3 +241,8 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: lx-music-desktop-x64-pacman
|
name: lx-music-desktop-x64-pacman
|
||||||
path: build/* x64.pacman
|
path: build/* x64.pacman
|
||||||
|
|
||||||
|
- name: Generate file MD5
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
md5sum *.deb *.rpm *.pacman *.AppImage
|
||||||
|
|
|
@ -49,6 +49,11 @@ jobs:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
||||||
|
|
||||||
|
- name: Generate file MD5
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
Get-FileHash *.exe,*.7z -Algorithm MD5 | Format-List
|
||||||
|
|
||||||
Mac:
|
Mac:
|
||||||
name: Mac
|
name: Mac
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
@ -89,6 +94,11 @@ jobs:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
||||||
|
|
||||||
|
- name: Generate file MD5
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
md5 *.dmg
|
||||||
|
|
||||||
Linux:
|
Linux:
|
||||||
name: Linux
|
name: Linux
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -134,3 +144,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
||||||
|
|
||||||
|
- name: Generate file MD5
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
md5sum *.deb *.rpm *.pacman *.AppImage
|
||||||
|
|
47
CHANGELOG.md
47
CHANGELOG.md
|
@ -6,6 +6,53 @@ Project versioning adheres to [Semantic Versioning](http://semver.org/).
|
||||||
Commit convention is based on [Conventional Commits](http://conventionalcommits.org).
|
Commit convention is based on [Conventional Commits](http://conventionalcommits.org).
|
||||||
Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
|
Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
|
|
||||||
|
## [1.19.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.18.0...v1.19.0) - 2022-03-20
|
||||||
|
|
||||||
|
### 新增
|
||||||
|
|
||||||
|
- 新增对播放详情页歌词大小、是否缩放、对齐方式的设置,可以去设置-播放详情页设置查看
|
||||||
|
- 新增播放详情页通过歌词调整播放进度,默认关闭,需要到设置-播放详情页设置开启,开启后在播放详情页拖动歌词时将会出现跳转当前行歌词播放的按钮
|
||||||
|
- 新增全屏状态,按F11可以进入、退出全屏状态,由于全屏时会隐藏控制栏按钮,所以需要使用鼠标右键双击(详情页的任意地方都可以)来关闭播放详情页
|
||||||
|
- 新增动态主题“道法自然”,你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。注:鼠标 右击 此主题项即可打开亮、暗色主题设置窗口。
|
||||||
|
- 新增对kw源卡拉OK歌词的支持
|
||||||
|
|
||||||
|
### 优化
|
||||||
|
|
||||||
|
- 优化Windows任务栏缩略图工具栏控制按钮在浅色任务栏下的显示效果
|
||||||
|
- 添加音频可视化与音频输出设备冲突的提示
|
||||||
|
- 优化歌词的播放偏移
|
||||||
|
- 优化托盘菜单操作(#686)
|
||||||
|
- 优化播放下载列表时的切歌性能
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
|
||||||
|
- 修复“当前的声音输出设备被改变时暂停播放歌曲”设置无效的问题
|
||||||
|
- 修复桌面歌词没有处理停止播放状态的问题
|
||||||
|
- 修复AppImage包无法运行的问题
|
||||||
|
- 修复Windows任务栏缩略图工具栏控制按钮的歌曲收藏按钮状态更新问题
|
||||||
|
- 修复使用链接导入的歌单无法在我的列表打开原歌单详情页的问题
|
||||||
|
- 修复播放下载列表的歌曲时增删下载任务导致正在的歌曲序号改变时,不会更新到新增序号的问题
|
||||||
|
|
||||||
|
### 文档
|
||||||
|
|
||||||
|
添加LX中定义的快捷操作汇总说明到常见问题中,这是目前可用的鼠标、键盘快捷操作,它们都可以在更新日志中找到
|
||||||
|
|
||||||
|
- 鼠标右击播放栏的歌曲图片封面可以定位当前播放的歌曲
|
||||||
|
- 鼠标右击播放栏进度条上的LRC按钮可以锁定/解锁桌面歌词
|
||||||
|
- 歌曲搜索框、歌单链接输入框内鼠标右击可以将当前剪贴板上的文字粘贴到输入框内
|
||||||
|
- 鼠标右击搜索界面中的单条搜索历史可以将其移除
|
||||||
|
- 歌曲列表内的文字在选中后,鼠标右击可以复制已选中的文字,此功能只对搜索、歌单、排行榜、我的列表中的列表有效
|
||||||
|
- 鼠标在播放详情页内右键双击可以关闭播放详情页
|
||||||
|
- 鼠标左击播放栏上的歌曲名字可以将它复制
|
||||||
|
- 鼠标右击“道法自然(英文Auto)”主题可以打开亮、暗主题设置窗口
|
||||||
|
- 歌曲搜索框的候选内容可以用键盘上下方向键选择,按回车键搜索已选内容
|
||||||
|
- 在歌单详情页按退格键可以返回歌单列表
|
||||||
|
- 歌曲列表中可以使用Ctrl、Shift键进行多选,这类似Windows下的文件选择,详情看常见问题列表多选部分
|
||||||
|
- 在我的列表内可以使用Ctrl+f键打开搜索框进行列表内歌曲搜索,搜索框按Esc键可以关闭搜索框,搜索框内按上下方向键可以选择歌曲,按回车键跳转到已选歌曲,按Ctrl+回车可以跳转并播放已选歌曲
|
||||||
|
- 在我的列表按住Ctrl键可以进入列表拖动模式,此时可以用鼠标拖动列表调整列表的位置
|
||||||
|
- 编辑列表名时按Esc键可以取消编辑
|
||||||
|
- 按F11可以进入、退出全屏状态
|
||||||
|
|
||||||
## [1.18.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.17.1...v1.18.0) - 2022-02-26
|
## [1.18.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.17.1...v1.18.0) - 2022-02-26
|
||||||
|
|
||||||
### 新增
|
### 新增
|
||||||
|
|
20
FAQ.md
20
FAQ.md
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
洛雪音乐的最初定位不是作为播放器开发的,它主要用于**查找歌曲**,软件的播放功能仅用于试听,不建议用作为常用播放器使用。
|
洛雪音乐的最初定位不是作为播放器开发的,它主要用于**查找歌曲**,软件的播放功能仅用于试听,不建议用作为常用播放器使用。
|
||||||
|
|
||||||
## LX Music中的音乐播放列表机制
|
## 音乐播放列表机制
|
||||||
|
|
||||||
1. 默认情况下,播放搜索列表、歌单列表、排行榜列表的歌曲时会自动将该歌曲添加到“我的列表”的试听列表后再播放,手动将歌曲添加到试听列表,再去试听列表找到这首歌点播放是等价的
|
1. 默认情况下,播放搜索列表、歌单列表、排行榜列表的歌曲时会自动将该歌曲添加到“我的列表”的试听列表后再播放,手动将歌曲添加到试听列表,再去试听列表找到这首歌点播放是等价的
|
||||||
2. 如果你想要播放多首歌曲,需要使用多选功能(若不知道如何多选请看常见问题)多选后,将歌曲这些歌曲添加到“我的列表”播放,或使用稍后播放功能播放
|
2. 如果你想要播放多首歌曲,需要使用多选功能(若不知道如何多选请看常见问题)多选后,将歌曲这些歌曲添加到“我的列表”播放,或使用稍后播放功能播放
|
||||||
|
@ -15,6 +15,24 @@
|
||||||
5. 对于排行榜详情列表,除了可以使用第2条的方式播放外,你可以在右击排行榜名字后弹出的菜单中,播放或收藏整个排行榜,这与第四条的歌单中的播放、与收藏按钮功能一致
|
5. 对于排行榜详情列表,除了可以使用第2条的方式播放外,你可以在右击排行榜名字后弹出的菜单中,播放或收藏整个排行榜,这与第四条的歌单中的播放、与收藏按钮功能一致
|
||||||
6. v1.18.0及之后新增了“双击列表里的歌曲时自动切换到当前列表播放”设置,默认关闭,此功能仅对歌单、排行榜有效
|
6. v1.18.0及之后新增了“双击列表里的歌曲时自动切换到当前列表播放”设置,默认关闭,此功能仅对歌单、排行榜有效
|
||||||
|
|
||||||
|
## 可用的鼠标、键盘快捷操作
|
||||||
|
|
||||||
|
- 鼠标右击播放栏的歌曲图片封面可以定位当前播放的歌曲
|
||||||
|
- 鼠标右击播放栏进度条上的`LRC`按钮可以锁定/解锁桌面歌词
|
||||||
|
- 歌曲搜索框、歌单链接输入框内鼠标右击可以将当前剪贴板上的文字粘贴到输入框内
|
||||||
|
- 鼠标右击搜索界面中的单条搜索历史可以将其移除
|
||||||
|
- 歌曲列表内的文字在选中后,鼠标右击可以复制已选中的文字,此功能只对搜索、歌单、排行榜、我的列表中的列表有效
|
||||||
|
- 鼠标在播放详情页内右键双击可以关闭播放详情页
|
||||||
|
- 鼠标左击播放栏上的歌曲名字可以将它复制
|
||||||
|
- 鼠标右击设置-主题设置的“道法自然(英文Auto)”主题可以打开亮、暗主题设置窗口
|
||||||
|
- 歌曲搜索框的候选内容可以用键盘上下方向键选择,按回车键搜索已选内容
|
||||||
|
- 在歌单详情页按退格键可以返回歌单列表
|
||||||
|
- 歌曲列表中可以使用`Ctrl`、`Shift`键进行多选,这类似Windows下的文件选择,详情看常见问题列表多选部分
|
||||||
|
- 在我的列表内可以使用`Ctrl + f`键打开搜索框进行列表内歌曲搜索,搜索框按`Esc`键可以关闭搜索框,搜索框内按上下方向键可以选择歌曲,按`回车`键跳转到已选歌曲,按`Ctrl + 回车`可以跳转并播放已选歌曲
|
||||||
|
- 在我的列表按住`Ctrl`键可以进入列表拖动模式,此时可以用鼠标拖动列表调整列表的位置
|
||||||
|
- 编辑列表名时按`Esc`键可以取消编辑
|
||||||
|
- 按`F11`可以进入、退出全屏状态(v1.19.0新增)
|
||||||
|
|
||||||
## 歌曲无法试听与下载
|
## 歌曲无法试听与下载
|
||||||
|
|
||||||
### 所有歌曲都提示 `请求异常😮,可以多试几次,若还是不行就换一首吧。。。`
|
### 所有歌曲都提示 `请求异常😮,可以多试几次,若还是不行就换一首吧。。。`
|
||||||
|
|
|
@ -56,6 +56,8 @@
|
||||||
从v1.17.0起支持 Scheme URL,可以使用此功能从浏览器等场景下调用LX Music,我们开发了一个[油猴脚本](https://github.com/lyswhut/lx-music-script#readme)配套使用,<br>
|
从v1.17.0起支持 Scheme URL,可以使用此功能从浏览器等场景下调用LX Music,我们开发了一个[油猴脚本](https://github.com/lyswhut/lx-music-script#readme)配套使用,<br>
|
||||||
脚本安装地址:<https://greasyfork.org/zh-CN/scripts/438148><br>
|
脚本安装地址:<https://greasyfork.org/zh-CN/scripts/438148><br>
|
||||||
|
|
||||||
|
若你想自己调用LX Music,可以看常见问题[Scheme URL支持](https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md#scheme-url%E6%94%AF%E6%8C%81)部分说明
|
||||||
|
|
||||||
#### 启动参数
|
#### 启动参数
|
||||||
|
|
||||||
目前软件已支持的启动参数如下:
|
目前软件已支持的启动参数如下:
|
||||||
|
@ -76,7 +78,7 @@
|
||||||
|
|
||||||
- Windows:`%APPDATA%/lx-music-desktop`
|
- Windows:`%APPDATA%/lx-music-desktop`
|
||||||
- Linux:`$XDG_CONFIG_HOME/lx-music-desktop` 或 `~/.config/lx-music-desktop`
|
- Linux:`$XDG_CONFIG_HOME/lx-music-desktop` 或 `~/.config/lx-music-desktop`
|
||||||
- macOS:`~/Library/Application/lx-music-desktop`
|
- macOS:`~/Library/Application Support/lx-music-desktop`
|
||||||
|
|
||||||
在Windows平台下,若程序目录下存在`portable`目录,则自动使用此目录作为数据存储目录(v1.17.0新增)。
|
在Windows平台下,若程序目录下存在`portable`目录,则自动使用此目录作为数据存储目录(v1.17.0新增)。
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "lx-music-desktop",
|
"name": "lx-music-desktop",
|
||||||
"version": "1.18.0",
|
"version": "1.19.0",
|
||||||
"description": "一个免费的音乐查找助手",
|
"description": "一个免费的音乐查找助手",
|
||||||
"main": "./dist/electron/main.js",
|
"main": "./dist/electron/main.js",
|
||||||
"productName": "lx-music-desktop",
|
"productName": "lx-music-desktop",
|
||||||
|
@ -173,7 +173,7 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.17.5",
|
"@babel/core": "^7.17.8",
|
||||||
"@babel/eslint-parser": "^7.17.0",
|
"@babel/eslint-parser": "^7.17.0",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
|
@ -183,25 +183,25 @@
|
||||||
"@babel/preset-env": "^7.16.11",
|
"@babel/preset-env": "^7.16.11",
|
||||||
"babel-loader": "^8.2.3",
|
"babel-loader": "^8.2.3",
|
||||||
"babel-preset-minify": "^0.5.1",
|
"babel-preset-minify": "^0.5.1",
|
||||||
"browserslist": "^4.19.3",
|
"browserslist": "^4.20.2",
|
||||||
"cfonts": "^2.10.0",
|
"cfonts": "^2.10.0",
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"changelog-parser": "^2.8.0",
|
"changelog-parser": "^2.8.1",
|
||||||
"copy-webpack-plugin": "^10.2.4",
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
"core-js": "^3.21.1",
|
"core-js": "^3.21.1",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "^6.6.0",
|
"css-loader": "^6.7.1",
|
||||||
"css-minimizer-webpack-plugin": "^3.4.1",
|
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||||
"del": "^6.0.0",
|
"del": "^6.0.0",
|
||||||
"electron": "^13.6.9",
|
"electron": "^13.6.9",
|
||||||
"electron-builder": "^23.0.1",
|
"electron-builder": "^23.0.2",
|
||||||
"electron-debug": "^3.2.0",
|
"electron-debug": "^3.2.0",
|
||||||
"electron-devtools-installer": "^3.2.0",
|
"electron-devtools-installer": "^3.2.0",
|
||||||
"electron-to-chromium": "^1.4.73",
|
"electron-to-chromium": "^1.4.88",
|
||||||
"electron-updater": "^5.0.0",
|
"electron-updater": "^5.0.0",
|
||||||
"eslint": "^8.10.0",
|
"eslint": "^8.11.0",
|
||||||
"eslint-config-standard": "^16.0.3",
|
"eslint-config-standard": "^16.0.3",
|
||||||
"eslint-formatter-friendly": "^7.0.0",
|
"eslint-formatter-friendly": "git+https://github.com/lyswhut/eslint-friendly-formatter.git#2170d1320e2fad13615a9dcf229669f0bb473a53",
|
||||||
"eslint-plugin-html": "^6.2.0",
|
"eslint-plugin-html": "^6.2.0",
|
||||||
"eslint-plugin-import": "^2.25.4",
|
"eslint-plugin-import": "^2.25.4",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
@ -214,9 +214,9 @@
|
||||||
"less": "^4.1.2",
|
"less": "^4.1.2",
|
||||||
"less-loader": "^10.2.0",
|
"less-loader": "^10.2.0",
|
||||||
"markdown-it": "^12.3.2",
|
"markdown-it": "^12.3.2",
|
||||||
"mini-css-extract-plugin": "^2.5.3",
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
"node-loader": "^2.0.0",
|
"node-loader": "^2.0.0",
|
||||||
"postcss": "^8.4.7",
|
"postcss": "^8.4.12",
|
||||||
"postcss-loader": "^6.2.1",
|
"postcss-loader": "^6.2.1",
|
||||||
"postcss-pxtorem": "^6.0.0",
|
"postcss-pxtorem": "^6.0.0",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
|
@ -224,7 +224,7 @@
|
||||||
"pug-plain-loader": "^1.1.0",
|
"pug-plain-loader": "^1.1.0",
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"spinnies": "^0.5.1",
|
"spinnies": "git+https://github.com/lyswhut/spinnies.git#233305c58694aa3b053e3ab9af9049993f918b9d",
|
||||||
"svg-sprite-loader": "^6.0.11",
|
"svg-sprite-loader": "^6.0.11",
|
||||||
"svg-transform-loader": "^2.0.13",
|
"svg-transform-loader": "^2.0.13",
|
||||||
"svgo-loader": "^3.0.0",
|
"svgo-loader": "^3.0.0",
|
||||||
|
@ -232,7 +232,7 @@
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"vue-loader": "^17.0.0",
|
"vue-loader": "^17.0.0",
|
||||||
"vue-template-compiler": "^2.6.14",
|
"vue-template-compiler": "^2.6.14",
|
||||||
"webpack": "^5.69.1",
|
"webpack": "^5.70.0",
|
||||||
"webpack-cli": "^4.9.2",
|
"webpack-cli": "^4.9.2",
|
||||||
"webpack-dev-server": "^4.7.4",
|
"webpack-dev-server": "^4.7.4",
|
||||||
"webpack-hot-middleware": "github:lyswhut/webpack-hot-middleware#329c4375134b89d39da23a56a94db651247c74a1",
|
"webpack-hot-middleware": "github:lyswhut/webpack-hot-middleware#329c4375134b89d39da23a56a94db651247c74a1",
|
||||||
|
@ -244,7 +244,7 @@
|
||||||
"electron-log": "^4.4.6",
|
"electron-log": "^4.4.6",
|
||||||
"electron-store": "^8.0.1",
|
"electron-store": "^8.0.1",
|
||||||
"font-list": "github:lyswhut/node-font-list#4edbb1933b49a9bac1eedd63a31da16b487fe57d",
|
"font-list": "github:lyswhut/node-font-list#4edbb1933b49a9bac1eedd63a31da16b487fe57d",
|
||||||
"http-terminator": "^3.0.4",
|
"http-terminator": "^3.2.0",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"image-size": "^1.0.1",
|
"image-size": "^1.0.1",
|
||||||
"koa": "^2.13.4",
|
"koa": "^2.13.4",
|
||||||
|
@ -255,10 +255,10 @@
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"socket.io": "^4.4.1",
|
"socket.io": "^4.4.1",
|
||||||
"sortablejs": "^1.14.0",
|
"sortablejs": "^1.14.0",
|
||||||
"utf-8-validate": "^5.0.8",
|
"utf-8-validate": "^5.0.9",
|
||||||
"vue": "^3.2.31",
|
"vue": "^3.2.31",
|
||||||
"vue-i18n": "^9.2.0-beta.30",
|
"vue-i18n": "^9.2.0-beta.32",
|
||||||
"vue-router": "^4.0.12",
|
"vue-router": "^4.0.14",
|
||||||
"vuex": "^4.0.2"
|
"vuex": "^4.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,44 @@
|
||||||
### 新增
|
### 新增
|
||||||
|
|
||||||
- 新增“双击列表里的歌曲时自动切换到当前列表播放”设置,此功能仅对歌单、排行榜有效,默认关闭
|
- 新增对播放详情页歌词大小、是否缩放、对齐方式的设置,可以去设置-播放详情页设置查看
|
||||||
- 新增打开收藏的在线列表的对应平台详情页功能,可以在我的列表-列表右键菜单中使用
|
- 新增播放详情页通过歌词调整播放进度,默认关闭,需要到设置-播放详情页设置开启,开启后在播放详情页拖动歌词时将会出现跳转当前行歌词播放的按钮
|
||||||
- 新增定时暂停播放功能,由于此功能大多数人可能不常用,所以将其放在设置-基本设置中
|
- 新增全屏状态,按F11可以进入、退出全屏状态,由于全屏时会隐藏控制栏按钮,所以需要使用鼠标右键双击(详情页的任意地方都可以)来关闭播放详情页
|
||||||
- 新增任务栏缩略图工具栏控制按钮(此功能仅在Windows平台可用),按钮分别为收藏/取消收藏(将歌曲添加到“我的收藏”列表)、上一曲、播放/暂停、下一曲
|
- 新增动态主题“道法自然”,你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。注:鼠标 右击 此主题项即可打开亮、暗色主题设置窗口。
|
||||||
- 新增设置-基本设置-软件字体设置,此设置可用于设置主界面的字体(已知的问题:Windows 7 下可能会出现字体列表为空的情况,这是当前系统的 Powershell 版本小于5.1导致的,请自行尝试看常见解决)
|
- 新增对kw源卡拉OK歌词的支持
|
||||||
- 新增Scheme URL对音乐搜索的调用支持,详情看常见问题-Scheme URL支持
|
|
||||||
- 新增Scheme URL以url传参的方式调用,详情看常见问题-Scheme URL支持
|
|
||||||
- 自定义源新增更新弹窗方法,同时自定义源管理新增是否允许源显示更新弹窗设置(出于防止滥用考虑),当源作者想要通知用户源已更新时,可以调用此方法弹窗告诉用户,调用说明看常见问题-自定义源部分
|
|
||||||
|
|
||||||
### 优化
|
### 优化
|
||||||
|
|
||||||
- 过滤tx源某些不支持播放的歌曲,解决播放此类内容会导致意外的问题
|
- 优化Windows任务栏缩略图工具栏控制按钮在浅色任务栏下的显示效果
|
||||||
- 把歌曲的热门评论与最新评论拆分成两个列表显示
|
- 添加音频可视化与音频输出设备冲突的提示
|
||||||
|
- 优化歌词的播放偏移
|
||||||
|
- 优化托盘菜单操作(#686)
|
||||||
|
- 优化播放下载列表时的切歌性能
|
||||||
|
|
||||||
### 修复
|
### 修复
|
||||||
|
|
||||||
- 修复排行榜名字右击菜单的播放功能在播放非激活的列表时的列表获取问题
|
- 修复“当前的声音输出设备被改变时暂停播放歌曲”设置无效的问题
|
||||||
- 修复修改列表名时无法使用`Ctrl`键的问题
|
- 修复桌面歌词没有处理停止播放状态的问题
|
||||||
- 修复wy源某些歌曲获取歌词翻译的问题处理
|
- 修复AppImage包无法运行的问题
|
||||||
- 修复下载功能的歌词换源时会进入死循环的问题
|
- 修复Windows任务栏缩略图工具栏控制按钮的歌曲收藏按钮状态更新问题
|
||||||
- 修复某些歌曲无法下载的问题
|
- 修复使用链接导入的歌单无法在我的列表打开原歌单详情页的问题
|
||||||
- 修复windows平台下软件目录存在`portable`文件夹时,仍会创建`C:\Users\<user>\AppData\Roaming\lx-music-desktop\Dictionaries\en-US-9-0.bdic`文件的问题,现在不会再创建文件,但仍会创建空目录(Electron的问题,目前暂无解决方法)
|
- 修复播放下载列表的歌曲时增删下载任务导致正在的歌曲序号改变时,不会更新到新增序号的问题
|
||||||
- 修复播放器的停止逻辑问题
|
|
||||||
|
|
||||||
### 其他
|
### 文档
|
||||||
|
|
||||||
- 更新electron到v13.6.9
|
添加LX中定义的快捷操作汇总说明到常见问题中,这是目前可用的鼠标、键盘快捷操作,它们都可以在更新日志中找到
|
||||||
|
|
||||||
|
- 鼠标右击播放栏的歌曲图片封面可以定位当前播放的歌曲
|
||||||
|
- 鼠标右击播放栏进度条上的LRC按钮可以锁定/解锁桌面歌词
|
||||||
|
- 歌曲搜索框、歌单链接输入框内鼠标右击可以将当前剪贴板上的文字粘贴到输入框内
|
||||||
|
- 鼠标右击搜索界面中的单条搜索历史可以将其移除
|
||||||
|
- 歌曲列表内的文字在选中后,鼠标右击可以复制已选中的文字,此功能只对搜索、歌单、排行榜、我的列表中的列表有效
|
||||||
|
- 鼠标在播放详情页内右键双击可以关闭播放详情页
|
||||||
|
- 鼠标左击播放栏上的歌曲名字可以将它复制
|
||||||
|
- 鼠标右击“道法自然(英文Auto)”主题可以打开亮、暗主题设置窗口
|
||||||
|
- 歌曲搜索框的候选内容可以用键盘上下方向键选择,按回车键搜索已选内容
|
||||||
|
- 在歌单详情页按退格键可以返回歌单列表
|
||||||
|
- 歌曲列表中可以使用Ctrl、Shift键进行多选,这类似Windows下的文件选择,详情看常见问题列表多选部分
|
||||||
|
- 在我的列表内可以使用Ctrl+f键打开搜索框进行列表内歌曲搜索,搜索框按Esc键可以关闭搜索框,搜索框内按上下方向键可以选择歌曲,按回车键跳转到已选歌曲,按Ctrl+回车可以跳转并播放已选歌曲
|
||||||
|
- 在我的列表按住Ctrl键可以进入列表拖动模式,此时可以用鼠标拖动列表调整列表的位置
|
||||||
|
- 编辑列表名时按Esc键可以取消编辑
|
||||||
|
- 按F11可以进入、退出全屏状态
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -106,7 +106,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 13,
|
id: 13,
|
||||||
name: '黑纸白字',
|
name: '黑灯瞎火',
|
||||||
className: 'black',
|
className: 'black',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -125,4 +125,6 @@ module.exports = {
|
||||||
className: 'happy_new_year',
|
className: 'happy_new_year',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
themeLights: [0, 1, 2, 3, 4, 10, 5, 6, 11, 12, 7, 8, 9],
|
||||||
|
themeDarks: [13, 7],
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ const path = require('path')
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
|
|
||||||
const defaultSetting = {
|
const defaultSetting = {
|
||||||
version: '1.0.51',
|
version: '1.0.54',
|
||||||
player: {
|
player: {
|
||||||
togglePlayMethod: 'listLoop',
|
togglePlayMethod: 'listLoop',
|
||||||
highQuality: false,
|
highQuality: false,
|
||||||
|
@ -19,6 +19,14 @@ const defaultSetting = {
|
||||||
waitPlayEndStop: true,
|
waitPlayEndStop: true,
|
||||||
waitPlayEndStopTime: '',
|
waitPlayEndStopTime: '',
|
||||||
},
|
},
|
||||||
|
playDetail: {
|
||||||
|
isZoomActiveLrc: true,
|
||||||
|
isShowLyricProgressSetting: false,
|
||||||
|
style: {
|
||||||
|
fontSize: 100,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
},
|
||||||
desktopLyric: {
|
desktopLyric: {
|
||||||
enable: false,
|
enable: false,
|
||||||
isLock: false,
|
isLock: false,
|
||||||
|
@ -97,7 +105,11 @@ const defaultSetting = {
|
||||||
port: '23332',
|
port: '23332',
|
||||||
},
|
},
|
||||||
windowSizeId: 2,
|
windowSizeId: 2,
|
||||||
themeId: 0,
|
theme: {
|
||||||
|
id: 0,
|
||||||
|
lightId: 0,
|
||||||
|
darkId: 13,
|
||||||
|
},
|
||||||
langId: null,
|
langId: null,
|
||||||
sourceId: 'kw',
|
sourceId: 'kw',
|
||||||
apiSource: 'temp',
|
apiSource: 'temp',
|
||||||
|
@ -116,7 +128,7 @@ const overwriteSetting = {
|
||||||
|
|
||||||
// 使用新年皮肤
|
// 使用新年皮肤
|
||||||
if (new Date().getMonth() < 2) {
|
if (new Date().getMonth() < 2) {
|
||||||
defaultSetting.themeId = 9
|
defaultSetting.theme.id = 9
|
||||||
defaultSetting.desktopLyric.theme = 3
|
defaultSetting.desktopLyric.theme = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ const names = {
|
||||||
close: 'close',
|
close: 'close',
|
||||||
min: 'min',
|
min: 'min',
|
||||||
max: 'max',
|
max: 'max',
|
||||||
|
fullscreen: 'fullscreen',
|
||||||
set_app_name: 'set_app_name',
|
set_app_name: 'set_app_name',
|
||||||
clear_cache: 'clear_cache',
|
clear_cache: 'clear_cache',
|
||||||
get_cache_size: 'get_cache_size',
|
get_cache_size: 'get_cache_size',
|
||||||
|
@ -15,6 +16,7 @@ const names = {
|
||||||
interval_callback: 'interval_callback',
|
interval_callback: 'interval_callback',
|
||||||
interval_cancel: 'interval_cancel',
|
interval_cancel: 'interval_cancel',
|
||||||
open_dev_tools: 'open_dev_tools',
|
open_dev_tools: 'open_dev_tools',
|
||||||
|
system_theme_change: 'system_theme_change',
|
||||||
|
|
||||||
set_music_meta: 'set_music_meta',
|
set_music_meta: 'set_music_meta',
|
||||||
progress: 'progress',
|
progress: 'progress',
|
||||||
|
|
|
@ -157,11 +157,6 @@ exports.initSetting = isShowErrorAlert => {
|
||||||
electronStore_config.set('setting.list.isSaveScrollLocation', scroll.enable)
|
electronStore_config.set('setting.list.isSaveScrollLocation', scroll.enable)
|
||||||
delete setting.list.scroll
|
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 后
|
// 从我的列表分离下载列表 v1.7.0 后
|
||||||
|
@ -173,6 +168,18 @@ exports.initSetting = isShowErrorAlert => {
|
||||||
|
|
||||||
const { version: settingVersion, setting: newSetting } = exports.mergeSetting(setting, electronStore_config.get('version'))
|
const { version: settingVersion, setting: newSetting } = exports.mergeSetting(setting, electronStore_config.get('version'))
|
||||||
|
|
||||||
|
// 修正拼写问题 v1.8.2 及以前
|
||||||
|
if (newSetting.player.isShowLyricTransition != null) {
|
||||||
|
newSetting.player.isShowLyricTranslation = newSetting.player.isShowLyricTransition
|
||||||
|
delete newSetting.player.isShowLyricTransition
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迁移v1.19.0之前的主题设置
|
||||||
|
if (newSetting.themeId != null) {
|
||||||
|
newSetting.theme.id = newSetting.themeId
|
||||||
|
delete newSetting.themeId
|
||||||
|
}
|
||||||
|
|
||||||
// 重置 ^0.18.2 排行榜ID
|
// 重置 ^0.18.2 排行榜ID
|
||||||
if (!newSetting.leaderboard.tabId.includes('__')) newSetting.leaderboard.tabId = 'kw__16'
|
if (!newSetting.leaderboard.tabId.includes('__')) newSetting.leaderboard.tabId = 'kw__16'
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"action": "Manage",
|
"action": "Manage",
|
||||||
"agree": "Accept",
|
"agree": "Accept",
|
||||||
|
"alert_button_text": "All right",
|
||||||
"audio_visualization": "Audio visualization (experimental)",
|
"audio_visualization": "Audio visualization (experimental)",
|
||||||
"back": "Back",
|
"back": "Back",
|
||||||
"cancel_button_text": "Cancel",
|
"cancel_button_text": "Cancel",
|
||||||
|
@ -168,7 +169,7 @@
|
||||||
"player__music_singer": "Artist: ",
|
"player__music_singer": "Artist: ",
|
||||||
"player__next": "Next",
|
"player__next": "Next",
|
||||||
"player__pause": "Pause",
|
"player__pause": "Pause",
|
||||||
"player__pic_tip": "Right click to locate the currently playing song in \"My List\"",
|
"player__pic_tip": "Play details page (right-click to locate the currently playing song in \"My List\")",
|
||||||
"player__play": "Play",
|
"player__play": "Play",
|
||||||
"player__play_toggle_mode_list": "Play in order",
|
"player__play_toggle_mode_list": "Play in order",
|
||||||
"player__play_toggle_mode_list_loop": "List Loop",
|
"player__play_toggle_mode_list_loop": "List Loop",
|
||||||
|
@ -227,6 +228,7 @@
|
||||||
"setting__basic_sourcename_real": "Original",
|
"setting__basic_sourcename_real": "Original",
|
||||||
"setting__basic_sourcename_title": "Select the name of music source",
|
"setting__basic_sourcename_title": "Select the name of music source",
|
||||||
"setting__basic_theme": "Theme",
|
"setting__basic_theme": "Theme",
|
||||||
|
"setting__basic_theme_auto_tip": "This is a dynamic theme, you can preset a light theme and a dark theme, and then it will automatically switch to the corresponding theme you preset according to the system's light and dark theme colors.\nNote: Right-click this theme item to open the light and dark theme setting window.",
|
||||||
"setting__basic_to_tray": "Do not exit the software when closing the software and minimize it to the system tray",
|
"setting__basic_to_tray": "Do not exit the software when closing the software and minimize it to the system tray",
|
||||||
"setting__basic_window_size": "Window size",
|
"setting__basic_window_size": "Window size",
|
||||||
"setting__basic_window_size_big": "Large",
|
"setting__basic_window_size_big": "Large",
|
||||||
|
@ -323,16 +325,29 @@
|
||||||
"setting__other_tray_theme_native": "White",
|
"setting__other_tray_theme_native": "White",
|
||||||
"setting__other_tray_theme_origin": "Primary Color",
|
"setting__other_tray_theme_origin": "Primary Color",
|
||||||
"setting__play": "Play",
|
"setting__play": "Play",
|
||||||
|
"setting__play_detail": "Play details page settings",
|
||||||
|
"setting__play_detail_align": "Lyric Alignment",
|
||||||
|
"setting__play_detail_align_center": "Centered",
|
||||||
|
"setting__play_detail_align_left": "Left",
|
||||||
|
"setting__play_detail_align_right": "Right",
|
||||||
|
"setting__play_detail_detail_lyric_progress": "Allows to adjust playback progress by lyrics",
|
||||||
|
"setting__play_detail_font_size": "Lyrics font size (you can use the keyboard + - adjust the font size on the playback details page)",
|
||||||
|
"setting__play_detail_font_size_current": "Current font size: {size}",
|
||||||
|
"setting__play_detail_font_size_reset": "Reset",
|
||||||
|
"setting__play_detail_font_zoom": "Zoom the currently playing lyrics",
|
||||||
"setting__play_lyric_lxlrc": "Use Karaoke-style lyrics playback (if supported)",
|
"setting__play_lyric_lxlrc": "Use Karaoke-style lyrics playback (if supported)",
|
||||||
"setting__play_lyric_s2t": "Convert the playing and downloading lyrics to Traditional Chinese",
|
"setting__play_lyric_s2t": "Convert the playing and downloading lyrics to Traditional Chinese",
|
||||||
"setting__play_lyric_transition": "Show lyrics translation",
|
"setting__play_lyric_transition": "Show lyrics translation",
|
||||||
"setting__play_mediaDevice": "Audio output",
|
"setting__play_mediaDevice": "Audio output",
|
||||||
"setting__play_mediaDevice_remove_stop_play": "Pause the song when the current sound output device is changed",
|
"setting__play_mediaDevice_remove_stop_play": "Pause the song when the current sound output device is changed",
|
||||||
"setting__play_mediaDevice_title": "Select a media device for audio output",
|
"setting__play_mediaDevice_title": "Select a media device for audio output",
|
||||||
|
"setting__play_media_device_error_tip": "This function conflicts with the audio visualization function. You have enabled audio visualization when you started the software this time. This setting is temporarily unavailable. Please restart the software and then modify this setting.",
|
||||||
|
"setting__play_media_device_tip": "This feature conflicts with Audio Visualization, both cannot be enabled at the same time, would you like to turn Audio Visualization off and apply the selected audio output settings?",
|
||||||
"setting__play_quality": "Play 320K quality songs first (if supported)",
|
"setting__play_quality": "Play 320K quality songs first (if supported)",
|
||||||
"setting__play_save_play_time": "Remember playback progress",
|
"setting__play_save_play_time": "Remember playback progress",
|
||||||
"setting__play_task_bar": "Show playing progress on the taskbar",
|
"setting__play_task_bar": "Show playing progress on the taskbar",
|
||||||
"setting__play_timeout": "Timed pause",
|
"setting__play_timeout": "Timed pause",
|
||||||
|
"setting__player_audio_visualization_tip": "The custom audio output device will conflict with the audio visualization function. After the audio visualization is enabled, the audio output device will be reset to the default output device. At present, this problem cannot be solved. Do you still want to enable it?",
|
||||||
"setting__search": "Search",
|
"setting__search": "Search",
|
||||||
"setting__search_focus_search_box": "Automatically focus the search box on startup",
|
"setting__search_focus_search_box": "Automatically focus the search box on startup",
|
||||||
"setting__search_history": "Search history",
|
"setting__search_history": "Search history",
|
||||||
|
@ -397,6 +412,8 @@
|
||||||
"sync__title": "Choose how to synchronize the list with {name}",
|
"sync__title": "Choose how to synchronize the list with {name}",
|
||||||
"tag__high_quality": "HQ",
|
"tag__high_quality": "HQ",
|
||||||
"tag__lossless": "SQ",
|
"tag__lossless": "SQ",
|
||||||
|
"theme_auto": "Auto",
|
||||||
|
"theme_auto_tip": "Right-click to open the light and dark theme settings window",
|
||||||
"theme_black": "Black",
|
"theme_black": "Black",
|
||||||
"theme_blue": "Blue",
|
"theme_blue": "Blue",
|
||||||
"theme_blue2": "Purple Blue",
|
"theme_blue2": "Purple Blue",
|
||||||
|
@ -410,6 +427,10 @@
|
||||||
"theme_pink": "Pink",
|
"theme_pink": "Pink",
|
||||||
"theme_purple": "Purple",
|
"theme_purple": "Purple",
|
||||||
"theme_red": "Red",
|
"theme_red": "Red",
|
||||||
|
"theme_selector_modal__dark_title": "dark theme",
|
||||||
|
"theme_selector_modal__light_title": "Bright theme",
|
||||||
|
"theme_selector_modal__title": "Follow system theme settings",
|
||||||
|
"theme_selector_modal__title_tip": "Note: You can set a light theme and a dark theme in advance, and then it will automatically switch to the corresponding theme you set in advance according to the light and dark theme colors of the system.",
|
||||||
"theme_yellow": "Yellow",
|
"theme_yellow": "Yellow",
|
||||||
"user_api__allow_show_update_alert": "Allow update popup to show",
|
"user_api__allow_show_update_alert": "Allow update popup to show",
|
||||||
"user_api__btn_export": "Export",
|
"user_api__btn_export": "Export",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"action": "操作",
|
"action": "操作",
|
||||||
"agree": "接受",
|
"agree": "接受",
|
||||||
|
"alert_button_text": "好吧",
|
||||||
"audio_visualization": "音频可视化(实验性)",
|
"audio_visualization": "音频可视化(实验性)",
|
||||||
"back": "返回",
|
"back": "返回",
|
||||||
"cancel_button_text": "我不",
|
"cancel_button_text": "我不",
|
||||||
|
@ -168,7 +169,7 @@
|
||||||
"player__music_singer": "艺术家:",
|
"player__music_singer": "艺术家:",
|
||||||
"player__next": "下一首",
|
"player__next": "下一首",
|
||||||
"player__pause": "暂停",
|
"player__pause": "暂停",
|
||||||
"player__pic_tip": "右击在“我的列表”定位当前播放的歌曲",
|
"player__pic_tip": "播放详情页(右击在“我的列表”定位当前播放的歌曲)",
|
||||||
"player__play": "播放",
|
"player__play": "播放",
|
||||||
"player__play_toggle_mode_list": "顺序播放",
|
"player__play_toggle_mode_list": "顺序播放",
|
||||||
"player__play_toggle_mode_list_loop": "列表循环",
|
"player__play_toggle_mode_list_loop": "列表循环",
|
||||||
|
@ -227,6 +228,7 @@
|
||||||
"setting__basic_sourcename_real": "原名",
|
"setting__basic_sourcename_real": "原名",
|
||||||
"setting__basic_sourcename_title": "选择音源名字类型",
|
"setting__basic_sourcename_title": "选择音源名字类型",
|
||||||
"setting__basic_theme": "主题颜色",
|
"setting__basic_theme": "主题颜色",
|
||||||
|
"setting__basic_theme_auto_tip": "此乃动态主题,你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。\n注:鼠标 右击 此主题项即可打开亮、暗色主题设置窗口。",
|
||||||
"setting__basic_to_tray": "关闭软件时不退出软件将其最小化到系统托盘",
|
"setting__basic_to_tray": "关闭软件时不退出软件将其最小化到系统托盘",
|
||||||
"setting__basic_window_size": "窗口尺寸",
|
"setting__basic_window_size": "窗口尺寸",
|
||||||
"setting__basic_window_size_big": "大",
|
"setting__basic_window_size_big": "大",
|
||||||
|
@ -323,16 +325,29 @@
|
||||||
"setting__other_tray_theme_native": "白色",
|
"setting__other_tray_theme_native": "白色",
|
||||||
"setting__other_tray_theme_origin": "原色",
|
"setting__other_tray_theme_origin": "原色",
|
||||||
"setting__play": "播放设置",
|
"setting__play": "播放设置",
|
||||||
|
"setting__play_detail": "播放详情页设置",
|
||||||
|
"setting__play_detail_align": "歌词对齐方式",
|
||||||
|
"setting__play_detail_align_center": "居中",
|
||||||
|
"setting__play_detail_align_left": "居左",
|
||||||
|
"setting__play_detail_align_right": "居右",
|
||||||
|
"setting__play_detail_detail_lyric_progress": "允许通过歌词调整播放进度",
|
||||||
|
"setting__play_detail_font_size": "歌词字体大小(可以在播放详情页使用键盘的 + - 调整字体大小)",
|
||||||
|
"setting__play_detail_font_size_current": "当前字体大小:{size}",
|
||||||
|
"setting__play_detail_font_size_reset": "重置",
|
||||||
|
"setting__play_detail_font_zoom": "缩放当前正在播放的歌词",
|
||||||
"setting__play_lyric_lxlrc": "使用卡拉OK式歌词播放(如果支持)",
|
"setting__play_lyric_lxlrc": "使用卡拉OK式歌词播放(如果支持)",
|
||||||
"setting__play_lyric_s2t": "将播放与下载的歌词转换为繁体中文",
|
"setting__play_lyric_s2t": "将播放与下载的歌词转换为繁体中文",
|
||||||
"setting__play_lyric_transition": "显示歌词翻译",
|
"setting__play_lyric_transition": "显示歌词翻译",
|
||||||
"setting__play_mediaDevice": "音频输出",
|
"setting__play_mediaDevice": "音频输出",
|
||||||
"setting__play_mediaDevice_remove_stop_play": "当前的声音输出设备被改变时暂停播放歌曲",
|
"setting__play_mediaDevice_remove_stop_play": "当前的声音输出设备被改变时暂停播放歌曲",
|
||||||
"setting__play_mediaDevice_title": "选择声音输出的媒体设备",
|
"setting__play_mediaDevice_title": "选择声音输出的媒体设备",
|
||||||
|
"setting__play_media_device_error_tip": "此功能与音频可视化功能冲突,你本次启动软件时已启用过音频可视化,此设置暂不可用,请 重启 软件后,再来修改此设置。",
|
||||||
|
"setting__play_media_device_tip": "此功能与音频可视化功能冲突,两者无法同时启用,是否将音频可视化关闭 并 应用所选音频输出设置?",
|
||||||
"setting__play_quality": "优先播放320K品质的歌曲(如果支持)",
|
"setting__play_quality": "优先播放320K品质的歌曲(如果支持)",
|
||||||
"setting__play_save_play_time": "记住播放进度",
|
"setting__play_save_play_time": "记住播放进度",
|
||||||
"setting__play_task_bar": "在任务栏上显示当前歌曲播放进度",
|
"setting__play_task_bar": "在任务栏上显示当前歌曲播放进度",
|
||||||
"setting__play_timeout": "定时暂停",
|
"setting__play_timeout": "定时暂停",
|
||||||
|
"setting__player_audio_visualization_tip": "自定义音频输出设备与音频可视化功能会冲突,启用了音频可视化后音频输出设备将会被重置为默认的输出设备,目前此问题暂无法解决,是否仍要开启?",
|
||||||
"setting__search": "搜索设置",
|
"setting__search": "搜索设置",
|
||||||
"setting__search_focus_search_box": "启动时自动聚焦搜索框",
|
"setting__search_focus_search_box": "启动时自动聚焦搜索框",
|
||||||
"setting__search_history": "显示历史搜索记录",
|
"setting__search_history": "显示历史搜索记录",
|
||||||
|
@ -397,6 +412,8 @@
|
||||||
"sync__title": "选择与 {name} 的列表同步方式",
|
"sync__title": "选择与 {name} 的列表同步方式",
|
||||||
"tag__high_quality": "HQ",
|
"tag__high_quality": "HQ",
|
||||||
"tag__lossless": "SQ",
|
"tag__lossless": "SQ",
|
||||||
|
"theme_auto": "道法自然",
|
||||||
|
"theme_auto_tip": "鼠标 右击 可打开亮、暗主题设置窗口",
|
||||||
"theme_black": "黑灯瞎火",
|
"theme_black": "黑灯瞎火",
|
||||||
"theme_blue": "蓝田生玉",
|
"theme_blue": "蓝田生玉",
|
||||||
"theme_blue2": "清热版蓝",
|
"theme_blue2": "清热版蓝",
|
||||||
|
@ -410,6 +427,10 @@
|
||||||
"theme_pink": "粉装玉琢",
|
"theme_pink": "粉装玉琢",
|
||||||
"theme_purple": "重斤球紫",
|
"theme_purple": "重斤球紫",
|
||||||
"theme_red": "热情似火",
|
"theme_red": "热情似火",
|
||||||
|
"theme_selector_modal__dark_title": "暗色主题",
|
||||||
|
"theme_selector_modal__light_title": "亮色主题",
|
||||||
|
"theme_selector_modal__title": "跟随系统主题设置",
|
||||||
|
"theme_selector_modal__title_tip": "注:你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。",
|
||||||
"theme_yellow": "信口雌黄",
|
"theme_yellow": "信口雌黄",
|
||||||
"user_api__allow_show_update_alert": "允许显示更新弹窗",
|
"user_api__allow_show_update_alert": "允许显示更新弹窗",
|
||||||
"user_api__btn_export": "导出",
|
"user_api__btn_export": "导出",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"action": "操作",
|
"action": "操作",
|
||||||
"agree": "接受",
|
"agree": "接受",
|
||||||
|
"alert_button_text": "好吧",
|
||||||
"audio_visualization": "音頻可視化(實驗性)",
|
"audio_visualization": "音頻可視化(實驗性)",
|
||||||
"back": "返回",
|
"back": "返回",
|
||||||
"cancel_button_text": "取消",
|
"cancel_button_text": "取消",
|
||||||
|
@ -168,7 +169,7 @@
|
||||||
"player__music_singer": "藝術家:",
|
"player__music_singer": "藝術家:",
|
||||||
"player__next": "下一首",
|
"player__next": "下一首",
|
||||||
"player__pause": "暫停",
|
"player__pause": "暫停",
|
||||||
"player__pic_tip": "右擊在“我的列表”定位當前播放的歌曲",
|
"player__pic_tip": "播放詳情頁(右擊在“我的列表”定位當前播放的歌曲)",
|
||||||
"player__play": "播放",
|
"player__play": "播放",
|
||||||
"player__play_toggle_mode_list": "順序播放",
|
"player__play_toggle_mode_list": "順序播放",
|
||||||
"player__play_toggle_mode_list_loop": "列表循環",
|
"player__play_toggle_mode_list_loop": "列表循環",
|
||||||
|
@ -227,6 +228,7 @@
|
||||||
"setting__basic_sourcename_real": "原名",
|
"setting__basic_sourcename_real": "原名",
|
||||||
"setting__basic_sourcename_title": "選擇音源名字類型",
|
"setting__basic_sourcename_title": "選擇音源名字類型",
|
||||||
"setting__basic_theme": "主題顏色",
|
"setting__basic_theme": "主題顏色",
|
||||||
|
"setting__basic_theme_auto_tip": "此乃動態主題,你可以預先設置一個亮色主題及暗色主題,此後將根據系統的亮、暗主題色自動切換為你預先設置的相應主題。\n注:鼠標 右擊 此主題項即可打開亮、暗色主題設置窗口。",
|
||||||
"setting__basic_to_tray": "關閉軟件時不退出軟件將其最小化到系統托盤",
|
"setting__basic_to_tray": "關閉軟件時不退出軟件將其最小化到系統托盤",
|
||||||
"setting__basic_window_size": "窗口尺寸",
|
"setting__basic_window_size": "窗口尺寸",
|
||||||
"setting__basic_window_size_big": "大",
|
"setting__basic_window_size_big": "大",
|
||||||
|
@ -323,16 +325,29 @@
|
||||||
"setting__other_tray_theme_native": "白色",
|
"setting__other_tray_theme_native": "白色",
|
||||||
"setting__other_tray_theme_origin": "原色",
|
"setting__other_tray_theme_origin": "原色",
|
||||||
"setting__play": "播放設置",
|
"setting__play": "播放設置",
|
||||||
|
"setting__play_detail": "播放詳情頁設置",
|
||||||
|
"setting__play_detail_align": "歌詞對齊方式",
|
||||||
|
"setting__play_detail_align_center": "居中",
|
||||||
|
"setting__play_detail_align_left": "居左",
|
||||||
|
"setting__play_detail_align_right": "居右",
|
||||||
|
"setting__play_detail_detail_lyric_progress": "允許通過歌詞調整播放進度",
|
||||||
|
"setting__play_detail_font_size": "歌詞字體大小(可以在播放詳情頁使用鍵盤的 + - 調整字體大小)",
|
||||||
|
"setting__play_detail_font_size_current": "當前字體大小:{size}",
|
||||||
|
"setting__play_detail_font_size_reset": "重置",
|
||||||
|
"setting__play_detail_font_zoom": "縮放當前正在播放的歌詞",
|
||||||
"setting__play_lyric_lxlrc": "使用卡拉OK式歌詞播放(如果支持)",
|
"setting__play_lyric_lxlrc": "使用卡拉OK式歌詞播放(如果支持)",
|
||||||
"setting__play_lyric_s2t": "將播放與下載的歌詞轉換為繁體中文",
|
"setting__play_lyric_s2t": "將播放與下載的歌詞轉換為繁體中文",
|
||||||
"setting__play_lyric_transition": "顯示歌詞翻譯",
|
"setting__play_lyric_transition": "顯示歌詞翻譯",
|
||||||
"setting__play_mediaDevice": "音頻輸出",
|
"setting__play_mediaDevice": "音頻輸出",
|
||||||
"setting__play_mediaDevice_remove_stop_play": "當前的聲音輸出設備被改變時暫停播放歌曲",
|
"setting__play_mediaDevice_remove_stop_play": "當前的聲音輸出設備被改變時暫停播放歌曲",
|
||||||
"setting__play_mediaDevice_title": "選擇聲音輸出的媒體設備",
|
"setting__play_mediaDevice_title": "選擇聲音輸出的媒體設備",
|
||||||
|
"setting__play_media_device_error_tip": "此功能與音頻可視化功能衝突,你本次啟動軟件時已啟用過音頻可視化,此設置暫不可用,請 重啟 軟件後,再來修改此設置。",
|
||||||
|
"setting__play_media_device_tip": "此功能與音頻可視化功能衝突,兩者無法同時啟用,是否將音頻可視化關閉 並 應用所選音頻輸出設置?",
|
||||||
"setting__play_quality": "優先播放320K品質的歌曲(如果支持)",
|
"setting__play_quality": "優先播放320K品質的歌曲(如果支持)",
|
||||||
"setting__play_save_play_time": "記住播放進度",
|
"setting__play_save_play_time": "記住播放進度",
|
||||||
"setting__play_task_bar": "在任務欄上顯示當前歌曲播放進度",
|
"setting__play_task_bar": "在任務欄上顯示當前歌曲播放進度",
|
||||||
"setting__play_timeout": "定時暫停",
|
"setting__play_timeout": "定時暫停",
|
||||||
|
"setting__player_audio_visualization_tip": "自定義音頻輸出設備與音頻可視化功能會衝突,啟用了音頻可視化後音頻輸出設備將會被重置為默認的輸出設備,目前此問題暫無法解決,是否仍要開啟?",
|
||||||
"setting__search": "搜索設置",
|
"setting__search": "搜索設置",
|
||||||
"setting__search_focus_search_box": "啟動時自動聚焦搜索框",
|
"setting__search_focus_search_box": "啟動時自動聚焦搜索框",
|
||||||
"setting__search_history": "顯示歷史搜索記錄",
|
"setting__search_history": "顯示歷史搜索記錄",
|
||||||
|
@ -397,6 +412,8 @@
|
||||||
"sync__title": "選擇與 {name} 的列表同步方式",
|
"sync__title": "選擇與 {name} 的列表同步方式",
|
||||||
"tag__high_quality": "HQ",
|
"tag__high_quality": "HQ",
|
||||||
"tag__lossless": "SQ",
|
"tag__lossless": "SQ",
|
||||||
|
"theme_auto": "道法自然",
|
||||||
|
"theme_auto_tip": "鼠標 右擊 可打開亮、暗主題設置窗口",
|
||||||
"theme_black": "黑燈瞎火",
|
"theme_black": "黑燈瞎火",
|
||||||
"theme_blue": "藍田生玉",
|
"theme_blue": "藍田生玉",
|
||||||
"theme_blue2": "清熱版藍",
|
"theme_blue2": "清熱版藍",
|
||||||
|
@ -410,6 +427,10 @@
|
||||||
"theme_pink": "粉裝玉琢",
|
"theme_pink": "粉裝玉琢",
|
||||||
"theme_purple": "重斤球紫",
|
"theme_purple": "重斤球紫",
|
||||||
"theme_red": "熱情似火",
|
"theme_red": "熱情似火",
|
||||||
|
"theme_selector_modal__dark_title": "暗色主題",
|
||||||
|
"theme_selector_modal__light_title": "亮色主題",
|
||||||
|
"theme_selector_modal__title": "跟隨系統主題設置",
|
||||||
|
"theme_selector_modal__title_tip": "注:你可以預先設置一個亮色主題及暗色主題,此後將根據系統的亮、暗主題色自動切換為你預先設置的相應主題。",
|
||||||
"theme_yellow": "信口雌黃",
|
"theme_yellow": "信口雌黃",
|
||||||
"user_api__allow_show_update_alert": "允許顯示更新彈窗",
|
"user_api__allow_show_update_alert": "允許顯示更新彈窗",
|
||||||
"user_api__btn_export": "導出",
|
"user_api__btn_export": "導出",
|
||||||
|
|
|
@ -26,6 +26,14 @@ class MainWindow extends EventEmitter {
|
||||||
this.emit(MAIN_WINDOW_EVENT_NAME.show)
|
this.emit(MAIN_WINDOW_EVENT_NAME.show)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.emit(MAIN_WINDOW_EVENT_NAME.focus)
|
||||||
|
}
|
||||||
|
|
||||||
|
blur() {
|
||||||
|
this.emit(MAIN_WINDOW_EVENT_NAME.blur)
|
||||||
|
}
|
||||||
|
|
||||||
hide() {
|
hide() {
|
||||||
this.emit(MAIN_WINDOW_EVENT_NAME.hide)
|
this.emit(MAIN_WINDOW_EVENT_NAME.hide)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ exports.mainWindow = {
|
||||||
ready_to_show: 'ready_to_show',
|
ready_to_show: 'ready_to_show',
|
||||||
show: 'show',
|
show: 'show',
|
||||||
hide: 'hide',
|
hide: 'hide',
|
||||||
|
focus: 'focus',
|
||||||
|
blur: 'blur',
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.tray = {
|
exports.tray = {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const electronDebug = require('electron-debug')
|
const electronDebug = require('electron-debug')
|
||||||
const { default: installExtension, VUEJS3_DEVTOOLS } = require('electron-devtools-installer')
|
const { default: installExtension, VUEJS_DEVTOOLS } = require('electron-devtools-installer')
|
||||||
// Install `electron-debug` with `devtron`
|
// Install `electron-debug` with `devtron`
|
||||||
electronDebug({
|
electronDebug({
|
||||||
showDevTools: true,
|
showDevTools: true,
|
||||||
|
@ -15,7 +15,7 @@ electronDebug({
|
||||||
|
|
||||||
// Install `vue-devtools`
|
// Install `vue-devtools`
|
||||||
electron.app.on('ready', () => {
|
electron.app.on('ready', () => {
|
||||||
installExtension(VUEJS3_DEVTOOLS)
|
installExtension(VUEJS_DEVTOOLS)
|
||||||
.then(name => console.log(`Added Extension: ${name}`))
|
.then(name => console.log(`Added Extension: ${name}`))
|
||||||
.catch(err => console.log('An error occurred: ', err))
|
.catch(err => console.log('An error occurred: ', err))
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const { app, BrowserWindow, shell } = require('electron')
|
const { app, BrowserWindow, shell, nativeTheme } = require('electron')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const urlSchemeRxp = /^lxmusic:\/\//
|
const urlSchemeRxp = /^lxmusic:\/\//
|
||||||
|
@ -170,7 +170,7 @@ function createWindow() {
|
||||||
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
|
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
|
||||||
resizable: false,
|
resizable: false,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
fullscreenable: false,
|
fullscreenable: true,
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
contextIsolation: false,
|
contextIsolation: false,
|
||||||
|
@ -180,7 +180,14 @@ function createWindow() {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
global.modules.mainWindow.loadURL(winURL + `?dt=${!!global.envParams.cmdParams.dt}&theme=${themes.find(t => t.id == global.appSetting.themeId)?.className ?? themes[0].className}`)
|
const shouldUseDarkColors = nativeTheme.shouldUseDarkColors
|
||||||
|
const themeId = global.appSetting.theme.id == 'auto'
|
||||||
|
? shouldUseDarkColors
|
||||||
|
? global.appSetting.theme.darkId
|
||||||
|
: global.appSetting.theme.lightId
|
||||||
|
: global.appSetting.theme.id
|
||||||
|
const themeClass = themes.find(t => t.id == themeId)?.className ?? themes[0].className
|
||||||
|
global.modules.mainWindow.loadURL(winURL + `?dt=${!!global.envParams.cmdParams.dt}&dark=${shouldUseDarkColors}&theme=${themeClass}`)
|
||||||
|
|
||||||
winEvent(global.modules.mainWindow)
|
winEvent(global.modules.mainWindow)
|
||||||
// global.modules.mainWindow.webContents.openDevTools()
|
// global.modules.mainWindow.webContents.openDevTools()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const { app, Tray, Menu, nativeImage } = require('electron')
|
const { app, Tray, Menu, nativeImage } = require('electron')
|
||||||
// const { isWin } = require('../../common/utils')
|
const { isWin } = require('@common/utils')
|
||||||
const { tray: TRAY_EVENT_NAME, common: COMMON_EVENT_NAME, mainWindow: MAIN_WINDOW_NAME } = require('../events/_name')
|
const { tray: TRAY_EVENT_NAME, common: COMMON_EVENT_NAME, mainWindow: MAIN_WINDOW_NAME } = require('../events/_name')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
let isEnableTray = null
|
let isEnableTray = null
|
||||||
|
@ -40,6 +40,14 @@ global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.ready_to_show, () => {
|
||||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.show, () => {
|
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.show, () => {
|
||||||
createMenu(global.modules.tray)
|
createMenu(global.modules.tray)
|
||||||
})
|
})
|
||||||
|
if (!isWin) {
|
||||||
|
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.focus, () => {
|
||||||
|
createMenu(global.modules.tray)
|
||||||
|
})
|
||||||
|
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.blur, () => {
|
||||||
|
createMenu(global.modules.tray)
|
||||||
|
})
|
||||||
|
}
|
||||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.hide, () => {
|
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.hide, () => {
|
||||||
createMenu(global.modules.tray)
|
createMenu(global.modules.tray)
|
||||||
})
|
})
|
||||||
|
@ -75,24 +83,27 @@ const destroyTray = () => {
|
||||||
const createMenu = tray => {
|
const createMenu = tray => {
|
||||||
if (!global.modules.tray) return
|
if (!global.modules.tray) return
|
||||||
let menu = []
|
let menu = []
|
||||||
global.modules.mainWindow && menu.push(global.modules.mainWindow.isVisible()
|
if (global.modules.mainWindow) {
|
||||||
? {
|
const isShow = global.modules.mainWindow.isVisible() && (isWin ? true : global.modules.mainWindow.isFocused())
|
||||||
label: '隐藏主界面',
|
menu.push(isShow
|
||||||
click() {
|
? {
|
||||||
global.modules.mainWindow.hide()
|
label: '隐藏主界面',
|
||||||
},
|
click() {
|
||||||
}
|
global.modules.mainWindow.hide()
|
||||||
: {
|
},
|
||||||
label: '显示主界面',
|
}
|
||||||
click() {
|
: {
|
||||||
if (!global.modules.mainWindow) return
|
label: '显示主界面',
|
||||||
if (!global.modules.mainWindow.isVisible()) {
|
click() {
|
||||||
global.modules.mainWindow.show()
|
if (!global.modules.mainWindow) return
|
||||||
}
|
if (!global.modules.mainWindow.isVisible()) {
|
||||||
global.modules.mainWindow.restore()
|
global.modules.mainWindow.show()
|
||||||
global.modules.mainWindow.focus()
|
}
|
||||||
},
|
global.modules.mainWindow.restore()
|
||||||
})
|
global.modules.mainWindow.focus()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
menu.push(global.appSetting.desktopLyric.enable
|
menu.push(global.appSetting.desktopLyric.enable
|
||||||
? {
|
? {
|
||||||
label: '关闭桌面歌词',
|
label: '关闭桌面歌词',
|
||||||
|
|
|
@ -22,10 +22,11 @@ require('./musicUrl')
|
||||||
require('./systemFonts')
|
require('./systemFonts')
|
||||||
require('./wait')
|
require('./wait')
|
||||||
require('./openDevtools')
|
require('./openDevtools')
|
||||||
|
require('./nativeTheme')
|
||||||
|
|
||||||
if (isWin) require('./taskbar')
|
if (isWin) require('./taskbar')
|
||||||
|
|
||||||
// require('./kw_decodeLyric')
|
require('./kw_decodeLyric')
|
||||||
|
|
||||||
require('./userApi')
|
require('./userApi')
|
||||||
require('./sync')
|
require('./sync')
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
const { nativeTheme } = require('electron')
|
||||||
|
|
||||||
|
const { NAMES: { mainWindow: ipcMainWindowNames }, mainSend } = require('@common/ipc')
|
||||||
|
|
||||||
|
nativeTheme.addListener('updated', (event) => {
|
||||||
|
// console.log(event.sender.shouldUseDarkColors)
|
||||||
|
if (!global.modules.mainWindow) return
|
||||||
|
mainSend(global.modules.mainWindow, ipcMainWindowNames.system_theme_change, event.sender.shouldUseDarkColors)
|
||||||
|
// console.log(nativeTheme.themeSource)
|
||||||
|
})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const { app } = require('electron')
|
const { app } = require('electron')
|
||||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
const { mainOn, mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||||
|
|
||||||
mainOn(ipcMainWindowNames.min, event => {
|
mainOn(ipcMainWindowNames.min, event => {
|
||||||
if (global.modules.mainWindow) {
|
if (global.modules.mainWindow) {
|
||||||
|
@ -16,3 +16,8 @@ mainOn(ipcMainWindowNames.close, (event, isForce) => {
|
||||||
global.isTrafficLightClose = true
|
global.isTrafficLightClose = true
|
||||||
if (global.modules.mainWindow) global.modules.mainWindow.close()
|
if (global.modules.mainWindow) global.modules.mainWindow.close()
|
||||||
})
|
})
|
||||||
|
mainHandle(ipcMainWindowNames.fullscreen, async(event, isFullscreen) => {
|
||||||
|
if (!global.modules.mainWindow) return false
|
||||||
|
await global.modules.mainWindow.setFullScreen(isFullscreen)
|
||||||
|
return isFullscreen
|
||||||
|
})
|
||||||
|
|
|
@ -26,6 +26,11 @@ module.exports = mainWindow => {
|
||||||
// })
|
// })
|
||||||
mainWindow.on('focus', () => {
|
mainWindow.on('focus', () => {
|
||||||
mainSend(mainWindow, ipcMainWindowNames.focus)
|
mainSend(mainWindow, ipcMainWindowNames.focus)
|
||||||
|
global.lx_event.mainWindow.focus()
|
||||||
|
})
|
||||||
|
|
||||||
|
mainWindow.on('blur', () => {
|
||||||
|
global.lx_event.mainWindow.blur()
|
||||||
})
|
})
|
||||||
|
|
||||||
mainWindow.once('ready-to-show', () => {
|
mainWindow.once('ready-to-show', () => {
|
||||||
|
|
|
@ -172,7 +172,6 @@ export default {
|
||||||
this.lyric.lines = lines
|
this.lyric.lines = lines
|
||||||
this.lyric.line = 0
|
this.lyric.line = 0
|
||||||
},
|
},
|
||||||
offset: 100,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -207,6 +206,13 @@ export default {
|
||||||
this.isPlay = false
|
this.isPlay = false
|
||||||
window.lrc.pause()
|
window.lrc.pause()
|
||||||
break
|
break
|
||||||
|
case 'stop':
|
||||||
|
this.isPlay = false
|
||||||
|
this.lyrics.lyric = ''
|
||||||
|
this.lyrics.tlyric = ''
|
||||||
|
this.lyrics.lxlyric = ''
|
||||||
|
this.setLyric()
|
||||||
|
break
|
||||||
case 'info':
|
case 'info':
|
||||||
// console.log('info', data)
|
// console.log('info', data)
|
||||||
this.lyrics.lyric = data.lrc
|
this.lyrics.lyric = data.lrc
|
||||||
|
@ -215,7 +221,9 @@ export default {
|
||||||
this.setLyric()
|
this.setLyric()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.lyric.line = data.line
|
this.lyric.line = data.line
|
||||||
rendererSend(NAMES.winLyric.get_lyric_info, 'status')
|
setTimeout(() => {
|
||||||
|
rendererSend(NAMES.winLyric.get_lyric_info, 'status')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
case 'music_info':
|
case 'music_info':
|
||||||
this.musicInfo.name = data.name
|
this.musicInfo.name = data.name
|
||||||
|
|
|
@ -16,24 +16,36 @@
|
||||||
<script>
|
<script>
|
||||||
import { useRefGetter, watch, onMounted } from '@renderer/utils/vueTools'
|
import { useRefGetter, watch, onMounted } from '@renderer/utils/vueTools'
|
||||||
import useApp from '@renderer/core/useApp'
|
import useApp from '@renderer/core/useApp'
|
||||||
|
import { isFullscreen } from '@renderer/core/share'
|
||||||
|
import { getFontSizeWithScreen } from '@renderer/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const theme = useRefGetter('theme')
|
const theme = useRefGetter('theme')
|
||||||
const font = useRefGetter('font')
|
const font = useRefGetter('font')
|
||||||
|
const windowSizeActive = useRefGetter('windowSizeActive')
|
||||||
|
|
||||||
const dom_root = document.getElementById('root')
|
const dom_root = document.getElementById('root')
|
||||||
|
|
||||||
watch(theme, (val) => {
|
watch(theme, (val) => {
|
||||||
dom_root.className = val
|
dom_root.className = val
|
||||||
}, {
|
|
||||||
immediate: true,
|
|
||||||
})
|
})
|
||||||
watch(font, (val) => {
|
watch(font, (val) => {
|
||||||
document.documentElement.style.fontFamily = val
|
document.documentElement.style.fontFamily = val
|
||||||
}, {
|
}, {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
})
|
})
|
||||||
|
watch(isFullscreen, val => {
|
||||||
|
if (val) {
|
||||||
|
document.body.classList.remove(window.dt ? 'disableTransparent' : 'transparent')
|
||||||
|
document.body.classList.add('fullscreen')
|
||||||
|
document.documentElement.style.fontSize = getFontSizeWithScreen(window.screen.width) + 'px'
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('fullscreen')
|
||||||
|
document.body.classList.add(window.dt ? 'disableTransparent' : 'transparent')
|
||||||
|
document.documentElement.style.fontSize = windowSizeActive.value.fontSize
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
useApp()
|
useApp()
|
||||||
|
|
||||||
|
@ -85,13 +97,13 @@ body {
|
||||||
|
|
||||||
.transparent {
|
.transparent {
|
||||||
padding: @shadow-app;
|
padding: @shadow-app;
|
||||||
#waiting-mask {
|
// #waiting-mask {
|
||||||
border-radius: @radius-border;
|
// border-radius: @radius-border;
|
||||||
left: @shadow-app;
|
// left: @shadow-app;
|
||||||
right: @shadow-app;
|
// right: @shadow-app;
|
||||||
top: @shadow-app;
|
// top: @shadow-app;
|
||||||
bottom: @shadow-app;
|
// bottom: @shadow-app;
|
||||||
}
|
// }
|
||||||
#root {
|
#root {
|
||||||
box-shadow: 0 0 @shadow-app rgba(0, 0, 0, 0.5);
|
box-shadow: 0 0 @shadow-app rgba(0, 0, 0, 0.5);
|
||||||
border-radius: @radius-border;
|
border-radius: @radius-border;
|
||||||
|
@ -114,6 +126,14 @@ body {
|
||||||
margin-right: 5Px;
|
margin-right: 5Px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.fullscreen {
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
#right {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -86,7 +86,8 @@ table {
|
||||||
flex-flow: row nowrap;
|
flex-flow: row nowrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
// border-top: 1px solid rgba(0, 0, 0, 0.12);
|
// border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
transition: background-color 0.2s ease;
|
transition: 0.2s ease;
|
||||||
|
transition-property: background-color, color;
|
||||||
border-bottom: 1px solid @color-theme_2-line;
|
border-bottom: 1px solid @color-theme_2-line;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -102,7 +103,7 @@ table {
|
||||||
flex: none;
|
flex: none;
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
// transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
@ -223,13 +224,13 @@ input, textarea {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-color: @color-scrollbar-thumb;
|
background-color: @color-scrollbar-thumb;
|
||||||
// background-color: rgba(0, 0, 0, 0.2);
|
// background-color: rgba(0, 0, 0, 0.2);
|
||||||
transition: all 0.4s ease;
|
transition: background-color 0.4s ease;
|
||||||
}
|
}
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
&::-webkit-scrollbar-thumb:hover {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-color: @color-scrollbar-thumb-hover;
|
background-color: @color-scrollbar-thumb-hover;
|
||||||
// background-color: rgba(0, 0, 0, 0.4);
|
// background-color: rgba(0, 0, 0, 0.4);
|
||||||
transition: all 0.4s ease;
|
transition: background-color 0.4s ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<ul :class="$style.list" :style="listStyles" ref="dom_list">
|
<ul :class="$style.list" :style="listStyles" ref="dom_list" role="toolbar" :aria-hidden="!show">
|
||||||
<li v-for="item in menus"
|
<li v-for="item in menus"
|
||||||
|
role="tab"
|
||||||
|
tabindex="0"
|
||||||
|
:aria-label="item[itemName]"
|
||||||
|
ignore-tip
|
||||||
:key="item.action"
|
:key="item.action"
|
||||||
@click="handleClick(item)"
|
@click="handleClick(item)"
|
||||||
v-show="!item.hide && (item.action == 'download' ? setting.download.enable : true)"
|
v-show="!item.hide && (item.action == 'download' ? setting.download.enable : true)"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
</div>
|
</div>
|
||||||
<ul class="selection-list scroll" :class="$style.list" :style="listStyles" ref="dom_list">
|
<ul class="selection-list scroll" :class="$style.list" :style="listStyles" ref="dom_list">
|
||||||
<li v-for="(item, index) in list" :key="index" :class="(itemKey ? item[itemKey] : item) == modelValue ? $style.active : null"
|
<li v-for="(item, index) in list" :key="index" :class="(itemKey ? item[itemKey] : item) == modelValue ? $style.active : null"
|
||||||
@click="handleClick(item)" :tips="itemName ? item[itemName] : item">{{itemName ? item[itemName] : item}}</li>
|
@click="handleClick(item)" :aria-label="itemName ? item[itemName] : item">{{itemName ? item[itemName] : item}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -141,8 +141,8 @@ export default {
|
||||||
const scrollContainerHeight = dom_scrollContainer.value.clientHeight
|
const scrollContainerHeight = dom_scrollContainer.value.clientHeight
|
||||||
const currentEndIndex = currentStartIndex + Math.ceil(scrollContainerHeight / itemHeight)
|
const currentEndIndex = currentStartIndex + Math.ceil(scrollContainerHeight / itemHeight)
|
||||||
const continuous = currentStartIndex <= endIndex && currentEndIndex >= startIndex
|
const continuous = currentStartIndex <= endIndex && currentEndIndex >= startIndex
|
||||||
const currentStartRenderIndex = Math.max(Math.floor(currentScrollTop / itemHeight) - props.outsideNum, 0)
|
const currentStartRenderIndex = Math.max(currentStartIndex - props.outsideNum, 0)
|
||||||
const currentEndRenderIndex = currentStartIndex + Math.ceil(scrollContainerHeight / itemHeight) + props.outsideNum
|
const currentEndRenderIndex = currentEndIndex + props.outsideNum + 1
|
||||||
// console.log(continuous)
|
// console.log(continuous)
|
||||||
// debugger
|
// debugger
|
||||||
if (continuous) {
|
if (continuous) {
|
||||||
|
@ -161,7 +161,7 @@ export default {
|
||||||
// // console.log('scroll up')
|
// // console.log('scroll up')
|
||||||
// views.value = createList(currentStartRenderIndex, currentEndRenderIndex)
|
// views.value = createList(currentStartRenderIndex, currentEndRenderIndex)
|
||||||
// } else return
|
// } else return
|
||||||
if (currentScrollTop == scrollTop) return
|
if (currentScrollTop == scrollTop && endIndex >= currentEndIndex) return
|
||||||
views.value = createList(currentStartRenderIndex, currentEndRenderIndex)
|
views.value = createList(currentStartRenderIndex, currentEndRenderIndex)
|
||||||
} else {
|
} else {
|
||||||
views.value = createList(currentStartRenderIndex, currentEndRenderIndex)
|
views.value = createList(currentStartRenderIndex, currentEndRenderIndex)
|
||||||
|
@ -215,19 +215,28 @@ export default {
|
||||||
return isScrolling ? scrollToValue : dom_scrollContainer.value.scrollTop
|
return isScrolling ? scrollToValue : dom_scrollContainer.value.scrollTop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
setTimeout(updateView)
|
||||||
|
}
|
||||||
|
|
||||||
const contentStyle = computed(() => ({
|
const contentStyle = computed(() => ({
|
||||||
display: 'block',
|
display: 'block',
|
||||||
height: props.list.length * props.itemHeight + 'px',
|
height: props.list.length * props.itemHeight + 'px',
|
||||||
}))
|
}))
|
||||||
|
|
||||||
watch(() => props.itemHeight, updateView)
|
const handleReset = list => {
|
||||||
watch(() => props.list, (list) => {
|
|
||||||
cachedList = Array(list.length)
|
cachedList = Array(list.length)
|
||||||
startIndex = -1
|
startIndex = -1
|
||||||
endIndex = -1
|
endIndex = -1
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
updateView()
|
updateView()
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
watch(() => props.itemHeight, () => {
|
||||||
|
handleReset(props.list)
|
||||||
|
})
|
||||||
|
watch(() => props.list, (list) => {
|
||||||
|
handleReset(list)
|
||||||
}, {
|
}, {
|
||||||
deep: true,
|
deep: true,
|
||||||
})
|
})
|
||||||
|
@ -238,9 +247,11 @@ export default {
|
||||||
startIndex = -1
|
startIndex = -1
|
||||||
endIndex = -1
|
endIndex = -1
|
||||||
updateView()
|
updateView()
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
})
|
})
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
dom_scrollContainer.value.removeEventListener('scroll', onScroll)
|
dom_scrollContainer.value.removeEventListener('scroll', onScroll)
|
||||||
|
window.removeEventListener('resize', handleResize)
|
||||||
if (cancelScroll) cancelScroll()
|
if (cancelScroll) cancelScroll()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -26,16 +26,29 @@ const themes = {
|
||||||
naruto: 'rgba(87,144,167,.14)',
|
naruto: 'rgba(87,144,167,.14)',
|
||||||
happy_new_year: 'rgba(192,57,43,.1)',
|
happy_new_year: 'rgba(192,57,43,.1)',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getBarWidth = canvasWidth => {
|
||||||
|
let barWidth = (canvasWidth / 128) * 2.5
|
||||||
|
const width = canvasWidth / 86
|
||||||
|
const diffWidth = barWidth - width
|
||||||
|
// console.log(barWidth - width)
|
||||||
|
// if (barWidth - width > 20) newBarWidth = 20
|
||||||
|
// barWidth = newBarWidth
|
||||||
|
return diffWidth > 32
|
||||||
|
? canvasWidth / 128 // 4k屏、超宽屏直接显示所有频谱条
|
||||||
|
: diffWidth > 12 ? width : barWidth
|
||||||
|
}
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const dom_canvas = ref(null)
|
const dom_canvas = ref(null)
|
||||||
const analyser = getAnalyser()
|
const analyser = getAnalyser()
|
||||||
|
|
||||||
let ctx
|
let ctx
|
||||||
let bufferLength
|
let bufferLength = 0
|
||||||
let dataArray
|
let dataArray
|
||||||
let WIDTH
|
let WIDTH
|
||||||
let HEIGHT
|
let HEIGHT
|
||||||
|
let MAX_HEIGHT
|
||||||
let barWidth
|
let barWidth
|
||||||
let barHeight
|
let barHeight
|
||||||
let x = 0
|
let x = 0
|
||||||
|
@ -89,7 +102,7 @@ export default {
|
||||||
// let b = 50
|
// let b = 50
|
||||||
|
|
||||||
// ctx.fillStyle = 'rgb(' + r + ',' + g + ',' + b + ')'
|
// ctx.fillStyle = 'rgb(' + r + ',' + g + ',' + b + ')'
|
||||||
barHeight = barHeight * frequencyAvg + barHeight * 0.42
|
barHeight = (barHeight * frequencyAvg + barHeight * 0.42) * MAX_HEIGHT
|
||||||
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight)
|
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight)
|
||||||
|
|
||||||
x += barWidth
|
x += barWidth
|
||||||
|
@ -101,7 +114,7 @@ export default {
|
||||||
analyser.fftSize = 256
|
analyser.fftSize = 256
|
||||||
bufferLength = analyser.frequencyBinCount
|
bufferLength = analyser.frequencyBinCount
|
||||||
// console.log(bufferLength)
|
// console.log(bufferLength)
|
||||||
barWidth = (WIDTH / bufferLength) * 2.5
|
barWidth = getBarWidth(WIDTH)
|
||||||
dataArray = new Uint8Array(bufferLength)
|
dataArray = new Uint8Array(bufferLength)
|
||||||
renderFrame()
|
renderFrame()
|
||||||
}
|
}
|
||||||
|
@ -110,14 +123,27 @@ export default {
|
||||||
isPlaying = false
|
isPlaying = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
const canvas = dom_canvas.value
|
||||||
|
canvas.width = canvas.clientWidth
|
||||||
|
canvas.height = canvas.clientHeight
|
||||||
|
WIDTH = canvas.width
|
||||||
|
HEIGHT = canvas.height
|
||||||
|
MAX_HEIGHT = Math.round(HEIGHT * 0.4 / 255 * 10000) / 10000
|
||||||
|
// console.log(MAX_HEIGHT)
|
||||||
|
barWidth = getBarWidth(WIDTH)
|
||||||
|
}
|
||||||
|
|
||||||
window.eventHub.on(eventPlayerNames.play, handlePlay)
|
window.eventHub.on(eventPlayerNames.play, handlePlay)
|
||||||
window.eventHub.on(eventPlayerNames.pause, handlePause)
|
window.eventHub.on(eventPlayerNames.pause, handlePause)
|
||||||
window.eventHub.on(eventPlayerNames.error, handlePause)
|
window.eventHub.on(eventPlayerNames.error, handlePause)
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
handlePause()
|
handlePause()
|
||||||
window.eventHub.off(eventPlayerNames.play, handlePlay)
|
window.eventHub.off(eventPlayerNames.play, handlePlay)
|
||||||
window.eventHub.off(eventPlayerNames.pause, handlePause)
|
window.eventHub.off(eventPlayerNames.pause, handlePause)
|
||||||
window.eventHub.off(eventPlayerNames.error, handlePause)
|
window.eventHub.off(eventPlayerNames.error, handlePause)
|
||||||
|
window.removeEventListener('resize', handleResize)
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -127,6 +153,8 @@ export default {
|
||||||
canvas.height = canvas.clientHeight
|
canvas.height = canvas.clientHeight
|
||||||
WIDTH = canvas.width
|
WIDTH = canvas.width
|
||||||
HEIGHT = canvas.height
|
HEIGHT = canvas.height
|
||||||
|
MAX_HEIGHT = Math.round(HEIGHT * 0.4 / 255 * 10000) / 10000
|
||||||
|
// console.log(MAX_HEIGHT)
|
||||||
if (isPlay.value) handlePlay()
|
if (isPlay.value) handlePlay()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ export default {
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
max-width: 300px;
|
max-width: 400px;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
|
|
@ -51,7 +51,7 @@ export default {
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
max-width: 300px;
|
max-width: 400px;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<material-modal :show="show" :bg-close="bgClose" @close="handleClose" :teleport="teleport">
|
<material-modal :show="show" :bg-close="bgClose" @close="handleClose" :teleport="teleport" max-width="70%">
|
||||||
<main :class="$style.main">
|
<main :class="$style.main">
|
||||||
<h2>{{$t('list_add__' + (isMove ? 'title_first_move' : 'title_first_add'))}} <span :class="$style.name">{{this.musicInfo && `${musicInfo.name}`}}</span> {{$t('list_add__title_last')}}</h2>
|
<h2>{{$t('list_add__' + (isMove ? 'title_first_move' : 'title_first_add'))}} <span :class="$style.name">{{this.musicInfo && `${musicInfo.name}`}}</span> {{$t('list_add__title_last')}}</h2>
|
||||||
<div class="scroll" :class="$style.btnContent">
|
<div class="scroll" :class="$style.btnContent">
|
||||||
<base-btn :class="$style.btn" :tips="$t('list_add__btn_title', { name: item.name })" :key="item.id" :disabled="item.isExist" @click="handleClick(index)" v-for="(item, index) in lists">{{item.name}}</base-btn>
|
<base-btn :class="$style.btn" :aria-label="$t('list_add__btn_title', { name: item.name })" :key="item.id" :disabled="item.isExist" @click="handleClick(index)" v-for="(item, index) in lists">{{item.name}}</base-btn>
|
||||||
<base-btn :class="[$style.btn, $style.newList, isEditing ? $style.editing : null]" @click="handleEditing($event)" :tips="$t('lists__new_list_btn')">
|
<base-btn :class="[$style.btn, $style.newList, isEditing ? $style.editing : null]" @click="handleEditing($event)" :aria-label="$t('lists__new_list_btn')">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" viewBox="0 0 42 42" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" viewBox="0 0 42 42" space="preserve">
|
||||||
<use xlink:href="#icon-addTo"></use>
|
<use xlink:href="#icon-addTo"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -74,15 +74,31 @@ export default {
|
||||||
return {
|
return {
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
newListName: '',
|
newListName: '',
|
||||||
|
rowNum: 3,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
spaceNum() {
|
spaceNum() {
|
||||||
return this.lists.length < 2 ? 0 : (3 - this.lists.length % 3 - 1)
|
return this.lists.length < 2 ? 0 : (this.rowNum - this.lists.length % this.rowNum - 1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
window.addEventListener('resize', this.handleResize)
|
||||||
|
this.handleResize()
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
window.removeEventListener('resize', this.handleResize)
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations('list', ['listAdd', 'listMove', 'createUserList']),
|
...mapMutations('list', ['listAdd', 'listMove', 'createUserList']),
|
||||||
|
handleResize() {
|
||||||
|
const width = window.innerWidth
|
||||||
|
this.rowNum = width < 1920
|
||||||
|
? 3
|
||||||
|
: width < 2560
|
||||||
|
? 4
|
||||||
|
: width < 3840 ? 5 : 6
|
||||||
|
},
|
||||||
handleClick(index) {
|
handleClick(index) {
|
||||||
this.isMove
|
this.isMove
|
||||||
? this.listMove({ fromId: this.fromListId, toId: this.lists[index].id, musicInfo: this.musicInfo })
|
? this.listMove({ fromId: this.fromListId, toId: this.lists[index].id, musicInfo: this.musicInfo })
|
||||||
|
@ -117,7 +133,7 @@ export default {
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
// padding: 15px 0;
|
// padding: 15px 0;
|
||||||
max-width: 620px;
|
// max-width: 70%;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
@ -147,14 +163,17 @@ export default {
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@item-width: (100% / 3);
|
||||||
.btn {
|
.btn {
|
||||||
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
padding: 0 10px !important;
|
padding: 0 10px !important;
|
||||||
width: 180px;
|
width: calc(@item-width - 15px);
|
||||||
|
min-width: 160px;
|
||||||
.mixin-ellipsis-1;
|
.mixin-ellipsis-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +200,9 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.newListInput {
|
.newListInput {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -191,9 +213,30 @@ export default {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 10px;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@item-width2: (100% / 4);
|
||||||
|
@media (min-width: 1920px){
|
||||||
|
.btn {
|
||||||
|
width: calc(@item-width2 - 15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@item-width3: (100% / 5);
|
||||||
|
@media (min-width: 2560px){
|
||||||
|
.btn {
|
||||||
|
width: calc(@item-width3 - 15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@item-width4: (100% / 6);
|
||||||
|
@media (min-width: 3840px){
|
||||||
|
.btn {
|
||||||
|
width: calc(@item-width4 - 15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
each(@themes, {
|
each(@themes, {
|
||||||
:global(#root.@{value}) {
|
:global(#root.@{value}) {
|
||||||
.main {
|
.main {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<material-modal :show="show" :bg-close="bgClose" @close="handleClose">
|
<material-modal :show="show" :bg-close="bgClose" @close="handleClose" max-width="70%">
|
||||||
<main :class="$style.main">
|
<main :class="$style.main">
|
||||||
<h2>{{$t('list_add__multiple_' + (isMove ? 'title_move' : 'title_add'), { num: musicList.length })}}</h2>
|
<h2>{{$t('list_add__multiple_' + (isMove ? 'title_move' : 'title_add'), { num: musicList.length })}}</h2>
|
||||||
<div class="scroll" :class="$style.btnContent">
|
<div class="scroll" :class="$style.btnContent">
|
||||||
<base-btn :class="$style.btn" :tips="$t('list_add__multiple_btn_title', { name: item.name })" :key="item.id" @click="handleClick(index)" v-for="(item, index) in lists">{{item.name}}</base-btn>
|
<base-btn :class="$style.btn" :aria-label="$t('list_add__multiple_btn_title', { name: item.name })" :key="item.id" @click="handleClick(index)" v-for="(item, index) in lists">{{item.name}}</base-btn>
|
||||||
<base-btn :class="[$style.btn, $style.newList, isEditing ? $style.editing : null]" @click="handleEditing($event)" :tips="$t('lists__new_list_btn')">
|
<base-btn :class="[$style.btn, $style.newList, isEditing ? $style.editing : null]" @click="handleEditing($event)" :aria-label="$t('lists__new_list_btn')">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" viewBox="0 0 42 42" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" viewBox="0 0 42 42" space="preserve">
|
||||||
<use xlink:href="#icon-addTo"></use>
|
<use xlink:href="#icon-addTo"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -74,16 +74,32 @@ export default {
|
||||||
return {
|
return {
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
newListName: '',
|
newListName: '',
|
||||||
|
rowNum: 3,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
||||||
spaceNum() {
|
spaceNum() {
|
||||||
return this.lists.length < 2 ? 0 : (3 - this.lists.length % 3 - 1)
|
return this.lists.length < 2 ? 0 : (this.rowNum - this.lists.length % this.rowNum - 1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
window.addEventListener('resize', this.handleResize)
|
||||||
|
this.handleResize()
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
window.removeEventListener('resize', this.handleResize)
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations('list', ['listAddMultiple', 'listMoveMultiple', 'createUserList']),
|
...mapMutations('list', ['listAddMultiple', 'listMoveMultiple', 'createUserList']),
|
||||||
|
handleResize() {
|
||||||
|
const width = window.innerWidth
|
||||||
|
this.rowNum = width < 1920
|
||||||
|
? 3
|
||||||
|
: width < 2560
|
||||||
|
? 4
|
||||||
|
: width < 3840 ? 5 : 6
|
||||||
|
},
|
||||||
handleClick(index) {
|
handleClick(index) {
|
||||||
this.isMove
|
this.isMove
|
||||||
? this.listMoveMultiple({ fromId: this.fromListId, toId: this.lists[index].id, list: this.musicList })
|
? this.listMoveMultiple({ fromId: this.fromListId, toId: this.lists[index].id, list: this.musicList })
|
||||||
|
@ -119,7 +135,7 @@ export default {
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
// padding: 15px 0;
|
// padding: 15px 0;
|
||||||
max-width: 620px;
|
// max-width: 620px;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
@ -145,14 +161,17 @@ export default {
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@item-width: (100% / 3);
|
||||||
.btn {
|
.btn {
|
||||||
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
padding: 0 10px !important;
|
padding: 0 10px !important;
|
||||||
width: 180px;
|
width: calc(@item-width - 15px);
|
||||||
|
min-width: 160px;
|
||||||
.mixin-ellipsis-1;
|
.mixin-ellipsis-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +198,9 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.newListInput {
|
.newListInput {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -189,9 +211,31 @@ export default {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 10px;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@item-width2: (100% / 4);
|
||||||
|
@media (min-width: 1920px){
|
||||||
|
.btn {
|
||||||
|
width: calc(@item-width2 - 15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@item-width3: (100% / 5);
|
||||||
|
@media (min-width: 2560px){
|
||||||
|
.btn {
|
||||||
|
width: calc(@item-width3 - 15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@item-width4: (100% / 6);
|
||||||
|
@media (min-width: 3840px){
|
||||||
|
.btn {
|
||||||
|
width: calc(@item-width4 - 15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
each(@themes, {
|
each(@themes, {
|
||||||
:global(#root.@{value}) {
|
:global(#root.@{value}) {
|
||||||
.main {
|
.main {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div :class="[$style.volume, {[$style.muted]: setting.player.isMute} ]">
|
<div :class="[$style.volume, {[$style.muted]: setting.player.isMute} ]">
|
||||||
<div :class="$style.volumeBar" ref="dom_volumeBar" :style="{ transform: `scaleX(${volume || 0})` }"></div>
|
<div :class="$style.volumeBar" ref="dom_volumeBar" :style="{ transform: `scaleX(${volume || 0})` }"></div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.volumeMask" @mousedown="handleVolumeMsDown" :tips="`${$t('player__volume')}${parseInt(volume * 100)}%`"></div>
|
<div :class="$style.volumeMask" @mousedown="handleVolumeMsDown" :aria-label="`${$t('player__volume')}${parseInt(volume * 100)}%`"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.controlBtn">
|
<div :class="$style.controlBtn" v-show="!isFullscreen">
|
||||||
<button type="button" :class="[$style.btn, $style.close]" :tips="$t('close')" @click="close">
|
<button type="button" :class="[$style.btn, $style.close]" :aria-label="$t('close')" @click="close">
|
||||||
<svg :class="$style.controlBtniIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
<svg :class="$style.controlBtniIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
||||||
<use xlink:href="#icon-window-close"></use>
|
<use xlink:href="#icon-window-close"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" :class="[$style.btn, $style.min]" :tips="$t('min')" @click="min">
|
<button type="button" :class="[$style.btn, $style.min]" :aria-label="$t('min')" @click="min">
|
||||||
<svg :class="$style.controlBtniIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
<svg :class="$style.controlBtniIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
||||||
<use xlink:href="#icon-window-minimize"></use>
|
<use xlink:href="#icon-window-minimize"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -16,10 +16,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { base as eventBaseName } from '@renderer/event/names'
|
import { base as eventBaseName } from '@renderer/event/names'
|
||||||
// import { getRandom } from '../../utils'
|
// import { getRandom } from '../../utils'
|
||||||
|
import { isFullscreen } from '@renderer/core/share'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
|
isFullscreen,
|
||||||
min() {
|
min() {
|
||||||
window.eventHub.emit(eventBaseName.min)
|
window.eventHub.emit(eventBaseName.min)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.menu">
|
<div :class="$style.menu">
|
||||||
<ul :class="$style.list">
|
<ul :class="$style.list" role="toolbar">
|
||||||
<li v-for="item in menus" :key="item.to">
|
<li v-for="item in menus" :key="item.to" :class="$style.navItem" role="presentation">
|
||||||
<router-link :class="$style.link" :active-class="$style.active" :to="item.to" :tips="item.tips">
|
<router-link :class="$style.link" :active-class="$style.active" role="tab" :aria-selected="$route.name == item.to" :to="item.to" :aria-label="item.tips">
|
||||||
<div :class="$style.icon">
|
<div :class="$style.icon">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" :viewBox="item.iconSize" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" :viewBox="item.iconSize" space="preserve">
|
||||||
<use :xlink:href="item.icon"></use>
|
<use :xlink:href="item.icon"></use>
|
||||||
|
@ -98,13 +98,26 @@ export default {
|
||||||
// .mixin-ellipsis-1;
|
// .mixin-ellipsis-1;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
.navItem {
|
||||||
|
position: relative;
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 84%;
|
||||||
|
}
|
||||||
|
}
|
||||||
.link {
|
.link {
|
||||||
display: block;
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
// display: block;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
position: relative;
|
// padding: 18px 3px;
|
||||||
padding: 18px 3px;
|
|
||||||
// margin: 5px 0;
|
// margin: 5px 0;
|
||||||
// border-left: 5px solid transparent;
|
// border-left: 5px solid transparent;
|
||||||
transition: @transition-theme;
|
transition: @transition-theme;
|
||||||
|
@ -114,6 +127,9 @@ export default {
|
||||||
font-size: 11.5px;
|
font-size: 11.5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.3s ease;
|
||||||
// border-radius: @radius-border;
|
// border-radius: @radius-border;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.aside">
|
<div :class="[$style.aside, { [$style.fullscreen]: isFullscreen }]">
|
||||||
<ControlBtns v-if="setting.controlBtnPosition == 'left'" />
|
<ControlBtns v-if="setting.controlBtnPosition == 'left'" />
|
||||||
<div :class="$style.logo" v-else>L X</div>
|
<div :class="$style.logo" v-else>L X</div>
|
||||||
<NavBar />
|
<NavBar />
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
import { isFullscreen } from '@renderer/core/share'
|
||||||
|
|
||||||
import ControlBtns from './ControlBtns'
|
import ControlBtns from './ControlBtns'
|
||||||
import NavBar from './NavBar'
|
import NavBar from './NavBar'
|
||||||
|
@ -15,6 +16,11 @@ import NavBar from './NavBar'
|
||||||
export default {
|
export default {
|
||||||
name: 'CoreAside',
|
name: 'CoreAside',
|
||||||
components: { ControlBtns, NavBar },
|
components: { ControlBtns, NavBar },
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
isFullscreen,
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['setting']),
|
...mapGetters(['setting']),
|
||||||
},
|
},
|
||||||
|
@ -36,6 +42,13 @@ export default {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
|
|
||||||
|
&.fullscreen {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
.logo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' style="display: none;")
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' style="display: none;" aria-hidden="true")
|
||||||
defs
|
defs
|
||||||
g#icon-search(fill='currentColor')
|
g#icon-search(fill='currentColor')
|
||||||
// 30.239 30.239
|
// 30.239 30.239
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.controlBtn">
|
<div :class="$style.controlBtn">
|
||||||
<common-volume-bar :setting="setting" />
|
<common-volume-bar :setting="setting" />
|
||||||
<div :class="$style.titleBtn" @click="toggleDesktopLyric" @contextmenu="toggleLockDesktopLyric" :tips="toggleDesktopLyricBtnTitle">
|
<div :class="$style.titleBtn" @click="toggleDesktopLyric" @contextmenu="toggleLockDesktopLyric" :aria-label="toggleDesktopLyricBtnTitle">
|
||||||
<svg v-show="setting.desktopLyric.enable" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 512 512" space="preserve">
|
<svg v-show="setting.desktopLyric.enable" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 512 512" space="preserve">
|
||||||
<use xlink:href="#icon-desktop-lyric-on"></use>
|
<use xlink:href="#icon-desktop-lyric-on"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
<use xlink:href="#icon-desktop-lyric-off"></use>
|
<use xlink:href="#icon-desktop-lyric-off"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.titleBtn" @click="toggleNextPlayMode" :tips="nextTogglePlayName">
|
<div :class="$style.titleBtn" @click="toggleNextPlayMode" :aria-label="nextTogglePlayName">
|
||||||
<svg v-show="setting.player.togglePlayMethod == 'listLoop'" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="80%" viewBox="0 0 24 24" space="preserve">
|
<svg v-show="setting.player.togglePlayMethod == 'listLoop'" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="80%" viewBox="0 0 24 24" space="preserve">
|
||||||
<use xlink:href="#icon-list-loop"></use>
|
<use xlink:href="#icon-list-loop"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
<use xlink:href="#icon-single"></use>
|
<use xlink:href="#icon-single"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.titleBtn" @click="addMusicTo" :tips="$t('player__add_music_to')">
|
<div :class="$style.titleBtn" @click="addMusicTo" :aria-label="$t('player__add_music_to')">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="80%" viewBox="0 0 512 512" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="80%" viewBox="0 0 512 512" space="preserve">
|
||||||
<use xlink:href="#icon-add-2"></use>
|
<use xlink:href="#icon-add-2"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
div(:class="$style.player")
|
div(:class="$style.player")
|
||||||
div(:class="$style.left" @contextmenu="handleToMusicLocation" @click="showPlayerDetail" :tips="$t('player__pic_tip')")
|
div(:class="$style.left" @contextmenu="handleToMusicLocation" @click="showPlayerDetail" :aria-label="$t('player__pic_tip')")
|
||||||
img(v-if="musicInfo.img" :src="musicInfo.img" @error="imgError")
|
img(v-if="musicInfo.img" :src="musicInfo.img" @error="imgError")
|
||||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='102%' width='100%' viewBox='0 0 60 60' space='preserve')
|
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='102%' width='100%' viewBox='0 0 60 60' space='preserve')
|
||||||
use(:xlink:href='`#${$style.iconPic}`')
|
use(:xlink:href='`#${$style.iconPic}`')
|
||||||
div(:class="$style.middle")
|
div(:class="$style.middle")
|
||||||
div(:class="$style.column1")
|
div(:class="$style.column1")
|
||||||
div(:class="$style.container")
|
div(:class="$style.container")
|
||||||
div(:class="$style.title" @click="handleCopy(title)" :tips="title + $t('copy_tip')") {{title}}
|
div(:class="$style.title" @click="handleCopy(title)" :aria-label="title + $t('copy_tip')") {{title}}
|
||||||
control-btns
|
control-btns
|
||||||
div(:class="$style.column2")
|
div(:class="$style.column2")
|
||||||
common-progress-bar(:progress="progress" :handleTransitionEnd="handleTransitionEnd" :isActiveTransition="isActiveTransition" v-if="!isShowPlayerDetail")
|
common-progress-bar(:progress="progress" :handleTransitionEnd="handleTransitionEnd" :isActiveTransition="isActiveTransition" v-if="!isShowPlayerDetail")
|
||||||
|
@ -18,15 +18,15 @@ div(:class="$style.player")
|
||||||
span(style="margin: 0 5px;") /
|
span(style="margin: 0 5px;") /
|
||||||
span {{maxPlayTimeStr}}
|
span {{maxPlayTimeStr}}
|
||||||
div(:class="$style.right")
|
div(:class="$style.right")
|
||||||
div(:class="$style.playBtn" @click='playPrev' :tips="$t('player__prev')" style="transform: rotate(180deg);")
|
div(:class="$style.playBtn" @click='playPrev' :aria-label="$t('player__prev')" style="transform: rotate(180deg);")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||||
use(xlink:href='#icon-nextMusic')
|
use(xlink:href='#icon-nextMusic')
|
||||||
div(:class="$style.playBtn" :tips="isPlay ? $t('player__pause') : $t('player__play')" @click='togglePlay')
|
div(:class="$style.playBtn" :aria-label="isPlay ? $t('player__pause') : $t('player__play')" @click='togglePlay')
|
||||||
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||||
use(xlink:href='#icon-pause')
|
use(xlink:href='#icon-pause')
|
||||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||||
use(xlink:href='#icon-play')
|
use(xlink:href='#icon-play')
|
||||||
div(:class="$style.playBtn" @click='playNext' :tips="$t('player__next')")
|
div(:class="$style.playBtn" @click='playNext' :aria-label="$t('player__next')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||||
use(xlink:href='#icon-nextMusic')
|
use(xlink:href='#icon-nextMusic')
|
||||||
|
|
||||||
|
@ -276,6 +276,7 @@ export default {
|
||||||
.column2 {
|
.column2 {
|
||||||
flex: none;
|
flex: none;
|
||||||
padding: 3px 0;
|
padding: 3px 0;
|
||||||
|
height: 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="['right', $style.right]">
|
<div :class="['right', $style.right]" :style="lrcFontSize">
|
||||||
<div :class="['lyric', $style.lyric, { [$style.draging]: isMsDown }]" @wheel="handleWheel" @mousedown="handleLyricMouseDown" ref="dom_lyric">
|
<div :class="['lyric', $style.lyric, { [$style.draging]: isMsDown }, { [$style.lrcActiveZoom]: isZoomActiveLrc }]" :style="lrcStyles" @wheel="handleWheel" @mousedown="handleLyricMouseDown" ref="dom_lyric">
|
||||||
<div :class="$style.lyricSpace"></div>
|
<div :class="['pre', $style.lyricSpace]"></div>
|
||||||
<div ref="dom_lyric_text"></div>
|
<div ref="dom_lyric_text"></div>
|
||||||
<div :class="$style.lyricSpace"></div>
|
<div :class="$style.lyricSpace"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<transition enter-active-class="animated fadeIn" leave-active-class="animated fadeOut">
|
||||||
|
<div :class="$style.skip" v-if="isShowLyricProgressSetting" v-show="isStopScroll">
|
||||||
|
<div :class="$style.line" ref="dom_skip_line"></div>
|
||||||
|
<span :class="$style.label">{{timeStr}}</span>
|
||||||
|
<base-btn :class="$style.skipBtn" @mouseenter="handleSkipMouseEnter" @mouseleave="handleSkipMouseLeave" @click="handleSkipPlay">
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="50%" viewBox="0 0 170 170" space="preserve">
|
||||||
|
<use xlink:href="#icon-play"></use>
|
||||||
|
</svg>
|
||||||
|
</base-btn>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
<transition enter-active-class="animated fadeIn" leave-active-class="animated fadeOut">
|
<transition enter-active-class="animated fadeIn" leave-active-class="animated fadeOut">
|
||||||
<div :class="[$style.lyricSelectContent, 'select', 'scroll', 'lyricSelectContent']" v-if="isShowLrcSelectContent" @contextmenu="handleCopySelectText">
|
<div :class="[$style.lyricSelectContent, 'select', 'scroll', 'lyricSelectContent']" v-if="isShowLrcSelectContent" @contextmenu="handleCopySelectText">
|
||||||
<div v-for="(info, index) in lyric.lines" :key="index" :class="[$style.lyricSelectline, { [$style.lrcActive]: lyric.line == index }]">
|
<div v-for="(info, index) in lyric.lines" :key="index" :class="[$style.lyricSelectline, { [$style.lrcActive]: lyric.line == index }]">
|
||||||
|
@ -20,27 +31,84 @@
|
||||||
<script>
|
<script>
|
||||||
import { clipboardWriteText } from '@renderer/utils'
|
import { clipboardWriteText } from '@renderer/utils'
|
||||||
import { lyric } from '@renderer/core/share/lyric'
|
import { lyric } from '@renderer/core/share/lyric'
|
||||||
import { isPlay, isShowLrcSelectContent } from '@renderer/core/share/player'
|
import { isFullscreen } from '@renderer/core/share'
|
||||||
// import { ref } from '@renderer/utils/vueTools'
|
import { isPlay, isShowLrcSelectContent, isShowPlayComment } from '@renderer/core/share/player'
|
||||||
|
import { onMounted, onBeforeUnmount, useCommit, useRefGetter, computed } from '@renderer/utils/vueTools'
|
||||||
import useLyric from '@renderer/utils/compositions/useLyric'
|
import useLyric from '@renderer/utils/compositions/useLyric'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
|
const setting = useRefGetter('setting')
|
||||||
|
const setPlayDetailLyricFont = useCommit('setPlayDetailLyricFont')
|
||||||
const {
|
const {
|
||||||
dom_lyric,
|
dom_lyric,
|
||||||
dom_lyric_text,
|
dom_lyric_text,
|
||||||
|
dom_skip_line,
|
||||||
isMsDown,
|
isMsDown,
|
||||||
|
isStopScroll,
|
||||||
|
timeStr,
|
||||||
handleLyricMouseDown,
|
handleLyricMouseDown,
|
||||||
handleWheel,
|
handleWheel,
|
||||||
|
handleSkipPlay,
|
||||||
|
handleSkipMouseEnter,
|
||||||
|
handleSkipMouseLeave,
|
||||||
} = useLyric({ isPlay, lyric })
|
} = useLyric({ isPlay, lyric })
|
||||||
|
|
||||||
|
const fontSizeUp = () => {
|
||||||
|
if (setting.value.playDetail.style.fontSize >= 200) return
|
||||||
|
setPlayDetailLyricFont(setting.value.playDetail.style.fontSize + 1)
|
||||||
|
}
|
||||||
|
const fontSizeDown = () => {
|
||||||
|
if (setting.value.playDetail.style.fontSize <= 70) return
|
||||||
|
setPlayDetailLyricFont(setting.value.playDetail.style.fontSize - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const lrcStyles = computed(() => {
|
||||||
|
return {
|
||||||
|
textAlign: setting.value.playDetail.style.align,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const lrcFontSize = computed(() => {
|
||||||
|
let size = setting.value.playDetail.style.fontSize / 100
|
||||||
|
if (isFullscreen.value) size = size *= 1.4
|
||||||
|
return {
|
||||||
|
'--playDetail-lrc-font-size': (isShowPlayComment.value ? size * 0.82 : size) + 'rem',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const isZoomActiveLrc = computed(() => setting.value.playDetail.isZoomActiveLrc)
|
||||||
|
const isShowLyricProgressSetting = computed(() => setting.value.playDetail.isShowLyricProgressSetting)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.eventHub.on('key_shift++_down', fontSizeUp)
|
||||||
|
window.eventHub.on('key_numadd_down', fontSizeUp)
|
||||||
|
window.eventHub.on('key_-_down', fontSizeDown)
|
||||||
|
window.eventHub.on('key_numsub_down', fontSizeDown)
|
||||||
|
})
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.eventHub.off('key_shift++_down', fontSizeUp)
|
||||||
|
window.eventHub.off('key_numadd_down', fontSizeUp)
|
||||||
|
window.eventHub.off('key_-_down', fontSizeDown)
|
||||||
|
window.eventHub.off('key_numsub_down', fontSizeDown)
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dom_lyric,
|
dom_lyric,
|
||||||
dom_lyric_text,
|
dom_lyric_text,
|
||||||
|
dom_skip_line,
|
||||||
isMsDown,
|
isMsDown,
|
||||||
|
timeStr,
|
||||||
handleLyricMouseDown,
|
handleLyricMouseDown,
|
||||||
handleWheel,
|
handleWheel,
|
||||||
|
handleSkipPlay,
|
||||||
|
handleSkipMouseEnter,
|
||||||
|
handleSkipMouseLeave,
|
||||||
lyric,
|
lyric,
|
||||||
|
lrcStyles,
|
||||||
|
lrcFontSize,
|
||||||
isShowLrcSelectContent,
|
isShowLrcSelectContent,
|
||||||
|
isShowLyricProgressSetting,
|
||||||
|
isZoomActiveLrc,
|
||||||
|
isStopScroll,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -90,7 +158,7 @@ export default {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 16px;
|
font-size: var(--playDetail-lrc-font-size, 16px);
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
&.draging {
|
&.draging {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
|
@ -98,9 +166,11 @@ export default {
|
||||||
:global {
|
:global {
|
||||||
.lrc-content {
|
.lrc-content {
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
margin: 16px 0;
|
padding: calc(var(--playDetail-lrc-font-size, 16px) / 2) 0;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
color: @color-player-detail-lyric;
|
color: @color-player-detail-lyric;
|
||||||
|
transition: @transition-theme;
|
||||||
|
transition-property: padding;
|
||||||
|
|
||||||
.translation {
|
.translation {
|
||||||
transition: @transition-theme !important;
|
transition: @transition-theme !important;
|
||||||
|
@ -119,13 +189,12 @@ export default {
|
||||||
color: @color-theme;
|
color: @color-theme;
|
||||||
}
|
}
|
||||||
.translation {
|
.translation {
|
||||||
font-size: .94em;
|
|
||||||
color: @color-theme;
|
color: @color-theme;
|
||||||
}
|
}
|
||||||
span {
|
// span {
|
||||||
// color: @color-theme;
|
// // color: @color-theme;
|
||||||
font-size: 1.1em;
|
// font-size: 1.1em;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
|
@ -153,6 +222,64 @@ export default {
|
||||||
// font-size: 1.2em;
|
// font-size: 1.2em;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
.lrcActiveZoom {
|
||||||
|
:global {
|
||||||
|
.lrc-content {
|
||||||
|
&.active {
|
||||||
|
.translation {
|
||||||
|
font-size: .94em;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(38% + var(--playDetail-lrc-font-size, 16px) + 4px);
|
||||||
|
left: 0;
|
||||||
|
// height: 6px;
|
||||||
|
width: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
// opacity: .5;
|
||||||
|
.line {
|
||||||
|
border-top: 1px dashed @color-player-detail-lyric-active;
|
||||||
|
opacity: .15;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
position: absolute;
|
||||||
|
right: 30px;
|
||||||
|
top: -14px;
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 12px;
|
||||||
|
color: @color-player-detail-lyric-active;
|
||||||
|
opacity: .7;
|
||||||
|
}
|
||||||
|
.skipBtn {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: none !important;
|
||||||
|
pointer-events: initial;
|
||||||
|
transition: @transition-theme;
|
||||||
|
transition-property: opacity;
|
||||||
|
opacity: .8;
|
||||||
|
&:hover {
|
||||||
|
opacity: .6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.lyricSelectContent {
|
.lyricSelectContent {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -217,6 +344,14 @@ each(@themes, {
|
||||||
// .lrc-active {
|
// .lrc-active {
|
||||||
// color: ~'@{color-@{value}-theme}';
|
// color: ~'@{color-@{value}-theme}';
|
||||||
// }
|
// }
|
||||||
|
.skip {
|
||||||
|
.line {
|
||||||
|
border-top-color: ~'@{color-@{value}-player-detail-lyric-active}';
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
color:~'@{color-@{value}-player-detail-lyric-active}';
|
||||||
|
}
|
||||||
|
}
|
||||||
.lyricSelectContent {
|
.lyricSelectContent {
|
||||||
background-color: ~'@{color-@{value}-theme_2-background_1}';
|
background-color: ~'@{color-@{value}-theme_2-background_1}';
|
||||||
color: ~'@{color-@{value}-player-detail-lyric}';
|
color: ~'@{color-@{value}-player-detail-lyric}';
|
||||||
|
|
|
@ -11,15 +11,15 @@ div(:class="$style.footer")
|
||||||
span(style="margin: 0 5px;") /
|
span(style="margin: 0 5px;") /
|
||||||
span {{maxPlayTimeStr}}
|
span {{maxPlayTimeStr}}
|
||||||
div(:class="$style.playControl")
|
div(:class="$style.playControl")
|
||||||
div(:class="$style.playBtn" @click="playPrev" style="transform: rotate(180deg);" :tips="$t('player__prev')")
|
div(:class="$style.playBtn" @click="playPrev" style="transform: rotate(180deg);" :aria-label="$t('player__prev')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||||
use(xlink:href='#icon-nextMusic')
|
use(xlink:href='#icon-nextMusic')
|
||||||
div(:class="$style.playBtn" @click="togglePlay" :tips="isPlay ? $t('player__pause') : $t('player__play')")
|
div(:class="$style.playBtn" @click="togglePlay" :aria-label="isPlay ? $t('player__pause') : $t('player__play')")
|
||||||
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||||
use(xlink:href='#icon-pause')
|
use(xlink:href='#icon-pause')
|
||||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||||
use(xlink:href='#icon-play')
|
use(xlink:href='#icon-play')
|
||||||
div(:class="$style.playBtn" @click="playNext" :tips="$t('player__next')")
|
div(:class="$style.playBtn" @click="playNext" :aria-label="$t('player__next')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||||
use(xlink:href='#icon-nextMusic')
|
use(xlink:href='#icon-nextMusic')
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
div(:class="$style.footerLeftControlBtns")
|
div(:class="$style.footerLeftControlBtns")
|
||||||
common-volume-bar(:setting="setting")
|
common-volume-bar(:setting="setting")
|
||||||
div(:class="[$style.footerLeftControlBtn, $style.lrcBtn]" @click="toggleDesktopLyric" @contextmenu="toggleLockDesktopLyric" :tips="toggleDesktopLyricBtnTitle")
|
div(:class="[$style.footerLeftControlBtn, $style.lrcBtn]" @click="toggleDesktopLyric" @contextmenu="toggleLockDesktopLyric" :aria-label="toggleDesktopLyricBtnTitle")
|
||||||
svg(v-show="setting.desktopLyric.enable" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='125%' viewBox='0 0 512 512' space='preserve')
|
svg(v-show="setting.desktopLyric.enable" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='125%' viewBox='0 0 512 512' space='preserve')
|
||||||
use(xlink:href='#icon-desktop-lyric-on')
|
use(xlink:href='#icon-desktop-lyric-on')
|
||||||
svg(v-show="!setting.desktopLyric.enable" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='125%' viewBox='0 0 512 512' space='preserve')
|
svg(v-show="!setting.desktopLyric.enable" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='125%' viewBox='0 0 512 512' space='preserve')
|
||||||
use(xlink:href='#icon-desktop-lyric-off')
|
use(xlink:href='#icon-desktop-lyric-off')
|
||||||
div(:class="[$style.footerLeftControlBtn, { [$style.active]: setting.player.audioVisualization }]" @click="toggleAudioVisualization" :tips="$t('audio_visualization')")
|
div(:class="[$style.footerLeftControlBtn, { [$style.active]: setting.player.audioVisualization }]" @click="toggleAudioVisualization" :aria-label="$t('audio_visualization')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-audio-wave')
|
use(xlink:href='#icon-audio-wave')
|
||||||
div(:class="[$style.footerLeftControlBtn, { [$style.active]: isShowLrcSelectContent }]" @click="toggleVisibleLrc" :tips="$t('lyric__select')")
|
div(:class="[$style.footerLeftControlBtn, { [$style.active]: isShowLrcSelectContent }]" @click="toggleVisibleLrc" :aria-label="$t('lyric__select')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-text')
|
use(xlink:href='#icon-text')
|
||||||
div(:class="[$style.footerLeftControlBtn, {[$style.active]: isShowPlayComment}]" @click="toggleVisibleComment" :tips="$t('comment__show')")
|
div(:class="[$style.footerLeftControlBtn, {[$style.active]: isShowPlayComment}]" @click="toggleVisibleComment" :aria-label="$t('comment__show')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-comment')
|
use(xlink:href='#icon-comment')
|
||||||
div(:class="$style.footerLeftControlBtn" @click="toggleNextPlayMode" :tips="nextTogglePlayName")
|
div(:class="$style.footerLeftControlBtn" @click="toggleNextPlayMode" :aria-label="nextTogglePlayName")
|
||||||
svg(v-show="setting.player.togglePlayMethod == 'listLoop'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
svg(v-show="setting.player.togglePlayMethod == 'listLoop'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-list-loop')
|
use(xlink:href='#icon-list-loop')
|
||||||
svg(v-show="setting.player.togglePlayMethod == 'random'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
svg(v-show="setting.player.togglePlayMethod == 'random'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
||||||
|
@ -26,7 +26,7 @@ div(:class="$style.footerLeftControlBtns")
|
||||||
use(xlink:href='#icon-single-loop')
|
use(xlink:href='#icon-single-loop')
|
||||||
svg(v-show="!setting.player.togglePlayMethod" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='120%' viewBox='0 0 24 24' space='preserve')
|
svg(v-show="!setting.player.togglePlayMethod" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='120%' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-single')
|
use(xlink:href='#icon-single')
|
||||||
div(:class="$style.footerLeftControlBtn" @click="isShowAddMusicTo = true" :tips="$t('player__add_music_to')")
|
div(:class="$style.footerLeftControlBtn" @click="isShowAddMusicTo = true" :aria-label="$t('player__add_music_to')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 512 512' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 512 512' space='preserve')
|
||||||
use(xlink:href='#icon-add-2')
|
use(xlink:href='#icon-add-2')
|
||||||
common-list-add-modal(v-model:show="isShowAddMusicTo" :musicInfo="musicInfoItem")
|
common-list-add-modal(v-model:show="isShowAddMusicTo" :musicInfo="musicInfoItem")
|
||||||
|
@ -46,12 +46,15 @@ import {
|
||||||
|
|
||||||
import useNextTogglePlay from '@renderer/utils/compositions/useNextTogglePlay'
|
import useNextTogglePlay from '@renderer/utils/compositions/useNextTogglePlay'
|
||||||
import useToggleDesktopLyric from '@renderer/utils/compositions/useToggleDesktopLyric'
|
import useToggleDesktopLyric from '@renderer/utils/compositions/useToggleDesktopLyric'
|
||||||
|
import { dialog } from '@renderer/plugins/Dialog'
|
||||||
|
import { setMediaDeviceId } from '@renderer/plugins/player'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const setting = useRefGetter('setting')
|
const setting = useRefGetter('setting')
|
||||||
const setAudioVisualization = useCommit('setAudioVisualization')
|
const setAudioVisualization = useCommit('setAudioVisualization')
|
||||||
|
const saveMediaDeviceId = useCommit('setMediaDeviceId')
|
||||||
|
|
||||||
const toggleVisibleLrc = () => {
|
const toggleVisibleLrc = () => {
|
||||||
setShowPlayLrcSelectContentLrc(!isShowLrcSelectContent.value)
|
setShowPlayLrcSelectContentLrc(!isShowLrcSelectContent.value)
|
||||||
|
@ -72,8 +75,19 @@ export default {
|
||||||
|
|
||||||
const isShowAddMusicTo = ref(false)
|
const isShowAddMusicTo = ref(false)
|
||||||
|
|
||||||
const toggleAudioVisualization = () => {
|
const toggleAudioVisualization = async() => {
|
||||||
setAudioVisualization(!setting.value.player.audioVisualization)
|
const newSetting = !setting.value.player.audioVisualization
|
||||||
|
if (newSetting && setting.value.player.mediaDeviceId != 'default') {
|
||||||
|
const confirm = await dialog.confirm({
|
||||||
|
message: t('setting__player_audio_visualization_tip'),
|
||||||
|
cancelButtonText: t('cancel_button_text'),
|
||||||
|
confirmButtonText: t('confirm_button_text'),
|
||||||
|
})
|
||||||
|
if (!confirm) return
|
||||||
|
saveMediaDeviceId('default')
|
||||||
|
await setMediaDeviceId('default').catch(_ => _)
|
||||||
|
}
|
||||||
|
setAudioVisualization(newSetting)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -3,7 +3,7 @@ div.comment(:class="$style.comment" ref="dom_container")
|
||||||
div(:class="$style.commentHeader")
|
div(:class="$style.commentHeader")
|
||||||
h3 {{$t('comment__title', { name: title })}}
|
h3 {{$t('comment__title', { name: title })}}
|
||||||
div(:class="$style.commentHeaderBtns")
|
div(:class="$style.commentHeaderBtns")
|
||||||
div(:class="$style.commentHeaderBtn" @click="handleShowComment" :tips="$t('comment__refresh')")
|
div(:class="$style.commentHeaderBtn" @click="handleShowComment" :aria-label="$t('comment__refresh')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' style='transform: rotate(45deg);' viewBox='0 0 24 24' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' style='transform: rotate(45deg);' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-refresh')
|
use(xlink:href='#icon-refresh')
|
||||||
div(:class="$style.commentHeaderBtn" @click="$emit('close')")
|
div(:class="$style.commentHeaderBtn" @click="$emit('close')")
|
||||||
|
@ -132,7 +132,13 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setWidth() {
|
setWidth() {
|
||||||
this.$refs.dom_container.style.width = this.$refs.dom_container.clientWidth + 'px'
|
setTimeout(() => {
|
||||||
|
this.$refs.dom_container.style.width = Math.floor(this.$refs.dom_container.parentNode.clientWidth * 0.5) + 'px'
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.handleToggleTab(this.tabActiveId, true)
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
async getComment(musicInfo, page, limit, retryNum = 0) {
|
async getComment(musicInfo, page, limit, retryNum = 0) {
|
||||||
let resp
|
let resp
|
||||||
|
@ -219,8 +225,8 @@ export default {
|
||||||
this.newComment.nextPage = page
|
this.newComment.nextPage = page
|
||||||
this.handleGetNewComment(this.currentMusicInfo, page, this.newComment.limit)
|
this.handleGetNewComment(this.currentMusicInfo, page, this.newComment.limit)
|
||||||
},
|
},
|
||||||
handleToggleTab(id) {
|
handleToggleTab(id, force) {
|
||||||
if (this.tabActiveId == id) return
|
if (!force && this.tabActiveId == id) return
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case 'hot':
|
case 'hot':
|
||||||
this.$refs.dom_tabMain.scrollLeft = 0
|
this.$refs.dom_tabMain.scrollLeft = 0
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
transition(enter-active-class="animated lightSpeedIn" leave-active-class="animated slideOutDown" @after-enter="handleAfterEnter" @after-leave="handleAfterLeave")
|
transition(enter-active-class="animated lightSpeedIn" leave-active-class="animated slideOutDown" @after-enter="handleAfterEnter" @after-leave="handleAfterLeave")
|
||||||
div(:class="$style.container" @contextmenu="handleContextMenu" v-if="isShowPlayerDetail")
|
div(:class="[$style.container, , { [$style.fullscreen]: isFullscreen }]" @contextmenu="handleContextMenu" v-if="isShowPlayerDetail")
|
||||||
//- div(:class="$style.bg" :style="bgStyle")
|
//- div(:class="$style.bg" :style="bgStyle")
|
||||||
//- div(:class="$style.bg2")
|
//- div(:class="$style.bg2")
|
||||||
div(:class="[$style.header, $style.controlBtnLeft]" v-if="setting.controlBtnPosition == 'left'")
|
div(:class="[$style.header, $style.controlBtnLeft]" v-if="setting.controlBtnPosition == 'left'")
|
||||||
div(:class="$style.controBtn")
|
div(:class="$style.controBtn")
|
||||||
button(type="button" :class="$style.hide" :tips="$t('player__hide_detail_tip')" @click="hide")
|
button(type="button" :class="$style.hide" :aria-label="$t('player__hide_detail_tip')" @click="hide")
|
||||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='80%' viewBox='0 0 30.727 30.727' space='preserve')
|
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='80%' viewBox='0 0 30.727 30.727' space='preserve')
|
||||||
use(xlink:href='#icon-window-hide')
|
use(xlink:href='#icon-window-hide')
|
||||||
button(type="button" :class="$style.min" :tips="$t('min')" @click="min")
|
button(type="button" :class="$style.min" :aria-label="$t('min')" @click="min")
|
||||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-window-minimize')
|
use(xlink:href='#icon-window-minimize')
|
||||||
|
|
||||||
//- button(type="button" :class="$style.max" @click="max")
|
//- button(type="button" :class="$style.max" @click="max")
|
||||||
button(type="button" :class="$style.close" :tips="$t('close')" @click="close")
|
button(type="button" :class="$style.close" :aria-label="$t('close')" @click="close")
|
||||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-window-close')
|
use(xlink:href='#icon-window-close')
|
||||||
div(:class="[$style.header, $style.controlBtnRight]" v-else)
|
div(:class="[$style.header, $style.controlBtnRight]" v-else)
|
||||||
div(:class="$style.controBtn")
|
div(:class="$style.controBtn")
|
||||||
button(type="button" :class="$style.hide" :tips="$t('player__hide_detail_tip')" @click="hide")
|
button(type="button" :class="$style.hide" :aria-label="$t('player__hide_detail_tip')" @click="hide")
|
||||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='35%' viewBox='0 0 30.727 30.727' space='preserve')
|
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='35%' viewBox='0 0 30.727 30.727' space='preserve')
|
||||||
use(xlink:href='#icon-window-hide')
|
use(xlink:href='#icon-window-hide')
|
||||||
button(type="button" :class="$style.min" :tips="$t('min')" @click="min")
|
button(type="button" :class="$style.min" :aria-label="$t('min')" @click="min")
|
||||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='60%' viewBox='0 0 24 24' space='preserve')
|
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='60%' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-window-minimize-2')
|
use(xlink:href='#icon-window-minimize-2')
|
||||||
|
|
||||||
//- button(type="button" :class="$style.max" @click="max")
|
//- button(type="button" :class="$style.max" @click="max")
|
||||||
button(type="button" :class="$style.close" :tips="$t('close')" @click="close")
|
button(type="button" :class="$style.close" :aria-label="$t('close')" @click="close")
|
||||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='60%' viewBox='0 0 24 24' space='preserve')
|
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='60%' viewBox='0 0 24 24' space='preserve')
|
||||||
use(xlink:href='#icon-window-close-2')
|
use(xlink:href='#icon-window-close-2')
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ transition(enter-active-class="animated lightSpeedIn" leave-active-class="animat
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useRefGetter, ref } from '@renderer/utils/vueTools'
|
import { useRefGetter, ref } from '@renderer/utils/vueTools'
|
||||||
|
import { isFullscreen } from '@renderer/core/share'
|
||||||
import { base as eventBaseName } from '@renderer/event/names'
|
import { base as eventBaseName } from '@renderer/event/names'
|
||||||
import {
|
import {
|
||||||
isShowPlayerDetail,
|
isShowPlayerDetail,
|
||||||
|
@ -117,6 +118,7 @@ export default {
|
||||||
handleAfterEnter,
|
handleAfterEnter,
|
||||||
handleAfterLeave,
|
handleAfterLeave,
|
||||||
visibled,
|
visibled,
|
||||||
|
isFullscreen,
|
||||||
min() {
|
min() {
|
||||||
window.eventHub.emit(eventBaseName.min)
|
window.eventHub.emit(eventBaseName.min)
|
||||||
},
|
},
|
||||||
|
@ -161,6 +163,15 @@ export default {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.fullscreen {
|
||||||
|
.header {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
> * {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// .bg {
|
// .bg {
|
||||||
// position: absolute;
|
// position: absolute;
|
||||||
|
@ -296,9 +307,6 @@ export default {
|
||||||
}
|
}
|
||||||
.right {
|
.right {
|
||||||
flex-basis: 30%;
|
flex-basis: 30%;
|
||||||
.lyric {
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
.lyricSelectContent {
|
.lyricSelectContent {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.control">
|
<div :class="$style.control" v-show="!isFullscreen">
|
||||||
<button type="button" :class="[$style.btn, $style.min]" :tips="$t('min')" @click="min">
|
<button type="button" :class="[$style.btn, $style.min]" :aria-label="$t('min')" @click="min">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="60%" viewBox="0 0 24 24" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="60%" viewBox="0 0 24 24" space="preserve">
|
||||||
<use xlink:href="#icon-window-minimize-2"></use>
|
<use xlink:href="#icon-window-minimize-2"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" :class="[$style.btn, $style.close]" :tips="$t('close')" @click="close">
|
<button type="button" :class="[$style.btn, $style.close]" :aria-label="$t('close')" @click="close">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="60%" viewBox="0 0 24 24" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="60%" viewBox="0 0 24 24" space="preserve">
|
||||||
<use xlink:href="#icon-window-close-2"></use>
|
<use xlink:href="#icon-window-close-2"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { base as eventBaseName } from '@renderer/event/names'
|
import { base as eventBaseName } from '@renderer/event/names'
|
||||||
|
import { isFullscreen } from '@renderer/core/share'
|
||||||
// import { getRandom } from '../../utils'
|
// import { getRandom } from '../../utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -29,6 +30,7 @@ export default {
|
||||||
close() {
|
close() {
|
||||||
window.eventHub.emit(eventBaseName.close)
|
window.eventHub.emit(eventBaseName.close)
|
||||||
},
|
},
|
||||||
|
isFullscreen,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="[$style.toolbar, setting.controlBtnPosition == 'left' ? $style.controlBtnLeft : $style.controlBtnRight]">
|
<div :class="[$style.toolbar, { [$style.fullscreen]: isFullscreen }, setting.controlBtnPosition == 'left' ? $style.controlBtnLeft : $style.controlBtnRight]">
|
||||||
<SearchInput />
|
<SearchInput />
|
||||||
<div :class="$style.logo" v-if="setting.controlBtnPosition == 'left'">L X</div>
|
<div :class="$style.logo" v-if="setting.controlBtnPosition == 'left'">L X</div>
|
||||||
<ControlBtns v-else />
|
<ControlBtns v-else />
|
||||||
|
@ -11,10 +11,16 @@ import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
import ControlBtns from './ControlBtns'
|
import ControlBtns from './ControlBtns'
|
||||||
import SearchInput from './SearchInput'
|
import SearchInput from './SearchInput'
|
||||||
|
import { isFullscreen } from '@renderer/core/share'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CoreToolBar',
|
name: 'CoreToolBar',
|
||||||
components: { SearchInput, ControlBtns },
|
components: { SearchInput, ControlBtns },
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
isFullscreen,
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['setting']),
|
...mapGetters(['setting']),
|
||||||
},
|
},
|
||||||
|
@ -34,6 +40,13 @@ export default {
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
|
&.fullscreen {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
.logo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.controlBtnLeft {
|
&.controlBtnLeft {
|
||||||
.control {
|
.control {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -44,11 +44,11 @@ material-modal(:show="versionInfo.showModal" @close="handleClose")
|
||||||
p 发现有新版本啦,但是自动更新功能出问题了,
|
p 发现有新版本啦,但是自动更新功能出问题了,
|
||||||
p
|
p
|
||||||
| 你可以去
|
| 你可以去
|
||||||
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" aria-label="点击打开") 软件发布页
|
||||||
| 或
|
| 或
|
||||||
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
|
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" aria-label="点击打开") 网盘
|
||||||
| (密码:
|
| (密码:
|
||||||
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
|
strong.hover(@click="handleCopy('glqw')" aria-label="点击复制") glqw
|
||||||
| ) 下载新版本,
|
| ) 下载新版本,
|
||||||
p
|
p
|
||||||
| 国内Windows/MAC用户推荐到
|
| 国内Windows/MAC用户推荐到
|
||||||
|
@ -61,11 +61,11 @@ material-modal(:show="versionInfo.showModal" @close="handleClose")
|
||||||
p 你当前所在网络访问GitHub较慢,导致新版本下载超时(已经下了半个钟了😳),你仍可选择继续等,但墙裂建议手动更新版本!
|
p 你当前所在网络访问GitHub较慢,导致新版本下载超时(已经下了半个钟了😳),你仍可选择继续等,但墙裂建议手动更新版本!
|
||||||
p
|
p
|
||||||
| 你可以去
|
| 你可以去
|
||||||
base-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
base-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" aria-label="点击打开") 软件发布页
|
||||||
| 或
|
| 或
|
||||||
base-btn(min @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
|
base-btn(min @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" aria-label="点击打开") 网盘
|
||||||
| (密码:
|
| (密码:
|
||||||
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
|
strong.hover(@click="handleCopy('glqw')" aria-label="点击复制") glqw
|
||||||
| )下载新版本,
|
| )下载新版本,
|
||||||
p
|
p
|
||||||
| 国内Windows/MAC用户推荐到
|
| 国内Windows/MAC用户推荐到
|
||||||
|
@ -82,11 +82,11 @@ material-modal(:show="versionInfo.showModal" @close="handleClose")
|
||||||
p 更新信息获取失败,可能是无法访问Github导致的,请手动检查更新!
|
p 更新信息获取失败,可能是无法访问Github导致的,请手动检查更新!
|
||||||
p
|
p
|
||||||
| 检查方法:打开
|
| 检查方法:打开
|
||||||
base-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
base-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" aria-label="点击打开") 软件发布页
|
||||||
| 或
|
| 或
|
||||||
base-btn(min @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
|
base-btn(min @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" aria-label="点击打开") 网盘
|
||||||
| (密码:
|
| (密码:
|
||||||
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
|
strong.hover(@click="handleCopy('glqw')" aria-label="点击复制") glqw
|
||||||
| )查看它们的
|
| )查看它们的
|
||||||
strong 版本号
|
strong 版本号
|
||||||
| 与当前版本({{versionInfo.version}})对比是否一样,
|
| 与当前版本({{versionInfo.version}})对比是否一样,
|
||||||
|
@ -115,11 +115,11 @@ material-modal(:show="versionInfo.showModal" @close="handleClose")
|
||||||
| 重新打开本弹窗。
|
| 重新打开本弹窗。
|
||||||
p
|
p
|
||||||
| 手动更新可以去
|
| 手动更新可以去
|
||||||
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" aria-label="点击打开") 软件发布页
|
||||||
| 或
|
| 或
|
||||||
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
|
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" aria-label="点击打开") 网盘
|
||||||
| (密码:
|
| (密码:
|
||||||
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
|
strong.hover(@click="handleCopy('glqw')" aria-label="点击复制") glqw
|
||||||
| ) 下载,
|
| ) 下载,
|
||||||
p 国内Windows/MAC用户推荐到网盘下载。
|
p 国内Windows/MAC用户推荐到网盘下载。
|
||||||
p 当前下载进度:{{progress}}
|
p 当前下载进度:{{progress}}
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
div(:class="$style.btns")
|
div(:class="$style.btns")
|
||||||
button(type="button" v-if="playBtn" @contextmenu.capture.stop :tips="$t('list__play')" @click.stop="handleClick('play')")
|
button(type="button" v-if="playBtn" @contextmenu.capture.stop :aria-label="$t('list__play')" @click.stop="handleClick('play')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 287.386 287.386' space='preserve' v-once)
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 287.386 287.386' space='preserve' v-once)
|
||||||
use(xlink:href='#icon-testPlay')
|
use(xlink:href='#icon-testPlay')
|
||||||
button(type="button" v-if="listAddBtn" @contextmenu.capture.stop :tips="$t('list__add_to')" @click.stop="handleClick('listAdd')")
|
button(type="button" v-if="listAddBtn" @contextmenu.capture.stop :aria-label="$t('list__add_to')" @click.stop="handleClick('listAdd')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve' v-once)
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve' v-once)
|
||||||
use(xlink:href='#icon-addTo')
|
use(xlink:href='#icon-addTo')
|
||||||
button(type="button" v-if="downloadBtn && setting.download.enable" @contextmenu.capture.stop :tips="$t('list__download')" @click.stop="handleClick('download')")
|
button(type="button" v-if="downloadBtn && setting.download.enable" @contextmenu.capture.stop :aria-label="$t('list__download')" @click.stop="handleClick('download')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 475.078 475.077' space='preserve' v-once)
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 475.078 475.077' space='preserve' v-once)
|
||||||
use(xlink:href='#icon-download')
|
use(xlink:href='#icon-download')
|
||||||
//- button(type="button" :tips="$t('list__add')" v-if="userInfo" @click.stop="handleClick('add')")
|
//- button(type="button" :aria-label="$t('list__add')" v-if="userInfo" @click.stop="handleClick('add')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve')
|
||||||
use(xlink:href='#icon-addTo')
|
use(xlink:href='#icon-addTo')
|
||||||
button(type="button" v-if="startBtn" @contextmenu.capture.stop :tips="$t('list__start')" @click.stop="handleClick('start')")
|
button(type="button" v-if="startBtn" @contextmenu.capture.stop :aria-label="$t('list__start')" @click.stop="handleClick('start')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve' v-once)
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve' v-once)
|
||||||
use(xlink:href='#icon-play')
|
use(xlink:href='#icon-play')
|
||||||
button(type="button" v-if="pauseBtn" @contextmenu.capture.stop :tips="$t('list__pause')" @click.stop="handleClick('pause')")
|
button(type="button" v-if="pauseBtn" @contextmenu.capture.stop :aria-label="$t('list__pause')" @click.stop="handleClick('pause')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve' v-once)
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve' v-once)
|
||||||
use(xlink:href='#icon-pause')
|
use(xlink:href='#icon-pause')
|
||||||
button(type="button" v-if="fileBtn" @contextmenu.capture.stop :tips="$t('list__file')" @click.stop="handleClick('file')")
|
button(type="button" v-if="fileBtn" @contextmenu.capture.stop :aria-label="$t('list__file')" @click.stop="handleClick('file')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='-61 0 512 512' space='preserve' v-once)
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='-61 0 512 512' space='preserve' v-once)
|
||||||
use(xlink:href='#icon-musicFile')
|
use(xlink:href='#icon-musicFile')
|
||||||
button(type="button" v-if="searchBtn" @contextmenu.capture.stop :tips="$t('list__search')" @click.stop="handleClick('search')")
|
button(type="button" v-if="searchBtn" @contextmenu.capture.stop :aria-label="$t('list__search')" @click.stop="handleClick('search')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 30.239 30.239' space='preserve' v-once)
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 30.239 30.239' space='preserve' v-once)
|
||||||
use(xlink:href='#icon-search')
|
use(xlink:href='#icon-search')
|
||||||
button(type="button" v-if="removeBtn" :tips="$t('list__remove')" @click.stop="handleClick('remove')")
|
button(type="button" v-if="removeBtn" :aria-label="$t('list__remove')" @click.stop="handleClick('remove')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve' v-once)
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve' v-once)
|
||||||
use(xlink:href='#icon-delete')
|
use(xlink:href='#icon-delete')
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ teleport(:to="teleport")
|
||||||
transition(enter-active-class="animated fadeIn" leave-active-class="animated fadeOut")
|
transition(enter-active-class="animated fadeIn" leave-active-class="animated fadeOut")
|
||||||
div(:class="$style.modal" v-show="showContent" @click="bgClose && close()")
|
div(:class="$style.modal" v-show="showContent" @click="bgClose && close()")
|
||||||
transition(:enter-active-class="inClass" :leave-active-class="outClass" @after-enter="$emit('after-enter', $event)" @after-leave="handleAfterLeave")
|
transition(:enter-active-class="inClass" :leave-active-class="outClass" @after-enter="$emit('after-enter', $event)" @after-leave="handleAfterLeave")
|
||||||
div(:class="$style.content" v-show="showContent" @click.stop)
|
div(:class="$style.content" v-show="showContent" @click.stop :style="contentStyle")
|
||||||
header(:class="$style.header")
|
header(:class="$style.header")
|
||||||
button(type="button" @click="close" v-if="closeBtn")
|
button(type="button" @click="close" v-if="closeBtn")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
|
||||||
|
@ -34,6 +34,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: '#root',
|
default: '#root',
|
||||||
},
|
},
|
||||||
|
maxWidth: {
|
||||||
|
type: String,
|
||||||
|
default: '76%',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
emits: ['after-enter', 'after-leave', 'close'],
|
emits: ['after-enter', 'after-leave', 'close'],
|
||||||
data() {
|
data() {
|
||||||
|
@ -91,6 +95,11 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['setting']),
|
...mapGetters(['setting']),
|
||||||
|
contentStyle() {
|
||||||
|
return {
|
||||||
|
maxWidth: this.maxWidth,
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'setting.randomAnimate'(n) {
|
'setting.randomAnimate'(n) {
|
||||||
|
@ -182,7 +191,7 @@ export default {
|
||||||
box-shadow: 0 0 3px rgba(0, 0, 0, .3);
|
box-shadow: 0 0 3px rgba(0, 0, 0, .3);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
max-height: 80%;
|
max-height: 80%;
|
||||||
max-width: 76%;
|
// max-width: 76%;
|
||||||
min-width: 220px;
|
min-width: 220px;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -20,13 +20,13 @@ div(:class="$style.songList")
|
||||||
div.list-item(@click="handleListItemClick($event, index)" @contextmenu="handleListItemRightClick($event, index)"
|
div.list-item(@click="handleListItemClick($event, index)" @contextmenu="handleListItemRightClick($event, index)"
|
||||||
:class="[{ selected: rightClickSelectedIndex == index }, { active: selectedList.includes(item) }]")
|
:class="[{ selected: rightClickSelectedIndex == index }, { active: selectedList.includes(item) }]")
|
||||||
div.list-item-cell.nobreak.center(:style="{ width: rowWidth.r1 }" style="padding-left: 3px; padding-right: 3px;" :class="$style.noSelect" @click.stop) {{index + 1}}
|
div.list-item-cell.nobreak.center(:style="{ width: rowWidth.r1 }" style="padding-left: 3px; padding-right: 3px;" :class="$style.noSelect" @click.stop) {{index + 1}}
|
||||||
div.list-item-cell.auto(:style="{ width: rowWidth.r2 }" :tips="item.name + ((item._types.ape || item._types.flac || item._types.wav) ? ` - ${$t('tag__lossless')}` : item._types['320k'] ? ` - ${$t('tag__high_quality')}` : '')")
|
div.list-item-cell.auto(:style="{ width: rowWidth.r2 }" :aria-label="item.name + ((item._types.ape || item._types.flac || item._types.wav) ? ` - ${$t('tag__lossless')}` : item._types['320k'] ? ` - ${$t('tag__high_quality')}` : '')")
|
||||||
span.select {{item.name}}
|
span.select {{item.name}}
|
||||||
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-if="item._types.ape || item._types.flac || item._types.wav") {{$t('tag__lossless')}}
|
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-if="item._types.ape || item._types.flac || item._types.wav") {{$t('tag__lossless')}}
|
||||||
span.badge.badge-theme-info(:class="[$style.labelQuality, $style.noSelect]" v-else-if="item._types['320k']") {{$t('tag__high_quality')}}
|
span.badge.badge-theme-info(:class="[$style.labelQuality, $style.noSelect]" v-else-if="item._types['320k']") {{$t('tag__high_quality')}}
|
||||||
div.list-item-cell(:style="{ width: rowWidth.r3 }" :tips="item.singer")
|
div.list-item-cell(:style="{ width: rowWidth.r3 }" :aria-label="item.singer")
|
||||||
span.select {{item.singer}}
|
span.select {{item.singer}}
|
||||||
div.list-item-cell(:style="{ width: rowWidth.r4 }" :tips="item.albumName")
|
div.list-item-cell(:style="{ width: rowWidth.r4 }" :aria-label="item.albumName")
|
||||||
span.select {{item.albumName}}
|
span.select {{item.albumName}}
|
||||||
div.list-item-cell(:style="{ width: rowWidth.r5 }")
|
div.list-item-cell(:style="{ width: rowWidth.r5 }")
|
||||||
span(:class="[$style.time, $style.noSelect]") {{item.interval || '--/--'}}
|
span(:class="[$style.time, $style.noSelect]") {{item.interval || '--/--'}}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { computed, useRefGetter, watch, ref, onBeforeUnmount } from '@renderer/utils/vueTools'
|
import { computed, useRefGetter, watch, ref, onBeforeUnmount } from '@renderer/utils/vueTools'
|
||||||
import { windowSizeList } from '@common/config'
|
import { windowSizeList, isFullscreen } from '@renderer/core/share'
|
||||||
|
import { getFontSizeWithScreen } from '@renderer/utils'
|
||||||
|
|
||||||
const useKeyEvent = ({ handleSelectAllData }) => {
|
const useKeyEvent = ({ handleSelectAllData }) => {
|
||||||
const keyEvent = {
|
const keyEvent = {
|
||||||
|
@ -49,7 +50,7 @@ export default ({ props }) => {
|
||||||
const setting = useRefGetter('setting')
|
const setting = useRefGetter('setting')
|
||||||
let lastSelectIndex = -1
|
let lastSelectIndex = -1
|
||||||
const listItemHeight = computed(() => {
|
const listItemHeight = computed(() => {
|
||||||
return parseInt(windowSizeList.find(item => item.id == setting.value.windowSizeId).fontSize) / 16 * 37
|
return Math.ceil((isFullscreen.value ? getFontSizeWithScreen() : parseInt(windowSizeList.find(item => item.id == setting.value.windowSizeId).fontSize)) * 2.3)
|
||||||
})
|
})
|
||||||
|
|
||||||
const removeAllSelect = () => {
|
const removeAllSelect = () => {
|
||||||
|
|
|
@ -6,24 +6,24 @@
|
||||||
<use xlink:href="#icon-left"></use>
|
<use xlink:href="#icon-left"></use>
|
||||||
</svg></span></li>
|
</svg></span></li>
|
||||||
<li v-else>
|
<li v-else>
|
||||||
<button type="button" @click="handleClick(page - 1)" :tips="$t('pagination__prev')">
|
<button type="button" @click="handleClick(page - 1)" :aria-label="$t('pagination__prev')">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 451.846 451.847" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 451.846 451.847" space="preserve">
|
||||||
<use xlink:href="#icon-left"></use>
|
<use xlink:href="#icon-left"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="allPage > btnLength && page > pageEvg+1" :class="$style.first">
|
<li v-if="allPage > btnLength && page > pageEvg+1" :class="$style.first">
|
||||||
<button type="button" @click="handleClick(1)" :tips="$t('pagination__page', { num: 1 })">
|
<button type="button" @click="handleClick(1)" :aria-label="$t('pagination__page', { num: 1 })">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 451.846 451.847" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 451.846 451.847" space="preserve">
|
||||||
<use xlink:href="#icon-first"></use>
|
<use xlink:href="#icon-first"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li v-for="(p, index) in pages" :key="index" :class="{[$style.active] : p == page}"><span v-if="p === page" v-text="page"></span>
|
<li v-for="(p, index) in pages" :key="index" :class="{[$style.active] : p == page}"><span v-if="p === page" v-text="page"></span>
|
||||||
<button v-else type="button" @click="handleClick(p)" v-text="p" :tips="$t('pagination__page', { num: p })"></button>
|
<button v-else type="button" @click="handleClick(p)" v-text="p" :aria-label="$t('pagination__page', { num: p })"></button>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="allPage > btnLength && allPage - page > pageEvg" :class="$style.last">
|
<li v-if="allPage > btnLength && allPage - page > pageEvg" :class="$style.last">
|
||||||
<button type="button" @click="handleClick(allPage)" :tips="$t('pagination__page', { num: allPage })">
|
<button type="button" @click="handleClick(allPage)" :aria-label="$t('pagination__page', { num: allPage })">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 451.846 451.847" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 451.846 451.847" space="preserve">
|
||||||
<use xlink:href="#icon-last"></use>
|
<use xlink:href="#icon-last"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
<use xlink:href="#icon-right"></use>
|
<use xlink:href="#icon-right"></use>
|
||||||
</svg></span></li>
|
</svg></span></li>
|
||||||
<li v-else>
|
<li v-else>
|
||||||
<button type="button" @click="handleClick(page + 1)" :tips="$t('pagination__next')">
|
<button type="button" @click="handleClick(page + 1)" :aria-label="$t('pagination__next')">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 451.846 451.847" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 451.846 451.847" space="preserve">
|
||||||
<use xlink:href="#icon-right"></use>
|
<use xlink:href="#icon-right"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ref, reactive, shallowRef, markRaw } from '@renderer/utils/vueTools'
|
import { ref, reactive, shallowRef, markRaw } from '@renderer/utils/vueTools'
|
||||||
import { windowSizeList as configWindowSizeList, themes as configThemes } from '@common/config'
|
import { windowSizeList as configWindowSizeList, themes as configThemes, themeLights as themeLightIds, themeDarks as themeDarkIds } from '@common/config'
|
||||||
import { version } from '../../../../package.json'
|
import { version } from '../../../../package.json'
|
||||||
process.versions.app = version
|
process.versions.app = version
|
||||||
|
|
||||||
|
@ -36,9 +36,14 @@ export const sync = window.sync = reactive({
|
||||||
devices: [],
|
devices: [],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
export const isFullscreen = ref(false)
|
||||||
|
|
||||||
export const windowSizeList = markRaw(configWindowSizeList)
|
export const windowSizeList = markRaw(configWindowSizeList)
|
||||||
export const themes = markRaw(configThemes)
|
export const themes = markRaw(configThemes)
|
||||||
|
export const themeLights = markRaw(configThemes.filter(t => themeLightIds.includes(t.id)))
|
||||||
|
export const themeDarks = markRaw(configThemes.filter(t => themeDarkIds.includes(t.id)))
|
||||||
|
export const themeShouldUseDarkColors = ref(window.shouldUseDarkColors)
|
||||||
|
delete window.shouldUseDarkColors
|
||||||
|
|
||||||
export const qualityList = shallowRef({})
|
export const qualityList = shallowRef({})
|
||||||
export const setQualityList = _qualityList => {
|
export const setQualityList = _qualityList => {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { openUrl } from '@renderer/utils'
|
import { openUrl } from '@renderer/utils'
|
||||||
import { base as eventBaseName } from '@renderer/event/names'
|
import { base as eventBaseName } from '@renderer/event/names'
|
||||||
import { onSetConfig } from '@renderer/utils/tools'
|
import { onSetConfig, onSystemThemeChange } from '@renderer/utils/tools'
|
||||||
|
import { isFullscreen, themeShouldUseDarkColors } from '@renderer/core/share'
|
||||||
|
import { rendererSend, NAMES, rendererInvoke } from '@common/ipc'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
toRaw,
|
toRaw,
|
||||||
useCommit,
|
useCommit,
|
||||||
onBeforeUnmount,
|
onBeforeUnmount,
|
||||||
watchEffect,
|
watch,
|
||||||
useRefGetter,
|
useRefGetter,
|
||||||
} from '@renderer/utils/vueTools'
|
} from '@renderer/utils/vueTools'
|
||||||
|
|
||||||
|
@ -22,6 +24,15 @@ const handleBodyClick = event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
if (/^https?:\/\//.test(event.target.href)) openUrl(event.target.href)
|
if (/^https?:\/\//.test(event.target.href)) openUrl(event.target.href)
|
||||||
}
|
}
|
||||||
|
const handle_open_devtools = event => {
|
||||||
|
rendererSend(NAMES.mainWindow.open_dev_tools)
|
||||||
|
}
|
||||||
|
const handle_fullscreen = event => {
|
||||||
|
if (event.event.repeat) return
|
||||||
|
rendererInvoke(NAMES.mainWindow.fullscreen, !isFullscreen.value).then(fullscreen => {
|
||||||
|
isFullscreen.value = fullscreen
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
dieableIgnoreMouseEvents,
|
dieableIgnoreMouseEvents,
|
||||||
|
@ -32,12 +43,13 @@ export default ({
|
||||||
}) => {
|
}) => {
|
||||||
const setSetting = useCommit('setSetting')
|
const setSetting = useCommit('setSetting')
|
||||||
const windowSizeActive = useRefGetter('windowSizeActive')
|
const windowSizeActive = useRefGetter('windowSizeActive')
|
||||||
|
const isShowAnimation = useRefGetter('isShowAnimation')
|
||||||
|
|
||||||
watchEffect(() => {
|
watch(windowSizeActive, ({ fontSize }) => {
|
||||||
document.documentElement.style.fontSize = windowSizeActive.value.fontSize
|
document.documentElement.style.fontSize = fontSize
|
||||||
})
|
})
|
||||||
watchEffect(() => {
|
watch(isShowAnimation, val => {
|
||||||
if (setting.value.isShowAnimation) {
|
if (val) {
|
||||||
if (document.body.classList.contains('disableAnimation')) {
|
if (document.body.classList.contains('disableAnimation')) {
|
||||||
document.body.classList.remove('disableAnimation')
|
document.body.classList.remove('disableAnimation')
|
||||||
}
|
}
|
||||||
|
@ -54,8 +66,15 @@ export default ({
|
||||||
window.eventHub.emit(eventBaseName.set_config, config)
|
window.eventHub.emit(eventBaseName.set_config, config)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const rSystemThemeChange = onSystemThemeChange((event, isDark) => {
|
||||||
|
// console.log(isDark)
|
||||||
|
themeShouldUseDarkColors.value = isDark
|
||||||
|
})
|
||||||
|
|
||||||
window.eventHub.emit(eventBaseName.bindKey)
|
window.eventHub.emit(eventBaseName.bindKey)
|
||||||
window.eventHub.on('key_escape_down', handle_key_esc_down)
|
window.eventHub.on('key_escape_down', handle_key_esc_down)
|
||||||
|
window.eventHub.on('key_mod+f12_down', handle_open_devtools)
|
||||||
|
window.eventHub.on('key_f11_down', handle_fullscreen)
|
||||||
document.body.addEventListener('click', handleBodyClick, true)
|
document.body.addEventListener('click', handleBodyClick, true)
|
||||||
|
|
||||||
if (isProd && !window.dt && !isLinux) {
|
if (isProd && !window.dt && !isLinux) {
|
||||||
|
@ -68,9 +87,12 @@ export default ({
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.eventHub.off('key_escape_down', handle_key_esc_down)
|
window.eventHub.off('key_escape_down', handle_key_esc_down)
|
||||||
|
window.eventHub.off('key_mod+f12_down', handle_open_devtools)
|
||||||
|
window.eventHub.off('key_f11_down', handle_fullscreen)
|
||||||
document.body.removeEventListener('click', handleBodyClick)
|
document.body.removeEventListener('click', handleBodyClick)
|
||||||
window.eventHub.emit(eventBaseName.unbindKey)
|
window.eventHub.emit(eventBaseName.unbindKey)
|
||||||
rSetConfig()
|
rSetConfig()
|
||||||
|
rSystemThemeChange()
|
||||||
|
|
||||||
if (isProd && !window.dt && !isLinux) {
|
if (isProd && !window.dt && !isLinux) {
|
||||||
document.body.removeEventListener('mouseenter', enableIgnoreMouseEvents)
|
document.body.removeEventListener('mouseenter', enableIgnoreMouseEvents)
|
||||||
|
|
|
@ -44,9 +44,11 @@ export default ({ setting }) => {
|
||||||
setDesktopLyricInfo('lyric', { lrc: musicInfo.lrc, tlrc: musicInfo.tlrc, lxlrc: musicInfo.lxlrc })
|
setDesktopLyricInfo('lyric', { lrc: musicInfo.lrc, tlrc: musicInfo.tlrc, lxlrc: musicInfo.lxlrc })
|
||||||
|
|
||||||
if (isPlay.value && (musicInfo.url || playMusicInfo.listId == 'download')) {
|
if (isPlay.value && (musicInfo.url || playMusicInfo.listId == 'download')) {
|
||||||
const time = getCurrentTime() * 1000
|
setTimeout(() => {
|
||||||
setDesktopLyricInfo('play', time)
|
const time = getCurrentTime() * 1000
|
||||||
lrc.play(time)
|
setDesktopLyricInfo('play', time)
|
||||||
|
lrc.play(time)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ import { setMediaDeviceId } from '@renderer/plugins/player'
|
||||||
import { isPlay } from '@renderer/core/share/player'
|
import { isPlay } from '@renderer/core/share/player'
|
||||||
import { player as eventPlayerNames } from '@renderer/event/names'
|
import { player as eventPlayerNames } from '@renderer/event/names'
|
||||||
|
|
||||||
|
const getDevices = async() => {
|
||||||
|
const devices = await navigator.mediaDevices.enumerateDevices()
|
||||||
|
return devices.filter(({ kind }) => kind == 'audiooutput')
|
||||||
|
}
|
||||||
|
|
||||||
export default ({ setting }) => {
|
export default ({ setting }) => {
|
||||||
let prevDeviceLabel = null
|
let prevDeviceLabel = null
|
||||||
|
@ -15,7 +19,7 @@ export default ({ setting }) => {
|
||||||
|
|
||||||
const setMediaDevice = async(mediaDeviceId) => {
|
const setMediaDevice = async(mediaDeviceId) => {
|
||||||
let label = prevDeviceLabel
|
let label = prevDeviceLabel
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices()
|
const devices = await getDevices()
|
||||||
let device = devices.find(device => device.deviceId === mediaDeviceId)
|
let device = devices.find(device => device.deviceId === mediaDeviceId)
|
||||||
if (device) {
|
if (device) {
|
||||||
mediaDeviceId = device.deviceId
|
mediaDeviceId = device.deviceId
|
||||||
|
@ -41,12 +45,15 @@ export default ({ setting }) => {
|
||||||
setting.value.player.isMediaDeviceRemovedStopPlay &&
|
setting.value.player.isMediaDeviceRemovedStopPlay &&
|
||||||
isPlay.value &&
|
isPlay.value &&
|
||||||
device.label != prevDeviceLabel
|
device.label != prevDeviceLabel
|
||||||
) window.eventHub.emit(eventPlayerNames.setTogglePlay)
|
) {
|
||||||
|
global.isPlayedStop = true
|
||||||
|
window.eventHub.emit(eventPlayerNames.setPause)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMediaListChange = async() => {
|
const handleMediaListChange = async() => {
|
||||||
let mediaDeviceId = setting.value.player.mediaDeviceId
|
let mediaDeviceId = setting.value.player.mediaDeviceId
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices()
|
const devices = await getDevices()
|
||||||
let device = devices.find(device => device.deviceId === mediaDeviceId)
|
let device = devices.find(device => device.deviceId === mediaDeviceId)
|
||||||
if (!device) device = devices.find(device => device.deviceId === 'default')
|
if (!device) device = devices.find(device => device.deviceId === 'default')
|
||||||
if (!device) device = { label: null, deviceId: null }
|
if (!device) device = { label: null, deviceId: null }
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { onBeforeUnmount, useCommit } from '@renderer/utils/vueTools'
|
import { onBeforeUnmount, useCommit } from '@renderer/utils/vueTools'
|
||||||
import { player as eventPlayerNames, taskbar as eventTaskbarNames } from '@renderer/event/names'
|
import { player as eventPlayerNames, taskbar as eventTaskbarNames, list as eventListNames } from '@renderer/event/names'
|
||||||
import { onTaskbarThumbarClick, setTaskbarThumbnailClip, setTaskbarThumbarButtons } from '@renderer/utils/tools'
|
import { onTaskbarThumbarClick, setTaskbarThumbnailClip, setTaskbarThumbarButtons } from '@renderer/utils/tools'
|
||||||
// import store from '@renderer/store'
|
// import store from '@renderer/store'
|
||||||
|
|
||||||
import { loveList, getList } from '@renderer/core/share/list'
|
import { loveList, getList } from '@renderer/core/share/list'
|
||||||
import { playMusicInfo } from '@renderer/core/share/player'
|
import { playMusicInfo } from '@renderer/core/share/player'
|
||||||
|
import { throttle } from '@renderer/utils'
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const listAdd = useCommit('list', 'listAdd')
|
const listAdd = useCommit('list', 'listAdd')
|
||||||
|
@ -54,6 +55,11 @@ export default () => {
|
||||||
const handleSetTaskbarThumbnailClip = (clip) => {
|
const handleSetTaskbarThumbnailClip = (clip) => {
|
||||||
setTaskbarThumbnailClip(clip)
|
setTaskbarThumbnailClip(clip)
|
||||||
}
|
}
|
||||||
|
const throttleListChange = throttle(listIds => {
|
||||||
|
if (!listIds.includes(loveList.id)) return
|
||||||
|
if (!updateCollectStatus()) return
|
||||||
|
setButtons()
|
||||||
|
})
|
||||||
// const updateSetting = () => {
|
// const updateSetting = () => {
|
||||||
// const setting = store.getters.setting
|
// const setting = store.getters.setting
|
||||||
// buttons.lrc = setting.desktopLyric.enable
|
// buttons.lrc = setting.desktopLyric.enable
|
||||||
|
@ -107,6 +113,7 @@ export default () => {
|
||||||
window.eventHub.on(eventPlayerNames.stop, handleStop)
|
window.eventHub.on(eventPlayerNames.stop, handleStop)
|
||||||
window.eventHub.on(eventPlayerNames.setPlayInfo, handleSetPlayInfo)
|
window.eventHub.on(eventPlayerNames.setPlayInfo, handleSetPlayInfo)
|
||||||
window.eventHub.on(eventTaskbarNames.setTaskbarThumbnailClip, handleSetTaskbarThumbnailClip)
|
window.eventHub.on(eventTaskbarNames.setTaskbarThumbnailClip, handleSetTaskbarThumbnailClip)
|
||||||
|
window.eventHub.on(eventListNames.listChange, throttleListChange)
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
rTaskbarThumbarClick()
|
rTaskbarThumbarClick()
|
||||||
|
@ -115,6 +122,7 @@ export default () => {
|
||||||
window.eventHub.off(eventPlayerNames.stop, handleStop)
|
window.eventHub.off(eventPlayerNames.stop, handleStop)
|
||||||
window.eventHub.off(eventPlayerNames.setPlayInfo, handleSetPlayInfo)
|
window.eventHub.off(eventPlayerNames.setPlayInfo, handleSetPlayInfo)
|
||||||
window.eventHub.off(eventTaskbarNames.setTaskbarThumbnailClip, handleSetTaskbarThumbnailClip)
|
window.eventHub.off(eventTaskbarNames.setTaskbarThumbnailClip, handleSetTaskbarThumbnailClip)
|
||||||
|
window.eventHub.off(eventListNames.listChange, throttleListChange)
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { onBeforeUnmount } from '@renderer/utils/vueTools'
|
import { onBeforeUnmount } from '@renderer/utils/vueTools'
|
||||||
|
|
||||||
import { player as eventPlayerNames, list as eventListNames } from '@renderer/event/names'
|
import { player as eventPlayerNames, list as eventListNames, download as eventDownloadNames } from '@renderer/event/names'
|
||||||
import { playInfo, playMusicInfo, updatePlayIndex } from '@renderer/core/share/player'
|
import { playInfo, playMusicInfo, updatePlayIndex } from '@renderer/core/share/player'
|
||||||
import { getList } from '@renderer/core/share/utils'
|
import { getList } from '@renderer/core/share/utils'
|
||||||
import { throttle } from '@renderer/utils'
|
import { throttle } from '@renderer/utils'
|
||||||
|
@ -30,9 +30,15 @@ export default ({ playNext }) => {
|
||||||
throttleListChange()
|
throttleListChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleDownloadListChange = () => {
|
||||||
|
handleListChange(['download'])
|
||||||
|
}
|
||||||
|
|
||||||
window.eventHub.on(eventListNames.listChange, handleListChange)
|
window.eventHub.on(eventListNames.listChange, handleListChange)
|
||||||
|
window.eventHub.on(eventDownloadNames.listChange, handleDownloadListChange)
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.eventHub.off(eventListNames.listChange, handleListChange)
|
window.eventHub.off(eventListNames.listChange, handleListChange)
|
||||||
|
window.eventHub.off(eventDownloadNames.listChange, handleDownloadListChange)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,3 @@ eventHub.on(syncName.send_sync_list, ({ action, data }) => {
|
||||||
if (!sync.enable) return
|
if (!sync.enable) return
|
||||||
rendererSend(NAMES.mainWindow.sync_list, { action, data })
|
rendererSend(NAMES.mainWindow.sync_list, { action, data })
|
||||||
})
|
})
|
||||||
eventHub.on('key_mod+f12_down', ({ action, data }) => {
|
|
||||||
if (!sync.enable) return
|
|
||||||
rendererSend(NAMES.mainWindow.open_dev_tools)
|
|
||||||
})
|
|
||||||
|
|
|
@ -6,12 +6,6 @@
|
||||||
<title>洛雪音乐助手</title>
|
<title>洛雪音乐助手</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
|
||||||
if (/theme=(\w+)/.test(window.location.href)) document.body.classList.add(RegExp.$1)
|
|
||||||
;/dt=(\w+)/.exec(window.location.href)
|
|
||||||
window.dt = RegExp.$1 == 'true'
|
|
||||||
document.body.classList.add(window.dt ? 'disableTransparent' : 'transparent')
|
|
||||||
</script>
|
|
||||||
<!-- <div id="waiting-mask">
|
<!-- <div id="waiting-mask">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="50%" viewbox="0 0 447.942 447.943">
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="50%" viewbox="0 0 447.942 447.943">
|
||||||
<path id="logo-path-1" d="M203.806.482c-19.668-3.346-35.76 11.139-35.76 31.086v206.166c-11.642-4.271-24.165-6.725-37.281-6.725-59.905 0-108.469 48.566-108.469 108.473 0 59.903 48.564 108.461 108.469 108.461 34.141 0 64.54-15.82 84.406-40.482l-49.658-49.664c-15.116-15.112-11.708-28.901-9.542-34.14 2.166-5.233 9.514-17.4 30.883-17.4h18.082v-56.885c0-21.132 14.617-38.862 34.266-43.745.032-44.373.032-81.808.032-81.808 140.147 0 131.724 83.974 115.325 132.196-6.42 18.884-2.601 22.05 10.893 7.354C536.473 77.106 298.38 16.566 203.806.482z"/>
|
<path id="logo-path-1" d="M203.806.482c-19.668-3.346-35.76 11.139-35.76 31.086v206.166c-11.642-4.271-24.165-6.725-37.281-6.725-59.905 0-108.469 48.566-108.469 108.473 0 59.903 48.564 108.461 108.469 108.461 34.141 0 64.54-15.82 84.406-40.482l-49.658-49.664c-15.116-15.112-11.708-28.901-9.542-34.14 2.166-5.233 9.514-17.4 30.883-17.4h18.082v-56.885c0-21.132 14.617-38.862 34.266-43.745.032-44.373.032-81.808.032-81.808 140.147 0 131.724 83.974 115.325 132.196-6.42 18.884-2.601 22.05 10.893 7.354C536.473 77.106 298.38 16.566 203.806.482z"/>
|
||||||
|
@ -20,5 +14,11 @@
|
||||||
</div> -->
|
</div> -->
|
||||||
<div id="root" style="display: none;">
|
<div id="root" style="display: none;">
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
if (/theme=(\w+)/.test(window.location.href)) document.getElementById('root').classList.add(RegExp.$1)
|
||||||
|
window.shouldUseDarkColors = /dark=true/.test(window.location.href)
|
||||||
|
window.dt = /dt=true/.test(window.location.href)
|
||||||
|
document.body.classList.add(window.dt ? 'disableTransparent' : 'transparent')
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<transition name="tips-fade" @after-leave="afterLeave">
|
<transition name="tips-fade" @after-leave="afterLeave">
|
||||||
<div v-show="visible" :style="{ left: position.left + 'px' , top: position.top + 'px', transform: transform }" ref="dom_tips" :class="$style.tips">{{message}}</div>
|
<div v-show="visible" :style="{ left: position.left + 'px' , top: position.top + 'px', transform: transform }" ref="dom_tips" :class="$style.tips" role="presentation">{{message}}</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,14 @@ let prevX = 0
|
||||||
let prevY = 0
|
let prevY = 0
|
||||||
let isDraging = false
|
let isDraging = false
|
||||||
|
|
||||||
|
const getTipText = el => {
|
||||||
|
return el.getAttribute('aria-label') && el.getAttribute('ignore-tip') == null ? el.getAttribute('aria-label') : null
|
||||||
|
}
|
||||||
|
|
||||||
const getTips = el =>
|
const getTips = el =>
|
||||||
el
|
el
|
||||||
? el.getAttribute('tips')
|
? getTipText(el)
|
||||||
? el.getAttribute('tips')
|
? getTipText(el)
|
||||||
: el.parentNode === document.documentElement
|
: el.parentNode === document.documentElement
|
||||||
? null
|
? null
|
||||||
: getTips(el.parentNode)
|
: getTips(el.parentNode)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { messages } from '@/lang'
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
locale: 'zh-cn',
|
locale: 'zh-cn',
|
||||||
fallbackLocale: 'zh-cn',
|
fallbackLocale: 'zh-cn',
|
||||||
|
allowComposition: true,
|
||||||
messages,
|
messages,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ export const getAnalyser = () => {
|
||||||
return analyser
|
return analyser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const hasInitedAnalyser = () => audioContext != null
|
||||||
|
|
||||||
export const setResource = src => {
|
export const setResource = src => {
|
||||||
if (audio) audio.src = src
|
if (audio) audio.src = src
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
import music from '../utils/music'
|
import music from '../utils/music'
|
||||||
import { themes, windowSizeList } from '@renderer/core/share'
|
import { themes, windowSizeList, themeShouldUseDarkColors } from '@renderer/core/share'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
theme(state) {
|
theme(state) {
|
||||||
let theme = themes.find(theme => theme.id == state.setting.themeId)
|
const themeId = state.setting.theme.id == 'auto'
|
||||||
return (theme && theme.className) || ''
|
? themeShouldUseDarkColors.value
|
||||||
|
? state.setting.theme.darkId
|
||||||
|
: state.setting.theme.lightId
|
||||||
|
: state.setting.theme.id
|
||||||
|
let theme = themes.find(theme => theme.id == themeId) ?? themes[0]
|
||||||
|
return theme.className
|
||||||
},
|
},
|
||||||
font(state) {
|
font(state) {
|
||||||
return state.setting.font
|
return state.setting.font
|
||||||
},
|
},
|
||||||
themes(state) {
|
themes(state) {
|
||||||
return {
|
return {
|
||||||
active: state.setting.themeId,
|
active: state.setting.theme.id,
|
||||||
|
lightId: state.setting.theme.lightId,
|
||||||
|
darkId: state.setting.theme.darkId,
|
||||||
list: themes,
|
list: themes,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -59,4 +66,7 @@ export default {
|
||||||
pactModalVisible(state) {
|
pactModalVisible(state) {
|
||||||
return !state.setting.isAgreePact
|
return !state.setting.isAgreePact
|
||||||
},
|
},
|
||||||
|
isShowAnimation(state) {
|
||||||
|
return state.setting.isShowAnimation
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import music from '../../utils/music'
|
import music from '../../utils/music'
|
||||||
import { markRawList } from '@renderer/utils/vueTools'
|
import { markRawList } from '@renderer/utils/vueTools'
|
||||||
|
import { deduplicationList } from '@renderer/utils'
|
||||||
|
|
||||||
const sourceList = {}
|
const sourceList = {}
|
||||||
const sources = []
|
const sources = []
|
||||||
const cache = new Map()
|
const cache = new Map()
|
||||||
|
@ -57,6 +59,7 @@ const actions = {
|
||||||
// : music[source].leaderboard.getList(bangId, page)
|
// : music[source].leaderboard.getList(bangId, page)
|
||||||
// ).then(result => commit('setList', { result, key }))
|
// ).then(result => commit('setList', { result, key }))
|
||||||
return music[source].leaderboard.getList(bangId, page).then(result => {
|
return music[source].leaderboard.getList(bangId, page).then(result => {
|
||||||
|
result.list = deduplicationList(result.list)
|
||||||
cache.set(key, result)
|
cache.set(key, result)
|
||||||
listInfo.list = markRawList(result.list)
|
listInfo.list = markRawList(result.list)
|
||||||
listInfo.total = result.total
|
listInfo.total = result.total
|
||||||
|
@ -75,6 +78,7 @@ const actions = {
|
||||||
return cache.has(key)
|
return cache.has(key)
|
||||||
? Promise.resolve(cache.get(key))
|
? Promise.resolve(cache.get(key))
|
||||||
: music[source].leaderboard.getList(bangId, page).then(result => {
|
: music[source].leaderboard.getList(bangId, page).then(result => {
|
||||||
|
result.list = markRawList(deduplicationList(result.list))
|
||||||
cache.set(key, result)
|
cache.set(key, result)
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
|
@ -89,7 +93,7 @@ const actions = {
|
||||||
: loadData(id, loadPage).then(result1 => load(++loadPage).then(result2 => [...result1.list, ...result2]))
|
: loadData(id, loadPage).then(result1 => load(++loadPage).then(result2 => [...result1.list, ...result2]))
|
||||||
}
|
}
|
||||||
return load().then(result2 => [...result.list, ...result2])
|
return load().then(result2 => [...result.list, ...result2])
|
||||||
})
|
}).then(list => deduplicationList(list))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,29 +36,52 @@ const playMusic = () => {
|
||||||
window.eventHub.emit(eventPlayerNames.playMusic)
|
window.eventHub.emit(eventPlayerNames.playMusic)
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterList = async({ playedList, listInfo, savePath, commit }) => {
|
const filterList = async({ playedList, listInfo, savePath, commit, isCheckFile }) => {
|
||||||
// if (this.list.listName === null) return
|
// if (this.list.listName === null) return
|
||||||
let list
|
// console.log(isCheckFile)
|
||||||
let canPlayList = []
|
if (isCheckFile) {
|
||||||
const filteredPlayedList = playedList.filter(({ listId, isTempPlay }) => listInfo.id === listId && !isTempPlay).map(({ musicInfo }) => musicInfo)
|
let list
|
||||||
if (listInfo.id == 'download') {
|
let canPlayList = []
|
||||||
list = []
|
const filteredPlayedList = playedList.filter(({ listId, isTempPlay }) => listInfo.id === listId && !isTempPlay).map(({ musicInfo }) => musicInfo)
|
||||||
for (const item of listInfo.list) {
|
if (listInfo.id == 'download') {
|
||||||
const filePath = path.join(savePath, item.metadata.fileName)
|
list = []
|
||||||
if (!await checkPath(filePath) || !item.isComplate || /\.ape$/.test(filePath)) continue
|
for (const item of listInfo.list) {
|
||||||
|
const filePath = path.join(savePath, item.metadata.fileName)
|
||||||
|
if (!await checkPath(filePath) || !item.isComplate || /\.ape$/.test(filePath)) continue
|
||||||
|
|
||||||
canPlayList.push(item)
|
canPlayList.push(item)
|
||||||
|
|
||||||
// 排除已播放音乐
|
// 排除已播放音乐
|
||||||
let index = filteredPlayedList.findIndex(m => m.songmid == item.songmid)
|
let index = filteredPlayedList.findIndex(m => m.songmid == item.songmid)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
filteredPlayedList.splice(index, 1)
|
filteredPlayedList.splice(index, 1)
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
|
list.push(item)
|
||||||
}
|
}
|
||||||
list.push(item)
|
} else {
|
||||||
|
list = listInfo.list.filter(s => {
|
||||||
|
// if (!assertApiSupport(s.source)) return false
|
||||||
|
canPlayList.push(s)
|
||||||
|
|
||||||
|
let index = filteredPlayedList.findIndex(m => m.songmid == s.songmid)
|
||||||
|
if (index > -1) {
|
||||||
|
filteredPlayedList.splice(index, 1)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
if (!list.length && playedList.length) {
|
||||||
|
commit('clearPlayedList')
|
||||||
|
return canPlayList
|
||||||
|
}
|
||||||
|
return list
|
||||||
} else {
|
} else {
|
||||||
list = listInfo.list.filter(s => {
|
let canPlayList = []
|
||||||
|
const filteredPlayedList = playedList.filter(({ listId, isTempPlay }) => listInfo.id === listId && !isTempPlay).map(({ musicInfo }) => musicInfo)
|
||||||
|
|
||||||
|
const list = listInfo.list.filter(s => {
|
||||||
// if (!assertApiSupport(s.source)) return false
|
// if (!assertApiSupport(s.source)) return false
|
||||||
canPlayList.push(s)
|
canPlayList.push(s)
|
||||||
|
|
||||||
|
@ -69,12 +92,12 @@ const filterList = async({ playedList, listInfo, savePath, commit }) => {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
if (!list.length && playedList.length) {
|
||||||
|
commit('clearPlayedList')
|
||||||
|
return canPlayList
|
||||||
|
}
|
||||||
|
return list
|
||||||
}
|
}
|
||||||
if (!list.length && playedList.length) {
|
|
||||||
commit('clearPlayedList')
|
|
||||||
return canPlayList
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMusicUrl = function(musicInfo, type, onToggleSource, retryedSource = [], originMusic) {
|
const getMusicUrl = function(musicInfo, type, onToggleSource, retryedSource = [], originMusic) {
|
||||||
|
@ -188,6 +211,7 @@ const actions = {
|
||||||
},
|
},
|
||||||
async getLrc({ commit, state }, musicInfo) {
|
async getLrc({ commit, state }, musicInfo) {
|
||||||
const lrcInfo = await getStoreLyric(musicInfo)
|
const lrcInfo = await getStoreLyric(musicInfo)
|
||||||
|
// lrcInfo = {}
|
||||||
// if (lrcRequest && lrcRequest.cancelHttp) lrcRequest.cancelHttp()
|
// if (lrcRequest && lrcRequest.cancelHttp) lrcRequest.cancelHttp()
|
||||||
if (lrcInfo.lyric && lrcInfo.tlyric != null) {
|
if (lrcInfo.lyric && lrcInfo.tlyric != null) {
|
||||||
// if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) {
|
// if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) {
|
||||||
|
@ -198,7 +222,15 @@ const actions = {
|
||||||
// commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
|
// commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if ((lrcInfo.lxlyric == null && musicInfo.source != 'kg') || lrcInfo.lxlyric != null) return lrcInfo
|
if (lrcInfo.lxlyric == null) {
|
||||||
|
switch (musicInfo.source) {
|
||||||
|
case 'kg':
|
||||||
|
case 'kw':
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return lrcInfo
|
||||||
|
}
|
||||||
|
} else return lrcInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// lrcRequest = music[musicInfo.source].getLyric(musicInfo)
|
// lrcRequest = music[musicInfo.source].getLyric(musicInfo)
|
||||||
|
@ -212,7 +244,7 @@ const actions = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async playPrev({ state, rootState, commit, getters }) {
|
async playPrev({ state, rootState, commit, getters }, { findNum = 0, excludeList = [] } = {}) {
|
||||||
const currentListId = playInfo.playListId
|
const currentListId = playInfo.playListId
|
||||||
const currentList = getList(currentListId)
|
const currentList = getList(currentListId)
|
||||||
if (playedList.length) {
|
if (playedList.length) {
|
||||||
|
@ -242,11 +274,13 @@ const actions = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isCheckFile = findNum > 2
|
||||||
let filteredList = await filterList({
|
let filteredList = await filterList({
|
||||||
listInfo: { id: currentListId, list: currentList },
|
listInfo: { id: currentListId, list: currentList },
|
||||||
playedList,
|
playedList: excludeList.length ? [...playedList, ...excludeList] : playedList,
|
||||||
savePath: rootState.setting.download.savePath,
|
savePath: rootState.setting.download.savePath,
|
||||||
commit,
|
commit,
|
||||||
|
isCheckFile,
|
||||||
})
|
})
|
||||||
if (!filteredList.length) return commit('setPlayMusicInfo', { listId: null, musicInfo: null })
|
if (!filteredList.length) return commit('setPlayMusicInfo', { listId: null, musicInfo: null })
|
||||||
|
|
||||||
|
@ -271,14 +305,24 @@ const actions = {
|
||||||
if (nextIndex < 0) return
|
if (nextIndex < 0) return
|
||||||
}
|
}
|
||||||
|
|
||||||
commit('setPlayMusicInfo', {
|
const nextPlayMusicInfo = {
|
||||||
musicInfo: filteredList[nextIndex],
|
musicInfo: filteredList[nextIndex],
|
||||||
listId: currentListId,
|
listId: currentListId,
|
||||||
})
|
}
|
||||||
|
if (currentListId == 'download' && !isCheckFile) {
|
||||||
|
if (!await checkPath(path.join(rootState.setting.download.savePath, nextPlayMusicInfo.musicInfo.metadata.fileName)) || !nextPlayMusicInfo.musicInfo.isComplate || /\.ape$/.test(nextPlayMusicInfo.musicInfo.metadata.fileName)) {
|
||||||
|
excludeList.push(nextPlayMusicInfo)
|
||||||
|
// console.log('findNum', findNum)
|
||||||
|
return this.dispatch('player/playPrev', { findNum: findNum + 1, excludeList })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
commit('setPlayMusicInfo', nextPlayMusicInfo)
|
||||||
playMusic()
|
playMusic()
|
||||||
},
|
},
|
||||||
async playNext({ state, rootState, commit, getters }) {
|
async playNext({ state, rootState, commit, getters }, { findNum = 0, excludeList = [] } = {}) {
|
||||||
if (tempPlayList.length) {
|
if (tempPlayList.length) { // 如果稍后播放列表存在歌曲则直接播放改列表的歌曲
|
||||||
const playMusicInfo = tempPlayList[0]
|
const playMusicInfo = tempPlayList[0]
|
||||||
commit('removeTempPlayList', 0)
|
commit('removeTempPlayList', 0)
|
||||||
commit('setPlayMusicInfo', playMusicInfo)
|
commit('setPlayMusicInfo', playMusicInfo)
|
||||||
|
@ -290,7 +334,7 @@ const actions = {
|
||||||
const currentListId = playInfo.playListId
|
const currentListId = playInfo.playListId
|
||||||
const currentList = getList(currentListId)
|
const currentList = getList(currentListId)
|
||||||
|
|
||||||
if (playedList.length) {
|
if (playedList.length) { // 移除已播放列表内不存在原列表的歌曲
|
||||||
let currentSongmid
|
let currentSongmid
|
||||||
if (playMusicInfo.isTempPlay) {
|
if (playMusicInfo.isTempPlay) {
|
||||||
const musicInfo = currentList[playInfo.listPlayIndex]
|
const musicInfo = currentList[playInfo.listPlayIndex]
|
||||||
|
@ -316,11 +360,13 @@ const actions = {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let filteredList = await filterList({
|
const isCheckFile = findNum > 2 // 针对下载列表,如果超过两次都碰到无效歌曲,则过滤整个列表内的无效歌曲
|
||||||
|
let filteredList = await filterList({ // 过滤已播放歌曲
|
||||||
listInfo: { id: currentListId, list: currentList },
|
listInfo: { id: currentListId, list: currentList },
|
||||||
playedList,
|
playedList: excludeList.length ? [...playedList, ...excludeList] : playedList,
|
||||||
savePath: rootState.setting.download.savePath,
|
savePath: rootState.setting.download.savePath,
|
||||||
commit,
|
commit,
|
||||||
|
isCheckFile,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!filteredList.length) return commit('setPlayMusicInfo', { listId: null, musicInfo: null })
|
if (!filteredList.length) return commit('setPlayMusicInfo', { listId: null, musicInfo: null })
|
||||||
|
@ -346,10 +392,19 @@ const actions = {
|
||||||
}
|
}
|
||||||
if (nextIndex < 0) return
|
if (nextIndex < 0) return
|
||||||
|
|
||||||
commit('setPlayMusicInfo', {
|
const nextPlayMusicInfo = {
|
||||||
musicInfo: filteredList[nextIndex],
|
musicInfo: filteredList[nextIndex],
|
||||||
listId: currentListId,
|
listId: currentListId,
|
||||||
})
|
}
|
||||||
|
if (currentListId == 'download' && !isCheckFile) { // 针对下载列表,检查文件是否可以播放
|
||||||
|
if (!await checkPath(path.join(rootState.setting.download.savePath, nextPlayMusicInfo.musicInfo.metadata.fileName)) || !nextPlayMusicInfo.musicInfo.isComplate || /\.ape$/.test(nextPlayMusicInfo.musicInfo.metadata.fileName)) {
|
||||||
|
excludeList.push(nextPlayMusicInfo)
|
||||||
|
// console.log('findNum', findNum)
|
||||||
|
return this.dispatch('player/playNext', { findNum: findNum + 1, excludeList })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commit('setPlayMusicInfo', nextPlayMusicInfo)
|
||||||
playMusic()
|
playMusic()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import music from '../../utils/music'
|
import music from '../../utils/music'
|
||||||
import { markRawList } from '@renderer/utils/vueTools'
|
import { markRawList } from '@renderer/utils/vueTools'
|
||||||
|
import { deduplicationList } from '@renderer/utils'
|
||||||
|
|
||||||
const sources = []
|
const sources = []
|
||||||
const sourceList = {}
|
const sourceList = {}
|
||||||
|
@ -85,7 +86,7 @@ sources.push({
|
||||||
})
|
})
|
||||||
|
|
||||||
// state
|
// state
|
||||||
const state = {
|
const state = window.state = {
|
||||||
sourceList,
|
sourceList,
|
||||||
list: [],
|
list: [],
|
||||||
text: '',
|
text: '',
|
||||||
|
@ -151,6 +152,7 @@ const mutations = {
|
||||||
},
|
},
|
||||||
setList(state, datas) {
|
setList(state, datas) {
|
||||||
let source = state.sourceList[datas.source]
|
let source = state.sourceList[datas.source]
|
||||||
|
datas.list = deduplicationList(datas.list)
|
||||||
source.list = markRawList(datas.list)
|
source.list = markRawList(datas.list)
|
||||||
source.total = datas.total
|
source.total = datas.total
|
||||||
source.allPage = datas.allPage
|
source.allPage = datas.allPage
|
||||||
|
@ -170,6 +172,7 @@ const mutations = {
|
||||||
total += source.total
|
total += source.total
|
||||||
// limit = Math.max(source.limit, limit)
|
// limit = Math.max(source.limit, limit)
|
||||||
}
|
}
|
||||||
|
list = deduplicationList(list)
|
||||||
state.allPage = Math.max(...pages)
|
state.allPage = Math.max(...pages)
|
||||||
state.total = total
|
state.total = total
|
||||||
state.limit = limit
|
state.limit = limit
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import music from '../../utils/music'
|
import music from '../../utils/music'
|
||||||
import { markRawList } from '@renderer/utils/vueTools'
|
import { markRawList } from '@renderer/utils/vueTools'
|
||||||
|
import { deduplicationList } from '@renderer/utils'
|
||||||
|
|
||||||
const sortList = {}
|
const sortList = {}
|
||||||
const sources = []
|
const sources = []
|
||||||
|
@ -91,6 +92,7 @@ const actions = {
|
||||||
? Promise.resolve(cache.get(key))
|
? Promise.resolve(cache.get(key))
|
||||||
: music[source]?.songList.getListDetail(id, page).then(result => ({ ...result, list: filterList(result.list) }))
|
: music[source]?.songList.getListDetail(id, page).then(result => ({ ...result, list: filterList(result.list) }))
|
||||||
).then(result => {
|
).then(result => {
|
||||||
|
result.list = markRawList(deduplicationList(result.list))
|
||||||
commit('setListDetail', { result, key, source, id, page })
|
commit('setListDetail', { result, key, source, id, page })
|
||||||
return result.list
|
return result.list
|
||||||
})
|
})
|
||||||
|
@ -103,9 +105,10 @@ const actions = {
|
||||||
return cache.has(key)
|
return cache.has(key)
|
||||||
? Promise.resolve(cache.get(key))
|
? Promise.resolve(cache.get(key))
|
||||||
: music[source]?.songList.getListDetail(id, page).then(result => {
|
: music[source]?.songList.getListDetail(id, page).then(result => {
|
||||||
|
result.list = markRawList(deduplicationList(result.list))
|
||||||
cache.set(key, result)
|
cache.set(key, result)
|
||||||
return result
|
return result
|
||||||
})
|
}) ?? Promise.reject(new Error('source not found'))
|
||||||
}
|
}
|
||||||
return loadData(id, 1).then(result => {
|
return loadData(id, 1).then(result => {
|
||||||
if (result.total <= result.limit) return filterList(result.list)
|
if (result.total <= result.limit) return filterList(result.list)
|
||||||
|
@ -117,7 +120,7 @@ const actions = {
|
||||||
: loadData(id, loadPage).then(result1 => loadDetail(++loadPage).then(result2 => [...result1.list, ...result2]))
|
: loadData(id, loadPage).then(result1 => loadDetail(++loadPage).then(result2 => [...result1.list, ...result2]))
|
||||||
}
|
}
|
||||||
return loadDetail().then(result2 => [...result.list, ...result2]).then(list => filterList(list))
|
return loadDetail().then(result2 => [...result.list, ...result2]).then(list => filterList(list))
|
||||||
})
|
}).then(list => deduplicationList(list))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +142,7 @@ const mutations = {
|
||||||
cache.set(key, result)
|
cache.set(key, result)
|
||||||
},
|
},
|
||||||
setListDetail(state, { result, key, source, id, page }) {
|
setListDetail(state, { result, key, source, id, page }) {
|
||||||
state.listDetail.list = markRawList(result.list)
|
state.listDetail.list = result.list
|
||||||
state.listDetail.id = id
|
state.listDetail.id = id
|
||||||
state.listDetail.source = source
|
state.listDetail.source = source
|
||||||
state.listDetail.total = result.total
|
state.listDetail.total = result.total
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export default {
|
export default {
|
||||||
setTheme(state, val) {
|
setTheme(state, val) {
|
||||||
state.setting.themeId = val
|
state.setting.theme.id = val
|
||||||
},
|
},
|
||||||
setSearchSource(state, { searchSource, tempSearchSource }) {
|
setSearchSource(state, { searchSource, tempSearchSource }) {
|
||||||
console.log(searchSource, tempSearchSource)
|
console.log(searchSource, tempSearchSource)
|
||||||
|
@ -35,6 +35,9 @@ export default {
|
||||||
state.setting.player.volume = val
|
state.setting.player.volume = val
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setPlayDetailLyricFont(state, val) {
|
||||||
|
state.setting.playDetail.style.fontSize = val
|
||||||
|
},
|
||||||
setPlayNextMode(state, val) {
|
setPlayNextMode(state, val) {
|
||||||
state.setting.player.togglePlayMethod = val
|
state.setting.player.togglePlayMethod = val
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,18 +1,75 @@
|
||||||
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from '@renderer/utils/vueTools'
|
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from '@renderer/utils/vueTools'
|
||||||
import { scrollTo } from '@renderer/utils'
|
import { scrollTo, throttle, formatPlayTime2 } from '@renderer/utils'
|
||||||
|
import { player as eventPlayerNames } from '@renderer/event/names'
|
||||||
|
|
||||||
export default ({ isPlay, lyric }) => {
|
export default ({ isPlay, lyric }) => {
|
||||||
const dom_lyric = ref(null)
|
const dom_lyric = ref(null)
|
||||||
const dom_lyric_text = ref(null)
|
const dom_lyric_text = ref(null)
|
||||||
|
const dom_skip_line = ref(null)
|
||||||
const isMsDown = ref(false)
|
const isMsDown = ref(false)
|
||||||
|
const isStopScroll = ref(false)
|
||||||
|
const timeStr = ref('--/--')
|
||||||
|
|
||||||
let msDownY = 0
|
let msDownY = 0
|
||||||
let msDownScrollY = 0
|
let msDownScrollY = 0
|
||||||
let isStopScroll = false
|
|
||||||
let timeout = null
|
let timeout = null
|
||||||
let cancelScrollFn
|
let cancelScrollFn
|
||||||
let dom_lines
|
let dom_lines
|
||||||
let isSetedLines = false
|
let isSetedLines = false
|
||||||
|
let point = {
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
}
|
||||||
|
let time = -1
|
||||||
|
let dom_pre_line = null
|
||||||
|
let isSkipMouseEnter = false
|
||||||
|
|
||||||
|
const handleSkipPlay = () => {
|
||||||
|
if (time == -1) return
|
||||||
|
handleSkipMouseLeave()
|
||||||
|
isStopScroll.value = false
|
||||||
|
window.eventHub.emit(eventPlayerNames.setProgress, time)
|
||||||
|
if (!isPlay.value) window.eventHub.emit(eventPlayerNames.setPlay)
|
||||||
|
}
|
||||||
|
const handleSkipMouseEnter = () => {
|
||||||
|
isSkipMouseEnter = true
|
||||||
|
clearLyricScrollTimeout()
|
||||||
|
}
|
||||||
|
const handleSkipMouseLeave = () => {
|
||||||
|
isSkipMouseEnter = false
|
||||||
|
startLyricScrollTimeout()
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTime = throttle(() => {
|
||||||
|
if (point.x == null) {
|
||||||
|
if (!dom_skip_line.value) return
|
||||||
|
const rect = dom_skip_line.value.getBoundingClientRect()
|
||||||
|
point.x = rect.x
|
||||||
|
point.y = rect.y
|
||||||
|
}
|
||||||
|
let dom = document.elementFromPoint(point.x, point.y)
|
||||||
|
if (dom_pre_line === dom) return
|
||||||
|
if (dom.tagName == 'SPAN') {
|
||||||
|
dom = dom.parentNode.parentNode
|
||||||
|
} else if (dom.classList.contains('font')) {
|
||||||
|
dom = dom.parentNode
|
||||||
|
}
|
||||||
|
if (dom.time == null) {
|
||||||
|
if (lyric.lines.length) {
|
||||||
|
time = dom.classList.contains('pre') ? 0 : lyric.lines[lyric.lines.length - 1].time ?? 0
|
||||||
|
if (time) time = time / 1000
|
||||||
|
timeStr.value = formatPlayTime2(time)
|
||||||
|
} else {
|
||||||
|
time = -1
|
||||||
|
timeStr.value = '--:--'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
time = dom.time
|
||||||
|
if (time) time = time / 1000
|
||||||
|
timeStr.value = formatPlayTime2(time)
|
||||||
|
}
|
||||||
|
dom_pre_line = dom
|
||||||
|
})
|
||||||
|
|
||||||
const handleScrollLrc = (duration = 300) => {
|
const handleScrollLrc = (duration = 300) => {
|
||||||
if (!dom_lines?.length || !dom_lyric.value) return
|
if (!dom_lines?.length || !dom_lyric.value) return
|
||||||
|
@ -20,7 +77,8 @@ export default ({ isPlay, lyric }) => {
|
||||||
cancelScrollFn()
|
cancelScrollFn()
|
||||||
cancelScrollFn = null
|
cancelScrollFn = null
|
||||||
}
|
}
|
||||||
if (isStopScroll) return
|
if (isSkipMouseEnter) return
|
||||||
|
if (isStopScroll.value) return
|
||||||
let dom_p = dom_lines[lyric.line]
|
let dom_p = dom_lines[lyric.line]
|
||||||
cancelScrollFn = scrollTo(dom_lyric.value, dom_p ? (dom_p.offsetTop - dom_lyric.value.clientHeight * 0.38) : 0, duration)
|
cancelScrollFn = scrollTo(dom_lyric.value, dom_p ? (dom_p.offsetTop - dom_lyric.value.clientHeight * 0.38) : 0, duration)
|
||||||
}
|
}
|
||||||
|
@ -31,9 +89,10 @@ export default ({ isPlay, lyric }) => {
|
||||||
}
|
}
|
||||||
const startLyricScrollTimeout = () => {
|
const startLyricScrollTimeout = () => {
|
||||||
clearLyricScrollTimeout()
|
clearLyricScrollTimeout()
|
||||||
|
if (isSkipMouseEnter) return
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
timeout = null
|
timeout = null
|
||||||
isStopScroll = false
|
isStopScroll.value = false
|
||||||
if (!isPlay.value) return
|
if (!isPlay.value) return
|
||||||
handleScrollLrc()
|
handleScrollLrc()
|
||||||
}, 3000)
|
}, 3000)
|
||||||
|
@ -53,25 +112,27 @@ export default ({ isPlay, lyric }) => {
|
||||||
}
|
}
|
||||||
const handleMouseMsMove = event => {
|
const handleMouseMsMove = event => {
|
||||||
if (isMsDown.value) {
|
if (isMsDown.value) {
|
||||||
if (!isStopScroll) isStopScroll = true
|
if (!isStopScroll.value) isStopScroll.value = true
|
||||||
if (cancelScrollFn) {
|
if (cancelScrollFn) {
|
||||||
cancelScrollFn()
|
cancelScrollFn()
|
||||||
cancelScrollFn = null
|
cancelScrollFn = null
|
||||||
}
|
}
|
||||||
dom_lyric.value.scrollTop = msDownScrollY + msDownY - event.clientY
|
dom_lyric.value.scrollTop = msDownScrollY + msDownY - event.clientY
|
||||||
startLyricScrollTimeout()
|
startLyricScrollTimeout()
|
||||||
|
setTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleWheel = (event) => {
|
const handleWheel = (event) => {
|
||||||
console.log(event.deltaY)
|
console.log(event.deltaY)
|
||||||
if (!isStopScroll) isStopScroll = true
|
if (!isStopScroll.value) isStopScroll.value = true
|
||||||
if (cancelScrollFn) {
|
if (cancelScrollFn) {
|
||||||
cancelScrollFn()
|
cancelScrollFn()
|
||||||
cancelScrollFn = null
|
cancelScrollFn = null
|
||||||
}
|
}
|
||||||
dom_lyric.value.scrollTop = dom_lyric.value.scrollTop + event.deltaY
|
dom_lyric.value.scrollTop = dom_lyric.value.scrollTop + event.deltaY
|
||||||
startLyricScrollTimeout()
|
startLyricScrollTimeout()
|
||||||
|
setTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
const setLyric = (lines) => {
|
const setLyric = (lines) => {
|
||||||
|
@ -139,8 +200,14 @@ export default ({ isPlay, lyric }) => {
|
||||||
return {
|
return {
|
||||||
dom_lyric,
|
dom_lyric,
|
||||||
dom_lyric_text,
|
dom_lyric_text,
|
||||||
|
dom_skip_line,
|
||||||
|
isStopScroll,
|
||||||
isMsDown,
|
isMsDown,
|
||||||
|
timeStr,
|
||||||
handleLyricMouseDown,
|
handleLyricMouseDown,
|
||||||
handleWheel,
|
handleWheel,
|
||||||
|
handleSkipPlay,
|
||||||
|
handleSkipMouseEnter,
|
||||||
|
handleSkipMouseLeave,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -560,3 +560,24 @@ export const saveStrToFile = (path, str) => new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const fileNameRxp = /[\\/:*?#"<>|]/g
|
const fileNameRxp = /[\\/:*?#"<>|]/g
|
||||||
export const filterFileName = name => name.replace(fileNameRxp, '')
|
export const filterFileName = name => name.replace(fileNameRxp, '')
|
||||||
|
|
||||||
|
|
||||||
|
export const getFontSizeWithScreen = (screenWidth = window.innerWidth) => {
|
||||||
|
return screenWidth <= 1440
|
||||||
|
? 16
|
||||||
|
: screenWidth <= 1920
|
||||||
|
? 18
|
||||||
|
: screenWidth <= 2560
|
||||||
|
? 20
|
||||||
|
: screenWidth <= 2560 ? 20 : 22
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const deduplicationList = list => {
|
||||||
|
const ids = new Set()
|
||||||
|
return list.filter(s => {
|
||||||
|
if (ids.has(s.songmid)) return false
|
||||||
|
ids.add(s.songmid)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ const createAnimation = (dom, duration) => new window.Animation(new window.Keyfr
|
||||||
// https://jsfiddle.net/ceqpnbky/1/
|
// https://jsfiddle.net/ceqpnbky/1/
|
||||||
|
|
||||||
module.exports = class FontPlayer {
|
module.exports = class FontPlayer {
|
||||||
constructor({ lyric = '', translationLyric = '', lineClassName = '', fontClassName = '', translationClassName = '', lineModeClassName = '', shadowContent = false, shadowClassName = '' }) {
|
constructor({ time = 0, lyric = '', translationLyric = '', lineClassName = '', fontClassName = '', translationClassName = '', lineModeClassName = '', shadowContent = false, shadowClassName = '' }) {
|
||||||
|
this.time = time
|
||||||
this.lyric = lyric
|
this.lyric = lyric
|
||||||
this.translationLyric = translationLyric
|
this.translationLyric = translationLyric
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ module.exports = class FontPlayer {
|
||||||
this.curFontNum = 0
|
this.curFontNum = 0
|
||||||
this.maxFontNum = 0
|
this.maxFontNum = 0
|
||||||
this._performanceTime = 0
|
this._performanceTime = 0
|
||||||
this._performanceOffsetTime = 0
|
this._startTime = 0
|
||||||
|
|
||||||
this.fontContent = null
|
this.fontContent = null
|
||||||
|
|
||||||
|
@ -51,6 +52,7 @@ module.exports = class FontPlayer {
|
||||||
this.isLineMode = false
|
this.isLineMode = false
|
||||||
|
|
||||||
this.lineContent = document.createElement('div')
|
this.lineContent = document.createElement('div')
|
||||||
|
this.lineContent.time = this.time
|
||||||
if (this.lineClassName) this.lineContent.classList.add(this.lineClassName)
|
if (this.lineClassName) this.lineContent.classList.add(this.lineClassName)
|
||||||
this.fontContent = document.createElement('div')
|
this.fontContent = document.createElement('div')
|
||||||
this.fontContent.style = 'position:relative;display:inline-block;'
|
this.fontContent.style = 'position:relative;display:inline-block;'
|
||||||
|
@ -139,12 +141,12 @@ module.exports = class FontPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentTime() {
|
_currentTime() {
|
||||||
return getNow() - this._performanceTime + this._performanceOffsetTime
|
return getNow() - this._performanceTime + this._startTime
|
||||||
}
|
}
|
||||||
|
|
||||||
_findcurFontNum(curTime) {
|
_findcurFontNum(curTime, startIndex = 0) {
|
||||||
const length = this.fonts.length
|
const length = this.fonts.length
|
||||||
for (let index = 0; index < length; index++) if (curTime <= this.fonts[index].startTime) return index === 0 ? 0 : index - 1
|
for (let index = startIndex; index < length; index++) if (curTime < this.fonts[index].startTime) return index == 0 ? 0 : index - 1
|
||||||
return length - 1
|
return length - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,9 +195,8 @@ module.exports = class FontPlayer {
|
||||||
_refresh() {
|
_refresh() {
|
||||||
this.curFontNum++
|
this.curFontNum++
|
||||||
// console.log('curFontNum time', this.fonts[this.curFontNum].time)
|
// console.log('curFontNum time', this.fonts[this.curFontNum].time)
|
||||||
if (this.curFontNum === this.maxFontNum) return this._handlePlayMaxFontNum()
|
if (this.curFontNum >= this.maxFontNum) return this._handlePlayMaxFontNum()
|
||||||
let curFont = this.fonts[this.curFontNum]
|
let curFont = this.fonts[this.curFontNum]
|
||||||
let nextFont = this.fonts[this.curFontNum + 1]
|
|
||||||
// console.log(curFont, nextFont, this.curFontNum, this.maxFontNum)
|
// console.log(curFont, nextFont, this.curFontNum, this.maxFontNum)
|
||||||
const currentTime = this._currentTime()
|
const currentTime = this._currentTime()
|
||||||
// console.log(curFont.text)
|
// console.log(curFont.text)
|
||||||
|
@ -204,27 +205,38 @@ module.exports = class FontPlayer {
|
||||||
// console.log(currentTime, driftTime)
|
// console.log(currentTime, driftTime)
|
||||||
|
|
||||||
if (driftTime >= 0 || this.curFontNum == 0) {
|
if (driftTime >= 0 || this.curFontNum == 0) {
|
||||||
|
let nextFont = this.fonts[this.curFontNum + 1]
|
||||||
this.delay = nextFont.startTime - curFont.startTime - driftTime
|
this.delay = nextFont.startTime - curFont.startTime - driftTime
|
||||||
if (this.delay > 0) {
|
if (this.delay > 0) {
|
||||||
|
if (this.isPlay) {
|
||||||
|
this.timeoutTools.start(() => {
|
||||||
|
if (!this.isPlay) return
|
||||||
|
this._refresh()
|
||||||
|
}, this.delay)
|
||||||
|
}
|
||||||
this._handlePlayFont(curFont, driftTime)
|
this._handlePlayFont(curFont, driftTime)
|
||||||
this.timeoutTools.start(() => {
|
return
|
||||||
if (!this.isPlay) return
|
} else {
|
||||||
this._refresh()
|
let newCurLineNum = this._findcurFontNum(currentTime, this.curFontNum + 1)
|
||||||
}, this.delay)
|
if (newCurLineNum > this.curFontNum) this.curFontNum = newCurLineNum - 1
|
||||||
|
for (let i = 0; i <= this.curFontNum; i++) this._handlePlayFont(this.fonts[i], 0, true)
|
||||||
|
this._refresh()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if (this.curFontNum == 0) {
|
} else if (this.curFontNum == 0) {
|
||||||
this.curFontNum--
|
this.curFontNum--
|
||||||
this.waitPlayTimeout.start(() => {
|
if (this.isPlay) {
|
||||||
if (!this.isPlay) return
|
this.waitPlayTimeout.start(() => {
|
||||||
this._refresh()
|
if (!this.isPlay) return
|
||||||
}, -driftTime)
|
this._refresh()
|
||||||
|
}, -driftTime)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.curFontNum = this._findcurFontNum(currentTime)
|
this.curFontNum = this._findcurFontNum(currentTime, this.curFontNum) - 1
|
||||||
for (let i = 0; i < this.curFontNum; i++) this._handlePlayFont(this.fonts[i], 0, true)
|
for (let i = 0; i <= this.curFontNum; i++) this._handlePlayFont(this.fonts[i], 0, true)
|
||||||
this.curFontNum--
|
// this.curFontNum--
|
||||||
this._refresh()
|
this._refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,14 +247,11 @@ module.exports = class FontPlayer {
|
||||||
|
|
||||||
if (this.isLineMode) return this._handlePlayLine(true)
|
if (this.isLineMode) return this._handlePlayLine(true)
|
||||||
this.isPlay = true
|
this.isPlay = true
|
||||||
this._performanceTime = getNow() - curTime
|
this._performanceTime = getNow()
|
||||||
this._performanceOffsetTime = 0
|
this._startTime = curTime
|
||||||
if (this._performanceTime < 0) {
|
|
||||||
this._performanceOffsetTime = -this._performanceTime
|
|
||||||
this._performanceTime = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
this.curFontNum = this._findcurFontNum(curTime)
|
this.curFontNum = this._findcurFontNum(curTime)
|
||||||
|
|
||||||
for (let i = this.curFontNum; i > -1; i--) {
|
for (let i = this.curFontNum; i > -1; i--) {
|
||||||
this._handlePlayFont(this.fonts[i], 0, true)
|
this._handlePlayFont(this.fonts[i], 0, true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ module.exports = class Lyric {
|
||||||
constructor({
|
constructor({
|
||||||
lyric = '',
|
lyric = '',
|
||||||
translationLyric = '',
|
translationLyric = '',
|
||||||
offset = 150,
|
offset = 0,
|
||||||
lineClassName = '',
|
lineClassName = '',
|
||||||
fontClassName = 'font',
|
fontClassName = 'font',
|
||||||
translationClassName = 'translation',
|
translationClassName = 'translation',
|
||||||
|
@ -61,7 +61,7 @@ module.exports = class Lyric {
|
||||||
font.reset()
|
font.reset()
|
||||||
font.lineContent.classList.remove(this.activeLineClassName)
|
font.lineContent.classList.remove(this.activeLineClassName)
|
||||||
}
|
}
|
||||||
} else if (num > this.playingLineNum + 1) {
|
} else if (num > this.playingLineNum) {
|
||||||
for (let i = Math.max(this.playingLineNum, 0); i < num; i++) {
|
for (let i = Math.max(this.playingLineNum, 0); i < num; i++) {
|
||||||
const font = this._lineFonts[i]
|
const font = this._lineFonts[i]
|
||||||
font.reset()
|
font.reset()
|
||||||
|
@ -79,7 +79,7 @@ module.exports = class Lyric {
|
||||||
font.lineContent.classList.remove(this.activeLineClassName)
|
font.lineContent.classList.remove(this.activeLineClassName)
|
||||||
font.reset()
|
font.reset()
|
||||||
}
|
}
|
||||||
} else if (num > this.playingLineNum + 1) {
|
} else if (num > this.playingLineNum) {
|
||||||
for (let i = Math.max(this.playingLineNum, 0); i < num; i++) {
|
for (let i = Math.max(this.playingLineNum, 0); i < num; i++) {
|
||||||
const font = this._lineFonts[i]
|
const font = this._lineFonts[i]
|
||||||
font.lineContent.classList.remove(this.activeLineClassName)
|
font.lineContent.classList.remove(this.activeLineClassName)
|
||||||
|
@ -106,6 +106,7 @@ module.exports = class Lyric {
|
||||||
if (this.isLineMode) {
|
if (this.isLineMode) {
|
||||||
this._lines = lyricLines.map(line => {
|
this._lines = lyricLines.map(line => {
|
||||||
const fontPlayer = new FontPlayer({
|
const fontPlayer = new FontPlayer({
|
||||||
|
time: line.time,
|
||||||
lyric: line.text,
|
lyric: line.text,
|
||||||
translationLyric: line.translation,
|
translationLyric: line.translation,
|
||||||
lineClassName: this.lineClassName,
|
lineClassName: this.lineClassName,
|
||||||
|
@ -127,6 +128,7 @@ module.exports = class Lyric {
|
||||||
} else {
|
} else {
|
||||||
this._lines = lyricLines.map(line => {
|
this._lines = lyricLines.map(line => {
|
||||||
const fontPlayer = new FontPlayer({
|
const fontPlayer = new FontPlayer({
|
||||||
|
time: line.time,
|
||||||
lyric: line.text,
|
lyric: line.text,
|
||||||
translationLyric: line.translation,
|
translationLyric: line.translation,
|
||||||
lineClassName: this.lineClassName,
|
lineClassName: this.lineClassName,
|
||||||
|
@ -164,5 +166,6 @@ module.exports = class Lyric {
|
||||||
this.lyric = lyric
|
this.lyric = lyric
|
||||||
this.translationLyric = translationLyric
|
this.translationLyric = translationLyric
|
||||||
this._init()
|
this._init()
|
||||||
|
this.linePlayer.offset = this.isLineMode ? this.offset + 90 : this.offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,8 @@ module.exports = class LinePlayer {
|
||||||
this.curLineNum = 0
|
this.curLineNum = 0
|
||||||
this.maxLine = 0
|
this.maxLine = 0
|
||||||
this.offset = offset
|
this.offset = offset
|
||||||
this.isOffseted = false
|
|
||||||
this._performanceTime = 0
|
this._performanceTime = 0
|
||||||
this._performanceOffsetTime = 0
|
this._startTime = 0
|
||||||
this._init()
|
this._init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,10 +38,17 @@ module.exports = class LinePlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
_initTag() {
|
_initTag() {
|
||||||
|
this.tags = {}
|
||||||
for (let tag in tagRegMap) {
|
for (let tag in tagRegMap) {
|
||||||
const matches = this.lyric.match(new RegExp(`\\[${tagRegMap[tag]}:([^\\]]*)]`, 'i'))
|
const matches = this.lyric.match(new RegExp(`\\[${tagRegMap[tag]}:([^\\]]*)]`, 'i'))
|
||||||
this.tags[tag] = (matches && matches[1]) || ''
|
this.tags[tag] = (matches && matches[1]) || ''
|
||||||
}
|
}
|
||||||
|
if (this.tags.offset) {
|
||||||
|
let offset = parseInt(this.tags.offset)
|
||||||
|
this.tags.offset = Number.isNaN(offset) ? 0 : offset
|
||||||
|
} else {
|
||||||
|
this.tags.offset = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_initLines() {
|
_initLines() {
|
||||||
|
@ -93,12 +99,13 @@ module.exports = class LinePlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentTime() {
|
_currentTime() {
|
||||||
return getNow() - this._performanceTime + this._performanceOffsetTime
|
return getNow() - this._performanceTime + this._startTime
|
||||||
}
|
}
|
||||||
|
|
||||||
_findCurLineNum(curTime) {
|
_findCurLineNum(curTime, startIndex = 0) {
|
||||||
|
if (curTime <= 0) return 0
|
||||||
const length = this.lines.length
|
const length = this.lines.length
|
||||||
for (let index = 0; index < length; index++) if (curTime <= this.lines[index].time) return index === 0 ? 0 : index - 1
|
for (let index = startIndex; index < length; index++) if (curTime <= this.lines[index].time) return index === 0 ? 0 : index - 1
|
||||||
return length - 1
|
return length - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,30 +117,35 @@ module.exports = class LinePlayer {
|
||||||
_refresh() {
|
_refresh() {
|
||||||
this.curLineNum++
|
this.curLineNum++
|
||||||
// console.log('curLineNum time', this.lines[this.curLineNum].time)
|
// console.log('curLineNum time', this.lines[this.curLineNum].time)
|
||||||
|
if (this.curLineNum >= this.maxLine) return this._handleMaxLine()
|
||||||
|
|
||||||
let curLine = this.lines[this.curLineNum]
|
let curLine = this.lines[this.curLineNum]
|
||||||
let nextLine = this.lines[this.curLineNum + 1]
|
|
||||||
const currentTime = this._currentTime()
|
const currentTime = this._currentTime()
|
||||||
const driftTime = currentTime - curLine.time
|
const driftTime = currentTime - curLine.time
|
||||||
|
|
||||||
if (driftTime >= 0 || this.curLineNum === 0) {
|
if (driftTime >= 0 || this.curLineNum === 0) {
|
||||||
if (this.curLineNum === this.maxLine) return this._handleMaxLine()
|
let nextLine = this.lines[this.curLineNum + 1]
|
||||||
this.delay = nextLine.time - curLine.time - driftTime
|
this.delay = nextLine.time - curLine.time - driftTime
|
||||||
|
|
||||||
if (this.delay > 0) {
|
if (this.delay > 0) {
|
||||||
if (!this.isOffseted && this.delay >= this.offset) {
|
if (this.isPlay) {
|
||||||
this._performanceOffsetTime += this.offset
|
timeoutTools.start(() => {
|
||||||
this.delay -= this.offset
|
if (!this.isPlay) return
|
||||||
this.isOffseted = true
|
this._refresh()
|
||||||
|
}, this.delay)
|
||||||
}
|
}
|
||||||
timeoutTools.start(() => {
|
|
||||||
if (!this.isPlay) return
|
|
||||||
this._refresh()
|
|
||||||
}, this.delay)
|
|
||||||
this.onPlay(this.curLineNum, curLine.text, currentTime)
|
this.onPlay(this.curLineNum, curLine.text, currentTime)
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
let newCurLineNum = this._findCurLineNum(currentTime, this.curLineNum + 1)
|
||||||
|
if (newCurLineNum > this.curLineNum) this.curLineNum = newCurLineNum - 1
|
||||||
|
this._refresh()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.curLineNum = this._findCurLineNum(currentTime) - 1
|
this.curLineNum = this._findCurLineNum(currentTime, this.curLineNum) - 1
|
||||||
this._refresh()
|
this._refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,14 +154,10 @@ module.exports = class LinePlayer {
|
||||||
this.pause()
|
this.pause()
|
||||||
this.isPlay = true
|
this.isPlay = true
|
||||||
|
|
||||||
this._performanceOffsetTime = 0
|
this._performanceTime = getNow() - parseInt(this.tags.offset + this.offset)
|
||||||
this._performanceTime = getNow() - curTime
|
this._startTime = curTime
|
||||||
if (this._performanceTime < 0) {
|
|
||||||
this._performanceOffsetTime = -this._performanceTime
|
|
||||||
this._performanceTime = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
this.curLineNum = this._findCurLineNum(curTime) - 1
|
this.curLineNum = this._findCurLineNum(this._currentTime()) - 1
|
||||||
|
|
||||||
this._refresh()
|
this._refresh()
|
||||||
}
|
}
|
||||||
|
@ -157,7 +165,6 @@ module.exports = class LinePlayer {
|
||||||
pause() {
|
pause() {
|
||||||
if (!this.isPlay) return
|
if (!this.isPlay) return
|
||||||
this.isPlay = false
|
this.isPlay = false
|
||||||
this.isOffseted = false
|
|
||||||
timeoutTools.clear()
|
timeoutTools.clear()
|
||||||
if (this.curLineNum === this.maxLine) return
|
if (this.curLineNum === this.maxLine) return
|
||||||
const currentTime = this._currentTime()
|
const currentTime = this._currentTime()
|
||||||
|
|
|
@ -720,7 +720,10 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
getDetailPageUrl(id) {
|
getDetailPageUrl(id) {
|
||||||
if (typeof id == 'string') id = id.replace('id_', '')
|
if (typeof id == 'string') {
|
||||||
|
if (/^https?:\/\//.test(id)) return id
|
||||||
|
id = id.replace('id_', '')
|
||||||
|
}
|
||||||
return `https://www.kugou.com/yy/special/single/${id}.html`
|
return `https://www.kugou.com/yy/special/single/${id}.html`
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ const kw = {
|
||||||
comment,
|
comment,
|
||||||
getLyric(songInfo, isGetLyricx) {
|
getLyric(songInfo, isGetLyricx) {
|
||||||
// let singer = songInfo.singer.indexOf('、') > -1 ? songInfo.singer.split('、')[0] : songInfo.singer
|
// let singer = songInfo.singer.indexOf('、') > -1 ? songInfo.singer.split('、')[0] : songInfo.singer
|
||||||
return lyric.getLyric(songInfo.songmid, isGetLyricx)
|
return lyric.getLyric(songInfo, isGetLyricx)
|
||||||
},
|
},
|
||||||
handleMusicInfo(songInfo) {
|
handleMusicInfo(songInfo) {
|
||||||
return this.getMusicInfo(songInfo).then(info => {
|
return this.getMusicInfo(songInfo).then(info => {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { httpFetch } from '../../request'
|
import { httpFetch } from '../../request'
|
||||||
|
import { decodeLyric, lrcTools } from './util'
|
||||||
import { decodeName } from '../../index'
|
import { decodeName } from '../../index'
|
||||||
|
|
||||||
|
/*
|
||||||
export default {
|
export default {
|
||||||
formatTime(time) {
|
formatTime(time) {
|
||||||
let m = parseInt(time / 60)
|
let m = parseInt(time / 60)
|
||||||
|
@ -63,33 +65,146 @@ export default {
|
||||||
return requestObj
|
return requestObj
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const buf_key = Buffer.from('yeelion')
|
||||||
|
const buf_key_len = buf_key.length
|
||||||
|
const buildParams = (id, isGetLyricx) => {
|
||||||
|
let params = `user=12345,web,web,web&requester=localhost&req=1&rid=MUSIC_${id}`
|
||||||
|
if (isGetLyricx) params += '&lrcx=1'
|
||||||
|
const buf_str = Buffer.from(params)
|
||||||
|
const buf_str_len = buf_str.length
|
||||||
|
const output = new Uint16Array(buf_str_len)
|
||||||
|
let i = 0
|
||||||
|
while (i < buf_str_len) {
|
||||||
|
let j = 0
|
||||||
|
while (j < buf_key_len && i < buf_str_len) {
|
||||||
|
output[i] = buf_key[j] ^ buf_str[i]
|
||||||
|
i++
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Buffer.from(output).toString('base64')
|
||||||
|
}
|
||||||
|
|
||||||
/* export default {
|
// console.log(buildParams('207527604', false))
|
||||||
lrcInfoRxp: /<lyric>(.+?)<\/lyric>[\s\S]+<lyric_zz>(.+?)<\/lyric_zz>/,
|
// console.log(buildParams('207527604', true))
|
||||||
parseLyricInfo(str) {
|
|
||||||
let result = str.match(this.lrcInfoRxp)
|
const timeExp = /^\[([\d:.]*)\]{1}/g
|
||||||
return result ? { lyric: result[1], lyric_zz: result[2] } : null
|
export default {
|
||||||
|
sortLrcArr(arr) {
|
||||||
|
const lrcSet = new Set()
|
||||||
|
let lrc = []
|
||||||
|
let lrcT = []
|
||||||
|
|
||||||
|
for (const item of arr) {
|
||||||
|
if (lrcSet.has(item.time)) {
|
||||||
|
if (lrc.length < 2) continue
|
||||||
|
const tItem = lrc.pop()
|
||||||
|
tItem.time = lrc[lrc.length - 1].time
|
||||||
|
lrcT.push(tItem)
|
||||||
|
lrc.push(item)
|
||||||
|
} else {
|
||||||
|
lrc.push(item)
|
||||||
|
lrcSet.add(item.time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lrcT.length) {
|
||||||
|
if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译
|
||||||
|
const tItem = lrc.pop()
|
||||||
|
tItem.time = lrc[lrc.length - 1].time
|
||||||
|
lrcT.push(tItem)
|
||||||
|
} else {
|
||||||
|
lrc = arr
|
||||||
|
lrcT = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
lrc,
|
||||||
|
lrcT,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
getLyric(songId, isGetLyricx = false) {
|
transformLrc(tags, lrclist) {
|
||||||
const requestObj = httpFetch(`http://player.kuwo.cn/webmusic/st/getNewMuiseByRid?rid=MUSIC_${songId}`)
|
return `${tags.join('\n')}\n${lrclist ? lrclist.map(l => `[${l.time}]${l.text}\n`).join('') : '暂无歌词'}`
|
||||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
},
|
||||||
console.log(body)
|
parseLrc(lrc) {
|
||||||
if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body)))
|
const lines = lrc.split(/\r\n|\r|\n/)
|
||||||
let info = this.parseLyricInfo(body)
|
let tags = []
|
||||||
if (!info) return Promise.reject(new Error(JSON.stringify(body)))
|
let lrcArr = []
|
||||||
Object.assign(requestObj, httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${isGetLyricx ? info.lyric_zz : info.lyric}`))
|
for (let i = 0; i < lines.length; i++) {
|
||||||
return requestObj.promise.then(({ statusCode, body, raw }) => {
|
const line = lines[i].trim()
|
||||||
if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body)))
|
let result = timeExp.exec(line)
|
||||||
return decodeLyric({ lrcBase64: raw.toString('base64'), isGetLyricx }).then(base64Data => {
|
if (result) {
|
||||||
return {
|
const text = line.replace(timeExp, '').trim()
|
||||||
lyric: Buffer.from(base64Data, 'base64').toString(),
|
lrcArr.push({
|
||||||
tlyric: '',
|
time: RegExp.$1,
|
||||||
}
|
text,
|
||||||
})
|
})
|
||||||
|
} else if (lrcTools.rxps.tagLine.test(line)) {
|
||||||
|
tags.push(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const lrcInfo = this.sortLrcArr(lrcArr)
|
||||||
|
return {
|
||||||
|
lyric: decodeName(this.transformLrc(tags, lrcInfo.lrc)),
|
||||||
|
tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(tags, lrcInfo.lrcT)) : '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// getLyric2(musicInfo, isGetLyricx = true) {
|
||||||
|
// const requestObj = httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`)
|
||||||
|
// requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => {
|
||||||
|
// if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body)))
|
||||||
|
// return decodeLyric({ lrcBase64: raw.toString('base64'), isGetLyricx }).then(base64Data => {
|
||||||
|
// let lrcInfo
|
||||||
|
// console.log(Buffer.from(base64Data, 'base64').toString())
|
||||||
|
// try {
|
||||||
|
// lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString())
|
||||||
|
// } catch {
|
||||||
|
// return Promise.reject(new Error('Get lyric failed'))
|
||||||
|
// }
|
||||||
|
// if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '')
|
||||||
|
// lrcInfo.lxlyric = lrcTools.parse(lrcInfo.lyric)
|
||||||
|
// // console.log(lrcInfo.lyric)
|
||||||
|
// // console.log(lrcInfo.tlyric)
|
||||||
|
// // console.log(lrcInfo.lxlyric)
|
||||||
|
// // console.log(JSON.stringify(lrcInfo))
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// return requestObj
|
||||||
|
// },
|
||||||
|
getLyric(musicInfo, isGetLyricx = true) {
|
||||||
|
// this.getLyric2(musicInfo)
|
||||||
|
const requestObj = httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`)
|
||||||
|
requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => {
|
||||||
|
if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body)))
|
||||||
|
return decodeLyric({ lrcBase64: raw.toString('base64'), isGetLyricx }).then(base64Data => {
|
||||||
|
// let lrcInfo
|
||||||
|
// try {
|
||||||
|
// lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString())
|
||||||
|
// } catch {
|
||||||
|
// return Promise.reject(new Error('Get lyric failed'))
|
||||||
|
// }
|
||||||
|
let lrcInfo
|
||||||
|
// console.log(Buffer.from(base64Data, 'base64').toString())
|
||||||
|
try {
|
||||||
|
lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString())
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(new Error('Get lyric failed'))
|
||||||
|
}
|
||||||
|
// console.log(lrcInfo)
|
||||||
|
if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '')
|
||||||
|
try {
|
||||||
|
lrcInfo.lxlyric = lrcTools.parse(lrcInfo.lyric)
|
||||||
|
} catch {
|
||||||
|
lrcInfo.lxlyric = ''
|
||||||
|
}
|
||||||
|
lrcInfo.lyric = lrcInfo.lyric.replace(lrcTools.rxps.wordTimeAll, '')
|
||||||
|
// console.log(lrcInfo)
|
||||||
|
return lrcInfo
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return requestObj
|
return requestObj
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
@ -308,7 +308,8 @@ export default {
|
||||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({ tags, hotTag, source: 'kw' }))
|
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({ tags, hotTag, source: 'kw' }))
|
||||||
},
|
},
|
||||||
getDetailPageUrl(id) {
|
getDetailPageUrl(id) {
|
||||||
if (/^digest-/.test(id)) {
|
if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||||
|
else if (/^digest-/.test(id)) {
|
||||||
let result = id.split('__')
|
let result = id.split('__')
|
||||||
id = result[1]
|
id = result[1]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { httpGet, httpFetch } from '../../request'
|
import { httpGet, httpFetch } from '../../request'
|
||||||
// import { rendererInvoke, NAMES } from '../../../../common/ipc'
|
import { rendererInvoke, NAMES } from '@common/ipc'
|
||||||
|
|
||||||
const kw_token = {
|
const kw_token = {
|
||||||
token: null,
|
token: null,
|
||||||
|
@ -54,7 +54,7 @@ export const getToken = (retryNum = 0) => new Promise((resolve, reject) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// export const decodeLyric = base64Data => rendererInvoke(NAMES.mainWindow.handle_kw_decode_lyric, base64Data)
|
export const decodeLyric = base64Data => rendererInvoke(NAMES.mainWindow.handle_kw_decode_lyric, base64Data)
|
||||||
|
|
||||||
export const tokenRequest = async(url, options = {}) => {
|
export const tokenRequest = async(url, options = {}) => {
|
||||||
let token = kw_token.token
|
let token = kw_token.token
|
||||||
|
@ -76,3 +76,83 @@ export const tokenRequest = async(url, options = {}) => {
|
||||||
})
|
})
|
||||||
return requestObj
|
return requestObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const lrcTools = {
|
||||||
|
rxps: {
|
||||||
|
wordLine: /^(\[\d{1,2}:.*\d{1,4}\])\s*(\S+(?:\s+\S+)*)?\s*/,
|
||||||
|
tagLine: /\[(ver|ti|ar|al|offset|by|kuwo):\s*(\S+(?:\s+\S+)*)\s*\]/,
|
||||||
|
wordTimeAll: /<(-?\d+),(-?\d+)(?:,-?\d+)?>/g,
|
||||||
|
wordTime: /<(-?\d+),(-?\d+)(?:,-?\d+)?>/,
|
||||||
|
},
|
||||||
|
offset: 1,
|
||||||
|
offset2: 1,
|
||||||
|
isOK: false,
|
||||||
|
lines: [],
|
||||||
|
tags: [],
|
||||||
|
getWordInfo(str, str2) {
|
||||||
|
const offset = parseInt(str)
|
||||||
|
const offset2 = parseInt(str2)
|
||||||
|
const startTime = Math.floor((offset + offset2) / (this.offset * 2))
|
||||||
|
const timeLength = Math.floor((offset - offset2) / (this.offset2 * 2))
|
||||||
|
return {
|
||||||
|
startTime,
|
||||||
|
timeLength,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parseLine(line) {
|
||||||
|
if (line.length < 6) return
|
||||||
|
let result = this.rxps.wordLine.exec(line)
|
||||||
|
if (result) {
|
||||||
|
const time = result[1]
|
||||||
|
let words = result[2]
|
||||||
|
if (words == null) {
|
||||||
|
words = ''
|
||||||
|
}
|
||||||
|
const wordTimes = words.match(this.rxps.wordTimeAll)
|
||||||
|
if (!wordTimes) return
|
||||||
|
// console.log(wordTimes)
|
||||||
|
for (const timeStr of wordTimes) {
|
||||||
|
const result = this.rxps.wordTime.exec(timeStr)
|
||||||
|
const wordInfo = this.getWordInfo(result[1], result[2])
|
||||||
|
words = words.replace(timeStr, `<${wordInfo.startTime},${wordInfo.timeLength}>`)
|
||||||
|
}
|
||||||
|
this.lines.push(time + words)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result = this.rxps.tagLine.exec(line)
|
||||||
|
if (!result) return
|
||||||
|
if (result[1] == 'kuwo') {
|
||||||
|
let content = result[2]
|
||||||
|
if (content != null && content.includes('][')) {
|
||||||
|
content = content.substring(0, content.indexOf(']['))
|
||||||
|
}
|
||||||
|
const valueOf = parseInt(content, 8)
|
||||||
|
this.offset = Math.floor(valueOf / 10)
|
||||||
|
this.offset2 = Math.floor(valueOf % 10)
|
||||||
|
if (this.offset == 0 || Number.isNaN(this.offset) || this.offset2 == 0 || Number.isNaN(this.offset2)) {
|
||||||
|
this.isOK = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.tags.push(line)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parse(lrc) {
|
||||||
|
// console.log(lrc)
|
||||||
|
const lines = lrc.split(/\r\n|\r|\n/)
|
||||||
|
const tools = Object.create(this)
|
||||||
|
tools.isOK = true
|
||||||
|
tools.offset = 1
|
||||||
|
tools.offset2 = 1
|
||||||
|
tools.lines = []
|
||||||
|
tools.tags = []
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (!tools.isOK) return ''
|
||||||
|
tools.parseLine(line)
|
||||||
|
}
|
||||||
|
if (!tools.lines.length) return ''
|
||||||
|
let lrcs = tools.lines.join('\n')
|
||||||
|
if (tools.tags.length) lrcs = `${tools.tags.join('\n')}\n${lrcs}`
|
||||||
|
return lrcs
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -357,6 +357,11 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
getDetailPageUrl(id) {
|
getDetailPageUrl(id) {
|
||||||
|
if (/playlist\/index\.html\?/.test(id)) {
|
||||||
|
id = id.replace(/.*(?:\?|&)id=(\d+)(?:&.*|$)/, '$1')
|
||||||
|
} else if (this.regExps.listDetailLink.test(id)) {
|
||||||
|
id = id.replace(this.regExps.listDetailLink, '$1')
|
||||||
|
}
|
||||||
return `https://music.migu.cn/v3/music/playlist/${id}`
|
return `https://music.migu.cn/v3/music/playlist/${id}`
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,11 +185,7 @@ export default {
|
||||||
return location == null ? link : location
|
return location == null ? link : location
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取歌曲列表内的音乐
|
async getListId(id) {
|
||||||
async getListDetail(id, tryNum = 0) {
|
|
||||||
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
|
||||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
|
||||||
|
|
||||||
if ((/[?&:/]/.test(id))) {
|
if ((/[?&:/]/.test(id))) {
|
||||||
let regx = /\/\/i\.y\.qq\.com/.test(id) ? this.regExps.listDetailLink1 : this.regExps.listDetailLink2
|
let regx = /\/\/i\.y\.qq\.com/.test(id) ? this.regExps.listDetailLink1 : this.regExps.listDetailLink2
|
||||||
if (!regx.test(id)) {
|
if (!regx.test(id)) {
|
||||||
|
@ -200,6 +196,14 @@ export default {
|
||||||
id = id.replace(regx, '$1')
|
id = id.replace(regx, '$1')
|
||||||
// console.log(id)
|
// console.log(id)
|
||||||
}
|
}
|
||||||
|
return id
|
||||||
|
},
|
||||||
|
// 获取歌曲列表内的音乐
|
||||||
|
async getListDetail(id, tryNum = 0) {
|
||||||
|
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
||||||
|
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||||
|
|
||||||
|
id = await this.getListId(id)
|
||||||
|
|
||||||
this._requestObj_listDetail = httpFetch(this.getListDetailUrl(id), {
|
this._requestObj_listDetail = httpFetch(this.getListDetailUrl(id), {
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -293,7 +297,9 @@ export default {
|
||||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({ tags, hotTag, source: 'tx' }))
|
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({ tags, hotTag, source: 'tx' }))
|
||||||
},
|
},
|
||||||
|
|
||||||
getDetailPageUrl(id) {
|
async getDetailPageUrl(id) {
|
||||||
|
id = await this.getListId(id)
|
||||||
|
|
||||||
return `https://y.qq.com/n/ryqq/playlist/${id}`
|
return `https://y.qq.com/n/ryqq/playlist/${id}`
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,23 +51,24 @@ export default {
|
||||||
|
|
||||||
async handleParseId(link, retryNum = 0) {
|
async handleParseId(link, retryNum = 0) {
|
||||||
if (this._requestObj_listDetailLink) this._requestObj_listDetailLink.cancelHttp()
|
if (this._requestObj_listDetailLink) this._requestObj_listDetailLink.cancelHttp()
|
||||||
if (retryNum > 2) return Promise.reject(new Error('link try max num'))
|
if (retryNum > 2) throw new Error('link try max num')
|
||||||
|
|
||||||
this._requestObj_listDetailLink = httpFetch(link)
|
this._requestObj_listDetailLink = httpFetch(link)
|
||||||
const { headers: { location }, statusCode } = await this._requestObj_listDetailLink.promise
|
const { headers: { location }, statusCode } = await this._requestObj_listDetailLink.promise
|
||||||
// console.log(headers)
|
// console.log(headers)
|
||||||
if (statusCode > 400) return this.handleParseId(link, ++retryNum)
|
if (statusCode > 400) return this.handleParseId(link, ++retryNum)
|
||||||
return location == null ? link : location
|
const url = location == null ? link : location
|
||||||
|
return this.regExps.listDetailLink.test(url)
|
||||||
|
? url.replace(this.regExps.listDetailLink, '$1')
|
||||||
|
: url.replace(this.regExps.listDetailLink2, '$1')
|
||||||
},
|
},
|
||||||
|
|
||||||
async getListDetail(id, page, tryNum = 0) { // 获取歌曲列表内的音乐
|
async getListId(id) {
|
||||||
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
let cookie
|
||||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
|
||||||
|
|
||||||
if (/###/.test(id)) {
|
if (/###/.test(id)) {
|
||||||
const [url, token] = id.split('###')
|
const [url, token] = id.split('###')
|
||||||
id = url
|
id = url
|
||||||
this.cookie = `MUSIC_U=${token}`
|
cookie = `MUSIC_U=${token}`
|
||||||
}
|
}
|
||||||
if ((/[?&:/]/.test(id))) {
|
if ((/[?&:/]/.test(id))) {
|
||||||
if (this.regExps.listDetailLink.test(id)) {
|
if (this.regExps.listDetailLink.test(id)) {
|
||||||
|
@ -79,6 +80,14 @@ export default {
|
||||||
}
|
}
|
||||||
// console.log(id)
|
// console.log(id)
|
||||||
}
|
}
|
||||||
|
return { id, cookie }
|
||||||
|
},
|
||||||
|
async getListDetail(rawId, page, tryNum = 0) { // 获取歌曲列表内的音乐
|
||||||
|
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
||||||
|
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||||
|
|
||||||
|
const { id, cookie } = await this.getListId(rawId)
|
||||||
|
if (cookie) this.cookie = cookie
|
||||||
|
|
||||||
this._requestObj_listDetail = httpFetch('https://music.163.com/api/linux/forward', {
|
this._requestObj_listDetail = httpFetch('https://music.163.com/api/linux/forward', {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
@ -290,7 +299,8 @@ export default {
|
||||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({ tags, hotTag, source: 'wy' }))
|
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({ tags, hotTag, source: 'wy' }))
|
||||||
},
|
},
|
||||||
|
|
||||||
getDetailPageUrl(id) {
|
async getDetailPageUrl(rawId) {
|
||||||
|
const { id } = await this.getListId(rawId)
|
||||||
return `https://music.163.com/#/playlist?id=${id}`
|
return `https://music.163.com/#/playlist?id=${id}`
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,3 +323,10 @@ export const setTaskbarThumbnailClip = (clip) => {
|
||||||
export const setTaskbarThumbarButtons = (buttons) => {
|
export const setTaskbarThumbarButtons = (buttons) => {
|
||||||
rendererSend(NAMES.mainWindow.taskbar_set_thumbar_buttons, buttons)
|
rendererSend(NAMES.mainWindow.taskbar_set_thumbar_buttons, buttons)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const onSystemThemeChange = callback => {
|
||||||
|
rendererOn(NAMES.mainWindow.system_theme_change, callback)
|
||||||
|
return () => {
|
||||||
|
rendererOff(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ div(:class="$style.download")
|
||||||
div.list-item(@click="handleDoubleClick($event, index)" @contextmenu="handleListItemRigthClick($event, index)"
|
div.list-item(@click="handleDoubleClick($event, index)" @contextmenu="handleListItemRigthClick($event, index)"
|
||||||
:class="[{[$style.active]: playListIndex == index }, { selected: selectedIndex == index }, { active: selectedData.includes(item) }]")
|
:class="[{[$style.active]: playListIndex == index }, { selected: selectedIndex == index }, { active: selectedData.includes(item) }]")
|
||||||
div.list-item-cell.nobreak.center(style="width: 5%; padding-left: 3px; padding-right: 3px;" @click.stop) {{index + 1}}
|
div.list-item-cell.nobreak.center(style="width: 5%; padding-left: 3px; padding-right: 3px;" @click.stop) {{index + 1}}
|
||||||
div.list-item-cell.auto(:tips="item.name")
|
div.list-item-cell.auto(:aria-label="item.name")
|
||||||
span.select {{item.name}}
|
span.select {{item.name}}
|
||||||
div.list-item-cell(style="width: 20%;") {{item.progress.progress}}%
|
div.list-item-cell(style="width: 20%;") {{item.progress.progress}}%
|
||||||
div.list-item-cell(style="width: 22%;" :tips="item.statusText") {{item.statusText}}
|
div.list-item-cell(style="width: 22%;" :aria-label="item.statusText") {{item.statusText}}
|
||||||
div.list-item-cell(style="width: 10%;") {{item.metadata.type && item.metadata.type.toUpperCase()}}
|
div.list-item-cell(style="width: 10%;") {{item.metadata.type && item.metadata.type.toUpperCase()}}
|
||||||
div.list-item-cell(style="width: 13%; padding-left: 0; padding-right: 0;")
|
div.list-item-cell(style="width: 13%; padding-left: 0; padding-right: 0;")
|
||||||
material-list-buttons(:index="index" :download-btn="false" :file-btn="item.status != downloadStatus.ERROR" remove-btn
|
material-list-buttons(:index="index" :download-btn="false" :file-btn="item.status != downloadStatus.ERROR" remove-btn
|
||||||
|
@ -36,10 +36,10 @@ div(:class="$style.download")
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters, mapActions, mapMutations } from 'vuex'
|
import { mapGetters, mapActions, mapMutations } from 'vuex'
|
||||||
import { checkPath, openDirInExplorer, openUrl } from '@renderer/utils'
|
import { checkPath, openDirInExplorer, openUrl, getFontSizeWithScreen } from '@renderer/utils'
|
||||||
import musicSdk from '@renderer/utils/music'
|
import musicSdk from '@renderer/utils/music'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { windowSizeList } from '@renderer/core/share'
|
import { windowSizeList, isFullscreen } from '@renderer/core/share'
|
||||||
import { playInfo, playMusicInfo } from '@renderer/core/share/player'
|
import { playInfo, playMusicInfo } from '@renderer/core/share/player'
|
||||||
import { downloadList, downloadStatus } from '@renderer/core/share/download'
|
import { downloadList, downloadStatus } from '@renderer/core/share/download'
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ export default {
|
||||||
playInfo,
|
playInfo,
|
||||||
downloadList,
|
downloadList,
|
||||||
downloadStatus,
|
downloadStatus,
|
||||||
|
isFullscreen,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -181,7 +182,7 @@ export default {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
listItemHeight() {
|
listItemHeight() {
|
||||||
return parseInt(windowSizeList.find(item => item.id == this.setting.windowSizeId).fontSize) / 16 * 37
|
return Math.ceil((this.isFullscreen ? getFontSizeWithScreen() : parseInt(windowSizeList.find(item => item.id == this.setting.windowSizeId).fontSize)) * 2.3)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
</div>
|
</div>
|
||||||
<ul class="scroll" :class="$style.listsContent" ref="dom_lists_list">
|
<ul class="scroll" :class="$style.listsContent" ref="dom_lists_list">
|
||||||
<li :class="[$style.listsItem, { [$style.active]: item.id == tabId }, { [$style.clicked]: boardListData.rightClickItemIndex == index }]"
|
<li :class="[$style.listsItem, { [$style.active]: item.id == tabId }, { [$style.clicked]: boardListData.rightClickItemIndex == index }]"
|
||||||
:tips="item.name" v-for="(item, index) in boardList" :key="item.id"
|
:aria-label="item.name" v-for="(item, index) in boardList" :key="item.id"
|
||||||
@click="handleToggleList(item.id)" @contextmenu="handleListsItemRigthClick($event, index)">
|
@click="handleToggleList(item.id)" @contextmenu="handleListsItemRigthClick($event, index)">
|
||||||
<span :class="$style.listsLabel">{{item.name}}</span>
|
<span :class="$style.listsLabel">{{item.name}}</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -50,10 +50,10 @@ div(:class="$style.search")
|
||||||
dl(:class="$style.noitemList" v-if="setting.search.isShowHistorySearch && historyList.length")
|
dl(:class="$style.noitemList" v-if="setting.search.isShowHistorySearch && historyList.length")
|
||||||
dt(:class="$style.noitemListTitle")
|
dt(:class="$style.noitemListTitle")
|
||||||
span {{$t('history_search')}}
|
span {{$t('history_search')}}
|
||||||
span(:class="$style.historyClearBtn" @click="clearHistory" :tips="$t('history_clear')")
|
span(:class="$style.historyClearBtn" @click="clearHistory" :aria-label="$t('history_clear')")
|
||||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 512 512' space='preserve')
|
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 512 512' space='preserve')
|
||||||
use(xlink:href='#icon-eraser')
|
use(xlink:href='#icon-eraser')
|
||||||
dd(:class="$style.noitemListItem" v-for="(item, index) in historyList" @contextmenu="removeHistory(index)" :key="index + item" @click="handleNoitemSearch(item)" :tips="$t('history_remove')") {{item}}
|
dd(:class="$style.noitemListItem" v-for="(item, index) in historyList" @contextmenu="removeHistory(index)" :key="index + item" @click="handleNoitemSearch(item)" :aria-label="$t('history_remove')") {{item}}
|
||||||
div(v-else :class="$style.noitem_list")
|
div(v-else :class="$style.noitem_list")
|
||||||
p {{$t('search__welcome')}}
|
p {{$t('search__welcome')}}
|
||||||
//- common-flow-btn(:show="isShowEditBtn && (searchSourceId == 'all' || assertApiSupport(searchSourceId))" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
//- common-flow-btn(:show="isShowEditBtn && (searchSourceId == 'all' || assertApiSupport(searchSourceId))" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||||
|
|
|
@ -18,12 +18,12 @@ div(:class="$style.list")
|
||||||
:class="[{ [$style.active]: playerInfo.isPlayList && playerInfo.playIndex === index }, { selected: selectedIndex == index || rightClickSelectedIndex == index }, { active: selectedList.includes(item) }, { [$style.disabled]: !assertApiSupport(item.source) }]"
|
:class="[{ [$style.active]: playerInfo.isPlayList && playerInfo.playIndex === index }, { selected: selectedIndex == index || rightClickSelectedIndex == index }, { active: selectedList.includes(item) }, { [$style.disabled]: !assertApiSupport(item.source) }]"
|
||||||
@contextmenu="handleListItemRightClick($event, index)")
|
@contextmenu="handleListItemRightClick($event, index)")
|
||||||
div.list-item-cell.nobreak.center(style="flex: 0 0 5%; padding-left: 3px; padding-right: 3px;" :class="$style.noSelect" @click.stop) {{index + 1}}
|
div.list-item-cell.nobreak.center(style="flex: 0 0 5%; padding-left: 3px; padding-right: 3px;" :class="$style.noSelect" @click.stop) {{index + 1}}
|
||||||
div.list-item-cell.auto(:tips="item.name + (isShowSource ? ` - ${item.source}` : '')")
|
div.list-item-cell.auto(:aria-label="item.name + (isShowSource ? ` - ${item.source}` : '')")
|
||||||
span.select {{item.name}}
|
span.select {{item.name}}
|
||||||
span(:class="[$style.labelSource, $style.noSelect]" v-if="isShowSource") {{item.source}}
|
span(:class="[$style.labelSource, $style.noSelect]" v-if="isShowSource") {{item.source}}
|
||||||
div.list-item-cell(style="flex: 0 0 22%;" :tips="item.singer")
|
div.list-item-cell(style="flex: 0 0 22%;" :aria-label="item.singer")
|
||||||
span.select {{item.singer}}
|
span.select {{item.singer}}
|
||||||
div.list-item-cell(style="flex: 0 0 22%;" :tips="item.albumName")
|
div.list-item-cell(style="flex: 0 0 22%;" :aria-label="item.albumName")
|
||||||
span.select {{item.albumName}}
|
span.select {{item.albumName}}
|
||||||
div.list-item-cell(style="flex: 0 0 9%;")
|
div.list-item-cell(style="flex: 0 0 9%;")
|
||||||
span(:class="[$style.time, $style.noSelect]") {{item.interval || '--/--'}}
|
span(:class="[$style.time, $style.noSelect]") {{item.interval || '--/--'}}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { computed, watch, ref, onBeforeUnmount } from '@renderer/utils/vueTools'
|
import { computed, watch, ref, onBeforeUnmount } from '@renderer/utils/vueTools'
|
||||||
import { windowSizeList } from '@renderer/core/share'
|
import { windowSizeList, isFullscreen } from '@renderer/core/share'
|
||||||
|
import { getFontSizeWithScreen } from '@renderer/utils'
|
||||||
|
|
||||||
const useKeyEvent = ({ handleSelectAllData }) => {
|
const useKeyEvent = ({ handleSelectAllData }) => {
|
||||||
const keyEvent = {
|
const keyEvent = {
|
||||||
|
@ -48,7 +49,7 @@ export default ({ list, setting }) => {
|
||||||
|
|
||||||
let lastSelectIndex = -1
|
let lastSelectIndex = -1
|
||||||
const listItemHeight = computed(() => {
|
const listItemHeight = computed(() => {
|
||||||
return parseInt(windowSizeList.find(item => item.id == setting.value.windowSizeId).fontSize) / 16 * 37
|
return Math.ceil((isFullscreen.value ? getFontSizeWithScreen() : parseInt(windowSizeList.find(item => item.id == setting.value.windowSizeId).fontSize)) * 2.3)
|
||||||
})
|
})
|
||||||
|
|
||||||
const removeAllSelect = () => {
|
const removeAllSelect = () => {
|
||||||
|
|
|
@ -2,31 +2,31 @@
|
||||||
<div :class="$style.lists" ref="dom_lists">
|
<div :class="$style.lists" ref="dom_lists">
|
||||||
<div :class="$style.listHeader">
|
<div :class="$style.listHeader">
|
||||||
<h2 :class="$style.listsTitle">{{$t('my_list')}}</h2>
|
<h2 :class="$style.listsTitle">{{$t('my_list')}}</h2>
|
||||||
<button :class="$style.listsAdd" @click="handleShowNewList" :tips="$t('lists__new_list_btn')">
|
<button :class="$style.listsAdd" @click="handleShowNewList" :aria-label="$t('lists__new_list_btn')">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="70%" viewBox="0 0 24 24" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="70%" viewBox="0 0 24 24" space="preserve">
|
||||||
<use xlink:href="#icon-list-add"></use>
|
<use xlink:href="#icon-list-add"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<ul class="scroll" :class="[$style.listsContent, { [$style.sortable]: keyEvent.isModDown }]" ref="dom_lists_list">
|
<ul class="scroll" :class="[$style.listsContent, { [$style.sortable]: keyEvent.isModDown }]" ref="dom_lists_list">
|
||||||
<li class="default-list" :class="[$style.listsItem, {[$style.active]: defaultList.id == listId}]" :tips="defaultList.name"
|
<li class="default-list" :class="[$style.listsItem, {[$style.active]: defaultList.id == listId}]" :aria-label="defaultList.name" :aria-selected="defaultList.id == listId"
|
||||||
@contextmenu="handleListsItemRigthClick($event, -2)" @click="handleListToggle(defaultList.id)"
|
@contextmenu="handleListsItemRigthClick($event, -2)" @click="handleListToggle(defaultList.id)"
|
||||||
>
|
>
|
||||||
<span :class="$style.listsLabel">{{defaultList.name}}</span>
|
<span :class="$style.listsLabel">{{defaultList.name}}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="default-list" :class="[$style.listsItem, {[$style.active]: loveList.id == listId}]" :tips="loveList.name"
|
<li class="default-list" :class="[$style.listsItem, {[$style.active]: loveList.id == listId}]" :aria-label="loveList.name" :aria-selected="loveList.id == listId"
|
||||||
@contextmenu="handleListsItemRigthClick($event, -1)" @click="handleListToggle(loveList.id)">
|
@contextmenu="handleListsItemRigthClick($event, -1)" @click="handleListToggle(loveList.id)">
|
||||||
<span :class="$style.listsLabel">{{loveList.name}}</span>
|
<span :class="$style.listsLabel">{{loveList.name}}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="user-list"
|
<li class="user-list"
|
||||||
:class="[$style.listsItem, {[$style.active]: item.id == listId}, {[$style.clicked]: listsData.rightClickItemIndex == index}, {[$style.fetching]: fetchingListStatus[item.id]}]" :data-index="index"
|
:class="[$style.listsItem, {[$style.active]: item.id == listId}, {[$style.clicked]: listsData.rightClickItemIndex == index}, {[$style.fetching]: fetchingListStatus[item.id]}]" :data-index="index"
|
||||||
@contextmenu="handleListsItemRigthClick($event, index)" :tips="item.name" v-for="(item, index) in userLists" :key="item.id"
|
@contextmenu="handleListsItemRigthClick($event, index)" :aria-label="item.name" v-for="(item, index) in userLists" :key="item.id" :aria-selected="defaultList.id == listId"
|
||||||
>
|
>
|
||||||
<span :class="$style.listsLabel" @click="handleListToggle(item.id, index + 2)">{{item.name}}</span>
|
<span :class="$style.listsLabel" @click="handleListToggle(item.id, index + 2)">{{item.name}}</span>
|
||||||
<input class="key-bind" :class="$style.listsInput" @contextmenu.stop type="text"
|
<input class="key-bind" :class="$style.listsInput" @contextmenu.stop type="text"
|
||||||
@keyup.enter="handleListsSave(index, $event)" @blur="handleListsSave(index, $event)" :value="item.name" :placeholder="item.name"/>
|
@keyup.enter="handleListsSave(index, $event)" @blur="handleListsSave(index, $event)" :value="item.name" :placeholder="item.name"/>
|
||||||
</li>
|
</li>
|
||||||
<transition enter-active-class="animated-fast slideInLeft" leave-active-class="animated-fast fadeOut" @after-leave="handleListsNewAfterLeave">
|
<transition enter-active-class="animated-fast slideInLeft" leave-active-class="animated-fast fadeOut" @after-leave="handleListsNewAfterLeave" @after-enter="$refs.dom_listsNewInput.focus()">
|
||||||
<li :class="[$style.listsItem, $style.listsNew, listsData.isNewLeave ? $style.newLeave : null]" v-if="listsData.isShowNewList">
|
<li :class="[$style.listsItem, $style.listsNew, listsData.isNewLeave ? $style.newLeave : null]" v-if="listsData.isShowNewList">
|
||||||
<input class="key-bind" :class="$style.listsInput" @contextmenu.stop ref="dom_listsNewInput" type="text" @keyup.enter="handleListsCreate"
|
<input class="key-bind" :class="$style.listsInput" @contextmenu.stop ref="dom_listsNewInput" type="text" @keyup.enter="handleListsCreate"
|
||||||
@blur="handleListsCreate" :placeholder="$t('lists__new_list_input')"/>
|
@blur="handleListsCreate" :placeholder="$t('lists__new_list_input')"/>
|
||||||
|
@ -263,9 +263,6 @@ export default {
|
||||||
},
|
},
|
||||||
handleShowNewList() {
|
handleShowNewList() {
|
||||||
this.listsData.isShowNewList = true
|
this.listsData.isShowNewList = true
|
||||||
this.$nextTick(() => {
|
|
||||||
this.$refs.dom_listsNewInput.focus()
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
handleListsNewAfterLeave() {
|
handleListsNewAfterLeave() {
|
||||||
this.listsData.isNewLeave = false
|
this.listsData.isNewLeave = false
|
||||||
|
@ -406,15 +403,15 @@ export default {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
openSourceDetailPage(index) {
|
async openSourceDetailPage(index) {
|
||||||
const { source, sourceListId } = this.userLists[index]
|
const { source, sourceListId } = this.userLists[index]
|
||||||
if (!sourceListId) return
|
if (!sourceListId) return
|
||||||
let url
|
let url
|
||||||
if (/board__/.test(sourceListId)) {
|
if (/board__/.test(sourceListId)) {
|
||||||
const id = sourceListId.replace(/board__/, '')
|
const id = sourceListId.replace(/board__/, '')
|
||||||
url = musicSdk[source].leaderboard.getDetailPageUrl(id)
|
url = musicSdk[source].leaderboard.getDetailPageUrl(id)
|
||||||
} else {
|
} else if (musicSdk[source].songList?.getDetailPageUrl) {
|
||||||
url = musicSdk[source].songList.getDetailPageUrl(sourceListId)
|
url = await musicSdk[source].songList.getDetailPageUrl(sourceListId)
|
||||||
}
|
}
|
||||||
if (!url) return
|
if (!url) return
|
||||||
openUrl(url)
|
openUrl(url)
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
<!-- <div class="scroll" :class="$style.toc">
|
<!-- <div class="scroll" :class="$style.toc">
|
||||||
<ul :class="$style.tocList">
|
<ul :class="$style.tocList">
|
||||||
<li :class="$style.tocListItem" v-for="h2 in toc.list" :key="h2.id">
|
<li :class="$style.tocListItem" v-for="h2 in toc.list" :key="h2.id">
|
||||||
<h2 :class="[$style.tocH2, toc.activeId == h2.id ? $style.active : null]" :tips="h2.title">
|
<h2 :class="[$style.tocH2, toc.activeId == h2.id ? $style.active : null]" :aria-label="h2.title">
|
||||||
<a :href="'#' + h2.id" @click.stop="toc.activeId = h2.id">{{h2.title}}</a>
|
<a :href="'#' + h2.id" @click.stop="toc.activeId = h2.id">{{h2.title}}</a>
|
||||||
</h2>
|
</h2>
|
||||||
<ul :class="$style.tocList" v-if="h2.children.length">
|
<ul :class="$style.tocList" v-if="h2.children.length">
|
||||||
<li :class="$style.tocSubListItem" v-for="h3 in h2.children" :key="h3.id">
|
<li :class="$style.tocSubListItem" v-for="h3 in h2.children" :key="h3.id">
|
||||||
<h3 :class="[$style.tocH3, toc.activeId == h3.id ? $style.active : null]" :tips="h3.title">
|
<h3 :class="[$style.tocH3, toc.activeId == h3.id ? $style.active : null]" :aria-label="h3.title">
|
||||||
<a :href="'#' + h3.id" @click.stop="toc.activeId = h3.id">{{h3.title}}</a>
|
<a :href="'#' + h3.id" @click.stop="toc.activeId = h3.id">{{h3.title}}</a>
|
||||||
</h3>
|
</h3>
|
||||||
</li>
|
</li>
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
<dl ref="dom_setting_list">
|
<dl ref="dom_setting_list">
|
||||||
<SettingBasic />
|
<SettingBasic />
|
||||||
<SettingPlay />
|
<SettingPlay />
|
||||||
|
<SettingPlayDetail />
|
||||||
<SettingDesktopLyric />
|
<SettingDesktopLyric />
|
||||||
<SettingSearch />
|
<SettingSearch />
|
||||||
<SettingList />
|
<SettingList />
|
||||||
|
@ -43,6 +44,7 @@ import { currentStting } from './setting'
|
||||||
|
|
||||||
import SettingBasic from './components/SettingBasic'
|
import SettingBasic from './components/SettingBasic'
|
||||||
import SettingPlay from './components/SettingPlay'
|
import SettingPlay from './components/SettingPlay'
|
||||||
|
import SettingPlayDetail from './components/SettingPlayDetail'
|
||||||
import SettingDesktopLyric from './components/SettingDesktopLyric'
|
import SettingDesktopLyric from './components/SettingDesktopLyric'
|
||||||
import SettingSearch from './components/SettingSearch'
|
import SettingSearch from './components/SettingSearch'
|
||||||
import SettingList from './components/SettingList'
|
import SettingList from './components/SettingList'
|
||||||
|
@ -61,6 +63,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
SettingBasic,
|
SettingBasic,
|
||||||
SettingPlay,
|
SettingPlay,
|
||||||
|
SettingPlayDetail,
|
||||||
SettingDesktopLyric,
|
SettingDesktopLyric,
|
||||||
SettingSearch,
|
SettingSearch,
|
||||||
SettingList,
|
SettingList,
|
||||||
|
@ -94,6 +97,9 @@ export default {
|
||||||
watch(() => setting.value.player.mediaDeviceId, val => {
|
watch(() => setting.value.player.mediaDeviceId, val => {
|
||||||
currentStting.value.player.mediaDeviceId = val
|
currentStting.value.player.mediaDeviceId = val
|
||||||
})
|
})
|
||||||
|
watch(() => setting.value.playDetail.style.fontSize, val => {
|
||||||
|
currentStting.value.playDetail.style.fontSize = val
|
||||||
|
})
|
||||||
watch(() => setting.value.player.isMute, val => {
|
watch(() => setting.value.player.isMute, val => {
|
||||||
currentStting.value.player.isMute = val
|
currentStting.value.player.isMute = val
|
||||||
})
|
})
|
||||||
|
@ -109,6 +115,9 @@ export default {
|
||||||
watch(() => setting.value.player.togglePlayMethod, val => {
|
watch(() => setting.value.player.togglePlayMethod, val => {
|
||||||
currentStting.value.player.togglePlayMethod = val
|
currentStting.value.player.togglePlayMethod = val
|
||||||
})
|
})
|
||||||
|
watch(() => setting.value.player.audioVisualization, val => {
|
||||||
|
currentStting.value.player.audioVisualization = val
|
||||||
|
})
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -3,15 +3,15 @@ dt#about {{$t('setting__about')}}
|
||||||
dd
|
dd
|
||||||
p.small
|
p.small
|
||||||
| 本软件完全免费,代码已开源,开源地址:
|
| 本软件完全免费,代码已开源,开源地址:
|
||||||
span.hover.underline(:tips="$t('setting__click_open')" @click="openUrl('https://github.com/lyswhut/lx-music-desktop#readme')") https://github.com/lyswhut/lx-music-desktop
|
span.hover.underline(:aria-label="$t('setting__click_open')" @click="openUrl('https://github.com/lyswhut/lx-music-desktop#readme')") https://github.com/lyswhut/lx-music-desktop
|
||||||
p.small
|
p.small
|
||||||
| 最新版网盘下载地址(网盘内有Windows、MAC版):
|
| 最新版网盘下载地址(网盘内有Windows、MAC版):
|
||||||
span.hover.underline(:tips="$t('setting__click_open')" @click="openUrl('https://www.lanzoui.com/b0bf2cfa/')") 网盘地址
|
span.hover.underline(:aria-label="$t('setting__click_open')" @click="openUrl('https://www.lanzoui.com/b0bf2cfa/')") 网盘地址
|
||||||
| 密码:
|
| 密码:
|
||||||
span.hover(:tips="$t('setting__click_copy')" @click="clipboardWriteText('glqw')") glqw
|
span.hover(:aria-label="$t('setting__click_copy')" @click="clipboardWriteText('glqw')") glqw
|
||||||
p.small
|
p.small
|
||||||
| 软件的常见问题可转至:
|
| 软件的常见问题可转至:
|
||||||
span.hover.underline(:tips="$t('setting__click_open')" @click="openUrl('https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md')") 常见问题
|
span.hover.underline(:aria-label="$t('setting__click_open')" @click="openUrl('https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md')") 常见问题
|
||||||
p.small
|
p.small
|
||||||
strong 本软件没有客服
|
strong 本软件没有客服
|
||||||
| ,但我们整理了一些常见的使用问题,
|
| ,但我们整理了一些常见的使用问题,
|
||||||
|
@ -19,11 +19,11 @@ dd
|
||||||
| 地阅读常见问题后,
|
| 地阅读常见问题后,
|
||||||
p.small
|
p.small
|
||||||
| 仍有问题可加企鹅群
|
| 仍有问题可加企鹅群
|
||||||
span.hover(:tips="$t('setting__click_open')" @click="openUrl('https://jq.qq.com/?_wv=1027&k=51ECeq2')") 830125506
|
span.hover(:aria-label="$t('setting__click_open')" @click="openUrl('https://jq.qq.com/?_wv=1027&k=51ECeq2')") 830125506
|
||||||
| 反馈
|
| 反馈
|
||||||
strong (为免满人,无事勿加,入群先看群公告)
|
strong (为免满人,无事勿加,入群先看群公告)
|
||||||
| ,或到 GitHub 提交
|
| ,或到 GitHub 提交
|
||||||
span.hover.underline(:tips="$t('setting__click_open')" @click="openUrl('https://github.com/lyswhut/lx-music-desktop/issues')") issue
|
span.hover.underline(:aria-label="$t('setting__click_open')" @click="openUrl('https://github.com/lyswhut/lx-music-desktop/issues')") issue
|
||||||
|
|
||||||
br
|
br
|
||||||
p.small
|
p.small
|
||||||
|
@ -32,7 +32,7 @@ dd
|
||||||
| ,
|
| ,
|
||||||
p
|
p
|
||||||
| 可以加入测试企鹅群
|
| 可以加入测试企鹅群
|
||||||
span.hover(:tips="$t('setting__click_open')" @click="openUrl('https://qm.qq.com/cgi-bin/qm/qr?k=zR6aYosQoKb07g4FGFZdO9n9zL1dhFpE&jump_from=webapi')") 768786588
|
span.hover(:aria-label="$t('setting__click_open')" @click="openUrl('https://qm.qq.com/cgi-bin/qm/qr?k=zR6aYosQoKb07g4FGFZdO9n9zL1dhFpE&jump_from=webapi')") 768786588
|
||||||
| ,注意:测试版的功可能会不稳定,
|
| ,注意:测试版的功可能会不稳定,
|
||||||
strong 打算潜水的勿加
|
strong 打算潜水的勿加
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ dd
|
||||||
| 你已签署本软件的
|
| 你已签署本软件的
|
||||||
base-btn(min @click="handleShowPact") 许可协议
|
base-btn(min @click="handleShowPact") 许可协议
|
||||||
| ,协议的在线版本在
|
| ,协议的在线版本在
|
||||||
strong.hover.underline(:tips="$t('setting__click_open')" @click="openUrl('https://github.com/lyswhut/lx-music-desktop#%E9%A1%B9%E7%9B%AE%E5%8D%8F%E8%AE%AE')") 这里
|
strong.hover.underline(:aria-label="$t('setting__click_open')" @click="openUrl('https://github.com/lyswhut/lx-music-desktop#%E9%A1%B9%E7%9B%AE%E5%8D%8F%E8%AE%AE')") 这里
|
||||||
| 。
|
| 。
|
||||||
br
|
br
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,15 @@ dd
|
||||||
h3#basic_theme {{$t('setting__basic_theme')}}
|
h3#basic_theme {{$t('setting__basic_theme')}}
|
||||||
div
|
div
|
||||||
ul(:class="$style.theme")
|
ul(:class="$style.theme")
|
||||||
li(v-for="theme in themes.list" :key="theme.id" :tips="$t('theme_' + theme.className)" @click="currentStting.themeId = theme.id" :class="[theme.className, {[$style.active]: themes.active == theme.id}]")
|
li(v-for="theme in themes.list" :key="theme.id" :aria-label="$t('theme_' + theme.className)" @click="currentStting.theme.id = theme.id" :class="[theme.className, {[$style.active]: themes.active == theme.id}]")
|
||||||
span
|
div(:class="$style.bg")
|
||||||
label {{$t('theme_' + theme.className)}}
|
label {{$t('theme_' + theme.className)}}
|
||||||
|
li(:aria-label="$t('theme_auto_tip')" @click="handleSetThemeAuto" @contextmenu="isShowThemeSelectorModal = true" :class="[$style.auto, themeClassName, {[$style.active]: themes.active == 'auto'}]")
|
||||||
|
div(:class="$style.bg")
|
||||||
|
div(:class="$style.bgContent")
|
||||||
|
div(:class="[$style.light, themes.lightTheme.className]")
|
||||||
|
div(:class="[$style.dark, themes.darkTheme.className]")
|
||||||
|
label {{$t('theme_auto')}}
|
||||||
|
|
||||||
dd
|
dd
|
||||||
div
|
div
|
||||||
|
@ -19,7 +25,7 @@ dd
|
||||||
p.gap-top
|
p.gap-top
|
||||||
base-btn.btn(min @click="isShowPlayTimeoutModal = true") {{$t('setting__play_timeout')}} {{ timeLabel ? ` (${timeLabel})` : '' }}
|
base-btn.btn(min @click="isShowPlayTimeoutModal = true") {{$t('setting__play_timeout')}} {{ timeLabel ? ` (${timeLabel})` : '' }}
|
||||||
|
|
||||||
dd(:tips="$t('setting__basic_source_title')")
|
dd(:aria-label="$t('setting__basic_source_title')")
|
||||||
h3#basic_source {{$t('setting__basic_source')}}
|
h3#basic_source {{$t('setting__basic_source')}}
|
||||||
div
|
div
|
||||||
.gap-top(v-for="item in apiSources" :key="item.id")
|
.gap-top(v-for="item in apiSources" :key="item.id")
|
||||||
|
@ -28,19 +34,19 @@ dd(:tips="$t('setting__basic_source_title')")
|
||||||
p.gap-top
|
p.gap-top
|
||||||
base-btn.btn(min @click="isShowUserApiModal = true") {{$t('setting__basic_source_user_api_btn')}}
|
base-btn.btn(min @click="isShowUserApiModal = true") {{$t('setting__basic_source_user_api_btn')}}
|
||||||
|
|
||||||
dd(:tips="$t('setting__basic_window_size_title')")
|
dd(:aria-label="$t('setting__basic_window_size_title')")
|
||||||
h3#basic_window_size {{$t('setting__basic_window_size')}}
|
h3#basic_window_size {{$t('setting__basic_window_size')}}
|
||||||
div
|
div
|
||||||
base-checkbox.gap-left(v-for="(item, index) in windowSizeList" :id="`setting_window_size_${item.id}`" name="setting_window_size"
|
base-checkbox.gap-left(v-for="(item, index) in windowSizeList" :id="`setting_window_size_${item.id}`" name="setting_window_size"
|
||||||
need v-model="currentStting.windowSizeId" :value="item.id" :label="$t('setting__basic_window_size_' + item.name)" :key="item.id")
|
need v-model="currentStting.windowSizeId" :disabled="isFullscreen" :value="item.id" :label="$t('setting__basic_window_size_' + item.name)" :key="item.id")
|
||||||
|
|
||||||
dd(:tips="$t('setting__basic_lang_title')")
|
dd(:aria-label="$t('setting__basic_lang_title')")
|
||||||
h3#basic_lang {{$t('setting__basic_lang')}}
|
h3#basic_lang {{$t('setting__basic_lang')}}
|
||||||
div
|
div
|
||||||
base-checkbox.gap-left(v-for="item in langList" :key="item.locale" :id="`setting_lang_${item.locale}`" name="setting_lang"
|
base-checkbox.gap-left(v-for="item in langList" :key="item.locale" :id="`setting_lang_${item.locale}`" name="setting_lang"
|
||||||
need v-model="currentStting.langId" :value="item.locale" :label="item.name")
|
need v-model="currentStting.langId" :value="item.locale" :label="item.name")
|
||||||
|
|
||||||
dd(:tips="$t('setting__basic_sourcename_title')")
|
dd(:aria-label="$t('setting__basic_sourcename_title')")
|
||||||
h3#basic_sourcename {{$t('setting__basic_sourcename')}}
|
h3#basic_sourcename {{$t('setting__basic_sourcename')}}
|
||||||
div
|
div
|
||||||
base-checkbox.gap-left(v-for="item in sourceNameTypes" :key="item.id" :id="`setting_abasic_sourcename_${item.id}`"
|
base-checkbox.gap-left(v-for="item in sourceNameTypes" :key="item.id" :id="`setting_abasic_sourcename_${item.id}`"
|
||||||
|
@ -55,20 +61,23 @@ dd
|
||||||
div
|
div
|
||||||
base-selection.gap-teft(:list="fontList" v-model="currentStting.font" item-key="id" item-name="label")
|
base-selection.gap-teft(:list="fontList" v-model="currentStting.font" item-key="id" item-name="label")
|
||||||
|
|
||||||
|
ThemeSelectorModal(v-model="isShowThemeSelectorModal")
|
||||||
play-timeout-modal(v-model="isShowPlayTimeoutModal")
|
play-timeout-modal(v-model="isShowPlayTimeoutModal")
|
||||||
user-api-modal(v-model="isShowUserApiModal")
|
user-api-modal(v-model="isShowUserApiModal")
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed, ref, useI18n, watch } from '@renderer/utils/vueTools'
|
import { computed, ref, useI18n, watch, useRefGetter } from '@renderer/utils/vueTools'
|
||||||
import { themes as themeList, windowSizeList, apiSource, userApi } from '@renderer/core/share'
|
import { themes as themeList, windowSizeList, apiSource, userApi, isFullscreen } from '@renderer/core/share'
|
||||||
import { langList } from '@/lang'
|
import { langList } from '@/lang'
|
||||||
import { currentStting } from '../setting'
|
import { currentStting } from '../setting'
|
||||||
import { setWindowSize } from '@renderer/utils'
|
import { setWindowSize } from '@renderer/utils'
|
||||||
import apiSourceInfo from '@renderer/utils/music/api-source-info'
|
import apiSourceInfo from '@renderer/utils/music/api-source-info'
|
||||||
import { useTimeout } from '@renderer/utils/timeoutStop'
|
import { useTimeout } from '@renderer/utils/timeoutStop'
|
||||||
import { getSystemFonts } from '@renderer/utils/tools'
|
import { getSystemFonts } from '@renderer/utils/tools'
|
||||||
|
import { dialog } from '@renderer/plugins/Dialog'
|
||||||
|
|
||||||
|
import ThemeSelectorModal from './ThemeSelectorModal'
|
||||||
import PlayTimeoutModal from './PlayTimeoutModal'
|
import PlayTimeoutModal from './PlayTimeoutModal'
|
||||||
import UserApiModal from './UserApiModal'
|
import UserApiModal from './UserApiModal'
|
||||||
|
|
||||||
|
@ -76,19 +85,34 @@ import UserApiModal from './UserApiModal'
|
||||||
export default {
|
export default {
|
||||||
name: 'SettingBasic',
|
name: 'SettingBasic',
|
||||||
components: {
|
components: {
|
||||||
|
ThemeSelectorModal,
|
||||||
PlayTimeoutModal,
|
PlayTimeoutModal,
|
||||||
UserApiModal,
|
UserApiModal,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { t, locale } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
|
|
||||||
|
const themeClassName = useRefGetter('theme')
|
||||||
const themes = computed(() => {
|
const themes = computed(() => {
|
||||||
return {
|
return {
|
||||||
active: currentStting.value.themeId,
|
active: currentStting.value.theme.id,
|
||||||
|
lightTheme: themeList.find(t => t.id == currentStting.value.theme.lightId) ?? themeList[0],
|
||||||
|
darkTheme: themeList.find(t => t.id == currentStting.value.theme.darkId) ?? themeList[0],
|
||||||
list: themeList,
|
list: themeList,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const isShowThemeSelectorModal = ref(false)
|
||||||
|
const handleSetThemeAuto = () => {
|
||||||
|
if (currentStting.value.theme.id == 'auto') return
|
||||||
|
currentStting.value.theme.id = 'auto'
|
||||||
|
if (window.localStorage.getItem('theme-auto-tip') != 'true') {
|
||||||
|
window.localStorage.setItem('theme-auto-tip', 'true')
|
||||||
|
dialog({
|
||||||
|
message: t('setting__basic_theme_auto_tip'),
|
||||||
|
confirmButtonText: t('ok'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(() => currentStting.value.apiSource, visible => {
|
watch(() => currentStting.value.apiSource, visible => {
|
||||||
apiSource.value = visible
|
apiSource.value = visible
|
||||||
|
@ -161,6 +185,9 @@ export default {
|
||||||
return {
|
return {
|
||||||
currentStting,
|
currentStting,
|
||||||
themes,
|
themes,
|
||||||
|
themeClassName,
|
||||||
|
isShowThemeSelectorModal,
|
||||||
|
handleSetThemeAuto,
|
||||||
isShowPlayTimeoutModal,
|
isShowPlayTimeoutModal,
|
||||||
timeLabel,
|
timeLabel,
|
||||||
apiSources,
|
apiSources,
|
||||||
|
@ -170,6 +197,7 @@ export default {
|
||||||
sourceNameTypes,
|
sourceNameTypes,
|
||||||
controlBtnPositionList,
|
controlBtnPositionList,
|
||||||
fontList,
|
fontList,
|
||||||
|
isFullscreen,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -199,7 +227,7 @@ export default {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
.bg {
|
||||||
display: block;
|
display: block;
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
|
@ -229,7 +257,7 @@ export default {
|
||||||
|
|
||||||
each(@themes, {
|
each(@themes, {
|
||||||
&:global(.@{value}) {
|
&:global(.@{value}) {
|
||||||
span {
|
.bg {
|
||||||
&:after {
|
&:after {
|
||||||
background-color: ~'@{color-@{value}-theme}';
|
background-color: ~'@{color-@{value}-theme}';
|
||||||
background-image: ~'@{color-@{value}-theme-bgimg}';
|
background-image: ~'@{color-@{value}-theme-bgimg}';
|
||||||
|
@ -237,6 +265,68 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
&.auto {
|
||||||
|
>.bg {
|
||||||
|
&:after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bgContent {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.light, .dark {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
&:after {
|
||||||
|
display: block;
|
||||||
|
content: ' ';
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.light {
|
||||||
|
&:after {
|
||||||
|
clip-path: polygon(0 0, 100% 0, 0 100%);
|
||||||
|
}
|
||||||
|
each(@themes, {
|
||||||
|
&:global(.@{value}) {
|
||||||
|
svg {
|
||||||
|
fill: ~'@{color-@{value}-theme}';
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
background-color: ~'@{color-@{value}-theme}';
|
||||||
|
background-image: ~'@{color-@{value}-theme-bgimg}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.dark {
|
||||||
|
&:after {
|
||||||
|
clip-path: polygon(0 100%, 100% 0, 100% 100%);
|
||||||
|
}
|
||||||
|
each(@themes, {
|
||||||
|
&:global(.@{value}) {
|
||||||
|
svg {
|
||||||
|
fill: ~'@{color-@{value}-theme}';
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
background-color: ~'@{color-@{value}-theme}';
|
||||||
|
background-image: ~'@{color-@{value}-theme-bgimg}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +337,7 @@ each(@themes, {
|
||||||
&.active {
|
&.active {
|
||||||
&:global(.@{value}) {
|
&:global(.@{value}) {
|
||||||
color: ~'@{color-@{value}-theme}';
|
color: ~'@{color-@{value}-theme}';
|
||||||
span {
|
.bg {
|
||||||
border-color: ~'@{color-@{value}-theme}';
|
border-color: ~'@{color-@{value}-theme}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,22 @@
|
||||||
dt#download {{$t('setting__download')}}
|
dt#download {{$t('setting__download')}}
|
||||||
dd
|
dd
|
||||||
base-checkbox(id="setting_download_enable" v-model="currentStting.download.enable" :label="$t('setting__download_enable')")
|
base-checkbox(id="setting_download_enable" v-model="currentStting.download.enable" :label="$t('setting__download_enable')")
|
||||||
dd(:tips="$t('setting__download_path_title')")
|
dd(:aria-label="$t('setting__download_path_title')")
|
||||||
h3#download_path {{$t('setting__download_path')}}
|
h3#download_path {{$t('setting__download_path')}}
|
||||||
div
|
div
|
||||||
p
|
p
|
||||||
| {{$t('setting__download_path_label')}}
|
| {{$t('setting__download_path_label')}}
|
||||||
span.auto-hidden.hover(:class="$style.savePath" @click="openDirInExplorer(currentStting.download.savePath)" :tips="$t('setting__download_path_open_label')") {{currentStting.download.savePath}}
|
span.auto-hidden.hover(:class="$style.savePath" @click="openDirInExplorer(currentStting.download.savePath)" :aria-label="$t('setting__download_path_open_label')") {{currentStting.download.savePath}}
|
||||||
p
|
p
|
||||||
base-btn.btn(min @click="handleChangeSavePath") {{$t('setting__download_path_change_btn')}}
|
base-btn.btn(min @click="handleChangeSavePath") {{$t('setting__download_path_change_btn')}}
|
||||||
dd
|
dd
|
||||||
h3#download_use_other_source
|
h3#download_use_other_source
|
||||||
| {{$t('setting__download_use_other_source')}}
|
| {{$t('setting__download_use_other_source')}}
|
||||||
svg-icon(class="help-icon" name="help-circle-outline" :tips="$t('setting__download_use_other_source_tip')")
|
svg-icon(class="help-icon" name="help-circle-outline" :aria-label="$t('setting__download_use_other_source_tip')")
|
||||||
div
|
div
|
||||||
base-checkbox(id="setting_download_isUseOtherSource" v-model="currentStting.download.isUseOtherSource" :label="$t('setting__is_enable')")
|
base-checkbox(id="setting_download_isUseOtherSource" v-model="currentStting.download.isUseOtherSource" :label="$t('setting__is_enable')")
|
||||||
div
|
div
|
||||||
dd(:tips="$t('setting__download_name_title')")
|
dd(:aria-label="$t('setting__download_name_title')")
|
||||||
h3#download_name {{$t('setting__download_name')}}
|
h3#download_name {{$t('setting__download_name')}}
|
||||||
div
|
div
|
||||||
base-checkbox.gap-left(:id="`setting_download_musicName_${item.value}`" name="setting_download_musicName" :value="item.value" :key="item.value" need
|
base-checkbox.gap-left(:id="`setting_download_musicName_${item.value}`" name="setting_download_musicName" :value="item.value" :key="item.value" need
|
||||||
|
@ -28,7 +28,7 @@ dd
|
||||||
base-checkbox(id="setting_download_isEmbedPic" v-model="currentStting.download.isEmbedPic" :label="$t('setting__download_embed_pic')")
|
base-checkbox(id="setting_download_isEmbedPic" v-model="currentStting.download.isEmbedPic" :label="$t('setting__download_embed_pic')")
|
||||||
.gap-top
|
.gap-top
|
||||||
base-checkbox(id="setting_download_isEmbedLyric" v-model="currentStting.download.isEmbedLyric" :label="$t('setting__download_embed_lyric')")
|
base-checkbox(id="setting_download_isEmbedLyric" v-model="currentStting.download.isEmbedLyric" :label="$t('setting__download_embed_lyric')")
|
||||||
dd(:tips="$t('setting__download_lyric_title')")
|
dd(:aria-label="$t('setting__download_lyric_title')")
|
||||||
h3#download_lyric {{$t('setting__download_lyric')}}
|
h3#download_lyric {{$t('setting__download_lyric')}}
|
||||||
div
|
div
|
||||||
base-checkbox(id="setting_download_isDownloadLrc" v-model="currentStting.download.isDownloadLrc" :label="$t('setting__is_enable')")
|
base-checkbox(id="setting_download_isDownloadLrc" v-model="currentStting.download.isDownloadLrc" :label="$t('setting__is_enable')")
|
||||||
|
|
|
@ -7,7 +7,7 @@ dd
|
||||||
base-checkbox(id="setting_list_scroll_enable" v-model="currentStting.list.isSaveScrollLocation" :label="$t('setting__list_scroll')")
|
base-checkbox(id="setting_list_scroll_enable" v-model="currentStting.list.isSaveScrollLocation" :label="$t('setting__list_scroll')")
|
||||||
.gap-top
|
.gap-top
|
||||||
base-checkbox(id="setting_list_clickAction_enable" v-model="currentStting.list.isClickPlayList" :label="$t('setting__list_click_action')")
|
base-checkbox(id="setting_list_clickAction_enable" v-model="currentStting.list.isClickPlayList" :label="$t('setting__list_click_action')")
|
||||||
dd(:tips="$t('setting__basic_sourcename_title')")
|
dd(:aria-label="$t('setting__basic_sourcename_title')")
|
||||||
h3#list_addMusicLocationType {{$t('setting__list_add_music_location_type')}}
|
h3#list_addMusicLocationType {{$t('setting__list_add_music_location_type')}}
|
||||||
div
|
div
|
||||||
base-checkbox.gap-left(id="setting_list_add_music_location_type_top"
|
base-checkbox.gap-left(id="setting_list_add_music_location_type_top"
|
||||||
|
|
|
@ -8,7 +8,7 @@ dd
|
||||||
dd
|
dd
|
||||||
h3#other_resource_cache
|
h3#other_resource_cache
|
||||||
| {{$t('setting__other_resource_cache')}}
|
| {{$t('setting__other_resource_cache')}}
|
||||||
svg-icon(class="help-icon" name="help-circle-outline" :tips="$t('setting__other_resource_cache_tip')")
|
svg-icon(class="help-icon" name="help-circle-outline" :aria-label="$t('setting__other_resource_cache_tip')")
|
||||||
div
|
div
|
||||||
p
|
p
|
||||||
| {{$t('setting__other_resource_cache_label')}}
|
| {{$t('setting__other_resource_cache_label')}}
|
||||||
|
@ -18,7 +18,7 @@ dd
|
||||||
dd
|
dd
|
||||||
h3#other_play_list_cache
|
h3#other_play_list_cache
|
||||||
| {{$t('setting__other_play_list_cache')}}
|
| {{$t('setting__other_play_list_cache')}}
|
||||||
svg-icon(class="help-icon" name="help-circle-outline" :tips="$t('setting__other_play_list_cache_tip')")
|
svg-icon(class="help-icon" name="help-circle-outline" :aria-label="$t('setting__other_play_list_cache_tip')")
|
||||||
|
|
||||||
div
|
div
|
||||||
base-btn.btn(min :disabled="isDisabledListCacheClear" @click="clearListCache") {{$t('setting__other_play_list_cache_clear_btn')}}
|
base-btn.btn(min :disabled="isDisabledListCacheClear" @click="clearListCache") {{$t('setting__other_play_list_cache_clear_btn')}}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue