You've already forked lx-music-desktop
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58e61e0bda | ||
|
|
42aa62cff0 | ||
|
|
bcf7b3fccb | ||
|
|
ff09378c6d | ||
|
|
99b0595e50 | ||
|
|
5321469c1d | ||
|
|
ef9eb83a75 | ||
|
|
c12bbc7f0f | ||
|
|
a16c4c3657 | ||
|
|
c8240448c6 | ||
|
|
d19569131c | ||
|
|
37eec4c971 | ||
|
|
65fe679ee2 | ||
|
|
a16b825c3b | ||
|
|
b9aedc9165 | ||
|
|
8bdbbc562c | ||
|
|
696f6c096c | ||
|
|
d0ef6aef1c | ||
|
|
7204b51439 | ||
|
|
6075a9d22f | ||
|
|
b15cfa1892 | ||
|
|
955375f423 | ||
|
|
2aa13a499a | ||
|
|
fb0e61f3b0 | ||
|
|
16149fdd38 | ||
|
|
a432080141 | ||
|
|
73072daa46 | ||
|
|
2f57345bd2 | ||
|
|
06075d561d | ||
|
|
db8ad7cde5 | ||
|
|
cacf39da69 | ||
|
|
4dc7937321 | ||
|
|
1c462ce152 | ||
|
|
2014d2495e | ||
|
|
dc5493f39f | ||
|
|
67ff5e5a4a | ||
|
|
22d56d31a9 | ||
|
|
785427674a | ||
|
|
581f6c6e1c | ||
|
|
7d0be85e84 | ||
|
|
04e75ab540 | ||
|
|
c117e33d24 | ||
|
|
cafdad6f9f | ||
|
|
05e212682c | ||
|
|
3f876202c1 | ||
|
|
57c75799a9 | ||
|
|
5cbf2d8047 | ||
|
|
3dd9ad9ead | ||
|
|
864bef483f | ||
|
|
9ea9fefe1d | ||
|
|
0b953a1517 | ||
|
|
80db293aca | ||
|
|
809be41e64 | ||
|
|
8a6ee68e58 | ||
|
|
da764721d9 | ||
|
|
0586639e07 | ||
|
|
0aeab00289 | ||
|
|
9564097f46 | ||
|
|
d4750f4c6e | ||
|
|
f1cc2fe72e | ||
|
|
6d90539e89 | ||
|
|
21f5ed6afd | ||
|
|
4cbbf2ac81 | ||
|
|
a035a2525a | ||
|
|
9727601752 | ||
|
|
9e9053c0eb | ||
|
|
507d495f3f | ||
|
|
a2f7547cdb | ||
|
|
d48308d913 | ||
|
|
78c0badd95 | ||
|
|
c81c33a430 | ||
|
|
1786376a9e | ||
|
|
aa973ea984 | ||
|
|
67aeeb0b2f |
@@ -5,6 +5,7 @@ cache:
|
||||
- node_modules
|
||||
- '%APPDATA%\npm-cache'
|
||||
- '%LOCALAPPDATA%\electron\Cache'
|
||||
- '%LOCALAPPDATA%\electron-builder\Cache'
|
||||
|
||||
install:
|
||||
- ps: Install-Product node 12 x64
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -69,3 +69,5 @@ dist
|
||||
publish/assets
|
||||
|
||||
publish/utils/githubToken.js
|
||||
|
||||
src/**/*-internal.js
|
||||
|
||||
139
CHANGELOG.md
139
CHANGELOG.md
@@ -6,6 +6,145 @@ Project versioning adheres to [Semantic Versioning](http://semver.org/).
|
||||
Commit convention is based on [Conventional Commits](http://conventionalcommits.org).
|
||||
Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||
|
||||
## [0.6.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.5...v0.6.0) - 2019-09-21
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增音乐**聚合搜索**,目前支持酷我、酷狗、百度源搜索
|
||||
- 新增代理功能
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化从《梦里嫦娥》皮肤切换到其他皮肤时侧栏动画的切换效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复试听列表没有歌曲时会显示列表加载中的Bug
|
||||
- 修复切换歌单列表详情时的UI Bug
|
||||
|
||||
## [0.5.5](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.4...v0.5.5) - 2019-09-13
|
||||
|
||||
### 新增
|
||||
|
||||
- 月是故乡明,祝大家中秋快乐🥮~~新增个性皮肤 **《月里嫦娥》**,时间仓促,皮肤还不是很完善,可以试试喜不喜欢~😉
|
||||
- 新增 MAC 版本退出快捷键支持
|
||||
- 新增点击播放器中的歌曲标题可以复制标题的功能(遇到好听的歌曲方便分享)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复 MAC 系统下软件关闭时再次从 dock 打开时报错的Bug
|
||||
- 修复下载的歌曲文件名中包含命名规则不允许的符号时下载失败的问题(若歌曲名包含这些符号会自动将其移除)
|
||||
- 修复 MAC 版本不能复制粘贴的问题
|
||||
|
||||
## [0.5.4](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.3...v0.5.4) - 2019-09-09
|
||||
|
||||
### 移除
|
||||
|
||||
- 下载的FLAC文件在修改歌曲信息后,软件无法播放,但使用本地播放器可以播放
|
||||
- 为了稳妥起见,暂时移除FLAC格式的meta信息修改
|
||||
- MP3格式无此问题
|
||||
|
||||
## [0.5.3](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.2...v0.5.3) - 2019-09-09
|
||||
|
||||
### 优化
|
||||
|
||||
- 更新所有依赖包到最新
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复试听酷狗源的音乐仍然获取320k音质导致获取失败的Bug
|
||||
|
||||
## [0.5.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.1...v0.5.2) - 2019-09-09
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增强迫症设置-离开搜索界面时是否清空搜索框
|
||||
- 设置-关于板块新增常见问题链接
|
||||
- 歌单左上角的分类按钮添加一个**向下图标**,方便识别该按钮为下拉框(该按钮可选择歌单类型,请自行尝试)
|
||||
|
||||
### 优化
|
||||
|
||||
- 略微优化最小化按钮字符
|
||||
- 优化试听列表的加载体验,当歌曲数过多时列表将延迟加载
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复下载管理的一些Bug
|
||||
|
||||
### 移除
|
||||
|
||||
- 因接口失效,移除网易云音源,酷狗音源仅支持播放128k音质
|
||||
|
||||
## [0.5.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.0...v0.5.1) - 2019-09-05
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增右上角最小化/关闭按钮鼠标滑过符号
|
||||
- 新增下载列表定位文件按钮
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复百度源歌单全部分类无法加载的问题
|
||||
- 修复更新弹窗无法弹出的问题
|
||||
|
||||
## [0.5.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.4.0...v0.5.0) - 2019-09-05
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增**封面嵌入**(默认开启,可到设置-下载设置关闭)
|
||||
- 新增**歌词下载**(默认关闭,可到设置-下载设置开启)
|
||||
- 新增单例应用功能(实现软件单开功能,禁止软件多开)
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化歌单列表动画
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复歌单无法翻页的问题
|
||||
- 修复在某些情况下,添加下载歌曲导致下载列表崩溃的问题
|
||||
- 修复版本更新弹窗Bug
|
||||
- 修复酷狗歌单推荐歌单出现在其他分类中的Bug
|
||||
|
||||
## [0.4.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.5...v0.4.0) - 2019-09-04
|
||||
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增**歌单**功能,目前支持酷我、酷狗、百度源歌单
|
||||
- 在设置界面-关于洛雪音乐说明部分新增**最新版网盘下载地址**与**打赏地址**
|
||||
- 新增酷狗 电音热歌榜、DJ热歌榜
|
||||
- 新增版本更新超时功能,对于部分无法访问GitHub的用户做更新超时提醒
|
||||
|
||||
### 移除
|
||||
|
||||
- **注意**:0.4.0以前的版本即将失效,请更新到0.4.0版本
|
||||
|
||||
## [0.3.5](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.4...v0.3.5) - 2019-08-30
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增**测试接口**,该接口同样速度较慢,但软件的大部分功能可用,**请自行切换到该接口**,找接口辛苦,且用且珍惜!
|
||||
|
||||
### 优化
|
||||
|
||||
- 取消需要刷新URL时windows任务栏进度显示错误状态(现显示为暂停状态)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复使用临时接口时在试听列表双击灰色歌曲仍然会进行播放的Bug
|
||||
- 修复歌词加载Bug
|
||||
|
||||
## [0.3.4](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.3...v0.3.4) - 2019-08-29
|
||||
|
||||
### 优化
|
||||
|
||||
- 减少接口不稳定带来的影响,适当增加请求等待时间
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复播放过程中URL过期不会刷新URL的问题
|
||||
|
||||
## [0.3.3](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.2...v0.3.3) - 2019-08-29
|
||||
|
||||
### 修复
|
||||
|
||||
48
README.md
48
README.md
@@ -4,7 +4,7 @@
|
||||
<a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/release/lyswhut/lx-music-desktop" alt="Release version"></a>
|
||||
<a href="https://ci.appveyor.com/project/lyswhut/lx-music-desktop"><img src="https://ci.appveyor.com/api/projects/status/flrsqd5ymp8fnte5?svg=true" alt="Build status"></a>
|
||||
<a href="https://travis-ci.org/lyswhut/lx-music-desktop"><img src="https://travis-ci.org/lyswhut/lx-music-desktop.svg?branch=master" alt="Build status"></a>
|
||||
<a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/latest/total" alt="Downloads"></a>
|
||||
<!-- <a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/latest/total" alt="Downloads"></a> -->
|
||||
<a href="https://github.com/lyswhut/lx-music-desktop/tree/dev"><img src="https://img.shields.io/github/package-json/v/lyswhut/lx-music-desktop/dev" alt="Dev branch version"></a>
|
||||
<!-- <a href="https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE"><img src="https://img.shields.io/github/license/lyswhut/lx-music-desktop" alt="License"></a> -->
|
||||
</p>
|
||||
@@ -46,18 +46,8 @@
|
||||
|
||||
软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)<br>
|
||||
软件下载请转到:[发布页面](https://github.com/lyswhut/lx-music-desktop/releases)<br>
|
||||
或者到网盘下载(网盘内有MAC、windows版):`https://www.lanzous.com/b906260/` 密码:`glqw`
|
||||
|
||||
歌曲默认下载到桌面,可自行到设置页面更改。<br>
|
||||
若排行榜上的某些歌曲**无法播放**,可尝试**直接搜索**该歌曲后播放。
|
||||
|
||||
#### 关于软件更新
|
||||
|
||||
软件启动时若发现新版本时会自动从本仓库下载安装包,下载完毕会弹窗提示更新。<br>
|
||||
若下载未完成时软件被关闭,下次启动软件会再次自动下载。<br>
|
||||
目前暂未添加跳过更新某个版本的功能。<br>
|
||||
注意:**绿色版**的软件更新功能**不可用**,为了能及时地获取更新,建议使用安装版!!<br>
|
||||
注意:**Mac版**、**Linux deb**版不支持自动更新!
|
||||
或者到网盘下载(网盘内有MAC、windows版):`https://www.lanzous.com/b906260/` 密码:`glqw`<br>
|
||||
使用常见问题请转至:[常见问题](https://github.com/lyswhut/lx-music-desktop#常见问题)
|
||||
|
||||
#### TODO
|
||||
|
||||
@@ -84,14 +74,40 @@ npm run pack
|
||||
|
||||
<p><a href="https://github.com/lyswhut/lx-music-desktop"><img width="100%" src="https://github.com/lyswhut/lx-music-desktop/blob/master/doc/images/app.png" alt="lx-music UI"></a></p>
|
||||
|
||||
### 常见问题
|
||||
|
||||
#### 歌曲无法试听与下载
|
||||
|
||||
该问题解决顺序如下:
|
||||
|
||||
1. 尝试更新到最新版本
|
||||
2. 尝试切换其他歌曲(或直接搜索该歌曲),若全部歌曲都无法试听与下载则进行下一步
|
||||
3. 尝试到设置-接口来源切换到其他接口
|
||||
4. 尝试切换网络(比如切到移动网络)
|
||||
5. 若还不行请到这个链接查看详情:<https://github.com/lyswhut/lx-music-desktop/issues/5>
|
||||
|
||||
#### Windows 7 下界面异常
|
||||
|
||||
当 win7 没有开启**透明效果**时界面将会显示异常,开启方法请自行百度
|
||||
|
||||
#### 软件更新
|
||||
|
||||
软件启动时若发现新版本时会自动从本仓库下载安装包,下载完毕会弹窗提示更新。<br>
|
||||
若下载未完成时软件被关闭,下次启动软件会再次自动下载。<br>
|
||||
若还是更新失败,可能是无法访问GitHub导致的,这时需要手动更新,即下载最新安装包直接覆盖安装即可。<br>
|
||||
注意:**绿色版**的软件更新功能**不可用**,为了能及时地获取更新,建议使用安装版!!<br>
|
||||
注意:**Mac版**、**Linux deb**版不支持自动更新!
|
||||
|
||||
### 致谢
|
||||
|
||||
感谢 [@messoer](https://github.com/messoer) 提供的部分音乐API!
|
||||
感谢 [@messoer](https://github.com/messoer) 曾经提供的部分音乐API!
|
||||
|
||||
### 免责声明
|
||||
|
||||
本软件仅用于测试 `electron 6.x` 在各种系统上的兼容性,使用本软件产生的任何涉及版权相关的数据请于24小时内删除。<br>
|
||||
使用本软件所造成的的后果由使用者承担!
|
||||
本项目**不开发或者破解直接获取音频数据**的功能,所有音频数据均来自**第三方接口**!<br>
|
||||
本软件仅用于**测试 `electron 6.x` 在各种系统上的兼容性**及用于**对比各大音乐平台歌单、排行榜等数据列表的差异性**,使用本软件产生的**任何涉及版权相关的数据**请于**24小时内删除**。<br>
|
||||
本软件仅用于学习交流使用,禁止用于商业用途,使用本软件所造成的的后果由使用者承担!<br>
|
||||
若对此有疑问请 mail to: lyswhut@qq.com
|
||||
|
||||
### 许可证
|
||||
|
||||
|
||||
2042
package-lock.json
generated
2042
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
70
package.json
70
package.json
@@ -1,36 +1,36 @@
|
||||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "0.3.3",
|
||||
"version": "0.6.0",
|
||||
"description": "一个免费的音乐下载助手",
|
||||
"main": "./dist/electron/main.js",
|
||||
"productName": "lx-music-desktop",
|
||||
"scripts": {
|
||||
"pack": "node build-config/pack.js && npm run pack:win",
|
||||
"pack:win": "npm run pack:win:setup && npm run pack:win:7z",
|
||||
"pack:win:setup": "cross-env TARGET=Setup ARCH=x64_x86 electron-builder -w=nsis --x64 --ia32",
|
||||
"pack:win:setup": "cross-env TARGET=win_安装版 ARCH=x64_x86 electron-builder -w=nsis --x64 --ia32",
|
||||
"pack:win:portable": "npm run pack:win:portable:x64_x86 && npm run pack:win:portable:x64 && npm run pack:win:portable:x86",
|
||||
"pack:win:portable:x64_x86": "cross-env TARGET=便携版 ARCH=x64_x86 electron-builder -w=portable --x64 --ia32",
|
||||
"pack:win:portable:x64": "cross-env TARGET=便携版 ARCH=x64 electron-builder -w=portable --x64",
|
||||
"pack:win:portable:x86": "cross-env TARGET=便携版 ARCH=x86 electron-builder -w=portable --ia32",
|
||||
"pack:win:7z": "npm run pack:win:7z:x64 && npm run pack:win:7z:x86",
|
||||
"pack:win:7z:x64": "cross-env TARGET=绿色版 ARCH=x64 electron-builder -w=7z --x64",
|
||||
"pack:win:7z:x86": "cross-env TARGET=绿色版 ARCH=x86 electron-builder -w=7z --ia32",
|
||||
"pack:win:7z:x64": "cross-env TARGET=win_绿色版 ARCH=x64 electron-builder -w=7z --x64",
|
||||
"pack:win:7z:x86": "cross-env TARGET=win_绿色版 ARCH=x86 electron-builder -w=7z --ia32",
|
||||
"publish": "node publish",
|
||||
"publish:gh": "node build-config/pack.js && npm run publish:win",
|
||||
"publish:win": "npm run publish:win:setup && npm run publish:win:7z",
|
||||
"publish:win:setup": "cross-env TARGET=Setup ARCH=x64_x86 electron-builder -w=nsis --x64 --ia32 -p always",
|
||||
"publish:win": "npm run publish:win:7z && npm run publish:win:setup",
|
||||
"publish:win:setup": "cross-env TARGET=Setup ARCH=x64_x86 electron-builder -w=nsis --x64 --ia32 -p onTagOrDraft",
|
||||
"publish:win:portable": "npm run publish:win:portable:x64_x86 && npm run publish:win:portable:x64 && npm run publish:win:portable:x86",
|
||||
"publish:win:portable:x64_x86": "cross-env TARGET=portable ARCH=x64_x86 electron-builder -w=portable --x64 --ia32 -p onTagOrDraft",
|
||||
"publish:win:portable:x64": "cross-env TARGET=portable ARCH=x64 electron-builder -w=portable --x64 -p onTagOrDraft",
|
||||
"publish:win:portable:x86": "cross-env TARGET=portable ARCH=x86 electron-builder -w=portable --ia32 -p onTagOrDraft",
|
||||
"publish:win:7z": "npm run publish:win:7z:x64 && npm run publish:win:7z:x86",
|
||||
"publish:win:7z:x64": "cross-env TARGET=green ARCH=win_x64 electron-builder -w=7z --x64 -p onTagOrDraft",
|
||||
"publish:win:7z:x64": "cross-env TARGET=green ARCH=win_x64 electron-builder -w=7z --x64 -p always",
|
||||
"publish:win:7z:x86": "cross-env TARGET=green ARCH=win_x86 electron-builder -w=7z --ia32 -p onTagOrDraft",
|
||||
"publish:gh:mac": "node build-config/pack.js && npm run publish:mac",
|
||||
"publish:mac": "npm run publish:mac:dmg",
|
||||
"publish:mac:dmg": "electron-builder -m=dmg -p onTagOrDraft",
|
||||
"publish:gh:linux": "node build-config/pack.js && npm run publish:linux",
|
||||
"publish:linux": "npm run publish:linux:appImage && npm run publish:linux:deb",
|
||||
"publish:linux": "npm run publish:linux:deb && npm run publish:linux:appImage",
|
||||
"publish:linux:appImage": "cross-env ARCH=x64 electron-builder -l=AppImage -p onTagOrDraft",
|
||||
"publish:linux:deb": "npm run publish:linux:deb:x64 && npm run publish:linux:deb:x86",
|
||||
"publish:linux:deb:x64": "cross-env ARCH=x64 electron-builder -l=deb --x64 -p onTagOrDraft",
|
||||
@@ -134,43 +134,43 @@
|
||||
},
|
||||
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/core": "^7.6.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"@babel/polyfill": "^7.4.4",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/polyfill": "^7.6.0",
|
||||
"@babel/preset-env": "^7.6.0",
|
||||
"autoprefixer": "^9.6.1",
|
||||
"babel-eslint": "^10.0.2",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-minify-webpack-plugin": "^0.3.1",
|
||||
"babel-preset-minify": "^0.5.0",
|
||||
"cfonts": "^2.4.4",
|
||||
"babel-preset-minify": "^0.5.1",
|
||||
"cfonts": "^2.4.5",
|
||||
"chalk": "^2.4.2",
|
||||
"changelog-parser": "^2.8.0",
|
||||
"copy-webpack-plugin": "^5.0.4",
|
||||
"core-js": "^3.2.1",
|
||||
"cos-nodejs-sdk-v5": "^2.5.11",
|
||||
"cross-env": "^5.2.0",
|
||||
"cos-nodejs-sdk-v5": "^2.5.12",
|
||||
"cross-env": "^6.0.0",
|
||||
"css-loader": "^3.2.0",
|
||||
"del": "^3.0.0",
|
||||
"electron": "^6.0.2",
|
||||
"del": "^5.1.0",
|
||||
"electron": "^6.0.10",
|
||||
"electron-builder": "^21.2.0",
|
||||
"electron-debug": "^3.0.1",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint-config-standard": "^13.0.1",
|
||||
"eslint": "^6.4.0",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"eslint-formatter-friendly": "^7.0.0",
|
||||
"eslint-loader": "^2.2.1",
|
||||
"eslint-loader": "^3.0.0",
|
||||
"eslint-plugin-html": "^6.0.0",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-node": "^9.1.0",
|
||||
"eslint-plugin-node": "^10.0.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"file-loader": "^4.2.0",
|
||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"less": "^3.9.0",
|
||||
"less": "^3.10.3",
|
||||
"less-loader": "^5.0.0",
|
||||
"markdown-it": "^9.1.0",
|
||||
"markdown-it": "^10.0.0",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"multispinner": "^0.2.1",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
@@ -180,32 +180,34 @@
|
||||
"pug-plain-loader": "^1.0.0",
|
||||
"raw-loader": "^3.1.0",
|
||||
"rimraf": "^3.0.0",
|
||||
"stylus": "^0.54.5",
|
||||
"stylus": "^0.54.7",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"terser-webpack-plugin": "^1.4.1",
|
||||
"terser-webpack-plugin": "^2.1.0",
|
||||
"url-loader": "^2.1.0",
|
||||
"vue-loader": "^15.7.1",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"webpack": "^4.39.2",
|
||||
"webpack-cli": "^3.3.6",
|
||||
"webpack-dev-server": "^3.8.0",
|
||||
"webpack": "^4.40.2",
|
||||
"webpack-cli": "^3.3.9",
|
||||
"webpack-dev-server": "^3.8.1",
|
||||
"webpack-hot-middleware": "^2.25.0",
|
||||
"webpack-merge": "^4.2.1"
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"electron-log": "^3.0.7",
|
||||
"electron-store": "^4.0.0",
|
||||
"electron-log": "^3.0.8",
|
||||
"electron-store": "^5.0.0",
|
||||
"electron-updater": "^4.1.2",
|
||||
"flac-metadata": "^0.1.1",
|
||||
"js-htmlencode": "^0.3.0",
|
||||
"lrc-file-parser": "^0.1.12",
|
||||
"node-downloader-helper": "^1.0.10",
|
||||
"node-id3": "^0.1.11",
|
||||
"request": "^2.88.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-electron": "^1.0.6",
|
||||
"vue-router": "^3.1.2",
|
||||
"vue-router": "^3.1.3",
|
||||
"vuex": "^3.1.1",
|
||||
"vuex-electron": "^1.0.3",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
### 新增
|
||||
|
||||
- 新增音乐**聚合搜索**,目前支持酷我、酷狗、百度源搜索
|
||||
- 新增代理功能
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化从《梦里嫦娥》皮肤切换到其他皮肤时侧栏动画的切换效果
|
||||
|
||||
### 修复
|
||||
|
||||
- **messoer**的接口已经关闭,暂时切换到临时接口使用,部分功能受限。。。
|
||||
- 修复设置界面更新出错时仍然显示更新下载中的问题
|
||||
- 修复手动定位播放进度条时存在偏差的问题
|
||||
- 屏蔽播放器中没有歌曲时对进度条的点击
|
||||
|
||||
- 修复试听列表没有歌曲时会显示列表加载中的Bug
|
||||
- 修复切换歌单列表详情时的UI Bug
|
||||
|
||||
@@ -1,7 +1,47 @@
|
||||
{
|
||||
"version": "0.3.3",
|
||||
"desc": "<h3>修复</h3>\n<ul>\n<li><strong>messoer</strong>的接口已经关闭,暂时切换到临时接口使用,部分功能受限。。。</li>\n<li>修复设置界面更新出错时仍然显示更新下载中的问题</li>\n<li>修复手动定位播放进度条时存在偏差的问题</li>\n<li>屏蔽播放器中没有歌曲时对进度条的点击</li>\n</ul>\n",
|
||||
"version": "0.6.0",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增音乐<strong>聚合搜索</strong>,目前支持酷我、酷狗、百度源搜索</li>\n<li>新增代理功能</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>优化从《梦里嫦娥》皮肤切换到其他皮肤时侧栏动画的切换效果</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复试听列表没有歌曲时会显示列表加载中的Bug</li>\n<li>修复切换歌单列表详情时的UI Bug</li>\n</ul>\n",
|
||||
"history": [
|
||||
{
|
||||
"version": "0.5.5",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>月是故乡明,祝大家中秋快乐🥮~~新增个性皮肤**《月里嫦娥》**,时间仓促,皮肤还不是很完善,可以试试喜不喜欢~😉</li>\n<li>新增 MAC 版本退出快捷键支持</li>\n<li>新增点击播放器中的歌曲标题可以复制标题的功能(遇到好听的歌曲方便分享)</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复 MAC 系统下软件关闭时再次从 dock 打开时报错的Bug</li>\n<li>修复下载的歌曲文件名中包含命名规则不允许的符号时下载失败的问题(若歌曲名包含这些符号会自动将其移除)</li>\n<li>修复 MAC 版本不能复制粘贴的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.5.4",
|
||||
"desc": "<h3>移除</h3>\n<ul>\n<li>下载的FLAC文件在修改歌曲信息后,软件无法播放,但使用本地播放器可以播放</li>\n<li>为了稳妥起见,暂时移除FLAC格式的meta信息修改</li>\n<li>MP3格式无此问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.5.3",
|
||||
"desc": "<h3>优化</h3>\n<ul>\n<li>更新所有依赖包到最新</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复试听酷狗源的音乐仍然获取320k音质导致获取失败的Bug</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.5.2",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增强迫症设置-离开搜索界面时是否清空搜索框</li>\n<li>设置-关于板块新增常见问题链接</li>\n<li>歌单左上角的分类按钮添加一个<strong>向下图标</strong>,方便识别该按钮为下拉框(该按钮可选择歌单类型,请自行尝试)</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>略微优化最小化按钮字符</li>\n<li>优化试听列表的加载体验,当歌曲数过多时列表将延迟加载</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复下载管理的一些Bug</li>\n</ul>\n<h3>移除</h3>\n<ul>\n<li>因接口失效,移除网易云音源,酷狗音源仅支持播放128k音质</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.5.1",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增右上角最小化/关闭按钮鼠标滑过符号</li>\n<li>新增下载列表定位文件按钮</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复百度源歌单全部分类无法加载的问题</li>\n<li>修复更新弹窗无法弹出的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.5.0",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增<strong>封面嵌入</strong>(默认开启,可到设置-下载设置关闭)</li>\n<li>新增<strong>歌词下载</strong>(默认关闭,可到设置-下载设置开启)</li>\n<li>新增单例应用功能(实现软件单开功能,禁止软件多开)</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>优化歌单列表动画</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复歌单无法翻页的问题</li>\n<li>修复在某些情况下,添加下载歌曲导致下载列表崩溃的问题</li>\n<li>修复版本更新弹窗Bug</li>\n<li>修复酷狗歌单推荐歌单出现在其他分类中的Bug</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.4.0",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增<strong>歌单</strong>功能,目前支持酷我、酷狗、百度源歌单</li>\n<li>在设置界面-关于洛雪音乐说明部分新增<strong>最新版网盘下载地址</strong>与<strong>打赏地址</strong></li>\n<li>新增酷狗 电音热歌榜、DJ热歌榜</li>\n<li>新增版本更新超时功能,对于部分无法访问GitHub的用户做更新超时提醒</li>\n</ul>\n<h3>移除</h3>\n<ul>\n<li><strong>注意</strong>:0.4.0以前的版本即将失效,请更新到0.4.0版本</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.3.5",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增<strong>测试接口</strong>,该接口同样速度较慢,但软件的大部分功能可用,<strong>请自行切换到该接口</strong>,找接口辛苦,且用且珍惜!</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>取消需要刷新URL时windows任务栏进度显示错误状态(现显示为暂停状态)</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复使用临时接口时在试听列表双击灰色歌曲仍然会进行播放的Bug</li>\n<li>修复歌词加载Bug</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.3.4",
|
||||
"desc": "<h3>优化</h3>\n<ul>\n<li>减少接口不稳定带来的影响,适当增加请求等待时间</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复播放过程中URL过期不会刷新URL的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.3.3",
|
||||
"desc": "<h3>修复</h3>\n<ul>\n<li><strong>messoer</strong>的接口已经关闭,暂时切换到临时接口使用,部分功能受限。。。</li>\n<li>修复设置界面更新出错时仍然显示更新下载中的问题</li>\n<li>修复手动定位播放进度条时存在偏差的问题</li>\n<li>屏蔽播放器中没有歌曲时对进度条的点击</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.3.2",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增酷狗排行榜其他音质下载</li>\n</ul>\n"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
export const isLinux = process.platform == 'linux'
|
||||
export const isWin = process.platform == 'win32'
|
||||
export const isMac = process.platform == 'darwin'
|
||||
const log = require('electron-log')
|
||||
|
||||
exports.isLinux = process.platform == 'linux'
|
||||
exports.isWin = process.platform == 'win32'
|
||||
exports.isMac = process.platform == 'darwin'
|
||||
|
||||
|
||||
exports.log = log
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
require('./request')
|
||||
require('./appName')
|
||||
// require('./appName')
|
||||
require('./musicMeta')
|
||||
|
||||
|
||||
6
src/main/events/musicMeta.js
Normal file
6
src/main/events/musicMeta.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { setMeta } = require('../utils/musicMeta')
|
||||
|
||||
mainOn('setMusicMeta', (event, { filePath, meta }) => {
|
||||
setMeta(filePath, meta)
|
||||
})
|
||||
@@ -1,11 +1,10 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
|
||||
module.exports = win => {
|
||||
mainOn('progress', (event, params) => {
|
||||
// console.log(params)
|
||||
win.setProgressBar(params.status, {
|
||||
mode: params.mode || 'normal',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
mainOn('progress', (event, params) => {
|
||||
// console.log(params)
|
||||
global.mainWindow && global.mainWindow.setProgressBar(params.status, {
|
||||
mode: params.mode || 'normal',
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
// const { app } = require('electron')
|
||||
const { mainOn } = require('../../common/icp')
|
||||
|
||||
module.exports = win => {
|
||||
mainOn('min', event => {
|
||||
if (win) {
|
||||
win.minimize()
|
||||
}
|
||||
})
|
||||
// mainOn('max', event => {
|
||||
// if (win) {
|
||||
// win.maximize()
|
||||
// }
|
||||
// })
|
||||
mainOn('close', event => {
|
||||
if (win) {
|
||||
win.close()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mainOn('min', event => {
|
||||
if (global.mainWindow) {
|
||||
global.mainWindow.minimize()
|
||||
}
|
||||
})
|
||||
// mainOn('max', event => {
|
||||
// if (global.mainWindow) {
|
||||
// global.mainWindow.maximize()
|
||||
// }
|
||||
// })
|
||||
mainOn('close', event => {
|
||||
if (global.mainWindow) {
|
||||
// global.mainWindowdow.destroy()
|
||||
// console.log('close')
|
||||
// app.quit()
|
||||
global.mainWindow.close()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
const { app, BrowserWindow, Menu } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
// 单例应用程序
|
||||
if (!app.requestSingleInstanceLock()) {
|
||||
app.quit()
|
||||
return
|
||||
}
|
||||
app.on('second-instance', (event, argv, cwd) => {
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) mainWindow.restore()
|
||||
mainWindow.focus()
|
||||
} else {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
require('./events')
|
||||
const progressBar = require('./events/progressBar')
|
||||
const trafficLight = require('./events/trafficLight')
|
||||
require('./events/progressBar')
|
||||
require('./events/trafficLight')
|
||||
const autoUpdate = require('./utils/autoUpdate')
|
||||
const { isLinux, isMac } = require('../common/utils')
|
||||
|
||||
@@ -16,10 +30,11 @@ const isDev = process.env.NODE_ENV !== 'production'
|
||||
|
||||
let mainWindow
|
||||
let winURL
|
||||
let isFirstCheckedUpdate = true
|
||||
|
||||
if (isDev) {
|
||||
global.__static = path.join(__dirname, '../static')
|
||||
winURL = `http://localhost:9080`
|
||||
winURL = 'http://localhost:9080'
|
||||
} else {
|
||||
global.__static = path.join(__dirname, '/static')
|
||||
winURL = `file://${__dirname}/index.html`
|
||||
@@ -29,7 +44,7 @@ function createWindow() {
|
||||
/**
|
||||
* Initial window options
|
||||
*/
|
||||
mainWindow = new BrowserWindow({
|
||||
mainWindow = global.mainWindow = new BrowserWindow({
|
||||
height: 590,
|
||||
useContentSize: true,
|
||||
width: 920,
|
||||
@@ -48,27 +63,54 @@ function createWindow() {
|
||||
|
||||
mainWindow.loadURL(winURL)
|
||||
|
||||
mainWindow.on('close', () => {
|
||||
mainWindow.setProgressBar(-1)
|
||||
})
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null
|
||||
mainWindow = global.mainWindow = null
|
||||
})
|
||||
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
trafficLight(mainWindow)
|
||||
progressBar(mainWindow)
|
||||
if (!isDev) autoUpdate(mainWindow)
|
||||
if (!isDev) {
|
||||
autoUpdate(isFirstCheckedUpdate)
|
||||
isFirstCheckedUpdate = false
|
||||
}
|
||||
}
|
||||
|
||||
if (isMac) {
|
||||
const template = [
|
||||
{
|
||||
label: app.getName(),
|
||||
submenu: [{ label: '关于洛雪音乐', role: 'about' }, { type: 'separator' }, { label: '隐藏', role: 'hide' }, { label: '显示其他', role: 'hideothers' }, { label: '显示全部', role: 'unhide' }, { type: 'separator' }, { label: '退出', click: () => app.quit() }],
|
||||
submenu: [
|
||||
{ label: '关于洛雪音乐', role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ label: '隐藏', role: 'hide' },
|
||||
{ label: '显示其他', role: 'hideothers' },
|
||||
{ label: '显示全部', role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ label: '退出', accelerator: 'Command+Q', click: () => app.quit() },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '窗口',
|
||||
role: 'window',
|
||||
submenu: [{ label: '最小化', role: 'minimize' }, { label: '关闭', role: 'close' }],
|
||||
submenu: [
|
||||
{ label: '最小化', role: 'minimize' },
|
||||
{ label: '关闭', role: 'close' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
submenu: [
|
||||
{ label: '撤销', accelerator: 'CmdOrCtrl+Z', role: 'undo' },
|
||||
{ label: '恢复', accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ label: '剪切', accelerator: 'CmdOrCtrl+X', role: 'cut' },
|
||||
{ label: '复制', accelerator: 'CmdOrCtrl+C', role: 'copy' },
|
||||
{ label: '粘贴', accelerator: 'CmdOrCtrl+V', role: 'paste' },
|
||||
{ label: '选择全部', accelerator: 'CmdOrCtrl+A', role: 'selectAll' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -77,12 +119,10 @@ if (isMac) {
|
||||
Menu.setApplicationMenu(null)
|
||||
}
|
||||
|
||||
app.once('ready', createWindow)
|
||||
app.on('ready', createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
if (!isMac) app.quit()
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
@@ -90,4 +130,3 @@ app.on('activate', () => {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const log = require('electron-log')
|
||||
const { log } = require('../../common/utils')
|
||||
const { autoUpdater } = require('electron-updater')
|
||||
const { mainOn } = require('../../common/icp')
|
||||
|
||||
@@ -21,7 +21,7 @@ log.info('App starting...')
|
||||
|
||||
function sendStatusToWindow(text) {
|
||||
log.info(text)
|
||||
// win.webContents.send('message', text)
|
||||
// global.mainWindow.webContents.send('message', text)
|
||||
}
|
||||
|
||||
|
||||
@@ -56,35 +56,50 @@ function sendStatusToWindow(text) {
|
||||
|
||||
// })
|
||||
|
||||
let waitEvent = []
|
||||
const handleSendEvent = action => {
|
||||
if (global.mainWindow) {
|
||||
setTimeout(() => { // 延迟发送事件,过早发送可能渲染进程还没启动完成
|
||||
global.mainWindow.webContents.send(action.type, action.info)
|
||||
}, 2000)
|
||||
} else {
|
||||
waitEvent.push(action)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = win => {
|
||||
module.exports = isFirstCheckedUpdate => {
|
||||
if (!isFirstCheckedUpdate) {
|
||||
if (waitEvent.length) {
|
||||
waitEvent.forEach((event, index) => {
|
||||
setTimeout(() => { // 延迟发送事件,过早发送可能渲染进程还没启动完成
|
||||
global.mainWindow.webContents.send(event.type, event.info)
|
||||
}, 2000 * (index + 1))
|
||||
})
|
||||
waitEvent = []
|
||||
}
|
||||
return
|
||||
}
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
sendStatusToWindow('Checking for update...')
|
||||
})
|
||||
autoUpdater.on('update-available', info => {
|
||||
sendStatusToWindow('Update available.')
|
||||
win.webContents.send('update-available', info)
|
||||
handleSendEvent({ type: 'update-available', info })
|
||||
})
|
||||
autoUpdater.on('update-not-available', info => {
|
||||
sendStatusToWindow('Update not available.')
|
||||
setTimeout(() => { // 延迟发送事件,过早发送可能渲染进程还启动完成
|
||||
win.webContents.send('update-not-available')
|
||||
}, 5000)
|
||||
handleSendEvent({ type: 'update-not-available' })
|
||||
})
|
||||
autoUpdater.on('error', () => {
|
||||
sendStatusToWindow('Error in auto-updater.')
|
||||
setTimeout(() => { // 延迟发送事件,过早发送可能渲染进程还启动完成
|
||||
win.webContents.send('update-error')
|
||||
}, 6000)
|
||||
handleSendEvent({ type: 'update-error' })
|
||||
})
|
||||
autoUpdater.on('download-progress', progressObj => {
|
||||
sendStatusToWindow('Download progress...')
|
||||
})
|
||||
autoUpdater.on('update-downloaded', info => {
|
||||
sendStatusToWindow('Update downloaded.')
|
||||
setTimeout(() => { // 延迟发送事件,过早发送可能渲染进程还启动完成
|
||||
win.webContents.send('update-downloaded')
|
||||
}, 2000)
|
||||
handleSendEvent({ type: 'update-downloaded' })
|
||||
})
|
||||
mainOn('quit-update', () => {
|
||||
setTimeout(() => {
|
||||
|
||||
38
src/main/utils/flacMeta.js
Normal file
38
src/main/utils/flacMeta.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const fs = require('fs')
|
||||
const flac = require('flac-metadata')
|
||||
|
||||
module.exports = (filenPath, meta) => {
|
||||
const reader = fs.createReadStream(filenPath)
|
||||
const tempPath = filenPath + '.lxmtemp'
|
||||
const writer = fs.createWriteStream(tempPath)
|
||||
const processor = new flac.Processor()
|
||||
if (meta.APIC) delete meta.APIC
|
||||
|
||||
const comments = []
|
||||
for (const key in meta) {
|
||||
comments.push(`${key.toUpperCase()}=${meta[key]}`)
|
||||
}
|
||||
const vendor = 'lx-music-desktop'
|
||||
|
||||
processor.on('preprocess', function(mdb) {
|
||||
// Remove existing VORBIS_COMMENT block, if any.
|
||||
if (mdb.type === flac.Processor.MDB_TYPE_VORBIS_COMMENT) {
|
||||
mdb.remove()
|
||||
}
|
||||
// Inject new VORBIS_COMMENT block.
|
||||
if (mdb.removed || mdb.isLast) {
|
||||
let mdbVorbis = flac.data.MetaDataBlockVorbisComment.create(mdb.isLast, vendor, comments)
|
||||
this.push(mdbVorbis.publish())
|
||||
}
|
||||
})
|
||||
|
||||
reader.pipe(processor).pipe(writer).on('finish', () => {
|
||||
fs.unlink(filenPath, err => {
|
||||
if (err) return console.log(err.message)
|
||||
fs.rename(tempPath, filenPath, err => {
|
||||
if (err) console.log(err.message)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
17
src/main/utils/mp3Meta.js
Normal file
17
src/main/utils/mp3Meta.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const NodeID3 = require('node-id3')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const request = require('request')
|
||||
const extReg = /^(\.(?:jpe?g|png)).*$/
|
||||
|
||||
module.exports = (filePath, meta) => {
|
||||
if (!meta.APIC) return NodeID3.write(meta, filePath)
|
||||
let picPath = filePath.replace(/\.mp3$/, '') + path.extname(meta.APIC).replace(extReg, '$1')
|
||||
request(meta.APIC).pipe(fs.createWriteStream(picPath)).on('finish', () => {
|
||||
meta.APIC = picPath
|
||||
NodeID3.write(meta, filePath)
|
||||
fs.unlink(picPath, err => {
|
||||
if (err) console.log(err.message)
|
||||
})
|
||||
})
|
||||
}
|
||||
14
src/main/utils/musicMeta.js
Normal file
14
src/main/utils/musicMeta.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const path = require('path')
|
||||
const mp3Meta = require('./mp3Meta')
|
||||
const flacMeta = require('./flacMeta')
|
||||
|
||||
exports.setMeta = (filePath, meta) => {
|
||||
switch (path.extname(filePath)) {
|
||||
case '.mp3':
|
||||
mp3Meta(filePath, meta)
|
||||
break
|
||||
case '.flac':
|
||||
flacMeta(filePath, meta)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -35,8 +35,12 @@ export default {
|
||||
isProd: process.env.NODE_ENV === 'production',
|
||||
isLinux,
|
||||
globalObj: {
|
||||
apiSource: 'messoer',
|
||||
apiSource: 'test',
|
||||
proxy: {
|
||||
|
||||
},
|
||||
},
|
||||
updateTimeout: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -97,23 +101,38 @@ export default {
|
||||
})
|
||||
})
|
||||
rendererOn('update-error', () => {
|
||||
if (!this.updateTimeout) return
|
||||
this.setVersionModalVisible({ isError: true })
|
||||
this.clearUpdateTimeout()
|
||||
this.$nextTick(() => {
|
||||
this.showUpdateModal()
|
||||
})
|
||||
})
|
||||
rendererOn('update-downloaded', () => {
|
||||
this.clearUpdateTimeout()
|
||||
this.setVersionModalVisible({ isError: false })
|
||||
this.showUpdateModal()
|
||||
})
|
||||
rendererOn('update-not-available', () => {
|
||||
if (!this.updateTimeout) return
|
||||
if (this.setting.ignoreVersion) this.setSetting(Object.assign({}, this.setting, { ignoreVersion: null }))
|
||||
this.clearUpdateTimeout()
|
||||
this.setNewVersion({
|
||||
version: this.version.version,
|
||||
})
|
||||
})
|
||||
// 更新超时定时器
|
||||
this.updateTimeout = setTimeout(() => {
|
||||
this.updateTimeout = null
|
||||
this.setVersionModalVisible({ isError: true })
|
||||
this.$nextTick(() => {
|
||||
this.showUpdateModal()
|
||||
})
|
||||
}, 180000)
|
||||
|
||||
this.initData()
|
||||
this.globalObj.apiSource = this.setting.apiSource
|
||||
this.globalObj.proxy = Object.assign({}, this.setting.network.proxy)
|
||||
window.globalObj = this.globalObj
|
||||
},
|
||||
enableIgnoreMouseEvents() {
|
||||
@@ -167,8 +186,14 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
clearUpdateTimeout() {
|
||||
if (!this.updateTimeout) return
|
||||
clearTimeout(this.updateTimeout)
|
||||
this.updateTimeout = null
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.clearUpdateTimeout()
|
||||
if (this.isProd) {
|
||||
body.removeEventListener('mouseenter', this.dieableIgnoreMouseEvents)
|
||||
body.removeEventListener('mouseleave', this.enableIgnoreMouseEvents)
|
||||
@@ -204,6 +229,10 @@ body {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: @color-theme-bgimg center center no-repeat;
|
||||
background-size: auto 100%;
|
||||
transition: background-color @transition-theme;
|
||||
background-color: @color-theme;
|
||||
}
|
||||
|
||||
#left {
|
||||
@@ -214,6 +243,8 @@ body {
|
||||
flex: auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
transition: background-color @transition-theme;
|
||||
background-color: @color-theme_2;
|
||||
}
|
||||
#toolbar, #player {
|
||||
flex: none;
|
||||
@@ -222,5 +253,15 @@ body {
|
||||
flex: auto;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
#container.@{value} {
|
||||
background-color: ~'@{color-@{value}-theme}';
|
||||
background-image: ~'@{color-@{value}-theme-bgimg}';
|
||||
#right {
|
||||
background-color: ~'@{color-@{value}-theme_2}';
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
|
||||
|
||||
BIN
src/renderer/assets/images/jqbg.jpg
Normal file
BIN
src/renderer/assets/images/jqbg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
@@ -36,11 +36,11 @@ table {
|
||||
}
|
||||
tbody {
|
||||
tr {
|
||||
border-top: 1px solid #e0e0e0;
|
||||
border-top: 1px solid @color-theme_2-line;
|
||||
// border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
transition: background-color 0.2s ease;
|
||||
&:hover {
|
||||
background-color: #eee;
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
@@ -103,6 +103,10 @@ strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
svg {
|
||||
transition: @transition-theme;
|
||||
transition-property: fill;
|
||||
@@ -168,5 +172,15 @@ each(@themes, {
|
||||
background-color: ~'@{color-@{value}-scrollbar-thumb-hover}';
|
||||
}
|
||||
}
|
||||
table {
|
||||
tbody {
|
||||
tr {
|
||||
border-top-color: ~'@{color-@{value}-theme_2-line}';
|
||||
&:hover {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
@import './colors.less';
|
||||
|
||||
@themes: green, yellow, blue, red, purple, orange, grey;
|
||||
@themes: green, yellow, blue, red, purple, orange, grey, midAutumn;
|
||||
|
||||
|
||||
// Colors
|
||||
// @color-theme: #03a678;
|
||||
@color-theme: #4daf7c;
|
||||
@color-theme-bgimg: none;
|
||||
@color-theme-hover: fadeout(lighten(@color-theme, 10%), 30%);
|
||||
@color-theme-active: fadeout(darken(@color-theme, 20%), 60%);
|
||||
@color-theme-font: #fff;
|
||||
@color-theme-font-label: lighten(@color-theme, 35%);
|
||||
|
||||
@color-theme_2: #fff;
|
||||
@color-theme_2: rgba(255, 255, 255, .9);
|
||||
@color-theme_2-background_2: #fff;
|
||||
@color-theme_2-hover: fadeout(lighten(@color-theme, 10%), 70%);
|
||||
@color-theme_2-active: fadeout(darken(@color-theme, 5%), 70%);
|
||||
@color-theme_2-font: darken(@color-theme_2, 70%);
|
||||
@color-theme_2-font-label: lighten(@color-theme, 40%);
|
||||
@color-theme_2-font-label: fadeout(@color-theme_2-font, 50%);
|
||||
@color-theme_2-line: lighten(@color-theme, 35%);
|
||||
@color-theme-sidebar: @color-theme;
|
||||
@color-btn: fadeout(darken(@color-theme, 5%), 15%);
|
||||
@color-btn-background: fadeout(lighten(@color-theme, 35%), 70%);
|
||||
|
||||
@@ -41,6 +45,7 @@
|
||||
@color-player-status-text: lighten(@color-theme_2-font, 10%);
|
||||
|
||||
@color-tab-btn-background: fadeout(lighten(@color-theme, 10%), 80%);
|
||||
@color-tab-btn-background-hover: @color-theme_2-hover;
|
||||
@color-tab-border-top: fadeout(lighten(@color-theme, 5%), 50%);
|
||||
@color-tab-border-bottom: lighten(@color-theme, 5%);
|
||||
|
||||
@@ -50,15 +55,19 @@
|
||||
|
||||
|
||||
@color-green-theme: #4daf7c;
|
||||
@color-green-theme-bgimg: none;
|
||||
@color-green-theme-hover: fadeout(lighten(@color-green-theme, 10%), 30%);
|
||||
@color-green-theme-active: fadeout(darken(@color-green-theme, 20%), 60%);
|
||||
@color-green-theme-font: #fff;
|
||||
@color-green-theme-font-label: lighten(@color-green-theme, 35%);
|
||||
@color-green-theme_2: #fff;
|
||||
@color-green-theme_2-background_2: #fff;
|
||||
@color-green-theme_2-hover: fadeout(lighten(@color-green-theme, 10%), 70%);
|
||||
@color-green-theme_2-active: fadeout(darken(@color-green-theme, 5%), 70%);
|
||||
@color-green-theme_2-font: darken(@color-green-theme_2, 70%);
|
||||
@color-green-theme_2-font-label: lighten(@color-green-theme, 40%);
|
||||
@color-green-theme_2-font-label: fadeout(@color-green-theme_2-font, 50%);
|
||||
@color-green-theme_2-line: lighten(@color-green-theme, 35%);
|
||||
@color-green-theme-sidebar: @color-green-theme;
|
||||
@color-green-btn: fadeout(darken(@color-green-theme, 5%), 15%);
|
||||
@color-green-btn-background: fadeout(lighten(@color-green-theme, 35%), 70%);
|
||||
@color-green-pagination-background: fadeout(lighten(@color-green-theme, 45%), 30%);
|
||||
@@ -77,20 +86,25 @@
|
||||
@color-green-player-progress-bar2: lighten(@color-green-theme, 12%);
|
||||
@color-green-player-status-text: lighten(@color-green-theme_2-font, 10%);
|
||||
@color-green-tab-btn-background: fadeout(lighten(@color-green-theme, 10%), 80%);
|
||||
@color-green-tab-btn-background-hover: @color-green-theme_2-hover;
|
||||
@color-green-tab-border-top: fadeout(lighten(@color-green-theme, 5%), 50%);
|
||||
@color-green-tab-border-bottom: lighten(@color-green-theme, 5%);
|
||||
|
||||
|
||||
@color-yellow-theme: #f2d35b;
|
||||
@color-yellow-theme-bgimg: none;
|
||||
@color-yellow-theme-hover: fadeout(lighten(@color-yellow-theme, 10%), 30%);
|
||||
@color-yellow-theme-active: fadeout(darken(@color-yellow-theme, 20%), 60%);
|
||||
@color-yellow-theme-font: #fff;
|
||||
@color-yellow-theme-font-label: lighten(@color-yellow-theme, 35%);
|
||||
@color-yellow-theme_2: #fff;
|
||||
@color-yellow-theme_2-background_2: #fff;
|
||||
@color-yellow-theme_2-hover: fadeout(lighten(@color-yellow-theme, 10%), 70%);
|
||||
@color-yellow-theme_2-active: fadeout(darken(@color-yellow-theme, 5%), 70%);
|
||||
@color-yellow-theme_2-font: darken(@color-yellow-theme_2, 70%);
|
||||
@color-yellow-theme_2-font-label: lighten(@color-yellow-theme, 40%);
|
||||
@color-yellow-theme_2-font-label: fadeout(@color-yellow-theme_2-font, 50%);
|
||||
@color-yellow-theme_2-line: lighten(@color-yellow-theme, 35%);
|
||||
@color-yellow-theme-sidebar: @color-yellow-theme;
|
||||
@color-yellow-btn: fadeout(darken(@color-yellow-theme, 5%), 15%);
|
||||
@color-yellow-btn-background: fadeout(lighten(@color-yellow-theme, 25%), 70%);
|
||||
@color-yellow-pagination-background: fadeout(lighten(@color-yellow-theme, 30%), 30%);
|
||||
@@ -109,19 +123,24 @@
|
||||
@color-yellow-player-progress-bar2: lighten(@color-yellow-theme, 12%);
|
||||
@color-yellow-player-status-text: lighten(@color-yellow-theme_2-font, 10%);
|
||||
@color-yellow-tab-btn-background: fadeout(lighten(@color-yellow-theme, 10%), 80%);
|
||||
@color-yellow-tab-btn-background-hover: @color-yellow-theme_2-hover;
|
||||
@color-yellow-tab-border-top: fadeout(lighten(@color-yellow-theme, 5%), 50%);
|
||||
@color-yellow-tab-border-bottom: lighten(@color-yellow-theme, 5%);
|
||||
|
||||
@color-orange-theme: #f5ab35;
|
||||
@color-orange-theme-bgimg: none;
|
||||
@color-orange-theme-hover: fadeout(lighten(@color-orange-theme, 10%), 30%);
|
||||
@color-orange-theme-active: fadeout(darken(@color-orange-theme, 20%), 60%);
|
||||
@color-orange-theme-font: #fff;
|
||||
@color-orange-theme-font-label: lighten(@color-orange-theme, 35%);
|
||||
@color-orange-theme_2: #fff;
|
||||
@color-orange-theme_2-background_2: #fff;
|
||||
@color-orange-theme_2-hover: fadeout(lighten(@color-orange-theme, 10%), 70%);
|
||||
@color-orange-theme_2-active: fadeout(darken(@color-orange-theme, 5%), 70%);
|
||||
@color-orange-theme_2-font: darken(@color-orange-theme_2, 70%);
|
||||
@color-orange-theme_2-font-label: lighten(@color-orange-theme, 40%);
|
||||
@color-orange-theme_2-font-label: fadeout(@color-orange-theme_2-font, 50%);
|
||||
@color-orange-theme_2-line: lighten(@color-orange-theme, 35%);
|
||||
@color-orange-theme-sidebar: @color-orange-theme;
|
||||
@color-orange-btn: fadeout(darken(@color-orange-theme, 5%), 15%);
|
||||
@color-orange-btn-background: fadeout(lighten(@color-orange-theme, 35%), 70%);
|
||||
@color-orange-pagination-background: fadeout(lighten(@color-orange-theme, 35%), 30%);
|
||||
@@ -140,19 +159,24 @@
|
||||
@color-orange-player-progress-bar2: lighten(@color-orange-theme, 12%);
|
||||
@color-orange-player-status-text: lighten(@color-orange-theme_2-font, 10%);
|
||||
@color-orange-tab-btn-background: fadeout(lighten(@color-orange-theme, 10%), 80%);
|
||||
@color-orange-tab-btn-background-hover: @color-orange-theme_2-hover;
|
||||
@color-orange-tab-border-top: fadeout(lighten(@color-orange-theme, 5%), 50%);
|
||||
@color-orange-tab-border-bottom: lighten(@color-orange-theme, 5%);
|
||||
|
||||
@color-blue-theme: #3498db;
|
||||
@color-blue-theme-bgimg: none;
|
||||
@color-blue-theme-hover: fadeout(lighten(@color-blue-theme, 10%), 30%);
|
||||
@color-blue-theme-active: fadeout(darken(@color-blue-theme, 20%), 60%);
|
||||
@color-blue-theme-font: #fff;
|
||||
@color-blue-theme-font-label: lighten(@color-blue-theme, 35%);
|
||||
@color-blue-theme_2: #fff;
|
||||
@color-blue-theme_2-background_2: #fff;
|
||||
@color-blue-theme_2-hover: fadeout(lighten(@color-blue-theme, 10%), 70%);
|
||||
@color-blue-theme_2-active: fadeout(darken(@color-blue-theme, 5%), 70%);
|
||||
@color-blue-theme_2-font: darken(@color-blue-theme_2, 70%);
|
||||
@color-blue-theme_2-font-label: lighten(@color-blue-theme, 40%);
|
||||
@color-blue-theme_2-font-label: fadeout(@color-blue-theme_2-font, 50%);
|
||||
@color-blue-theme_2-line: lighten(@color-blue-theme, 35%);
|
||||
@color-blue-theme-sidebar: @color-blue-theme;
|
||||
@color-blue-btn: fadeout(darken(@color-blue-theme, 5%), 15%);
|
||||
@color-blue-btn-background: fadeout(lighten(@color-blue-theme, 35%), 70%);
|
||||
@color-blue-pagination-background: fadeout(lighten(@color-blue-theme, 40%), 30%);
|
||||
@@ -171,10 +195,12 @@
|
||||
@color-blue-player-progress-bar2: lighten(@color-blue-theme, 12%);
|
||||
@color-blue-player-status-text: lighten(@color-blue-theme_2-font, 10%);
|
||||
@color-blue-tab-btn-background: fadeout(lighten(@color-blue-theme, 10%), 80%);
|
||||
@color-blue-tab-btn-background-hover: @color-blue-theme_2-hover;
|
||||
@color-blue-tab-border-top: fadeout(lighten(@color-blue-theme, 5%), 50%);
|
||||
@color-blue-tab-border-bottom: lighten(@color-blue-theme, 5%);
|
||||
|
||||
@color-red-theme: #d64541;
|
||||
@color-red-theme-bgimg: none;
|
||||
@color-red-theme-hover: fadeout(lighten(@color-red-theme, 10%), 30%);
|
||||
@color-red-theme-active: fadeout(darken(@color-red-theme, 20%), 60%);
|
||||
@color-red-theme-font: #fff;
|
||||
@@ -182,8 +208,11 @@
|
||||
@color-red-theme_2: #fff;
|
||||
@color-red-theme_2-hover: fadeout(lighten(@color-red-theme, 10%), 70%);
|
||||
@color-red-theme_2-active: fadeout(darken(@color-red-theme, 5%), 70%);
|
||||
@color-red-theme_2-background_2: #fff;
|
||||
@color-red-theme_2-font: darken(@color-red-theme_2, 70%);
|
||||
@color-red-theme_2-font-label: lighten(@color-red-theme, 40%);
|
||||
@color-red-theme_2-font-label: fadeout(@color-red-theme_2-font, 50%);
|
||||
@color-red-theme_2-line: lighten(@color-red-theme, 35%);
|
||||
@color-red-theme-sidebar: @color-red-theme;
|
||||
@color-red-btn: fadeout(darken(@color-red-theme, 5%), 15%);
|
||||
@color-red-btn-background: fadeout(lighten(@color-red-theme, 35%), 70%);
|
||||
@color-red-pagination-background: fadeout(lighten(@color-red-theme, 40%), 30%);
|
||||
@@ -204,19 +233,24 @@
|
||||
@color-red-tab-border-top: fadeout(lighten(@color-red-theme, 25%), 70%);
|
||||
@color-red-tab-border-bottom: lighten(@color-red-theme, 35%);
|
||||
@color-red-tab-btn-background: fadeout(lighten(@color-red-theme, 10%), 80%);
|
||||
@color-red-tab-btn-background-hover: @color-red-theme_2-hover;
|
||||
@color-red-tab-border-top: fadeout(lighten(@color-red-theme, 5%), 50%);
|
||||
@color-red-tab-border-bottom: lighten(@color-red-theme, 5%);
|
||||
|
||||
@color-purple-theme: #9b59b6;
|
||||
@color-purple-theme-bgimg: none;
|
||||
@color-purple-theme-hover: fadeout(lighten(@color-purple-theme, 10%), 30%);
|
||||
@color-purple-theme-active: fadeout(darken(@color-purple-theme, 20%), 60%);
|
||||
@color-purple-theme-font: #fff;
|
||||
@color-purple-theme-font-label: lighten(@color-purple-theme, 35%);
|
||||
@color-purple-theme_2: #fff;
|
||||
@color-purple-theme_2-background_2: #fff;
|
||||
@color-purple-theme_2-hover: fadeout(lighten(@color-purple-theme, 10%), 70%);
|
||||
@color-purple-theme_2-active: fadeout(darken(@color-purple-theme, 5%), 70%);
|
||||
@color-purple-theme_2-font: darken(@color-purple-theme_2, 70%);
|
||||
@color-purple-theme_2-font-label: lighten(@color-purple-theme, 40%);
|
||||
@color-purple-theme_2-font-label: fadeout(@color-purple-theme_2-font, 50%);
|
||||
@color-purple-theme_2-line: lighten(@color-purple-theme, 35%);
|
||||
@color-purple-theme-sidebar: @color-purple-theme;
|
||||
@color-purple-btn: fadeout(darken(@color-purple-theme, 5%), 15%);
|
||||
@color-purple-btn-background: fadeout(lighten(@color-purple-theme, 35%), 70%);
|
||||
@color-purple-pagination-background: fadeout(lighten(@color-purple-theme, 40%), 30%);
|
||||
@@ -235,19 +269,24 @@
|
||||
@color-purple-player-progress-bar2: lighten(@color-purple-theme, 12%);
|
||||
@color-purple-player-status-text: lighten(@color-purple-theme_2-font, 10%);
|
||||
@color-purple-tab-btn-background: fadeout(lighten(@color-purple-theme, 10%), 80%);
|
||||
@color-purple-tab-btn-background-hover: @color-purple-theme_2-hover;
|
||||
@color-purple-tab-border-top: fadeout(lighten(@color-purple-theme, 5%), 50%);
|
||||
@color-purple-tab-border-bottom: lighten(@color-purple-theme, 5%);
|
||||
|
||||
@color-grey-theme: #6c7a89;
|
||||
@color-grey-theme-bgimg: none;
|
||||
@color-grey-theme-hover: fadeout(lighten(@color-grey-theme, 10%), 30%);
|
||||
@color-grey-theme-active: fadeout(darken(@color-grey-theme, 20%), 60%);
|
||||
@color-grey-theme-font: #fff;
|
||||
@color-grey-theme-font-label: lighten(@color-grey-theme, 35%);
|
||||
@color-grey-theme_2: #fff;
|
||||
@color-grey-theme_2-background_2: #fff;
|
||||
@color-grey-theme_2-hover: fadeout(lighten(@color-grey-theme, 10%), 70%);
|
||||
@color-grey-theme_2-active: fadeout(darken(@color-grey-theme, 5%), 70%);
|
||||
@color-grey-theme_2-font: darken(@color-grey-theme_2, 70%);
|
||||
@color-grey-theme_2-font-label: lighten(@color-grey-theme, 40%);
|
||||
@color-grey-theme_2-font-label: fadeout(@color-grey-theme_2-font, 50%);
|
||||
@color-grey-theme_2-line: lighten(@color-grey-theme, 35%);
|
||||
@color-grey-theme-sidebar: @color-grey-theme;
|
||||
@color-grey-btn: fadeout(darken(@color-grey-theme, 5%), 15%);
|
||||
@color-grey-btn-background: fadeout(lighten(@color-grey-theme, 35%), 70%);
|
||||
@color-grey-pagination-background: fadeout(lighten(@color-grey-theme, 45%), 30%);
|
||||
@@ -266,9 +305,46 @@
|
||||
@color-grey-player-progress-bar2: lighten(@color-grey-theme, 12%);
|
||||
@color-grey-player-status-text: lighten(@color-grey-theme_2-font, 10%);
|
||||
@color-grey-tab-btn-background: fadeout(lighten(@color-grey-theme, 10%), 80%);
|
||||
@color-grey-tab-btn-background-hover: @color-grey-theme_2-hover;
|
||||
@color-grey-tab-border-top: fadeout(lighten(@color-grey-theme, 5%), 50%);
|
||||
@color-grey-tab-border-bottom: lighten(@color-grey-theme, 5%);
|
||||
|
||||
@color-midAutumn-theme: rgba(74, 55, 82, 1);
|
||||
@color-midAutumn-theme-bgimg: url(../images/jqbg.jpg);
|
||||
@color-midAutumn-theme-hover: fadeout(lighten(@color-midAutumn-theme, 10%), 30%);
|
||||
@color-midAutumn-theme-active: fadeout(lighten(@color-midAutumn-theme, 15%), 60%);
|
||||
@color-midAutumn-theme-font: rgba(246, 233, 255, 0.9);
|
||||
@color-midAutumn-theme-font-label: fadeout(lighten(@color-midAutumn-theme, 20%), 20%);
|
||||
@color-midAutumn-theme_2: rgba(255, 255, 255, .93);
|
||||
@color-midAutumn-theme_2-background_2: #eeedef;
|
||||
@color-midAutumn-theme_2-hover: fadeout(lighten(@color-midAutumn-theme, 10%), 65%);
|
||||
@color-midAutumn-theme_2-active: fadeout(darken(@color-midAutumn-theme, 5%), 70%);
|
||||
@color-midAutumn-theme_2-font: darken(@color-midAutumn-theme_2, 70%);
|
||||
@color-midAutumn-theme_2-font-label: lighten(@color-midAutumn-theme, 40%);
|
||||
@color-midAutumn-theme_2-line: lighten(@color-midAutumn-theme, 54%);
|
||||
@color-midAutumn-theme-sidebar: rgba(255, 255, 255, 0);
|
||||
@color-midAutumn-btn: fadeout(darken(@color-midAutumn-theme, 5%), 15%);
|
||||
@color-midAutumn-btn-background: fadeout(lighten(@color-midAutumn-theme, 35%), 70%);
|
||||
@color-midAutumn-pagination-background: fadeout(lighten(@color-midAutumn-theme, 45%), 50%);
|
||||
@color-midAutumn-pagination-hover: fadeout(lighten(@color-midAutumn-theme, 10%), 70%);
|
||||
@color-midAutumn-pagination-active: fadeout(darken(@color-midAutumn-theme, 10%), 70%);
|
||||
@color-midAutumn-pagination-select: fadeout(lighten(@color-midAutumn-theme, 10%), 55%);
|
||||
@color-midAutumn-search-form-background: fadeout(lighten(@color-midAutumn-theme, 50%), 10%);
|
||||
@color-midAutumn-search-list-hover: fadeout(darken(@color-midAutumn-theme, 10%), 70%);
|
||||
@color-midAutumn-scrollbar-track: fadeout(@color-midAutumn-theme, 80%);
|
||||
@color-midAutumn-scrollbar-thumb: fadeout(@color-midAutumn-theme, 60%);
|
||||
@color-midAutumn-scrollbar-thumb-hover: fadeout(@color-midAutumn-theme, 40%);
|
||||
@color-midAutumn-player-pic-c1: fadeout(@color-midAutumn-theme_2, 50%);
|
||||
@color-midAutumn-player-pic-c2: darken(@color-midAutumn-theme_2, 30%);
|
||||
@color-midAutumn-player-progress: darken(@color-midAutumn-theme_2, 6%);
|
||||
@color-midAutumn-player-progress-bar1: darken(@color-midAutumn-theme_2, 12%);
|
||||
@color-midAutumn-player-progress-bar2: lighten(@color-midAutumn-theme, 12%);
|
||||
@color-midAutumn-player-status-text: lighten(@color-midAutumn-theme_2-font, 10%);
|
||||
@color-midAutumn-tab-btn-background: fadeout(lighten(@color-midAutumn-theme, 10%), 80%);
|
||||
@color-midAutumn-tab-btn-background-hover: @color-midAutumn-theme_2-hover;
|
||||
@color-midAutumn-tab-border-top: fadeout(lighten(@color-midAutumn-theme, 5%), 50%);
|
||||
@color-midAutumn-tab-border-bottom: lighten(@color-midAutumn-theme, 5%);
|
||||
|
||||
|
||||
// Width
|
||||
@width-app-left: 180px;
|
||||
|
||||
@@ -9,7 +9,7 @@ div(:class="$style.aside")
|
||||
dt 在线音乐
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="search") 搜索
|
||||
//- dd
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="songList") 歌单
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="leaderboard") 排行榜
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
// box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
transition: @transition-theme;
|
||||
transition-property: background-color;
|
||||
background-color: @color-theme;
|
||||
background-color: @color-theme-sidebar;
|
||||
// background-color: @color-aside-background;
|
||||
// border-right: 2px solid @color-theme;
|
||||
-webkit-app-region: drag;
|
||||
@@ -122,7 +122,7 @@ export default {
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.aside {
|
||||
background-color: ~'@{color-@{value}-theme}';
|
||||
background-color: ~'@{color-@{value}-theme-sidebar}';
|
||||
}
|
||||
.logo {
|
||||
color: ~'@{color-@{value}-theme-font}';
|
||||
|
||||
@@ -54,6 +54,20 @@ svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/19
|
||||
path(fill='currentColor' d='M219.791,152.899c-0.818,11.185-4.039,21.758-9.569,31.426c-3.635,6.354-1.43,14.452,4.919,18.087c2.082,1.187,4.34,1.751,6.576,1.751c4.599,0,9.062-2.393,11.517-6.675c7.508-13.138,11.889-27.491,12.986-42.663c1.714-23.397-4.836-46.781-18.455-65.845c-4.256-5.96-12.536-7.332-18.491-3.081c-5.959,4.259-7.337,12.531-3.08,18.491C216.218,118.425,221.055,135.653,219.791,152.899z')
|
||||
path(fill='currentColor' d='M290.7,158c3.34-45.736-16.508-89.592-53.097-117.318c-5.841-4.433-14.146-3.27-18.568,2.556c-4.428,5.838-3.283,14.151,2.558,18.568c29.401,22.281,45.355,57.521,42.668,94.252c-2.02,27.636-14.375,53.159-34.787,71.867c-5.396,4.95-5.758,13.339-0.808,18.729c2.609,2.854,6.188,4.298,9.771,4.298c3.194,0,6.41-1.154,8.953-3.484C272.805,224.175,288.184,192.408,290.7,158z')
|
||||
|
||||
|
||||
g#icon-sdCard
|
||||
// 0 0 291.13 291.13
|
||||
path(fill='currentColor' d="M 50.981 282.415 c 1.722 -2.372 5.494 -4.293 8.419 -4.293 h 172.331 c 2.92 0 6.695 1.921 8.419 4.293 l 6.339 8.715 h 41.74 V 18.538 C 288.23 8.298 279.929 0 269.698 0 H 48.988 L 2.9 49.632 V 291.13 h 41.744 L 50.981 282.415 Z M 240.348 27.418 c 0 -2.926 2.371 -5.302 5.302 -5.302 h 17.668 c 2.931 0 5.303 2.376 5.303 5.302 v 50.373 c 0 2.928 -2.372 5.302 -5.303 5.302 H 245.65 c -2.931 0 -5.302 -2.375 -5.302 -5.302 V 27.418 Z M 197.929 27.418 c 0 -2.926 2.371 -5.302 5.302 -5.302 h 17.668 c 2.931 0 5.303 2.376 5.303 5.302 v 50.373 c 0 2.928 -2.372 5.302 -5.303 5.302 h -17.668 c -2.931 0 -5.302 -2.375 -5.302 -5.302 V 27.418 Z M 155.509 27.418 c 0 -2.926 2.372 -5.302 5.303 -5.302 h 17.668 c 2.931 0 5.303 2.376 5.303 5.302 v 50.373 c 0 2.928 -2.372 5.302 -5.303 5.302 h -17.668 c -2.931 0 -5.303 -2.375 -5.303 -5.302 V 27.418 Z M 113.088 27.418 c 0 -2.926 2.376 -5.302 5.302 -5.302 h 17.673 c 2.926 0 5.303 2.376 5.303 5.302 v 50.373 c 0 2.928 -2.377 5.302 -5.303 5.302 H 118.39 c -2.926 0 -5.302 -2.375 -5.302 -5.302 V 27.418 Z M 70.668 27.418 c 0 -2.926 2.377 -5.302 5.303 -5.302 h 17.673 c 2.926 0 5.302 2.376 5.302 5.302 v 50.373 c 0 2.928 -2.376 5.302 -5.302 5.302 H 75.971 c -2.926 0 -5.303 -2.375 -5.303 -5.302 V 27.418 Z M 28.25 104.303 V 53.93 c 0 -2.926 2.377 -5.302 5.303 -5.302 h 17.673 c 2.925 0 5.302 2.376 5.302 5.302 v 50.373 c 0 2.928 -2.377 5.303 -5.302 5.303 H 33.552 C 30.626 109.605 28.25 107.231 28.25 104.303 Z")
|
||||
g#icon-musicFolder
|
||||
// 0 0 247.498 247.498
|
||||
path(fill='currentColor' d="M 0 200.188 c 0 14.645 11.871 26.513 26.512 26.513 h 194.475 c 14.639 0 26.512 -11.868 26.512 -26.513 V 86.192 c 0 -14.641 -11.873 -26.512 -26.512 -26.512 H 0 V 200.188 Z M 85.553 156.537 c 4.137 -0.869 8.2 -0.678 11.788 0.373 v -43.856 c 0 -3 2.11 -5.605 5.049 -6.224 l 53.047 -11.19 l 0.011 -0.005 c 0.196 -0.041 0.414 -0.041 0.621 -0.062 c 0.228 -0.021 0.445 -0.07 0.673 -0.07 c 0 0 0 0 0.011 0 c 0.093 0 0.171 0.021 0.259 0.025 c 0.331 0.011 0.663 0.034 0.984 0.102 c 0.201 0.041 0.383 0.111 0.579 0.171 c 0.197 0.062 0.404 0.106 0.601 0.184 c 0.207 0.091 0.404 0.207 0.606 0.318 c 0.155 0.085 0.315 0.155 0.471 0.256 c 0.182 0.117 0.337 0.269 0.508 0.407 c 0.155 0.121 0.311 0.228 0.445 0.362 c 0.146 0.143 0.27 0.311 0.404 0.471 c 0.124 0.153 0.269 0.295 0.383 0.471 c 0.135 0.197 0.238 0.414 0.342 0.621 c 0.088 0.153 0.176 0.295 0.254 0.456 c 0.14 0.323 0.238 0.668 0.326 1.012 c 0.01 0.065 0.041 0.122 0.062 0.186 v 0.006 c 0.042 0.223 0.052 0.46 0.073 0.688 c 0.021 0.202 0.062 0.404 0.062 0.604 c 0 0.005 0 0.005 0 0.01 v 58.148 c 0 0.367 -0.041 0.74 -0.113 1.103 c -0.135 8.196 -7.208 15.866 -17.233 17.999 c -11.319 2.413 -22.113 -3.2 -24.096 -12.521 c -1.983 -9.331 5.6 -18.838 16.93 -21.251 c 4.137 -0.87 8.202 -0.674 11.785 0.373 v -36.001 l -40.317 8.502 v 52.985 c 0 0.373 -0.042 0.74 -0.106 1.098 c -0.143 8.202 -7.216 15.876 -17.233 18.01 c -11.33 2.407 -22.121 -3.2 -24.104 -12.521 C 66.64 168.452 74.223 158.945 85.553 156.537 Z")
|
||||
g#icon-musicFile
|
||||
// -61 0 512 512
|
||||
path(fill='currentColor' d='m295 120.5h86.230469l-111.230469-111.695312v86.53125c0 13.875 11.214844 25.164062 25 25.164062zm0 0')
|
||||
path(fill='currentColor' d='m240 346.5c0 8.269531 6.730469 15 15 15s15-6.730469 15-15v-15.25h-15c-7.960938 0-15 6.324219-15 15.25zm0 0')
|
||||
path(fill='currentColor' d='m295 150.5c-30.328125 0-55-24.746094-55-55.167969v-95.332031h-185c-30.328125 0-55 24.746094-55 55.167969v401.667969c0 30.417968 24.671875 55.164062 55 55.164062h280c30.328125 0 55-24.746094 55-55.167969v-306.332031zm5 196c0 24.8125-20.1875 45-45 45s-45-20.1875-45-45c0-25.507812 20.53125-45.25 45-45.25h15v-56.144531l-90 22.59375v108.925781c0 24.8125-20.1875 45-45 45s-45-20.1875-45-45c0-25.507812 20.53125-45.25 45-45.25h15v-75.375c0-6.878906 4.675781-12.875 11.347656-14.546875l120-30.125c9.46875-2.382813 18.652344 4.796875 18.652344 14.546875zm0 0')
|
||||
path(fill='currentColor' d='m120 376.625c0 8.269531 6.730469 15 15 15s15-6.730469 15-15v-15.25h-15c-7.960938 0-15 6.324219-15 15.25zm0 0')
|
||||
g#icon-down
|
||||
// 0 0 451.847 451.847
|
||||
path(fill='currentColor' d='M225.923,354.706c-8.098,0-16.195-3.092-22.369-9.263L9.27,151.157c-12.359-12.359-12.359-32.397,0-44.751c12.354-12.354,32.388-12.354,44.748,0l171.905,171.915l171.906-171.909c12.359-12.354,32.391-12.354,44.744,0c12.365,12.354,12.365,32.392,0,44.751L248.292,345.449C242.115,351.621,234.018,354.706,225.923,354.706z')
|
||||
</template>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ div(:class="$style.player")
|
||||
div(:class="$style.right")
|
||||
div(:class="$style.column1")
|
||||
div(:class="$style.container")
|
||||
div(:class="$style.title") {{title}}
|
||||
div(:class="$style.title" @click="handleCopy(title)" :title="title + '(点击复制)'") {{title}}
|
||||
div(:class="$style.volumeContent")
|
||||
div(:class="$style.volume" @click.stop='handleChangeVolume' :title="`当前音量:${volumeStr}%`")
|
||||
div(:class="$style.volumeBar" :style="{ width: volumeStr + '%' }")
|
||||
@@ -48,7 +48,7 @@ div(:class="$style.player")
|
||||
<script>
|
||||
import Lyric from 'lrc-file-parser'
|
||||
import { rendererSend } from '../../../common/icp'
|
||||
import { formatPlayTime2, getRandom, checkPath, setTitle } from '../../utils'
|
||||
import { formatPlayTime2, getRandom, checkPath, setTitle, clipboardWriteText } from '../../utils'
|
||||
import { mapGetters, mapActions, mapMutations } from 'vuex'
|
||||
import { requestMsg } from '../../utils/message'
|
||||
|
||||
@@ -194,31 +194,17 @@ export default {
|
||||
// console.log('code', this.audio.error.code)
|
||||
if (!this.musicInfo.songmid) return
|
||||
console.log('出错')
|
||||
if (this.audio.error.code !== 1 && this.retryNum < 3) { // 若音频URL无效则尝试刷新3次URL
|
||||
this.stopPlay()
|
||||
if (this.listId != 'download' && this.audio.error.code !== 1 && this.retryNum < 3) { // 若音频URL无效则尝试刷新3次URL
|
||||
// console.log(this.retryNum)
|
||||
this.audioErrorTime = this.audio.currentTime // 记录出错的播放时间
|
||||
this.retryNum++
|
||||
this.setUrl(this.list[this.playIndex], true)
|
||||
this.status = 'URL过期,正在刷新URL...'
|
||||
return
|
||||
}
|
||||
this.stopPlay()
|
||||
this.sendProgressEvent(this.progress, 'error')
|
||||
|
||||
// let urls = this.player_info.targetSong.urls
|
||||
// if (urls && urls.some((url, index) => {
|
||||
// if (this.musicInfo.musicUrl.includes(url)) {
|
||||
// let newUrl = urls[index + 1]
|
||||
// if (!newUrl) return false
|
||||
// this.musicInfo.musicUrl = this.musicInfo.musicUrl.replace(url, newUrl)
|
||||
// // this.musicInfo.musicUrl = newUrl ? this.musicInfo.musicUrl.replace(url, newUrl) : this.setFormTag(this.musicInfo.musicUrl.replace(url, urls[0]))
|
||||
// return true
|
||||
// }
|
||||
// })) {
|
||||
// this.audio.src = this.musicInfo.musicUrl
|
||||
// // console.log(this.musicInfo.musicUrl)
|
||||
// } else {
|
||||
// this.handleNext()
|
||||
// }
|
||||
this.sendProgressEvent(this.progress, 'error')
|
||||
this.status = '音频加载出错,5 秒后切换下一首'
|
||||
this.addDelayNextTimeout()
|
||||
})
|
||||
@@ -277,6 +263,7 @@ export default {
|
||||
this.audioErrorTime = 0
|
||||
|
||||
if (this.listId == 'download') {
|
||||
console.log(targetSong.filePath)
|
||||
if (!checkPath(targetSong.filePath) || !targetSong.isComplate || /\.ape$/.test(targetSong.filePath)) {
|
||||
return this.list.length == 1 ? null : this.handleNext()
|
||||
}
|
||||
@@ -297,7 +284,7 @@ export default {
|
||||
}
|
||||
},
|
||||
checkDelayNextTimeout() {
|
||||
console.log(this.delayNextTimeout)
|
||||
// console.log(this.delayNextTimeout)
|
||||
if (this.delayNextTimeout) {
|
||||
clearTimeout(this.delayNextTimeout)
|
||||
this.delayNextTimeout = null
|
||||
@@ -384,7 +371,7 @@ export default {
|
||||
getPlayType(highQuality, songInfo) {
|
||||
switch (songInfo.source) {
|
||||
case 'wy':
|
||||
// case 'kg':
|
||||
case 'kg':
|
||||
return '128k'
|
||||
}
|
||||
let type = songInfo._types['192k'] ? '192k' : '128k'
|
||||
@@ -415,12 +402,12 @@ export default {
|
||||
}
|
||||
},
|
||||
setLrc(targetSong) {
|
||||
this.musicInfo.lrc = targetSong.lyric
|
||||
this.musicInfo.lrc = targetSong.lrc
|
||||
|
||||
let lrcP = this.musicInfo.lrc
|
||||
? Promise.resolve()
|
||||
: this.getLrc(targetSong).then(() => {
|
||||
this.musicInfo.lrc = targetSong.lyric
|
||||
this.musicInfo.lrc = targetSong.lrc
|
||||
})
|
||||
|
||||
lrcP
|
||||
@@ -428,8 +415,8 @@ export default {
|
||||
this.lyric.lrc.setLyric(this.musicInfo.lrc)
|
||||
if (this.isPlay && (this.musicInfo.url || this.listId == 'download')) this.lyric.lrc.play(this.audio.currentTime * 1000)
|
||||
})
|
||||
.catch(err => {
|
||||
this.status = err.message
|
||||
.catch(() => {
|
||||
this.status = '歌词获取失败'
|
||||
})
|
||||
},
|
||||
handleRemoveMusic() {
|
||||
@@ -469,6 +456,9 @@ export default {
|
||||
handleSaveVolume(volume) {
|
||||
this.setVolume(volume)
|
||||
},
|
||||
handleCopy(text) {
|
||||
clipboardWriteText(text)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -481,8 +471,7 @@ export default {
|
||||
height: @height-player;
|
||||
// background-color: rgb(245, 245, 245);
|
||||
transition: @transition-theme;
|
||||
transition-property: background-color, border-color;
|
||||
background-color: @color-theme_2;
|
||||
transition-property: border-color;
|
||||
border-top: 2px solid @color-theme;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
@@ -506,7 +495,7 @@ export default {
|
||||
max-height: 100%;
|
||||
transition: @transition-theme;
|
||||
transition-property: border-color;
|
||||
border: 2px solid @color-theme_2;
|
||||
border: 2px solid @color-theme_2-background_2;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
@@ -679,13 +668,12 @@ export default {
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.player {
|
||||
background-color: ~'@{color-@{value}-theme_2}';
|
||||
border-top-color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
.left {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
img {
|
||||
border-color: ~'@{color-@{value}-theme_2}';
|
||||
border-color: ~'@{color-@{value}-theme_2-background_2}';
|
||||
}
|
||||
}
|
||||
.play-btn {
|
||||
|
||||
@@ -48,7 +48,6 @@ export default {
|
||||
display: flex;
|
||||
height: @height-toolbar;
|
||||
justify-content: flex-end;
|
||||
background-color: @color-theme_2;
|
||||
align-items: center;
|
||||
padding-left: 15px;
|
||||
-webkit-app-region: drag;
|
||||
@@ -58,13 +57,6 @@ export default {
|
||||
.input {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.toolbar {
|
||||
background-color: ~'@{color-@{value}-theme_2}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// img {
|
||||
// flex: none;
|
||||
@@ -83,8 +75,14 @@ each(@themes, {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
-webkit-app-region: no-drag;
|
||||
&:hover {
|
||||
button:before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
width: @height-toolbar;
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -99,11 +97,18 @@ each(@themes, {
|
||||
content: ' ';
|
||||
display: block;
|
||||
border-radius: 50%;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
transition: opacity @transition-theme;
|
||||
}
|
||||
|
||||
&.min:after {
|
||||
background-color: @color-minBtn;
|
||||
}
|
||||
@@ -116,6 +121,7 @@ each(@themes, {
|
||||
|
||||
&.min:hover:after {
|
||||
background-color: lighten(@color-minBtn, 10%);
|
||||
opacity: 1;
|
||||
}
|
||||
&.max:hover:after {
|
||||
background-color: lighten(@color-maxBtn, 10%);
|
||||
@@ -125,4 +131,25 @@ each(@themes, {
|
||||
}
|
||||
}
|
||||
}
|
||||
.min {
|
||||
&:before {
|
||||
content: ' ';
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
left: @height-toolbar / 2 - 4;
|
||||
top: @height-toolbar / 2 - 1;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.close {
|
||||
&:before {
|
||||
content: '×';
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,6 @@ div(:class="$style.view")
|
||||
|
||||
.view {
|
||||
position: relative;
|
||||
background-color: @color-theme_2;
|
||||
> * {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
@@ -22,12 +21,4 @@ div(:class="$style.view")
|
||||
// overflow: hidden;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.view {
|
||||
background-color: ~'@{color-@{value}-theme_2}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
|
||||
@@ -156,7 +156,7 @@ export default {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid @color-theme_2-font-label;
|
||||
transition: border-color 0.2s ease;
|
||||
border-radius: 15%;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ each(@themes, {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
// border: 1px solid #ccc;
|
||||
&:after {
|
||||
border-color: #ccc;
|
||||
border-color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
||||
| {{ info.name }}
|
||||
br
|
||||
| {{ info.singer }}
|
||||
material-btn(:class="$style.btn" :title="!checkSource(type.type) && '目前网易云音源仅支持下载128k音质'" :disabled="!checkSource(type.type)" :key="type.type" @click="handleClick(type.type)" v-for="type in info.types") {{getTypeName(type.type)}} {{ type.type.toUpperCase() }}{{ type.size && ` - ${type.size.toUpperCase()}` }}
|
||||
material-btn(:class="$style.btn" :title="!checkSource(type.type) && '目前酷狗音源仅支持下载128k音质'" :disabled="!checkSource(type.type)" :key="type.type" @click="handleClick(type.type)" v-for="type in info.types") {{getTypeName(type.type)}} {{ type.type.toUpperCase() }}{{ type.size && ` - ${type.size.toUpperCase()}` }}
|
||||
|
||||
</template>
|
||||
|
||||
@@ -52,7 +52,7 @@ export default {
|
||||
checkSource(type) {
|
||||
switch (this.musicInfo.source) {
|
||||
case 'wy':
|
||||
// case 'kg':
|
||||
case 'kg':
|
||||
return type == '128k'
|
||||
|
||||
default:
|
||||
|
||||
90
src/renderer/components/material/Input.vue
Normal file
90
src/renderer/components/material/Input.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template lang="pug">
|
||||
input(:class="$style.input" :type="type" :placeholder="placeholder" v-model.trim="text" :disabled="disabled"
|
||||
@focus="$emit('focus', $event)" @blur="$emit('blur', $event)" @input="$emit('input', text)" @change="$emit('change', text)"
|
||||
@keyup.enter="submit")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: '',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(n) {
|
||||
this.text = n
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleInput() {
|
||||
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.input {
|
||||
display: inline-block;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
padding: 7px 8px;
|
||||
color: @color-btn;
|
||||
outline: none;
|
||||
transition: background-color 0.2s ease;
|
||||
background-color: @color-btn-background;
|
||||
&[disabled] {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
&:hover, &:focus {
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&:active {
|
||||
background-color: @color-theme_2-active;
|
||||
}
|
||||
}
|
||||
|
||||
.min {
|
||||
padding: 3px 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.input {
|
||||
color: ~'@{color-@{value}-btn}';
|
||||
background-color: ~'@{color-@{value}-btn-background}';
|
||||
&:hover, &:focus {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
}
|
||||
&:active {
|
||||
background-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -15,6 +15,9 @@ div(:class="$style.btns")
|
||||
button(type="button" v-if="pauseBtn" title="暂停" @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')
|
||||
use(xlink:href='#icon-pause')
|
||||
button(type="button" v-if="fileBtn" title="定位文件" @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')
|
||||
use(xlink:href='#icon-musicFile')
|
||||
button(type="button" v-if="removeBtn" title="移除" @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')
|
||||
use(xlink:href='#icon-delete')
|
||||
@@ -57,6 +60,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
fileBtn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo']),
|
||||
|
||||
@@ -34,8 +34,14 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['source']),
|
||||
...mapGetters('search', ['info']),
|
||||
...mapGetters(['route', 'setting']),
|
||||
...mapGetters('search', ['searchText']),
|
||||
isAutoClearInput() {
|
||||
return this.setting.odc.isAutoClearSearchInput
|
||||
},
|
||||
source() {
|
||||
return this.setting.search.tempSearchSource
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
list(n) {
|
||||
@@ -43,9 +49,12 @@ export default {
|
||||
this.listStyle.height = this.$refs.dom_list.scrollHeight + 'px'
|
||||
})
|
||||
},
|
||||
'info.text'(n) {
|
||||
'searchText'(n) {
|
||||
if (n !== this.text) this.text = n
|
||||
},
|
||||
route(n) {
|
||||
if (this.isAutoClearInput && n.name != 'search' && this.text) this.text = ''
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleTemplistClick(index) {
|
||||
@@ -70,16 +79,16 @@ export default {
|
||||
query: {
|
||||
text: this.text,
|
||||
},
|
||||
})
|
||||
}).catch(_ => _)
|
||||
},
|
||||
handleInput() {
|
||||
if (this.text === '') {
|
||||
this.list.splice(0, this.list.length)
|
||||
music[this.source.id].tempSearch.cancelTempSearch()
|
||||
music[this.source].tempSearch.cancelTempSearch()
|
||||
return
|
||||
}
|
||||
if (!this.isShow) this.showList()
|
||||
music[this.source.id].tempSearch.search(this.text).then(list => {
|
||||
music[this.source].tempSearch.search(this.text).then(list => {
|
||||
this.list = list
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
@@ -90,7 +90,7 @@ export default {
|
||||
border-left: 2px solid @color-tab-border-bottom;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-left-radius: 4px;
|
||||
color: @color-btn;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -108,7 +108,7 @@ export default {
|
||||
left: 0;
|
||||
border-bottom: 2px solid @color-tab-border-bottom;
|
||||
border-left: 2px solid @color-tab-border-bottom;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-left-radius: 4px;
|
||||
background-color: @color-theme_2;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
|
||||
235
src/renderer/components/material/SongList.vue
Normal file
235
src/renderer/components/material/SongList.vue
Normal file
@@ -0,0 +1,235 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.songList")
|
||||
transition(enter-active-class="animated fadeIn" leave-active-class="animated fadeOut")
|
||||
div(v-if="list.length" :class="$style.list")
|
||||
div(:class="$style.thead")
|
||||
table
|
||||
thead
|
||||
tr
|
||||
th.nobreak.center(style="width: 37px;")
|
||||
material-checkbox(id="search_select_all" v-model="isSelectAll" @change="handleSelectAllData"
|
||||
:indeterminate="isIndeterminate" :title="isSelectAll && !isIndeterminate ? '全不选' : '全选'")
|
||||
th.nobreak(style="width: 25%;") 歌曲名
|
||||
th.nobreak(style="width: 20%;") 歌手
|
||||
th.nobreak(style="width: 22%;") 专辑
|
||||
th.nobreak(style="width: 18%;") 操作
|
||||
th.nobreak(style="width: 10%;") 时长
|
||||
div.scroll(:class="$style.tbody" ref="dom_scrollContent")
|
||||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid' @click="handleDoubleClick(index)")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdList" @change="handleChangeSelect" :value="item")
|
||||
td.break(style="width: 25%;")
|
||||
| {{item.name}}
|
||||
span.badge.badge-info(v-if="item._types['320k']") 高品质
|
||||
span.badge.badge-success(v-if="item._types.ape || item._types.flac") 无损
|
||||
td.break(style="width: 20%;") {{item.singer}}
|
||||
td.break(style="width: 22%;") {{item.albumName}}
|
||||
td(style="width: 18%;")
|
||||
material-list-buttons(:index="index" :search-btn="true" :play-btn="item.source == 'kw' || (!isAPITemp && item.source != 'tx' && item.source != 'wy')" :download-btn="item.source == 'kw' || (!isAPITemp && item.source != 'tx' && item.source != 'wy')" :remove-btn="false" @btn-click="handleListBtnClick")
|
||||
//- button.btn-info(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k'] || item._types.flac" @click.stop='openDownloadModal(index)') 下载
|
||||
//- button.btn-secondary(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k']" @click.stop='testPlay(index)') 试听
|
||||
//- button.btn-success(type='button' v-if="(item._types['128k'] || item._types['192k'] || item._types['320k']) && userInfo" @click.stop='showListModal(index)') +
|
||||
td(style="width: 10%;") {{item.interval || '--/--'}}
|
||||
div(:class="$style.pagination")
|
||||
material-pagination(:count="total" :limit="limit" :page="page" @btn-click="handleTogglePage")
|
||||
div(v-else :class="$style.noitem")
|
||||
p(v-html="noItem")
|
||||
material-flow-btn(:show="isShowEditBtn && (source == 'kw' || !isAPITemp)" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { scrollTo } from '../../utils'
|
||||
export default {
|
||||
name: 'MaterialSongList',
|
||||
model: {
|
||||
prop: 'selectdData',
|
||||
event: 'input',
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
selectdData: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
},
|
||||
noItem: {
|
||||
type: String,
|
||||
default: '列表加载中...',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
isAPITemp() {
|
||||
return this.setting.apiSource == 'temp'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectdList(n) {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isShowEditBtn = true
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
}
|
||||
},
|
||||
selectdData(n) {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isShowEditBtn = true
|
||||
this.selectdList = [...n]
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
this.resetSelect()
|
||||
}
|
||||
},
|
||||
list(n) {
|
||||
this.resetSelect()
|
||||
if (!this.list.length) return
|
||||
this.$nextTick(() => scrollTo(this.$refs.dom_scrollContent, 0))
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
clickTime: 0,
|
||||
clickIndex: -1,
|
||||
isSelectAll: false,
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
selectdList: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleDoubleClick(index) {
|
||||
if (
|
||||
window.performance.now() - this.clickTime > 400 ||
|
||||
this.clickIndex !== index
|
||||
) {
|
||||
this.clickTime = window.performance.now()
|
||||
this.clickIndex = index
|
||||
return
|
||||
}
|
||||
this.emitEvent((this.source == 'kw' || (!this.isAPITemp && this.list[index].source != 'tx' && this.list[index].source != 'wy')) ? 'testPlay' : 'search', index)
|
||||
this.clickTime = 0
|
||||
this.clickIndex = -1
|
||||
},
|
||||
handleListBtnClick(info) {
|
||||
this.emitEvent('listBtnClick', info)
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdList = isSelect ? [...this.list] : []
|
||||
this.$emit('input', [...this.selectdList])
|
||||
},
|
||||
resetSelect() {
|
||||
this.selectdList = false
|
||||
this.selectdList = []
|
||||
},
|
||||
handleTogglePage(page) {
|
||||
this.emitEvent('togglePage', page)
|
||||
},
|
||||
handleFlowBtnClick(action) {
|
||||
this.emitEvent('flowBtnClick', action)
|
||||
},
|
||||
emitEvent(action, data) {
|
||||
this.$emit('action', { action, data })
|
||||
},
|
||||
handleChangeSelect() {
|
||||
this.$emit('input', [...this.selectdList])
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
.song-list {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.list {
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
.thead {
|
||||
flex: none;
|
||||
}
|
||||
.tbody {
|
||||
flex: auto;
|
||||
overflow-y: auto;
|
||||
td {
|
||||
font-size: 12px;
|
||||
:global(.badge) {
|
||||
margin-right: 3px;
|
||||
&:first-child {
|
||||
margin-left: 3px;
|
||||
}
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.pagination {
|
||||
text-align: center;
|
||||
padding: 15px 0;
|
||||
// left: 50%;
|
||||
// transform: translateX(-50%);
|
||||
}
|
||||
.noitem {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
p {
|
||||
font-size: 24px;
|
||||
color: @color-theme_2-font-label;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.noitem {
|
||||
p {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
@@ -95,15 +95,15 @@ export default {
|
||||
margin-left: 0;
|
||||
button {
|
||||
border-top-left-radius: 3px;
|
||||
// border-bottom-left-radius: 3px;
|
||||
// border-bottom-left-radius: 4px;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
border-right: 2px solid @color-tab-border-top;
|
||||
border-top-right-radius: 3px;
|
||||
border-top-right-radius: 4px;
|
||||
button {
|
||||
border-top-right-radius: 3px;
|
||||
// border-bottom-right-radius: 3px;
|
||||
// border-bottom-right-radius: 4px;
|
||||
}
|
||||
}
|
||||
button {
|
||||
@@ -122,7 +122,7 @@ export default {
|
||||
// border-left-color: @color-theme_2-hover;
|
||||
// border-right-color: @color-theme_2-hover;
|
||||
button {
|
||||
background-color: @color-theme_2-hover;
|
||||
background-color: @color-tab-btn-background-hover;
|
||||
}
|
||||
}
|
||||
&:active {
|
||||
@@ -133,7 +133,7 @@ export default {
|
||||
}
|
||||
}
|
||||
&.active {
|
||||
border-bottom-color: @color-theme_2;
|
||||
border-bottom-color: @color-theme_2-background_2;
|
||||
border-top-color: @color-tab-border-bottom;
|
||||
border-left-color: @color-tab-border-bottom;
|
||||
border-right-color: @color-tab-border-bottom;
|
||||
@@ -144,7 +144,7 @@ export default {
|
||||
width: 0;
|
||||
}
|
||||
button {
|
||||
background-color: @color-theme_2;
|
||||
background-color: @color-theme_2-background_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,7 +193,7 @@ each(@themes, {
|
||||
// border-left-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
// border-right-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
button {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
background-color: ~'@{color-@{value}-tab-btn-background-hover}';
|
||||
}
|
||||
}
|
||||
&:active {
|
||||
@@ -209,7 +209,7 @@ each(@themes, {
|
||||
border-left-color: ~'@{color-@{value}-tab-border-bottom}';
|
||||
border-right-color: ~'@{color-@{value}-tab-border-bottom}';
|
||||
button {
|
||||
background-color: ~'@{color-@{value}-theme_2}';
|
||||
background-color: ~'@{color-@{value}-theme_2-background_2}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
240
src/renderer/components/material/TagList.vue
Normal file
240
src/renderer/components/material/TagList.vue
Normal file
@@ -0,0 +1,240 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.tagList")
|
||||
div(:class="$style.label" ref="dom_btn" @click="handleShow")
|
||||
span {{value.name}}
|
||||
div(:class="[$style.icon, show ? $style.active : '']")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.847 451.847' space='preserve')
|
||||
use(xlink:href='#icon-down')
|
||||
div.scroll(:class="$style.list" @click.stop ref="dom_list" :style="listStyle")
|
||||
div(:class="$style.tag" @click="handleClick(null)") 默认
|
||||
dl(v-for="type in list")
|
||||
dt(:class="$style.type") {{type.name}}
|
||||
dd(:class="$style.tag" v-for="tag in type.list" @click="handleClick(tag)") {{tag.name}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isChildren } from '../../utils'
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
listStyle: {
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(n) {
|
||||
this.$nextTick(() => {
|
||||
if (n) {
|
||||
let sh = this.$refs.dom_list.scrollHeight
|
||||
this.listStyle.height = (sh > 250 ? 250 : sh) + 'px'
|
||||
this.listStyle.opacity = 1
|
||||
this.listStyle.overflow = 'auto'
|
||||
} else {
|
||||
this.listStyle.height = 0
|
||||
this.listStyle.opacity = 0
|
||||
}
|
||||
})
|
||||
},
|
||||
list() {
|
||||
this.$refs.dom_list.scrollTop = 0
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener('click', this.handleHide)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('click', this.handleHide)
|
||||
},
|
||||
methods: {
|
||||
handleHide(e) {
|
||||
// if (e && e.target.parentNode != this.$refs.dom_list && this.show) return this.show = false
|
||||
if (e && (e.target == this.$refs.dom_btn || isChildren(this.$refs.dom_btn, e.target))) return
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
}, 50)
|
||||
},
|
||||
handleClick(item) {
|
||||
if (!item) {
|
||||
item = {
|
||||
name: '默认',
|
||||
id: null,
|
||||
}
|
||||
}
|
||||
if (item.id === this.value.id) return this.handleShow()
|
||||
this.$emit('input', item)
|
||||
this.$emit('change', item)
|
||||
this.handleShow()
|
||||
},
|
||||
handleShow() {
|
||||
this.show = !this.show
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.tag-list {
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.label {
|
||||
padding: 8px 15px;
|
||||
// background-color: @color-btn-background;
|
||||
transition: background-color @transition-theme;
|
||||
border-top: 2px solid @color-tab-border-bottom;
|
||||
// border-left: 2px solid @color-tab-border-bottom;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
// border-top-left-radius: 3px;
|
||||
color: @color-btn;
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
|
||||
span {
|
||||
flex: auto;
|
||||
}
|
||||
.icon {
|
||||
flex: none;
|
||||
margin-left: 7px;
|
||||
line-height: 0;
|
||||
svg {
|
||||
width: 1em;
|
||||
transition: transform .2s ease;
|
||||
transform: rotate(0);
|
||||
}
|
||||
&.active {
|
||||
svg{
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&:active {
|
||||
background-color: @color-theme_2-active;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
width: 646px;
|
||||
left: 0;
|
||||
border-bottom: 2px solid @color-tab-border-bottom;
|
||||
border-right: 2px solid @color-tab-border-bottom;
|
||||
border-bottom-right-radius: 5px;
|
||||
background-color: @color-theme_2;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
transition: .25s ease;
|
||||
transition-property: height, opacity;
|
||||
z-index: 10;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
|
||||
li {
|
||||
cursor: pointer;
|
||||
padding: 8px 15px;
|
||||
// color: @color-btn;
|
||||
text-align: center;
|
||||
outline: none;
|
||||
transition: background-color @transition-theme;
|
||||
background-color: @color-btn-background;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&:active {
|
||||
background-color: @color-theme_2-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.type {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 3px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
background-color: @color-btn-background;
|
||||
padding: 8px 10px;
|
||||
border-radius: @radius-progress-border;
|
||||
transition: background-color @transition-theme;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&:active {
|
||||
background-color: @color-theme_2-active;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.label {
|
||||
border-top-color: ~'@{color-@{value}-tab-border-bottom}';
|
||||
// border-left-color: ~'@{color-@{value}-tab-border-bottom}';
|
||||
color: ~'@{color-@{value}-btn}';
|
||||
&:hover {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
}
|
||||
&:active {
|
||||
background-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
border-bottom-color: ~'@{color-@{value}-tab-border-bottom}';
|
||||
border-right-color: ~'@{color-@{value}-tab-border-bottom}';
|
||||
// border-left-color: ~'@{color-@{value}-tab-border-bottom}';
|
||||
li {
|
||||
// color: ~'@{color-@{value}-btn}';
|
||||
background-color: ~'@{color-@{value}-btn-background}';
|
||||
&:hover {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
}
|
||||
&:active {
|
||||
background-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tag {
|
||||
background-color: ~'@{color-@{value}-btn-background}';
|
||||
&:hover {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
}
|
||||
&:active {
|
||||
background-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="version.showModal" @close="handleClose")
|
||||
main(:class="$style.main" v-if="version.newVersion")
|
||||
h2 {{ version.isError ? '🌟发现新版本🌟' : '🚀程序更新🚀'}}
|
||||
h2 {{ version.isError ? (isUnknow ? '❓ 版本信息获取失败 ❓' : '🌟发现新版本🌟') : '🚀程序更新🚀'}}
|
||||
|
||||
div.scroll(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
@@ -16,15 +16,14 @@ material-modal(:show="version.showModal" @close="handleClose")
|
||||
p(v-html="ver.desc")
|
||||
|
||||
div(:class="$style.footer" v-if="version.isError")
|
||||
div(:class="$style.desc")
|
||||
div(:class="$style.desc" v-if="!isUnknow")
|
||||
p 发现有新版本啦,但是自动更新功能出问题了
|
||||
p
|
||||
| 如果你所用的软件是
|
||||
strong 安装版
|
||||
| ,可以到QQ群:830125506 反馈哦
|
||||
p
|
||||
| 你现在可以选择继续使用当前版本或
|
||||
strong 去发布页下载新版本
|
||||
| ,推荐到
|
||||
strong 网盘
|
||||
| 下载
|
||||
div(:class="$style.btns")
|
||||
material-btn(:class="$style.btn" @click.onec="handleIgnoreClick") 忽略该版本
|
||||
material-btn(:class="$style.btn" @click.onec="handleOpenPageClick") 去下载新版本
|
||||
@@ -59,6 +58,9 @@ export default {
|
||||
|
||||
return arr
|
||||
},
|
||||
isUnknow() {
|
||||
return this.version.newVersion.version == '0.0.0'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setVersionModalVisible', 'setSetting']),
|
||||
@@ -73,7 +75,7 @@ export default {
|
||||
this.setSetting(Object.assign({}, this.setting, { ignoreVersion: this.version.newVersion.version }))
|
||||
},
|
||||
handleOpenPageClick() {
|
||||
openUrl('https://github.com/lyswhut/lx-music-desktop')
|
||||
openUrl('https://github.com/lyswhut/lx-music-desktop#readme')
|
||||
},
|
||||
handleRestartClick(event) {
|
||||
this.handleClose()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Vue from 'vue'
|
||||
// import { sync } from 'vuex-router-sync'
|
||||
import { sync } from 'vuex-router-sync'
|
||||
|
||||
// Components
|
||||
import './components'
|
||||
@@ -11,7 +11,7 @@ import App from './App'
|
||||
import router from './route'
|
||||
import store from './store'
|
||||
|
||||
// sync(store, router)
|
||||
sync(store, router)
|
||||
|
||||
if (!process.env.IS_WEB) {
|
||||
|
||||
|
||||
@@ -6,7 +6,13 @@ export default {
|
||||
getVersionInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
httpGet(`https://raw.githubusercontent.com/${author.name}/${name}/master/publish/version.json`, (err, resp, body) => {
|
||||
if (err) return reject(err)
|
||||
if (err) {
|
||||
return resolve({
|
||||
version: '0.0.0',
|
||||
desc: '<h3>版本信息获取失败</h3><ul><li>更新信息获取失败,可能是无法访问Github导致的,请手动检查更新!</li><li>检查方法:去设置-关于洛雪音乐打开<strong>开源地址</strong>或<strong>网盘地址</strong>查看<strong>版本号</strong>与当前版本对比是否最新</li></ul>',
|
||||
history: [],
|
||||
})
|
||||
}
|
||||
resolve(body)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -31,4 +31,7 @@ export default {
|
||||
version(state) {
|
||||
return state.version
|
||||
},
|
||||
route(state) {
|
||||
return state.route
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import fs from 'fs'
|
||||
import path from 'path'
|
||||
import music from '../../utils/music'
|
||||
import { getMusicType } from '../../utils/music/utils'
|
||||
import { setMeta, saveLrc } from '../../utils'
|
||||
|
||||
// state
|
||||
const state = {
|
||||
@@ -21,6 +22,8 @@ const state = {
|
||||
const dls = {}
|
||||
const tryNum = {}
|
||||
|
||||
const filterFileName = /[\\/:*?#"<>|]/g
|
||||
|
||||
// getters
|
||||
const getters = {
|
||||
list: state => state.list || [],
|
||||
@@ -75,6 +78,43 @@ const getUrl = (downloadInfo, isRefresh) => {
|
||||
return url && !isRefresh ? Promise.resolve({ url }) : music[downloadInfo.musicInfo.source].getMusicUrl(downloadInfo.musicInfo, downloadInfo.type).promise
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置歌曲meta信息
|
||||
* @param {*} downloadInfo
|
||||
* @param {*} filePath
|
||||
* @param {*} isEmbedPic
|
||||
*/
|
||||
const saveMeta = (downloadInfo, filePath, isEmbedPic) => {
|
||||
if (downloadInfo.type === 'ape' || downloadInfo.type === 'flac') return
|
||||
const promise = isEmbedPic
|
||||
? downloadInfo.musicInfo.img
|
||||
? Promise.resolve(downloadInfo.musicInfo.img)
|
||||
: music[downloadInfo.musicInfo.source].getPic(downloadInfo.musicInfo).promise
|
||||
: Promise.resolve()
|
||||
promise.then(url => {
|
||||
setMeta(filePath, {
|
||||
title: downloadInfo.musicInfo.name,
|
||||
artist: downloadInfo.musicInfo.singer,
|
||||
album: downloadInfo.musicInfo.albumName,
|
||||
APIC: url,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存歌词
|
||||
* @param {*} downloadInfo
|
||||
* @param {*} filePath
|
||||
*/
|
||||
const downloadLyric = (downloadInfo, filePath) => {
|
||||
const promise = downloadInfo.musicInfo.lrc
|
||||
? Promise.resolve(downloadInfo.musicInfo.lrc)
|
||||
: music[downloadInfo.musicInfo.source].getLyric(downloadInfo.musicInfo).promise
|
||||
promise.then(lrc => {
|
||||
if (lrc) saveLrc(filePath.replace(/(mp3|flac|ape)$/, 'lrc'), lrc)
|
||||
})
|
||||
}
|
||||
|
||||
// actions
|
||||
const actions = {
|
||||
createDownload({ state, rootState, commit }, { musicInfo, type }) {
|
||||
@@ -87,7 +127,7 @@ const actions = {
|
||||
url: null,
|
||||
fileName: `${rootState.setting.download.fileName
|
||||
.replace('歌名', musicInfo.name)
|
||||
.replace('歌手', musicInfo.singer)}.${ext}`,
|
||||
.replace('歌手', musicInfo.singer)}.${ext}`.replace(filterFileName, ''),
|
||||
progress: {
|
||||
downloaded: 0,
|
||||
total: 0,
|
||||
@@ -133,8 +173,16 @@ const actions = {
|
||||
method: 'get',
|
||||
override: true,
|
||||
onEnd() {
|
||||
if (downloadInfo.progress.progress != '100.00') {
|
||||
delete dls[downloadInfo.key]
|
||||
return this.dispatch('download/startTask', downloadInfo)
|
||||
}
|
||||
commit('onEnd', downloadInfo)
|
||||
_this.dispatch('download/startTask')
|
||||
const filePath = path.join(options.path, options.fileName)
|
||||
|
||||
saveMeta(downloadInfo, filePath, rootState.setting.download.isEmbedPic)
|
||||
if (rootState.setting.download.isDownloadLrc) downloadLyric(downloadInfo, filePath)
|
||||
console.log('on complate')
|
||||
},
|
||||
onError(err) {
|
||||
|
||||
@@ -62,7 +62,7 @@ const mutations = {
|
||||
datas.musicInfo.img = datas.url
|
||||
},
|
||||
setLrc(state, datas) {
|
||||
datas.musicInfo.lyric = datas.lrc
|
||||
datas.musicInfo.lrc = datas.lrc
|
||||
},
|
||||
setList(state, { list, listId, index }) {
|
||||
state.list = list
|
||||
|
||||
@@ -1,41 +1,103 @@
|
||||
import music from '../../utils/music'
|
||||
const sources = []
|
||||
const sourceList = {}
|
||||
const sourceMaxPage = {}
|
||||
for (const source of music.sources) {
|
||||
const musicSearch = music[source.id].musicSearch
|
||||
if (!musicSearch) continue
|
||||
sources.push(source)
|
||||
sourceList[source.id] = {
|
||||
page: 1,
|
||||
allPage: 0,
|
||||
limit: 30,
|
||||
total: 0,
|
||||
list: [],
|
||||
}
|
||||
sourceMaxPage[source.id] = 0
|
||||
}
|
||||
|
||||
sources.push({
|
||||
id: 'all',
|
||||
name: '聚合搜索',
|
||||
})
|
||||
|
||||
// state
|
||||
const state = {
|
||||
sourceList,
|
||||
list: [],
|
||||
text: '',
|
||||
page: 1,
|
||||
limit: 30,
|
||||
allPage: 1,
|
||||
total: 0,
|
||||
sourceMaxPage,
|
||||
}
|
||||
|
||||
// getters
|
||||
const getters = {
|
||||
list: state => state.list || [],
|
||||
limit: state => state.limit,
|
||||
info: state => ({ page: state.page, text: state.text }),
|
||||
listInfo: state => ({ allPage: state.allPage, total: state.total }),
|
||||
sources: () => sources,
|
||||
sourceList: state => state.sourceList || [],
|
||||
searchText: state => state.text,
|
||||
allList: state => ({ list: state.list, allPage: state.allPage, page: state.page, total: state.total, limit: state.limit, sourceMaxPage: state.sourceMaxPage }),
|
||||
}
|
||||
|
||||
// actions
|
||||
const actions = {
|
||||
search({ commit, rootState }, { text, page, limit }) {
|
||||
return music[rootState.setting.sourceId].musicSearch.search(text, page, limit)
|
||||
.then(data => commit('setList', { list: data.list, allPage: data.allPage, total: data.total, text, page }))
|
||||
if (rootState.setting.search.searchSource == 'all') {
|
||||
let task = []
|
||||
for (const source of sources) {
|
||||
if (source.id == 'all') continue
|
||||
task.push(music[source.id].musicSearch.search(text, page))
|
||||
}
|
||||
Promise.all(task).then(results => commit('setLists', { results, text, page }))
|
||||
} else {
|
||||
return music[rootState.setting.search.searchSource].musicSearch.search(text, page, limit)
|
||||
.then(data => commit('setList', { text, page, ...data }))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// mitations
|
||||
const mutations = {
|
||||
setList(state, datas) {
|
||||
state.list = datas.list
|
||||
state.total = datas.total
|
||||
state.allPage = datas.allPage
|
||||
state.page = datas.page
|
||||
let source = state.sourceList[datas.source]
|
||||
source.list = datas.list
|
||||
source.total = datas.total
|
||||
source.allPage = datas.allPage
|
||||
source.page = datas.page
|
||||
source.limit = datas.limit
|
||||
state.text = datas.text
|
||||
},
|
||||
setLists(state, { results, text, page }) {
|
||||
let pages = []
|
||||
let total = 0
|
||||
let limit = 0
|
||||
let list = []
|
||||
for (const source of results) {
|
||||
state.sourceMaxPage[source.source] = source.allPage
|
||||
if (source.allPage < page) continue
|
||||
list.push(...source.list)
|
||||
pages.push(source.allPage)
|
||||
total += source.total
|
||||
limit += source.limit
|
||||
}
|
||||
list.sort((a, b) => b.name.charCodeAt(0) - a.name.charCodeAt(0))
|
||||
state.allPage = Math.max(...pages)
|
||||
state.total = total
|
||||
state.limit = limit
|
||||
state.page = page
|
||||
state.text = text
|
||||
state.list = list
|
||||
},
|
||||
clearList(state) {
|
||||
for (const source of Object.keys(state.sourceList)) {
|
||||
state.sourceList[source].list.length = 0
|
||||
state.sourceList[source].page = 0
|
||||
state.sourceList[source].allPage = 0
|
||||
state.sourceList[source].total = 0
|
||||
state.sourceMaxPage[source] = 0
|
||||
}
|
||||
state.list.length = 0
|
||||
state.page = 0
|
||||
state.allPage = 0
|
||||
|
||||
110
src/renderer/store/modules/songList.js
Normal file
110
src/renderer/store/modules/songList.js
Normal file
@@ -0,0 +1,110 @@
|
||||
import music from '../../utils/music'
|
||||
const sortList = {}
|
||||
const sources = []
|
||||
for (const source of music.sources) {
|
||||
const songList = music[source.id].songList
|
||||
if (!songList) continue
|
||||
sortList[source.id] = songList.sortList
|
||||
sources.push(source)
|
||||
}
|
||||
|
||||
// state
|
||||
const state = {
|
||||
tags: {},
|
||||
list: {
|
||||
list: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
limit: 30,
|
||||
key: null,
|
||||
},
|
||||
listDetail: {
|
||||
list: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
limit: 30,
|
||||
key: null,
|
||||
},
|
||||
selectListInfo: {},
|
||||
isVisibleListDetail: false,
|
||||
}
|
||||
|
||||
sources.forEach(source => {
|
||||
state.tags[source.id] = null
|
||||
})
|
||||
|
||||
|
||||
// getters
|
||||
const getters = {
|
||||
sourceInfo: () => ({ sources, sortList }),
|
||||
tags: state => state.tags,
|
||||
isVisibleListDetail: state => state.isVisibleListDetail,
|
||||
selectListInfo: state => state.selectListInfo,
|
||||
listData(state) {
|
||||
return state.list
|
||||
},
|
||||
listDetail(state) {
|
||||
return state.listDetail
|
||||
},
|
||||
}
|
||||
|
||||
// actions
|
||||
const actions = {
|
||||
getTags({ state, rootState, commit }) {
|
||||
let source = rootState.setting.songList.source
|
||||
return music[source].songList.getTags().then(result => commit('setTags', { tags: result, source }))
|
||||
},
|
||||
getList({ state, rootState, commit }, page) {
|
||||
let source = rootState.setting.songList.source
|
||||
let tabId = rootState.setting.songList.tagInfo.id
|
||||
let sortId = rootState.setting.songList.sortId
|
||||
// console.log(sortId)
|
||||
let key = `${source}${sortId}${tabId}${page}`
|
||||
if (state.list.list.length && state.list.key == key) return true
|
||||
return music[source].songList.getList(sortId, tabId, page).then(result => commit('setList', { result, key, page }))
|
||||
},
|
||||
getListDetail({ state, rootState, commit }, { id, page }) {
|
||||
let source = rootState.setting.songList.source
|
||||
let key = `${source}${id}${page}`
|
||||
if (state.listDetail.list.length && state.listDetail.key == key) return true
|
||||
return music[source].songList.getListDetail(id, page).then(result => commit('setListDetail', { result, key, page }))
|
||||
},
|
||||
}
|
||||
|
||||
// mitations
|
||||
const mutations = {
|
||||
setTags(state, { tags, source }) {
|
||||
state.tags[source] = tags
|
||||
},
|
||||
setList(state, { result, key, page }) {
|
||||
state.list.list = result.list
|
||||
state.list.total = result.total
|
||||
state.list.limit = result.limit
|
||||
state.list.page = page
|
||||
state.list.key = key
|
||||
},
|
||||
setListDetail(state, { result, key, page }) {
|
||||
state.listDetail.list = result.list
|
||||
state.listDetail.total = result.total
|
||||
state.listDetail.limit = result.limit
|
||||
state.listDetail.page = page
|
||||
state.listDetail.key = key
|
||||
},
|
||||
setVisibleListDetail(state, bool) {
|
||||
state.isVisibleListDetail = bool
|
||||
},
|
||||
setSelectListInfo(state, info) {
|
||||
state.selectListInfo = info
|
||||
},
|
||||
clearListDetail(state) {
|
||||
state.listDetail.list = []
|
||||
},
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations,
|
||||
}
|
||||
@@ -2,8 +2,9 @@ export default {
|
||||
setTheme(state, val) {
|
||||
state.setting.themeId = val
|
||||
},
|
||||
setSource(state, val) {
|
||||
state.setting.sourceId = val
|
||||
setSearchSource(state, { searchSource, tempSearchSource }) {
|
||||
if (searchSource != null) state.setting.search.searchSource = searchSource
|
||||
if (tempSearchSource != null) state.setting.search.tempSearchSource = tempSearchSource
|
||||
},
|
||||
setSetting(state, val) {
|
||||
state.setting = val
|
||||
@@ -12,6 +13,11 @@ export default {
|
||||
if (tabId != null) state.setting.leaderboard.tabId = tabId
|
||||
if (source != null) state.setting.leaderboard.source = source
|
||||
},
|
||||
setSongList(state, { sortId, tagInfo, source }) {
|
||||
if (tagInfo != null) state.setting.songList.tagInfo = tagInfo
|
||||
if (sortId != null) state.setting.songList.sortId = sortId
|
||||
if (source != null) state.setting.songList.source = source
|
||||
},
|
||||
setNewVersion(state, val) {
|
||||
// val.history.forEach(ver => {
|
||||
// ver.desc = ver.desc.replace(/\n/g, '<br>')
|
||||
|
||||
@@ -44,6 +44,11 @@ export default {
|
||||
name: '灰常美丽',
|
||||
class: 'grey',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: '月里嫦娥',
|
||||
class: 'midAutumn',
|
||||
},
|
||||
],
|
||||
version: {
|
||||
version,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import fs from 'fs'
|
||||
import { shell, remote } from 'electron'
|
||||
import { shell, remote, clipboard } from 'electron'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
import crypto from 'crypto'
|
||||
import { rendererSend } from '../../common/icp'
|
||||
|
||||
/**
|
||||
* 获取两个数之间的随机整数,大于等于min,小于max
|
||||
@@ -42,6 +43,7 @@ export const b64DecodeUnicode = str => {
|
||||
export const decodeName = str => str.replace(/'/g, '\'')
|
||||
|
||||
export const scrollTo = (element, to, duration = 300, fn = function() {}) => {
|
||||
if (!element) return
|
||||
const start = element.scrollTop || element.scrollY
|
||||
const change = to - start
|
||||
const increment = 10
|
||||
@@ -162,7 +164,7 @@ export const isChildren = (parent, children) => {
|
||||
* @param {*} setting
|
||||
*/
|
||||
export const updateSetting = setting => {
|
||||
const defaultVersion = '1.0.4'
|
||||
const defaultVersion = '1.0.9'
|
||||
const defaultSetting = {
|
||||
version: defaultVersion,
|
||||
player: {
|
||||
@@ -178,20 +180,45 @@ export const updateSetting = setting => {
|
||||
savePath: path.join(os.homedir(), 'Desktop'),
|
||||
fileName: '歌名 - 歌手',
|
||||
maxDownloadNum: 3,
|
||||
isDownloadLrc: false,
|
||||
isEmbedPic: true,
|
||||
},
|
||||
leaderboard: {
|
||||
source: 'kw',
|
||||
tabId: 'kwbiaosb',
|
||||
},
|
||||
songList: {
|
||||
source: 'kg',
|
||||
sortId: '5',
|
||||
tagInfo: {
|
||||
name: '默认',
|
||||
id: null,
|
||||
},
|
||||
},
|
||||
odc: {
|
||||
isAutoClearSearchInput: false,
|
||||
},
|
||||
search: {
|
||||
searchSource: 'kw',
|
||||
tempSearchSource: 'kw',
|
||||
},
|
||||
network: {
|
||||
proxy: {
|
||||
enable: false,
|
||||
host: '',
|
||||
port: '',
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
},
|
||||
themeId: 0,
|
||||
sourceId: 'kw',
|
||||
apiSource: 'temp',
|
||||
apiSource: 'test',
|
||||
randomAnimate: true,
|
||||
ignoreVersion: null,
|
||||
}
|
||||
const overwriteSetting = {
|
||||
version: defaultVersion,
|
||||
sourceId: 'kw',
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +229,7 @@ export const updateSetting = setting => {
|
||||
objectDeepMerge(defaultSetting, overwriteSetting)
|
||||
setting = defaultSetting
|
||||
}
|
||||
if (setting.apiSource == 'messoer') setting.apiSource = 'temp' // 强制设置回 temp 接口源
|
||||
if (setting.apiSource != 'temp') setting.apiSource = 'test' // 强制设置回 test 接口源
|
||||
return setting
|
||||
}
|
||||
|
||||
@@ -228,3 +255,29 @@ export const setTitle = title => {
|
||||
* @param {*} str
|
||||
*/
|
||||
export const toMD5 = str => crypto.createHash('md5').update(str).digest('hex')
|
||||
|
||||
/**
|
||||
* 复制文本到剪贴板
|
||||
* @param {*} str
|
||||
*/
|
||||
export const clipboardWriteText = str => clipboard.writeText(str)
|
||||
|
||||
/**
|
||||
* 设置音频 meta 信息
|
||||
* @param {*} filePath
|
||||
* @param {*} meta
|
||||
*/
|
||||
export const setMeta = (filePath, meta) => {
|
||||
rendererSend('setMusicMeta', { filePath, meta })
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存歌词文件
|
||||
* @param {*} filePath
|
||||
* @param {*} lrc
|
||||
*/
|
||||
export const saveLrc = (filePath, lrc) => {
|
||||
fs.writeFile(filePath, lrc, 'utf8', err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import kw_api_temp from './kw/api-temp'
|
||||
// import kw_api_messoer from './kw/api-messoer'
|
||||
import kw_api_test from './kw/api-test'
|
||||
// import tx_api_messoer from './tx/api-messoer'
|
||||
// import kg_api_messoer from './kg/api-messoer'
|
||||
// import wy_api_messoer from './wy/api-messoer'
|
||||
// import bd_api_messoer from './bd/api-messoer'
|
||||
import kw_api_internal from './kw/api-internal'
|
||||
import tx_api_internal from './tx/api-internal'
|
||||
import kg_api_internal from './kg/api-internal'
|
||||
import wy_api_internal from './wy/api-internal'
|
||||
import bd_api_internal from './bd/api-internal'
|
||||
import kg_api_test from './kg/api-test'
|
||||
import wy_api_test from './wy/api-test'
|
||||
import bd_api_test from './bd/api-test'
|
||||
// import kw_api_internal from './kw/api-internal'
|
||||
// import tx_api_internal from './tx/api-internal'
|
||||
// import kg_api_internal from './kg/api-internal'
|
||||
// import wy_api_internal from './wy/api-internal'
|
||||
// import bd_api_internal from './bd/api-internal'
|
||||
|
||||
const apis = {
|
||||
// kw_api_messoer,
|
||||
kw_api_test,
|
||||
// tx_api_messoer,
|
||||
// kg_api_messoer,
|
||||
// wy_api_messoer,
|
||||
// bd_api_messoer,
|
||||
kw_api_internal,
|
||||
tx_api_internal,
|
||||
kg_api_internal,
|
||||
wy_api_internal,
|
||||
bd_api_internal,
|
||||
kg_api_test,
|
||||
wy_api_test,
|
||||
bd_api_test,
|
||||
// kw_api_internal,
|
||||
// tx_api_internal,
|
||||
// kg_api_internal,
|
||||
// wy_api_internal,
|
||||
// bd_api_internal,
|
||||
kw_api_temp,
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ const getAPI = source => {
|
||||
switch (window.globalObj.apiSource) {
|
||||
// case 'messoer':
|
||||
// return apis[`${source}_api_messoer`]
|
||||
case 'internal':
|
||||
return apis[`${source}_api_internal`]
|
||||
case 'test':
|
||||
return apis[`${source}_api_test`]
|
||||
case 'temp':
|
||||
return apis[`${source}_api_temp`]
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../messoer'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/baidu/url?id=${songInfo.songmid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo, size = '500') {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/baidu/pic?id=${songInfo.songmid}&imageSize=${size}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/baidu/lrc?id=${songInfo.songmid}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body ? Promise.resolve(body) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_messoer
|
||||
19
src/renderer/utils/music/bd/api-test.js
Normal file
19
src/renderer/utils/music/bd/api-test.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_test = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`http://ts.tempmusic.tk/url/bd/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_test
|
||||
@@ -1,18 +1,33 @@
|
||||
import leaderboard from './leaderboard'
|
||||
import api_source from '../api-source'
|
||||
import musicInfo from './musicInfo'
|
||||
import songList from './songList'
|
||||
import { httpFatch } from '../../request'
|
||||
import musicSearch from './musicSearch'
|
||||
|
||||
const bd = {
|
||||
leaderboard,
|
||||
songList,
|
||||
musicSearch,
|
||||
getMusicUrl(songInfo, type) {
|
||||
return api_source('bd').getMusicUrl(songInfo, type)
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
return api_source('bd').getLyric(songInfo)
|
||||
},
|
||||
getPic(songInfo) {
|
||||
return api_source('bd').getPic(songInfo)
|
||||
const requestObj = this.getMusicInfo(songInfo)
|
||||
requestObj.promise = requestObj.promise.then(info => info.pic_premium)
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = this.getMusicInfo(songInfo)
|
||||
requestObj.promise = requestObj.promise.then(info => httpFatch(info.lrclink).promise.then(resp => resp.body))
|
||||
return requestObj
|
||||
},
|
||||
// getLyric(songInfo) {
|
||||
// return api_source('bd').getLyric(songInfo)
|
||||
// },
|
||||
// getPic(songInfo) {
|
||||
// return api_source('bd').getPic(songInfo)
|
||||
// },
|
||||
getMusicInfo(songInfo) {
|
||||
return musicInfo.getMusicInfo(songInfo.songmid)
|
||||
},
|
||||
|
||||
@@ -85,7 +85,7 @@ export default {
|
||||
size,
|
||||
}
|
||||
types.push({ type: 'flac', size })
|
||||
_types['flac'] = {
|
||||
_types.flac = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,7 @@ export default {
|
||||
list,
|
||||
limit: this.limit,
|
||||
page: parseInt(info[3]),
|
||||
source: 'bd',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
import { httpFatch } from '../../request'
|
||||
|
||||
export default {
|
||||
cache: {},
|
||||
getMusicInfo(songmid) {
|
||||
if (this.cache[songmid]) {
|
||||
return { promise: Promise.resolve(this.cache[songmid]) }
|
||||
}
|
||||
const requestObj = httpFatch(`https://musicapi.qianqian.com/v1/restserver/ting?method=baidu.ting.song.getSongLink&format=json&from=bmpc&version=1.0.0&version_d=11.1.6.0&songid=${songmid}&type=1&res=1&s_protocol=1&aac=2&project=tpass`)
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.error_code == 22000 ? body.reqult.songinfo : Promise.reject(new Error('获取音乐信息失败'))
|
||||
// console.log(body)
|
||||
if (body.error_code == 22000) {
|
||||
this.cache[songmid] = body.result.songinfo
|
||||
return body.result.songinfo
|
||||
}
|
||||
return Promise.reject(new Error('获取音乐信息失败'))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
|
||||
88
src/renderer/utils/music/bd/musicSearch.js
Normal file
88
src/renderer/utils/music/bd/musicSearch.js
Normal file
@@ -0,0 +1,88 @@
|
||||
// import '../../polyfill/array.find'
|
||||
// import jshtmlencode from 'js-htmlencode'
|
||||
import { httpFatch } from '../../request'
|
||||
import { formatPlayTime } from '../../index'
|
||||
// import { debug } from '../../utils/env'
|
||||
// import { formatSinger } from './util'
|
||||
|
||||
let searchRequest
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page) {
|
||||
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
|
||||
searchRequest = httpFatch(`http://tingapi.ting.baidu.com/v1/restserver/ting?from=android&version=5.6.5.6&method=baidu.ting.search.merge&format=json&query=${encodeURIComponent(str)}&page_no=${page}&page_size=${this.limit}&type=0&data_source=0&use_cluster=1`)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
handleResult(rawData) {
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
rawData.forEach(item => {
|
||||
if (ids.has(item.song_id)) return
|
||||
ids.add(item.song_id)
|
||||
const types = []
|
||||
const _types = {}
|
||||
let size = null
|
||||
let itemTypes = item.all_rate.split(',')
|
||||
if (itemTypes.includes('128')) {
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
if (itemTypes.includes('320')) {
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
if (itemTypes.includes('flac')) {
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
// types.reverse()
|
||||
|
||||
list.push({
|
||||
singer: item.author.replace(',', '、'),
|
||||
name: item.title,
|
||||
albumName: item.album_title,
|
||||
albumId: item.album_id,
|
||||
source: 'bd',
|
||||
interval: formatPlayTime(parseInt(item.file_duration)),
|
||||
songmid: item.song_id,
|
||||
img: null,
|
||||
lrc: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
})
|
||||
})
|
||||
return list
|
||||
},
|
||||
search(str, page = 1, { limit } = {}) {
|
||||
if (limit != null) this.limit = limit
|
||||
|
||||
return this.musicSearch(str, page).then(result => {
|
||||
if (!result || result.error_code !== 22000) return this.search(str, page, { limit })
|
||||
let list = this.handleResult(result.result.song_info.song_list)
|
||||
|
||||
if (list == null) return this.search(str, page, { limit })
|
||||
|
||||
this.total = result.result.song_info.total
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / this.limit)
|
||||
|
||||
return Promise.resolve({
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit: this.limit,
|
||||
total: this.total,
|
||||
source: 'bd',
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -13,11 +13,11 @@ export default {
|
||||
sortList: [
|
||||
{
|
||||
name: '最热',
|
||||
id: '最热',
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
id: '最新',
|
||||
id: '0',
|
||||
},
|
||||
],
|
||||
aesPassEncod(jsonData) {
|
||||
@@ -89,7 +89,7 @@ export default {
|
||||
},
|
||||
getListUrl(sortType, tagName, page) {
|
||||
return this.createUrl({
|
||||
channelname: tagName,
|
||||
channelname: tagName || '全部',
|
||||
from: 'qianqianmini',
|
||||
offset: (page - 1) * this.limit_list,
|
||||
order_type: sortType,
|
||||
@@ -114,8 +114,9 @@ export default {
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
if (body.error_code !== this.successCode) return this.getTags()
|
||||
return {
|
||||
hotTag: this.filterInfoHotTag(body.data.hot),
|
||||
tags: this.filterTagInfo(body.data.tags),
|
||||
hotTag: this.filterInfoHotTag(body.result.hot),
|
||||
tags: this.filterTagInfo(body.result.tags),
|
||||
source: 'bd',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -123,16 +124,18 @@ export default {
|
||||
return rawList.map(item => ({
|
||||
name: item,
|
||||
id: item,
|
||||
source: 'bd',
|
||||
}))
|
||||
},
|
||||
filterTagInfo(rawList) {
|
||||
return rawList.map(type => ({
|
||||
type: type.first,
|
||||
name: type.first,
|
||||
list: type.second.map(item => ({
|
||||
parent_id: type.first,
|
||||
parent_name: type.first,
|
||||
id: item,
|
||||
name: item,
|
||||
source: 'bd',
|
||||
})),
|
||||
}))
|
||||
},
|
||||
@@ -144,12 +147,13 @@ export default {
|
||||
this.getListUrl(sortId, tagId, page)
|
||||
)
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.error_code !== this.successCode) return this.getSongList(sortId, tagId, page)
|
||||
// if (body.error_code !== this.successCode) return this.getList(sortId, tagId, page)
|
||||
return {
|
||||
list: this.filterList(body.diyInfo),
|
||||
total: body.nums,
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'bd',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -174,6 +178,7 @@ export default {
|
||||
img: item.list_pic_large || item.list_pic,
|
||||
grade: item.grade,
|
||||
desc: item.desc || item.tag,
|
||||
source: 'bd',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -191,6 +196,7 @@ export default {
|
||||
page,
|
||||
limit: this.limit_song,
|
||||
total: body.result.song_num,
|
||||
source: 'bd',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -215,7 +221,7 @@ export default {
|
||||
}
|
||||
if (itemTypes.includes('flac')) {
|
||||
types.push({ type: 'flac', size })
|
||||
_types['flac'] = {
|
||||
_types.flac = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../messoer'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../messoer'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/kugou/url?id=${songInfo._types[type].hash}&quality=${type.replace(/k$/, '')}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/kugou/pic?id=${songInfo.hash}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/kugou/lrc?id=${songInfo.hash}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body ? Promise.resolve(body) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_messoer
|
||||
41
src/renderer/utils/music/kg/api-test.js
Normal file
41
src/renderer/utils/music/kg/api-test.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_test = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`http://ts.tempmusic.tk/url/kg/${songInfo._types[type].hash}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFatch(`http://ts.tempmusic.tk/pic/kg/${songInfo.hash}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = httpFatch(`http://ts.tempmusic.tk/lrc/kg/${songInfo.hash}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_test
|
||||
@@ -1,9 +1,12 @@
|
||||
import leaderboard from './leaderboard'
|
||||
import api_source from '../api-source'
|
||||
|
||||
import songList from './songList'
|
||||
import musicSearch from './musicSearch'
|
||||
|
||||
const kg = {
|
||||
leaderboard,
|
||||
songList,
|
||||
musicSearch,
|
||||
getMusicUrl(songInfo, type) {
|
||||
return api_source('kg').getMusicUrl(songInfo, type)
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
},
|
||||
{
|
||||
id: 'kgwlhgb',
|
||||
name: '网络红歌榜',
|
||||
name: '网络榜',
|
||||
bangid: '23784',
|
||||
},
|
||||
{
|
||||
@@ -30,29 +30,29 @@ export default {
|
||||
},
|
||||
{
|
||||
id: 'kggfjqb',
|
||||
name: '古风金曲榜',
|
||||
name: '古风榜',
|
||||
bangid: '33161',
|
||||
},
|
||||
{
|
||||
id: 'kgyyjqb',
|
||||
name: '粤语金曲榜',
|
||||
name: '粤语榜',
|
||||
bangid: '33165',
|
||||
},
|
||||
{
|
||||
id: 'kgomjqb',
|
||||
name: '欧美金曲榜',
|
||||
name: '欧美榜',
|
||||
bangid: '33166',
|
||||
},
|
||||
// {
|
||||
// id: 'kgdyrgb',
|
||||
// name: '电音热歌榜',
|
||||
// bangid: '33160',
|
||||
// },
|
||||
// {
|
||||
// id: 'kgjdrgb',
|
||||
// name: 'DJ热歌榜',
|
||||
// bangid: '24971',
|
||||
// },
|
||||
{
|
||||
id: 'kgdyrgb',
|
||||
name: '电音榜',
|
||||
bangid: '33160',
|
||||
},
|
||||
{
|
||||
id: 'kgjdrgb',
|
||||
name: 'DJ热歌榜',
|
||||
bangid: '24971',
|
||||
},
|
||||
// {
|
||||
// id: 'kghyxgb',
|
||||
// name: '华语新歌榜',
|
||||
@@ -159,6 +159,7 @@ export default {
|
||||
list: listData,
|
||||
limit,
|
||||
page,
|
||||
source: 'kg',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
92
src/renderer/utils/music/kg/musicSearch.js
Normal file
92
src/renderer/utils/music/kg/musicSearch.js
Normal file
@@ -0,0 +1,92 @@
|
||||
// import '../../polyfill/array.find'
|
||||
// import jshtmlencode from 'js-htmlencode'
|
||||
import { httpFatch } from '../../request'
|
||||
import { formatPlayTime, sizeFormate } from '../../index'
|
||||
// import { debug } from '../../utils/env'
|
||||
// import { formatSinger } from './util'
|
||||
|
||||
let searchRequest
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page) {
|
||||
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
|
||||
searchRequest = httpFatch(`http://ioscdn.kugou.com/api/v3/search/song?keyword=${encodeURIComponent(str)}&page=${page}&pagesize=${this.limit}&showtype=10&plat=2&version=7910&tag=1&correct=1&privilege=1&sver=5`)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
handleResult(rawData) {
|
||||
// console.log(rawData)
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
rawData.forEach(item => {
|
||||
if (ids.has(item.audio_id)) return
|
||||
ids.add(item.audio_id)
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.filesize !== 0) {
|
||||
let size = sizeFormate(item.filesize)
|
||||
types.push({ type: '128k', size, hash: item.hash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: item.hash,
|
||||
}
|
||||
}
|
||||
if (item['320filesize'] !== 0) {
|
||||
let size = sizeFormate(item['320filesize'])
|
||||
types.push({ type: '320k', size, hash: item['320hash'] })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: item['320hash'],
|
||||
}
|
||||
}
|
||||
if (item.sqfilesize !== 0) {
|
||||
let size = sizeFormate(item.sqfilesize)
|
||||
types.push({ type: 'flac', size, hash: item.sqhash })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: item.sqhash,
|
||||
}
|
||||
}
|
||||
list.push({
|
||||
singer: item.singername,
|
||||
name: item.songname,
|
||||
albumName: item.album_name,
|
||||
albumId: item.album_id,
|
||||
songmid: item.audio_id,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(item.duration),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.hash,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
})
|
||||
})
|
||||
return list
|
||||
},
|
||||
search(str, page = 1, { limit } = {}) {
|
||||
if (limit != null) this.limit = limit
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page).then(result => {
|
||||
if (!result || result.errcode !== 0) return this.search(str, page, { limit })
|
||||
let list = this.handleResult(result.data.info)
|
||||
|
||||
if (list == null) return this.search(str, page, { limit })
|
||||
|
||||
this.total = result.data.total
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / this.limit)
|
||||
|
||||
return Promise.resolve({
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit: this.limit,
|
||||
total: this.total,
|
||||
source: 'kg',
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -2,12 +2,14 @@ import { httpFatch } from '../../request'
|
||||
import { formatPlayTime, sizeFormate } from '../../index'
|
||||
|
||||
export default {
|
||||
_requestObj_tagInfo: null,
|
||||
_requestObj_tags: null,
|
||||
_requestObj_listInfo: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listRecommend: null,
|
||||
_requestObj_listDetail: null,
|
||||
currentTagInfo: {
|
||||
id: null,
|
||||
info: null,
|
||||
id: undefined,
|
||||
info: undefined,
|
||||
},
|
||||
sortList: [
|
||||
{
|
||||
@@ -37,36 +39,30 @@ export default {
|
||||
getInfoUrl(tagId) {
|
||||
return tagId
|
||||
? `http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&cdn=cdn&t=5&c=${tagId}`
|
||||
: `http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&`
|
||||
: 'http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&'
|
||||
},
|
||||
getSongListUrl(sortId, tagId, page) {
|
||||
return `http://www2.kugou.kugou.com/yueku/v9/special/index/getData/getData.html&cdn=cdn&t=${sortId}&c=${tagId}?is_ajax=1&p=${page}`
|
||||
if (tagId == null) tagId = ''
|
||||
return `http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_ajax=1&cdn=cdn&t=${sortId}&c=${tagId}&p=${page}`
|
||||
},
|
||||
getSongListDetailUrl(id) {
|
||||
return `http://www2.kugou.kugou.com/yueku/v9/special/single/${id}-5-9999.html`
|
||||
},
|
||||
|
||||
getTagInfo(tagId) {
|
||||
if (this._requestObj_tagInfo) this._requestObj_tagInfo.cancelHttp()
|
||||
this._requestObj_tagInfo = httpFatch(this.getInfoUrl(tagId))
|
||||
return this._requestObj_tagInfo.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getTagInfo(tagId)
|
||||
return {
|
||||
hotTag: this.filterInfoHotTag(body.data.hotTag),
|
||||
tags: this.filterTagInfo(body.data.tagids),
|
||||
tagInfo: {
|
||||
limit: body.data.params.pagesize,
|
||||
page: body.data.params.p,
|
||||
total: body.data.params.total,
|
||||
},
|
||||
}
|
||||
})
|
||||
/**
|
||||
* 格式化播放数量
|
||||
* @param {*} num
|
||||
*/
|
||||
formatPlayCount(num) {
|
||||
if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿'
|
||||
if (num > 10000) return parseInt(num / 1000) / 10 + '万'
|
||||
return num
|
||||
},
|
||||
filterInfoHotTag(rawData) {
|
||||
const result = []
|
||||
if (rawData.status !== 1) return result
|
||||
for (let index = 0; index < Object.keys(rawData.data).lengt; index++) {
|
||||
let tag = rawData.data[index.toString()]
|
||||
for (const key of Object.keys(rawData.data)) {
|
||||
let tag = rawData.data[key]
|
||||
result.push({
|
||||
id: tag.id,
|
||||
name: tag.special_name,
|
||||
@@ -76,17 +72,19 @@ export default {
|
||||
},
|
||||
filterTagInfo(rawData) {
|
||||
const result = []
|
||||
for (const type of Object.keys(rawData)) {
|
||||
for (const name of Object.keys(rawData)) {
|
||||
result.push({
|
||||
type,
|
||||
list: rawData[type].data.map(tag => ({
|
||||
name,
|
||||
list: rawData[name].data.map(tag => ({
|
||||
parent_id: tag.parent_id,
|
||||
parent_name: tag.pname,
|
||||
id: tag.id,
|
||||
name: tag.name,
|
||||
source: 'kg',
|
||||
})),
|
||||
})
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
getSongList(sortId, tagId, page) {
|
||||
@@ -96,12 +94,12 @@ export default {
|
||||
)
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getSongList(sortId, tagId, page)
|
||||
return this.filterList(body.data)
|
||||
return this.filterList(body.special_db)
|
||||
})
|
||||
},
|
||||
getSongListRecommend() {
|
||||
if (this._requestObj_listRecommend) this._requestObj_listRecommend.cancelHttp()
|
||||
this._requestObj_listRecommendRecommend = httpFatch(
|
||||
this._requestObj_listRecommend = httpFatch(
|
||||
'http://everydayrec.service.kugou.com/guess_special_recommend',
|
||||
{
|
||||
method: 'post',
|
||||
@@ -123,19 +121,20 @@ export default {
|
||||
)
|
||||
return this._requestObj_listRecommend.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getSongListRecommend()
|
||||
return this.filterList(body.data)
|
||||
return this.filterList(body.data.special_list)
|
||||
})
|
||||
},
|
||||
filterList(rawData) {
|
||||
return rawData.map(item => ({
|
||||
play_count: item.total_play_count,
|
||||
play_count: item.total_play_count || this.formatPlayCount(item.play_count),
|
||||
id: item.specialid,
|
||||
author: item.nickname,
|
||||
name: item.specialname,
|
||||
time: item.publish_time,
|
||||
img: item.img,
|
||||
time: item.publish_time || item.publishtime,
|
||||
img: item.img || item.imgurl,
|
||||
grade: item.grade,
|
||||
desc: item.intro,
|
||||
source: 'kg',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -150,6 +149,7 @@ export default {
|
||||
page: 1,
|
||||
limit: 10000,
|
||||
total: listData.length,
|
||||
source: 'kg',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -200,7 +200,7 @@ export default {
|
||||
interval: formatPlayTime(item.duration / 1000),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.HASH,
|
||||
hash: item.hash,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
@@ -210,11 +210,15 @@ export default {
|
||||
|
||||
// 获取列表信息
|
||||
getListInfo(tagId) {
|
||||
return this.getTagInfo(tagId).then(info => {
|
||||
if (this._requestObj_listInfo) this._requestObj_listInfo.cancelHttp()
|
||||
this._requestObj_listInfo = httpFatch(this.getInfoUrl(tagId))
|
||||
return this._requestObj_listInfo.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getListInfo(tagId)
|
||||
return {
|
||||
limit: info.tagInfo.limit,
|
||||
page: info.tagInfo.page,
|
||||
total: info.tagInfo.total,
|
||||
limit: body.data.params.pagesize,
|
||||
page: body.data.params.p,
|
||||
total: body.data.params.total,
|
||||
source: 'kg',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -231,8 +235,8 @@ export default {
|
||||
return info
|
||||
})
|
||||
)
|
||||
if (!tagId) tasks.push(this.getSongListRecommend()) // 如果是所有类别,则顺便获取推荐列表
|
||||
Promise.all(tasks).then(([list, info, recommendList]) => {
|
||||
if (!tagId && page === 1 && sortId === this.sortList[0].id) tasks.push(this.getSongListRecommend()) // 如果是所有类别,则顺便获取推荐列表
|
||||
return Promise.all(tasks).then(([list, info, recommendList]) => {
|
||||
if (recommendList) list.unshift(...recommendList)
|
||||
return {
|
||||
list,
|
||||
@@ -243,10 +247,14 @@ export default {
|
||||
|
||||
// 获取标签
|
||||
getTags() {
|
||||
return this.getTagInfo().then(info => {
|
||||
if (this._requestObj_tags) this._requestObj_tags.cancelHttp()
|
||||
this._requestObj_tags = httpFatch(this.getInfoUrl())
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getTags()
|
||||
return {
|
||||
hotTag: info.hotTag,
|
||||
tags: info.tags,
|
||||
hotTag: this.filterInfoHotTag(body.data.hotTag),
|
||||
tags: this.filterTagInfo(body.data.tagids),
|
||||
source: 'kg',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../messoer'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../messoer'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/kuwo/url?id=${songInfo.songmid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/kuwo/pic?id=${songInfo.songmid}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_messoer
|
||||
@@ -1,24 +1,18 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_temp = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`http://45.32.53.128:3002/m/kw/u/${songInfo.songmid}/${type}`, {
|
||||
const requestObj = httpFatch(`http://tm.tempmusic.tk/url/kw/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
headers,
|
||||
timeout,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(body.msg))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFatch(`http://45.32.53.128:3002/m/kw/i/${songInfo.songmid}`, {
|
||||
method: 'get',
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(body.msg))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_temp
|
||||
|
||||
30
src/renderer/utils/music/kw/api-test.js
Normal file
30
src/renderer/utils/music/kw/api-test.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_test = {
|
||||
// getMusicUrl(songInfo, type) {
|
||||
// const requestObj = httpFatch(`http://45.32.53.128:3002/m/kw/u/${songInfo.songmid}/${type}`, {
|
||||
// method: 'get',
|
||||
// headers,
|
||||
// timeout,
|
||||
// })
|
||||
// requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
// return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(body.msg))
|
||||
// })
|
||||
// return requestObj
|
||||
// },
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`http://ts.tempmusic.tk/url/kw/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_test
|
||||
@@ -4,7 +4,9 @@ import musicSearch from './musicSearch'
|
||||
import { formatSinger } from './util'
|
||||
import leaderboard from './leaderboard'
|
||||
import lyric from './lyric'
|
||||
import pic from './pic'
|
||||
import api_source from '../api-source'
|
||||
import songList from './songList'
|
||||
|
||||
const kw = {
|
||||
_musicInfoRequestObj: null,
|
||||
@@ -31,6 +33,7 @@ const kw = {
|
||||
tempSearch,
|
||||
musicSearch,
|
||||
leaderboard,
|
||||
songList,
|
||||
getLyric(songInfo) {
|
||||
// let singer = songInfo.singer.indexOf('、') > -1 ? songInfo.singer.split('、')[0] : songInfo.singer
|
||||
return lyric.getLyric(songInfo.songmid)
|
||||
@@ -91,7 +94,7 @@ const kw = {
|
||||
},
|
||||
|
||||
getPic(songInfo) {
|
||||
return api_source('kw').getPic(songInfo)
|
||||
return pic.getPic(songInfo)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -133,13 +133,13 @@ export default {
|
||||
}
|
||||
if (formats.indexOf('AL')) {
|
||||
types.push({ type: 'ape', size: null })
|
||||
_types['ape'] = {
|
||||
_types.ape = {
|
||||
size: null,
|
||||
}
|
||||
}
|
||||
if (formats.indexOf('ALFLAC')) {
|
||||
types.push({ type: 'flac', size: null })
|
||||
_types['flac'] = {
|
||||
_types.flac = {
|
||||
size: null,
|
||||
}
|
||||
}
|
||||
@@ -187,6 +187,7 @@ export default {
|
||||
list,
|
||||
limit: this.limit,
|
||||
page,
|
||||
source: 'kw',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -121,7 +121,7 @@ export default {
|
||||
}
|
||||
return result
|
||||
},
|
||||
search(str, page = 1, { limit }) {
|
||||
search(str, page = 1, { limit } = {}) {
|
||||
if (limit != null) this.limit = limit
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page).then(result => {
|
||||
@@ -138,6 +138,8 @@ export default {
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
total: this.total,
|
||||
limit: this.limit,
|
||||
source: 'kw',
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
9
src/renderer/utils/music/kw/pic.js
Normal file
9
src/renderer/utils/music/kw/pic.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { httpFatch } from '../../request'
|
||||
|
||||
export default {
|
||||
getPic({ songmid }) {
|
||||
const requestObj = httpFatch(`http://artistpicserver.kuwo.cn/pic.web?corp=kuwo&type=rid_pic&pictype=500&size=500&rid=${songmid}`)
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => body)
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
@@ -7,63 +7,70 @@ export default {
|
||||
_requestObj_hotTags: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listDetail: null,
|
||||
limit_list: 100,
|
||||
limit_song: 25,
|
||||
limit_list: 25,
|
||||
limit_song: 100,
|
||||
successCode: 200,
|
||||
sortList: [
|
||||
{
|
||||
name: '最热',
|
||||
id: 'hot',
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
id: 'new',
|
||||
},
|
||||
{
|
||||
name: '最热',
|
||||
id: 'hot',
|
||||
},
|
||||
],
|
||||
tagsUrl: 'http://wapi.kuwo.cn/api/pc/classify/playlist/getTagList?cmd=rcm_keyword_playlist&user=0&prod=kwplayer_pc_9.0.5.0&vipver=9.0.5.0&source=kwplayer_pc_9.0.5.0&loginUid=0&loginSid=0&appUid=76039576',
|
||||
hotTagUrl: 'http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmTagList?loginUid=0&loginSid=0&appUid=76039576',
|
||||
getListUrl({ sortType, id, page }) {
|
||||
return id
|
||||
? `http://wapi.kuwo.cn/api/pc/classify/playlist/getTagPlayList?loginUid=0&loginSid=0&appUid=76039576&id=${id}&pn=${page}&rn=${this.limit}`
|
||||
: `http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmPlayList?loginUid=0&loginSid=0&appUid=76039576&pn=${page}&rn=${this.limit}&order=${sortType}`
|
||||
getListUrl({ sortId, id, type, page }) {
|
||||
if (!id) return `http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmPlayList?loginUid=0&loginSid=0&appUid=76039576&&pn=${page}&rn=${this.limit_list}&order=${sortId}`
|
||||
switch (type) {
|
||||
case '10000': return `http://wapi.kuwo.cn/api/pc/classify/playlist/getTagPlayList?loginUid=0&loginSid=0&appUid=76039576&pn=${page}&id=${id}&rn=${this.limit_list}`
|
||||
case '43': return `http://mobileinterfaces.kuwo.cn/er.s?type=get_pc_qz_data&f=web&id=${id}&prod=pc`
|
||||
}
|
||||
// http://wapi.kuwo.cn/api/pc/classify/playlist/getTagPlayList?loginUid=0&loginSid=0&appUid=76039576&id=173&pn=1&rn=100
|
||||
},
|
||||
getListDetailUrl(id, page) {
|
||||
return `http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}&rn=${this.limit}&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1`
|
||||
// http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=2858093057&pn=0&rn=100&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1
|
||||
return `http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}&rn=${this.limit_song}&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1`
|
||||
// http://mobileinterfaces.kuwo.cn/er.s?type=get_pc_qz_data&f=web&id=140&prod=pc
|
||||
},
|
||||
|
||||
|
||||
// http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=2849349915&pn=0&rn=100&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1
|
||||
// 获取标签
|
||||
getTags() {
|
||||
getTag() {
|
||||
if (this._requestObj_tags) this._requestObj_tags.cancelHttp()
|
||||
this._requestObj_tags = httpFatch(this.tagsUrl)
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getTags()
|
||||
return this.filterTagInfo(body.data.tags)
|
||||
if (body.code !== this.successCode) return this.getTag()
|
||||
return this.filterTagInfo(body.data)
|
||||
})
|
||||
},
|
||||
// 获取标签
|
||||
getHotTags() {
|
||||
getHotTag() {
|
||||
if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp()
|
||||
this._requestObj_hotTags = httpFatch(this.hotTagUrl)
|
||||
return this._requestObj_hotTags.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getHotTags()
|
||||
return this.filterInfoHotTag(body.data.data)
|
||||
if (body.code !== this.successCode) return this.getHotTag()
|
||||
return this.filterInfoHotTag(body.data[0].data)
|
||||
})
|
||||
},
|
||||
filterInfoHotTag(rawList) {
|
||||
return rawList.map(item => ({
|
||||
id: item.id,
|
||||
id: `${item.id}-${item.digest}`,
|
||||
name: item.name,
|
||||
source: 'kw',
|
||||
}))
|
||||
},
|
||||
filterTagInfo(rawList) {
|
||||
return rawList.map(type => ({
|
||||
type: type.name,
|
||||
name: type.name,
|
||||
list: type.data.map(item => ({
|
||||
parent_id: type.id,
|
||||
parent_name: type.name,
|
||||
id: item.id,
|
||||
id: `${item.id}-${item.digest}`,
|
||||
name: item.name,
|
||||
source: 'kw',
|
||||
})),
|
||||
}))
|
||||
},
|
||||
@@ -71,16 +78,35 @@ export default {
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page) {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
this._requestObj_list = httpFatch(
|
||||
this.getListUrl({ sortId, id: tagId, page })
|
||||
)
|
||||
let id
|
||||
let type
|
||||
if (tagId) {
|
||||
let arr = tagId.split('-')
|
||||
id = arr[0]
|
||||
type = arr[1]
|
||||
} else {
|
||||
id = null
|
||||
}
|
||||
this._requestObj_list = httpFatch(this.getListUrl({ sortId, id, type, page }))
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getList({ sortId, id: tagId, page })
|
||||
if (!id || type == '10000') {
|
||||
if (body.code !== this.successCode) return this.getListUrl({ sortId, id, type, page })
|
||||
return {
|
||||
list: this.filterList(body.data.data),
|
||||
total: body.data.total,
|
||||
page: body.data.pn,
|
||||
limit: body.data.rn,
|
||||
source: 'kw',
|
||||
}
|
||||
} else if (!body.length) {
|
||||
return this.getListUrl({ sortId, id, type, page })
|
||||
}
|
||||
return {
|
||||
list: this.filterList(body.data.data),
|
||||
total: body.data.total,
|
||||
page: body.data.pn,
|
||||
limit: body.data.rn,
|
||||
list: this.filterList2(body),
|
||||
total: 1000,
|
||||
page,
|
||||
limit: 1000,
|
||||
source: 'kw',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -105,8 +131,26 @@ export default {
|
||||
img: item.img,
|
||||
grade: item.favorcnt / 10,
|
||||
desc: item.desc,
|
||||
source: 'kw',
|
||||
}))
|
||||
},
|
||||
filterList2(rawData) {
|
||||
const list = []
|
||||
rawData.forEach(item => {
|
||||
if (!item.label) return
|
||||
list.push(...item.list.map(item => ({
|
||||
play_count: item.play_count === undefined ? null : this.formatPlayCount(item.listencnt),
|
||||
id: item.id,
|
||||
author: item.uname,
|
||||
name: item.name,
|
||||
// time: item.publish_time,
|
||||
img: item.img,
|
||||
grade: item.favorcnt / 10,
|
||||
desc: item.desc,
|
||||
})))
|
||||
})
|
||||
return list
|
||||
},
|
||||
|
||||
// 获取歌曲列表内的音乐
|
||||
getListDetail(id, page) {
|
||||
@@ -117,10 +161,11 @@ export default {
|
||||
return this._requestObj_listDetail.promise.then(({ body }) => {
|
||||
if (body.result !== 'ok') return this.getListDetail(id, page)
|
||||
return {
|
||||
list: this.filterListDetail(body.data.musiclist),
|
||||
list: this.filterListDetail(body.musiclist),
|
||||
page,
|
||||
limit: body.rn,
|
||||
total: body.total,
|
||||
source: 'kw',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -144,7 +189,7 @@ export default {
|
||||
}
|
||||
if (formats.indexOf('ALFLAC')) {
|
||||
types.push({ type: 'flac', size: null })
|
||||
_types['flac'] = {
|
||||
_types.flac = {
|
||||
size: null,
|
||||
}
|
||||
}
|
||||
@@ -165,7 +210,9 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getTags() {
|
||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({ tags, hotTag }))
|
||||
},
|
||||
}
|
||||
|
||||
// getList
|
||||
|
||||
@@ -6,4 +6,4 @@ export const headers = {
|
||||
}
|
||||
|
||||
|
||||
export const timeout = 10000
|
||||
export const timeout = 15000
|
||||
@@ -1,6 +1,6 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../messoer'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { headers, timeout } from '../messoer'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/tencent/url?id=${songInfo.strMediaMid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/tencent/url?id=${songInfo.strMediaMid}&quality=${type.replace(/k$/, '')}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
@@ -196,6 +196,7 @@ export default {
|
||||
list: this.filterData(data.toplist.data.songInfoList),
|
||||
limit: this.limit,
|
||||
page: 1,
|
||||
source: 'tx',
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const types = ['flac', 'ape', '320k', '192k', '128k']
|
||||
export const getMusicType = (info, type) => {
|
||||
switch (window.globalObj.apiSource) {
|
||||
// case 'kg':
|
||||
case 'kg':
|
||||
case 'wy':
|
||||
return '128k'
|
||||
}
|
||||
@@ -15,4 +15,5 @@ export const getMusicType = (info, type) => {
|
||||
for (const type of rangeType) {
|
||||
if (info._types[type]) return type
|
||||
}
|
||||
return '128k'
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../messoer'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../messoer'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/netease/url?id=${songInfo.songmid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/netease/pic?id=${songInfo.songmid}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = httpFatch(`https://v1.itooi.cn/netease/lrc?id=${songInfo.songmid}&isRedirect=0`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body ? Promise.resolve(body) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_messoer
|
||||
41
src/renderer/utils/music/wy/api-test.js
Normal file
41
src/renderer/utils/music/wy/api-test.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_test = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFatch(`http://ts.tempmusic.tk/url/wy/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFatch(`http://ts.tempmusic.tk/pic/wy/${songInfo.songmid}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = httpFatch(`http://ts.tempmusic.tk/lrc/wy/${songInfo.songmid}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_test
|
||||
@@ -98,7 +98,7 @@ export default {
|
||||
case 999000:
|
||||
size = null
|
||||
types.push({ type: 'flac', size })
|
||||
_types['flac'] = {
|
||||
_types.flac = {
|
||||
size,
|
||||
}
|
||||
case 320000:
|
||||
@@ -155,6 +155,7 @@ export default {
|
||||
list,
|
||||
limit: this.limit,
|
||||
page,
|
||||
source: 'tx',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -2,12 +2,14 @@ import request from 'request'
|
||||
// import progress from 'request-progress'
|
||||
import { debugRequest } from './env'
|
||||
import { requestMsg } from './message'
|
||||
import { bHh } from './music/messoer'
|
||||
import { bHh } from './music/options'
|
||||
// import fs from 'fs'
|
||||
|
||||
const headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
|
||||
}
|
||||
// var proxyUrl = "http://" + user + ":" + password + "@" + host + ":" + port;
|
||||
// var proxiedRequest = request.defaults({'proxy': proxyUrl});
|
||||
|
||||
/**
|
||||
* promise 形式的请求方法
|
||||
@@ -41,8 +43,8 @@ const buildHttpPromose = (url, options) => {
|
||||
const obj = {
|
||||
promise: p,
|
||||
cancelHttp() {
|
||||
console.log('cancel')
|
||||
if (!requestObj) return
|
||||
console.log('cancel')
|
||||
cancelHttp(requestObj)
|
||||
cancelFn(new Error(requestMsg.cancelRequest))
|
||||
requestObj = null
|
||||
@@ -215,6 +217,10 @@ export const http_jsonp = (url, options, callback) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getProxyInfo = () => window.globalObj.proxy.enable
|
||||
? `http://${window.globalObj.proxy.username}:${window.globalObj.proxy.password}@${window.globalObj.proxy.host}:${window.globalObj.proxy.port};`
|
||||
: undefined
|
||||
|
||||
const fatchData = (url, method, options, callback) => {
|
||||
// console.log(url, options)
|
||||
console.log('---start---', url)
|
||||
@@ -229,8 +235,11 @@ const fatchData = (url, method, options, callback) => {
|
||||
method,
|
||||
headers: Object.assign({}, headers, options.headers || {}),
|
||||
Origin: options.origin,
|
||||
data: options.data,
|
||||
body: options.body,
|
||||
form: options.form,
|
||||
formData: options.formData,
|
||||
timeout: options.timeout || 10000,
|
||||
proxy: getProxyInfo(),
|
||||
json: options.format === undefined || options.format === 'json',
|
||||
}, (err, resp, body) => {
|
||||
if (err) return callback(err, null)
|
||||
|
||||
@@ -23,9 +23,9 @@ div(:class="$style.download")
|
||||
td.break(style="width: 28%;") {{item.musicInfo.name}} - {{item.musicInfo.singer}}
|
||||
td.break(style="width: 22%;") {{item.progress.progress}}%
|
||||
td.break(style="width: 15%;") {{item.statusText}}
|
||||
td.break(style="width: 10%;") {{item.type.toUpperCase()}}
|
||||
td.break(style="width: 10%;") {{item.type && item.type.toUpperCase()}}
|
||||
td(style="width: 20%; padding-left: 0; padding-right: 0;")
|
||||
material-list-buttons(:index="index" :download-btn="false" :start-btn="!item.isComplate && item.status != downloadStatus.WAITING && (item.status != downloadStatus.RUN)"
|
||||
material-list-buttons(:index="index" :download-btn="false" :file-btn="true" :start-btn="!item.isComplate && item.status != downloadStatus.WAITING && (item.status != downloadStatus.RUN)"
|
||||
:pause-btn="!item.isComplate && (item.status == downloadStatus.RUN || item.status == downloadStatus.WAITING)"
|
||||
:play-btn="item.status == downloadStatus.COMPLETED" @btn-click="handleListBtnClick")
|
||||
material-flow-btn(:show="isShowEditBtn" :play-btn="false" :download-btn="false" :add-btn="false" :start-btn="true" :pause-btn="true" @btn-click="handleFlowBtnClick")
|
||||
@@ -34,8 +34,7 @@ div(:class="$style.download")
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions, mapMutations } from 'vuex'
|
||||
import { checkPath } from '../utils'
|
||||
|
||||
import { checkPath, openDirInExplorer } from '../utils'
|
||||
export default {
|
||||
name: 'Download',
|
||||
data() {
|
||||
@@ -129,6 +128,9 @@ export default {
|
||||
case 'remove':
|
||||
this.removeTask(info.index)
|
||||
break
|
||||
case 'file':
|
||||
this.handleOpenFolder(info.index)
|
||||
break
|
||||
}
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
@@ -148,7 +150,7 @@ export default {
|
||||
this.handleStartTask(index)
|
||||
})
|
||||
break
|
||||
case 'pause':
|
||||
case 'pause': {
|
||||
let runs = []
|
||||
this.selectdData.forEach(item => {
|
||||
if (item.isComplate || item.status == this.downloadStatus.PAUSE) return
|
||||
@@ -164,12 +166,18 @@ export default {
|
||||
this.handlePauseTask(index)
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'remove':
|
||||
this.removeTaskMultiple(this.selectdData)
|
||||
break
|
||||
}
|
||||
this.resetSelect()
|
||||
},
|
||||
handleOpenFolder(index) {
|
||||
let path = this.list[index].filePath
|
||||
if (!checkPath(path)) return
|
||||
openDirInExplorer(path)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,51 +1,15 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.leaderboard")
|
||||
div(:class="$style.header")
|
||||
material-tab(:class="$style.tab" :list="types" item-key="id" item-name="name" v-model="tabId")
|
||||
material-tab(:class="$style.tab" :list="types" align="left" item-key="id" item-name="name" v-model="tabId")
|
||||
material-select(:class="$style.select" :list="sourceInfo.sources" item-key="id" item-name="name" v-model="source")
|
||||
div(:class="$style.content")
|
||||
div(v-if="list.length" :class="$style.list")
|
||||
div(:class="$style.thead")
|
||||
table
|
||||
thead
|
||||
tr
|
||||
th.nobreak.center(style="width: 37px;")
|
||||
material-checkbox(id="search_select_all" v-model="isSelectAll" @change="handleSelectAllData"
|
||||
:indeterminate="isIndeterminate" :title="isSelectAll && !isIndeterminate ? '全不选' : '全选'")
|
||||
th.nobreak(style="width: 25%;") 歌曲名
|
||||
th.nobreak(style="width: 20%;") 歌手
|
||||
th.nobreak(style="width: 22%;") 专辑
|
||||
th.nobreak(style="width: 18%;") 操作
|
||||
th.nobreak(style="width: 10%;") 时长
|
||||
div.scroll(:class="$style.tbody" ref="dom_scrollContent")
|
||||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid' @click="handleDoubleClick(index)")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
td.break(style="width: 25%;")
|
||||
| {{item.name}}
|
||||
//- span.badge.badge-info(v-if="item._types['320k']") 高品质
|
||||
//- span.badge.badge-success(v-if="item._types.ape || item._types.flac") 无损
|
||||
td.break(style="width: 20%;") {{item.singer}}
|
||||
td.break(style="width: 22%;") {{item.albumName}}
|
||||
td(style="width: 18%;")
|
||||
material-list-buttons(:index="index" :search-btn="true" :play-btn="item.source == 'kw' || !isAPITemp" :download-btn="item.source == 'kw' || !isAPITemp" :remove-btn="false" @btn-click="handleListBtnClick")
|
||||
//- button.btn-info(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k'] || item._types.flac" @click.stop='openDownloadModal(index)') 下载
|
||||
//- button.btn-secondary(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k']" @click.stop='testPlay(index)') 试听
|
||||
//- button.btn-success(type='button' v-if="(item._types['128k'] || item._types['192k'] || item._types['320k']) && userInfo" @click.stop='showListModal(index)') +
|
||||
td(style="width: 10%;") {{item.interval || '--/--'}}
|
||||
div(:class="$style.pagination")
|
||||
material-pagination(:count="info.total" :limit="info.limit" :page="info.page" @btn-click="handleTogglePage")
|
||||
material-song-list(v-model="selectdData" @action="handleSongListAction" :source="source" :page="page" :limit="info.limit" :total="info.total" :list="list")
|
||||
material-download-modal(:show="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false")
|
||||
material-download-multiple-modal(:show="isShowDownloadMultiple" :list="selectdData" @select="handleAddDownloadMultiple" @close="isShowDownloadMultiple = false")
|
||||
material-flow-btn(:show="isShowEditBtn && (source == 'kw' || !isAPITemp)" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations, mapActions } from 'vuex'
|
||||
import { scrollTo } from '../utils'
|
||||
// import music from '../utils/music'
|
||||
export default {
|
||||
name: 'Leaderboard',
|
||||
data() {
|
||||
@@ -53,14 +17,9 @@ export default {
|
||||
tabId: null,
|
||||
source: null,
|
||||
page: 1,
|
||||
clickTime: 0,
|
||||
clickIndex: -1,
|
||||
isShowDownload: false,
|
||||
musicInfo: null,
|
||||
selectdData: [],
|
||||
isSelectAll: false,
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
isShowDownloadMultiple: false,
|
||||
}
|
||||
},
|
||||
@@ -81,27 +40,12 @@ export default {
|
||||
if (!o && this.page !== 1) return
|
||||
this.getList(1).then(() => {
|
||||
this.page = this.info.page
|
||||
scrollTo(this.$refs.dom_scrollContent, 0)
|
||||
})
|
||||
},
|
||||
source(n, o) {
|
||||
this.setLeaderboard({ source: n })
|
||||
if (o) this.tabId = this.types[0] && this.types[0].id
|
||||
},
|
||||
selectdData(n) {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isShowEditBtn = true
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
}
|
||||
},
|
||||
list() {
|
||||
this.resetSelect()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.source = this.setting.leaderboard.source
|
||||
@@ -114,19 +58,6 @@ export default {
|
||||
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
|
||||
...mapMutations('list', ['defaultListAdd', 'defaultListAddMultiple']),
|
||||
...mapMutations('player', ['setList']),
|
||||
handleDoubleClick(index) {
|
||||
if (
|
||||
window.performance.now() - this.clickTime > 400 ||
|
||||
this.clickIndex !== index
|
||||
) {
|
||||
this.clickTime = window.performance.now()
|
||||
this.clickIndex = index
|
||||
return
|
||||
}
|
||||
(this.source == 'kw' || !this.isAPITemp) ? this.testPlay(index) : this.handleSearch(index)
|
||||
this.clickTime = 0
|
||||
this.clickIndex = -1
|
||||
},
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
case 'download':
|
||||
@@ -150,6 +81,7 @@ export default {
|
||||
if (index == null) {
|
||||
targetSong = this.selectdData[0]
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
this.resetSelect()
|
||||
} else {
|
||||
targetSong = this.list[index]
|
||||
this.defaultListAdd(targetSong)
|
||||
@@ -177,31 +109,21 @@ export default {
|
||||
handleTogglePage(page) {
|
||||
this.getList(page).then(() => {
|
||||
this.page = this.info.page
|
||||
this.$nextTick(() => {
|
||||
scrollTo(this.$refs.dom_scrollContent, 0)
|
||||
})
|
||||
})
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdData = isSelect ? [...this.list] : []
|
||||
},
|
||||
resetSelect() {
|
||||
this.isSelectAll = false
|
||||
this.selectdData = []
|
||||
},
|
||||
handleAddDownload(type) {
|
||||
this.createDownload({ musicInfo: this.musicInfo, type })
|
||||
this.isShowDownload = false
|
||||
},
|
||||
handleAddDownloadMultiple(type) {
|
||||
switch (this.source) {
|
||||
// case 'kg':
|
||||
case 'kg':
|
||||
case 'wy':
|
||||
type = '128k'
|
||||
}
|
||||
this.createDownloadMultiple({ list: [...this.selectdData], type })
|
||||
this.resetSelect()
|
||||
this.isShowDownloadMultiple = false
|
||||
this.resetSelect()
|
||||
},
|
||||
handleFlowBtnClick(action) {
|
||||
switch (action) {
|
||||
@@ -210,7 +132,6 @@ export default {
|
||||
break
|
||||
case 'play':
|
||||
this.testPlay()
|
||||
this.resetSelect()
|
||||
break
|
||||
case 'add':
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
@@ -218,6 +139,23 @@ export default {
|
||||
break
|
||||
}
|
||||
},
|
||||
handleSongListAction({ action, data }) {
|
||||
switch (action) {
|
||||
case 'listBtnClick':
|
||||
return this.handleListBtnClick(data)
|
||||
case 'togglePage':
|
||||
return this.handleTogglePage(data)
|
||||
case 'flowBtnClick':
|
||||
return this.handleFlowBtnClick(data)
|
||||
case 'testPlay':
|
||||
return this.testPlay(data)
|
||||
case 'search':
|
||||
return this.handleSearch(data)
|
||||
}
|
||||
},
|
||||
resetSelect() {
|
||||
this.selectdData = []
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -250,46 +188,5 @@ export default {
|
||||
overflow: hidden;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
.list {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
// table {
|
||||
// position: relative;
|
||||
// thead {
|
||||
// position: fixed;
|
||||
// width: 100%;
|
||||
// th {
|
||||
// width: 100%;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
.thead {
|
||||
flex: none;
|
||||
}
|
||||
.tbody {
|
||||
flex: auto;
|
||||
overflow-y: auto;
|
||||
td {
|
||||
font-size: 12px;
|
||||
:global(.badge) {
|
||||
margin-right: 3px;
|
||||
&:first-child {
|
||||
margin-left: 3px;
|
||||
}
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.pagination {
|
||||
text-align: center;
|
||||
padding: 15px 0;
|
||||
// left: 50%;
|
||||
// transform: translateX(-50%);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.list")
|
||||
//- transition
|
||||
div(v-if="list.length" :class="$style.content")
|
||||
div(v-if="delayShow && list.length" :class="$style.content")
|
||||
div(:class="$style.thead")
|
||||
table
|
||||
thead
|
||||
@@ -18,7 +18,7 @@
|
||||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid'
|
||||
@click="handleDoubleClick(index)" :class="[isPlayList && playIndex === index ? $style.active : '', isAPITemp && item.source != 'kw' ? $style.disabled : '']")
|
||||
@click="handleDoubleClick(index)" :class="[isPlayList && playIndex === index ? $style.active : '', (isAPITemp && item.source != 'kw') || item.source == 'tx' || item.source == 'wy' ? $style.disabled : '']")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
td.break(style="width: 25%;") {{item.name}}
|
||||
@@ -37,6 +37,7 @@
|
||||
//- button.btn-success(type='button' v-if="(item._types['128k'] || item._types['192k'] || item._types['320k']) && userInfo" @click.stop='showListModal(index)') +
|
||||
td(style="width: 10%;") {{item.interval || '--/--'}}
|
||||
div(:class="$style.noItem" v-else)
|
||||
p(v-text="list.length ? '加载中...' : '列表竟然是空的...'")
|
||||
material-download-modal(:show="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false")
|
||||
material-download-multiple-modal(:show="isShowDownloadMultiple" :list="selectdData" @select="handleAddDownloadMultiple" @close="isShowDownloadMultiple = false")
|
||||
material-flow-btn(:show="isShowEditBtn" :add-btn="false" :play-btn="false" @btn-click="handleFlowBtnClick")
|
||||
@@ -57,6 +58,7 @@ export default {
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
isShowDownloadMultiple: false,
|
||||
delayShow: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -119,6 +121,11 @@ export default {
|
||||
// this.handleSearch(this.text, this.page)
|
||||
// }
|
||||
// },
|
||||
mounted() {
|
||||
if (this.list.length > 150) {
|
||||
setTimeout(() => this.delayShow = true, 200)
|
||||
} else this.delayShow = true
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('list', ['defaultListRemove', 'defaultListRemoveMultiple']),
|
||||
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
|
||||
@@ -137,6 +144,7 @@ export default {
|
||||
this.clickIndex = -1
|
||||
},
|
||||
testPlay(index) {
|
||||
if ((this.isAPITemp && this.list[index].source != 'kw') || this.list[index].source == 'tx' || this.list[index].source == 'wy') return
|
||||
this.setList({ list: this.list, listId: 'test', index })
|
||||
},
|
||||
handleRemove(index) {
|
||||
@@ -144,16 +152,16 @@ export default {
|
||||
},
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
case 'download':
|
||||
case 'download': {
|
||||
const minfo = this.list[info.index]
|
||||
if (this.isAPITemp && minfo.source != 'kw') return
|
||||
if ((this.isAPITemp && minfo.source != 'kw') || minfo.source == 'tx' || minfo.source == 'wy') return
|
||||
this.musicInfo = minfo
|
||||
this.$nextTick(() => {
|
||||
this.isShowDownload = true
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'play':
|
||||
if (this.isAPITemp && this.list[info.index].source != 'kw') return
|
||||
this.testPlay(info.index)
|
||||
break
|
||||
case 'remove':
|
||||
@@ -173,7 +181,7 @@ export default {
|
||||
this.selectdData = []
|
||||
},
|
||||
handleAddDownloadMultiple(type) {
|
||||
const list = this.setting.apiSource == 'temp' ? this.selectdData.filter(s => s.source == 'kw') : [...this.selectdData]
|
||||
const list = this.setting.apiSource == 'temp' ? this.selectdData.filter(s => s.source == 'kw') : this.selectdData.filter(s => s.source != 'tx' && s.source != 'wy')
|
||||
this.createDownloadMultiple({ list, type })
|
||||
this.resetSelect()
|
||||
this.isShowDownloadMultiple = false
|
||||
@@ -239,6 +247,20 @@ export default {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.no-item {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
p {
|
||||
font-size: 24px;
|
||||
color: @color-theme_2-font-label;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.tbody {
|
||||
@@ -248,6 +270,12 @@ each(@themes, {
|
||||
}
|
||||
}
|
||||
}
|
||||
.no-item {
|
||||
p {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.search")
|
||||
//- transition
|
||||
div(v-if="list.length" :class="$style.list")
|
||||
div(:class="$style.header")
|
||||
material-tab(:class="$style.tab" :list="sources" align="left" item-key="id" item-name="name" v-model="searchSourceId")
|
||||
div(v-if="listInfo.list.length" :class="$style.list")
|
||||
div(:class="$style.thead")
|
||||
table
|
||||
thead
|
||||
@@ -17,7 +19,7 @@
|
||||
div.scroll(:class="$style.tbody" ref="dom_scrollContent")
|
||||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid' @click="handleDoubleClick(index)")
|
||||
tr(v-for='(item, index) in listInfo.list' :key='item.songmid' @click="handleDoubleClick(index)")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
td.break(style="width: 25%;")
|
||||
@@ -27,15 +29,18 @@
|
||||
td.break(style="width: 20%;") {{item.singer}}
|
||||
td.break(style="width: 25%;") {{item.albumName}}
|
||||
td(style="width: 15%;")
|
||||
material-list-buttons(:index="index" :remove-btn="false" @btn-click="handleListBtnClick")
|
||||
material-list-buttons(:index="index" :remove-btn="false" :class="$style.listBtn"
|
||||
:play-btn="item.source == 'kw' || (!isAPITemp && item.source != 'tx' && item.source != 'wy')"
|
||||
:download-btn="item.source == 'kw' || (!isAPITemp && item.source != 'tx' && item.source != 'wy')"
|
||||
@btn-click="handleListBtnClick")
|
||||
td(style="width: 10%;") {{item.interval}}
|
||||
div(:class="$style.pagination")
|
||||
material-pagination(:count="listInfo.total" :limit="limit" :page="page" @btn-click="handleTogglePage")
|
||||
material-pagination(:count="listInfo.total" :limit="listInfo.limit" :page="page" @btn-click="handleTogglePage")
|
||||
div(v-else :class="$style.noitem")
|
||||
p 搜我所想~~😉
|
||||
material-download-modal(:show="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false")
|
||||
material-download-multiple-modal(:show="isShowDownloadMultiple" :list="selectdData" @select="handleAddDownloadMultiple" @close="isShowDownloadMultiple = false")
|
||||
material-flow-btn(:show="isShowEditBtn" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||
material-flow-btn(:show="isShowEditBtn && (searchSourceId == 'kw' || searchSourceId == 'all' || !isAPITemp)" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -57,25 +62,22 @@ export default {
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
isShowDownloadMultiple: false,
|
||||
searchSourceId: null,
|
||||
}
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (to.query.text === undefined) return
|
||||
if (to.query.text === '') {
|
||||
this.clearList()
|
||||
} else {
|
||||
this.text = to.query.text
|
||||
this.page = 1
|
||||
this.handleSearch(this.text, this.page)
|
||||
}
|
||||
this.text = to.query.text
|
||||
this.page = 1
|
||||
this.handleSearch(this.text, this.page)
|
||||
next()
|
||||
},
|
||||
mounted() {
|
||||
// console.log('mounted')
|
||||
this.searchSourceId = this.setting.search.searchSource
|
||||
if (this.$route.query.text === undefined) {
|
||||
let info = this.$store.getters['search/info']
|
||||
this.text = info.text
|
||||
this.page = info.page
|
||||
this.text = this.$store.getters['search/searchText']
|
||||
this.page = this.listInfo.page
|
||||
} else if (this.$route.query.text === '') {
|
||||
this.clearList()
|
||||
} else {
|
||||
@@ -89,30 +91,49 @@ export default {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isIndeterminate = len !== this.listInfo.list.length
|
||||
this.isShowEditBtn = true
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
}
|
||||
},
|
||||
list() {
|
||||
'listInfo.list'() {
|
||||
this.resetSelect()
|
||||
},
|
||||
searchSourceId(n) {
|
||||
if (n === this.setting.search.searchSource) return
|
||||
this.$nextTick(() => {
|
||||
this.page = 1
|
||||
this.handleSearch(this.text, this.page)
|
||||
})
|
||||
this.setSearchSource({
|
||||
searchSource: n,
|
||||
})
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo']),
|
||||
...mapGetters('search', ['list', 'limit', 'listInfo']),
|
||||
...mapGetters(['userInfo', 'setting']),
|
||||
...mapGetters('search', ['sourceList', 'allList', 'sources']),
|
||||
...mapGetters('list', ['defaultList']),
|
||||
listInfo() {
|
||||
return this.setting.search.searchSource == 'all' ? this.allList : this.sourceList[this.setting.search.searchSource]
|
||||
},
|
||||
isAPITemp() {
|
||||
return this.setting.apiSource == 'temp'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setSearchSource']),
|
||||
...mapActions('search', ['search']),
|
||||
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
|
||||
...mapMutations('search', ['clearList', 'setPage']),
|
||||
...mapMutations('list', ['defaultListAdd', 'defaultListAddMultiple']),
|
||||
...mapMutations('player', ['setList']),
|
||||
handleSearch(text, page) {
|
||||
this.search({ text, page, limit: this.limit }).then(data => {
|
||||
if (text === '') return this.clearList()
|
||||
|
||||
this.search({ text, page, limit: this.listInfo.limit }).then(data => {
|
||||
this.page = page
|
||||
this.$nextTick(() => {
|
||||
scrollTo(this.$refs.dom_scrollContent, 0)
|
||||
@@ -135,7 +156,7 @@ export default {
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
case 'download':
|
||||
this.musicInfo = this.list[info.index]
|
||||
this.musicInfo = this.listInfo.list[info.index]
|
||||
this.$nextTick(() => {
|
||||
this.isShowDownload = true
|
||||
})
|
||||
@@ -151,9 +172,10 @@ export default {
|
||||
let targetSong
|
||||
if (index == null) {
|
||||
targetSong = this.selectdData[0]
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
this.defaultListAddMultiple(this.filterList(this.selectdData))
|
||||
} else {
|
||||
targetSong = this.list[index]
|
||||
if ((this.isAPITemp && this.listInfo.list[index].source != 'kw') || this.listInfo.list[index].source == 'tx' || this.listInfo.list[index].source == 'wy') return
|
||||
targetSong = this.listInfo.list[index]
|
||||
this.defaultListAdd(targetSong)
|
||||
}
|
||||
let targetIndex = this.defaultList.list.findIndex(
|
||||
@@ -175,12 +197,12 @@ export default {
|
||||
this.isShowDownload = false
|
||||
},
|
||||
handleAddDownloadMultiple(type) {
|
||||
this.createDownloadMultiple({ list: [...this.selectdData], type })
|
||||
this.createDownloadMultiple({ list: this.filterList(this.selectdData), type })
|
||||
this.resetSelect()
|
||||
this.isShowDownloadMultiple = false
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdData = isSelect ? [...this.list] : []
|
||||
this.selectdData = isSelect ? [...this.listInfo.list] : []
|
||||
},
|
||||
resetSelect() {
|
||||
this.isSelectAll = false
|
||||
@@ -196,11 +218,14 @@ export default {
|
||||
this.resetSelect()
|
||||
break
|
||||
case 'add':
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
this.defaultListAddMultiple(this.filterList(this.selectdData))
|
||||
this.resetSelect()
|
||||
break
|
||||
}
|
||||
},
|
||||
filterList(list) {
|
||||
return this.setting.apiSource == 'temp' ? list.filter(s => s.source == 'kw') : list.filter(s => s.source != 'tx' && s.source != 'wy')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -211,6 +236,11 @@ export default {
|
||||
.search {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
.header {
|
||||
flex: none;
|
||||
}
|
||||
.list {
|
||||
position: relative;
|
||||
@@ -218,6 +248,8 @@ export default {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
flex: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
.thead {
|
||||
flex: none;
|
||||
@@ -238,6 +270,9 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.listBtn {
|
||||
min-height: 24px;
|
||||
}
|
||||
.pagination {
|
||||
text-align: center;
|
||||
padding: 15px 0;
|
||||
@@ -245,8 +280,9 @@ export default {
|
||||
// transform: translateX(-50%);
|
||||
}
|
||||
.noitem {
|
||||
flex: auto;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
@@ -254,7 +290,17 @@ export default {
|
||||
|
||||
p {
|
||||
font-size: 24px;
|
||||
color: #ccc;
|
||||
color: @color-theme_2-font-label;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.noitem {
|
||||
p {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
|
||||
@@ -32,7 +32,7 @@ div.scroll(:class="$style.setting")
|
||||
div
|
||||
material-checkbox(id="setting_player_highQuality" v-model="current_setting.player.highQuality" label="是否启用")
|
||||
dd(title='在任务栏上显示当前歌曲播放进度')
|
||||
h3 是否启用任务栏播放进度条
|
||||
h3 任务栏播放进度条
|
||||
div
|
||||
material-checkbox(id="setting_player_showTaskProgess" v-model="current_setting.player.isShowTaskProgess" label="是否启用")
|
||||
dt 下载设置
|
||||
@@ -49,11 +49,36 @@ div.scroll(:class="$style.setting")
|
||||
div
|
||||
material-checkbox(:id="`setting_download_musicName_${item.value}`" :class="$style.gapLeft" name="setting_download_musicName" :value="item.value" :key="item.value" need
|
||||
v-model="current_setting.download.fileName" v-for="item in musicNames" :label="item.name")
|
||||
dd(title='是否将封面嵌入音频文件中')
|
||||
h3 封面嵌入(只支持MP3格式)
|
||||
div
|
||||
material-checkbox(id="setting_download_isEmbedPic" v-model="current_setting.download.isEmbedPic" label="是否启用")
|
||||
dd(title='是否同时下载歌词文件')
|
||||
h3 歌词下载
|
||||
div
|
||||
material-checkbox(id="setting_download_isDownloadLrc" v-model="current_setting.download.isDownloadLrc" label="是否启用")
|
||||
//- dt 列表设置
|
||||
//- dd(title='播放列表是否显示专辑栏')
|
||||
h3 专辑栏
|
||||
div
|
||||
material-checkbox(id="setting_list_showalbum" v-model="current_setting.list.isShowAlbumName" label="是否显示专辑栏")
|
||||
dt 网络设置
|
||||
dd
|
||||
h3 代理设置(歌曲下载暂不支持代理)
|
||||
div
|
||||
p
|
||||
material-checkbox(id="setting_network_proxy_enable" v-model="current_setting.network.proxy.enable" @change="handleProxyChange('enable')" label="是否启用")
|
||||
p
|
||||
material-input(:class="$style.gapLeft" v-model="current_setting.network.proxy.host" @change="handleProxyChange('host')" placeholder="主机")
|
||||
material-input(:class="$style.gapLeft" v-model="current_setting.network.proxy.port" @change="handleProxyChange('port')" placeholder="端口")
|
||||
p
|
||||
material-input(:class="$style.gapLeft" v-model="current_setting.network.proxy.username" @change="handleProxyChange('username')" placeholder="用户名")
|
||||
material-input(:class="$style.gapLeft" v-model="current_setting.network.proxy.password" @change="handleProxyChange('password')" type="password" placeholder="密码")
|
||||
dt 强迫症设置
|
||||
dd
|
||||
h3 离开搜索界面时清空搜索框
|
||||
div
|
||||
material-checkbox(id="setting_odc_isAutoClearSearchInput" v-model="current_setting.odc.isAutoClearSearchInput" label="是否启用")
|
||||
dt 备份与恢复
|
||||
dd
|
||||
h3 部分数据
|
||||
@@ -81,7 +106,32 @@ div.scroll(:class="$style.setting")
|
||||
dd
|
||||
p.small
|
||||
| 本软件完全免费,代码已开源,开源地址:
|
||||
span.hover(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop')") https://github.com/lyswhut/lx-music-desktop
|
||||
span.hover.underline(title="点击打开" @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop#readme')") https://github.com/lyswhut/lx-music-desktop
|
||||
p.small
|
||||
| 最新版网盘下载地址(网盘内有Windows、MAC版):
|
||||
span.hover.underline(title="点击打开" @click="handleOpenUrl('https://www.lanzous.com/b906260/')") 网盘地址
|
||||
| 密码:
|
||||
span.hover(title="点击复制" @click="clipboardWriteText('glqw')") glqw
|
||||
p.small
|
||||
| 软件的常见问题可转至:
|
||||
span.hover.underline(title="点击打开" @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop#常见问题')") 常见问题
|
||||
//- p.small
|
||||
| 怀念曾经的
|
||||
strong @messoer
|
||||
| ,非常感谢曾经为本软件提供数据源!
|
||||
p.small
|
||||
| 阅读常见问题后仍有问题可 mail to:
|
||||
span.hover(title="点击复制" @click="clipboardWriteText('lyswhut@qq.com')") lyswhut@qq.com
|
||||
| 或到 GitHub 提交
|
||||
span.hover.underline(title="点击打开" @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/issues')") issue
|
||||
p.small
|
||||
| 若觉得好用的话可以去 GitHub 点个
|
||||
strong star
|
||||
| 支持作者哦~~🍻
|
||||
p
|
||||
span 如果你资金充裕,还可以
|
||||
material-btn(@click="handleOpenUrl('https://cdn.stsky.cn/qrc.png')" min title="土豪,你好 🙂") 打赏下作者
|
||||
span ,以帮我分担点服务器费用~❤️
|
||||
p.small
|
||||
| 本软件仅用于学习交流使用,禁止将本软件用于
|
||||
strong 非法用途
|
||||
@@ -92,15 +142,6 @@ div.scroll(:class="$style.setting")
|
||||
| 使用本软件造成的一切后果由
|
||||
strong 使用者
|
||||
| 承担!
|
||||
p.small
|
||||
| 本软件的部分接口使用自 https://github.com/messoer ,非常感谢
|
||||
strong @messoer
|
||||
| !
|
||||
p.small 若有问题可 mail to:lyswhut@qq.com 或到 GitHub 提交 issue
|
||||
p.small
|
||||
| 若觉得好用的话可以去 GitHub 点个
|
||||
strong star
|
||||
| 支持作者哦~~🍻
|
||||
p
|
||||
small By:
|
||||
| 落雪无痕
|
||||
@@ -108,7 +149,7 @@ div.scroll(:class="$style.setting")
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { openDirInExplorer, openSelectDir, openSaveDir, updateSetting, openUrl } from '../utils'
|
||||
import { openDirInExplorer, openSelectDir, openSaveDir, updateSetting, openUrl, clipboardWriteText } from '../utils'
|
||||
import { rendererSend } from '../../common/icp'
|
||||
import fs from 'fs'
|
||||
|
||||
@@ -137,6 +178,20 @@ export default {
|
||||
download: {
|
||||
savePath: '',
|
||||
fileName: '歌名 - 歌手',
|
||||
isDownloadLrc: false,
|
||||
isEmbedPic: true,
|
||||
},
|
||||
network: {
|
||||
proxy: {
|
||||
enable: false,
|
||||
host: '',
|
||||
port: '',
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
},
|
||||
odc: {
|
||||
isAutoClearSearchInput: false,
|
||||
},
|
||||
themeId: 0,
|
||||
sourceId: 0,
|
||||
@@ -162,20 +217,25 @@ export default {
|
||||
},
|
||||
],
|
||||
apiSources: [
|
||||
{
|
||||
id: 'messoer',
|
||||
// label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)',
|
||||
label: '由 messoer 提供的接口(该接口已关闭)',
|
||||
disabled: true,
|
||||
},
|
||||
// {
|
||||
// id: 'messoer',
|
||||
// // label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)',
|
||||
// label: '由 messoer 提供的接口(该接口已关闭)',
|
||||
// disabled: true,
|
||||
// },
|
||||
// {
|
||||
// id: 'internal',
|
||||
// label: '内置接口(只能试听或下载128k音质,该接口支持软件的所有功能)',
|
||||
// disabled: false,
|
||||
// },
|
||||
{
|
||||
id: 'test',
|
||||
label: '测试接口(软件的大部分功能可用,该接口访问速度略慢)',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: 'temp',
|
||||
label: '临时接口(软件的某些功能将不可用,但可下载无损等音质)',
|
||||
label: '临时接口(软件的某些功能不可用,该接口比测试接口快一些,建议测试接口不可用再使用本接口)',
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
@@ -374,6 +434,15 @@ export default {
|
||||
showUpdateModal() {
|
||||
this.setVersionModalVisible({ isShow: true })
|
||||
},
|
||||
clipboardWriteText(text) {
|
||||
clipboardWriteText(text)
|
||||
},
|
||||
handleProxyChange(key) {
|
||||
window.globalObj.proxy[key] = this.current_setting.network.proxy[key]
|
||||
},
|
||||
openRewardModal() {
|
||||
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -434,7 +503,9 @@ export default {
|
||||
|
||||
.theme {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
// padding: 0 15px;
|
||||
margin-bottom: -20px;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
@@ -444,6 +515,7 @@ export default {
|
||||
// color: @color-theme;
|
||||
margin-right: 30px;
|
||||
transition: color .3s ease;
|
||||
margin-bottom: 20px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
@@ -464,6 +536,9 @@ export default {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
background-position: center;
|
||||
background-size: auto 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,6 +547,7 @@ export default {
|
||||
span {
|
||||
&:after {
|
||||
background-color: ~'@{color-@{value}-theme}';
|
||||
background-image: ~'@{color-@{value}-theme-bgimg}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,402 @@
|
||||
<template lang="pug">
|
||||
div
|
||||
h2 推荐
|
||||
div(:class="$style.container")
|
||||
transition(enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut")
|
||||
div(:class="$style.songListDetailContent" v-show="isVisibleListDetail")
|
||||
div(:class="$style.songListHeader")
|
||||
div(:class="$style.songListHeaderLeft")
|
||||
img(:src="selectListInfo.img")
|
||||
span(:class="$style.playNum" v-if="selectListInfo.play_count") {{selectListInfo.play_count}}
|
||||
div(:class="$style.songListHeaderMiddle")
|
||||
h3(:title="selectListInfo.name") {{selectListInfo.name}}
|
||||
p(:title="selectListInfo.desc") {{selectListInfo.desc}}
|
||||
div(:class="$style.songListHeaderRight")
|
||||
material-btn(:class="$style.closeDetailButton" @click="hideListDetail") 返回
|
||||
material-song-list(v-model="selectdData" @action="handleSongListAction" :source="source" :page="listDetail.page" :limit="listDetail.limit" :total="listDetail.total" :list="listDetail.list")
|
||||
transition(enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut")
|
||||
div(:class="$style.songListContent" v-show="!isVisibleListDetail")
|
||||
div(:class="$style.header")
|
||||
material-tag-list(:class="$style.tagList" :list="tagList" v-model="tagInfo")
|
||||
material-tab(:class="$style.tab" :list="sorts" item-key="id" item-name="name" v-model="sortId")
|
||||
material-select(:class="$style.select" :list="sourceInfo.sources" item-key="id" item-name="name" v-model="source")
|
||||
div.scroll(:class="$style.songList" ref="dom_scrollContent")
|
||||
ul
|
||||
li(:class="$style.item" v-for="(item, index) in listData.list" @click="handleItemClick(index)")
|
||||
div(:class="$style.left")
|
||||
img(:src="item.img")
|
||||
div(:class="$style.right" :src="item.img")
|
||||
h4(:title="item.name") {{item.name}}
|
||||
p(:title="item.desc") {{item.desc}}
|
||||
li(:class="$style.item" style="cursor: default;" v-if="listData.list && listData.list.length && listData.list.length % 3 == 2")
|
||||
div(:class="$style.pagination")
|
||||
material-pagination(:count="listData.total" :limit="listData.limit" :page="listData.page" @btn-click="handleToggleListPage")
|
||||
material-download-modal(:show="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false")
|
||||
material-download-multiple-modal(:show="isShowDownloadMultiple" :list="selectdData" @select="handleAddDownloadMultiple" @close="isShowDownloadMultiple = false")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations, mapActions } from 'vuex'
|
||||
import { scrollTo } from '../utils'
|
||||
// import music from '../utils/music'
|
||||
export default {
|
||||
name: 'SongList',
|
||||
data() {
|
||||
return {
|
||||
count: 0,
|
||||
tagInfo: {
|
||||
name: '默认',
|
||||
id: null,
|
||||
},
|
||||
sortId: undefined,
|
||||
source: null,
|
||||
isShowDownload: false,
|
||||
musicInfo: null,
|
||||
selectdData: [],
|
||||
isShowDownloadMultiple: false,
|
||||
isToggleSource: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
...mapGetters('songList', ['sourceInfo', 'tags', 'listData', 'isVisibleListDetail', 'selectListInfo', 'listDetail']),
|
||||
...mapGetters('list', ['defaultList']),
|
||||
sorts() {
|
||||
return this.source ? this.sourceInfo.sortList[this.source] : []
|
||||
},
|
||||
isAPITemp() {
|
||||
return this.setting.apiSource == 'temp'
|
||||
},
|
||||
tagList() {
|
||||
return this.tags[this.source] ? this.tags[this.source].tags : []
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
sortId(n, o) {
|
||||
this.setSongList({ sortId: n })
|
||||
if (o === undefined && this.listData.page !== 1) return
|
||||
this.$nextTick(() => {
|
||||
this.getList(1).then(() => {
|
||||
this.$nextTick(() => {
|
||||
scrollTo(this.$refs.dom_scrollContent, 0)
|
||||
})
|
||||
})
|
||||
})
|
||||
// if (this.isVisibleListDetail) this.setVisibleListDetail(false)
|
||||
},
|
||||
tagInfo(n, o) {
|
||||
this.setSongList({ tagInfo: n })
|
||||
if (!o && this.listData.page !== 1) return
|
||||
if (this.isToggleSource) {
|
||||
this.isToggleSource = false
|
||||
return
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.getList(1).then(() => {
|
||||
this.$nextTick(() => {
|
||||
scrollTo(this.$refs.dom_scrollContent, 0)
|
||||
})
|
||||
})
|
||||
})
|
||||
// if (this.isVisibleListDetail) this.setVisibleListDetail(false)
|
||||
},
|
||||
source(n, o) {
|
||||
this.setSongList({ source: n })
|
||||
if (!this.tags[n]) this.getTags()
|
||||
if (o) {
|
||||
this.isToggleSource = true
|
||||
this.tagInfo = {
|
||||
name: '默认',
|
||||
id: null,
|
||||
}
|
||||
this.sortId = this.sorts[0] && this.sorts[0].id
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.source = this.setting.songList.source
|
||||
this.isToggleSource = true
|
||||
this.tagInfo = this.setting.songList.tagInfo
|
||||
this.sortId = this.setting.songList.sortId
|
||||
},
|
||||
methods: {
|
||||
add() {
|
||||
this.count++
|
||||
...mapMutations(['setSongList']),
|
||||
...mapActions('songList', ['getTags', 'getList', 'getListDetail']),
|
||||
...mapMutations('songList', ['setVisibleListDetail', 'setSelectListInfo', 'clearListDetail']),
|
||||
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
|
||||
...mapMutations('list', ['defaultListAdd', 'defaultListAddMultiple']),
|
||||
...mapMutations('player', ['setList']),
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
case 'download':
|
||||
this.musicInfo = this.listDetail.list[info.index]
|
||||
this.$nextTick(() => {
|
||||
this.isShowDownload = true
|
||||
})
|
||||
break
|
||||
case 'play':
|
||||
this.testPlay(info.index)
|
||||
break
|
||||
case 'search':
|
||||
this.handleSearch(info.index)
|
||||
break
|
||||
// case 'add':
|
||||
// break
|
||||
}
|
||||
},
|
||||
testPlay(index) {
|
||||
let targetSong
|
||||
if (index == null) {
|
||||
targetSong = this.selectdData[0]
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
this.resetSelect()
|
||||
} else {
|
||||
targetSong = this.listDetail.list[index]
|
||||
this.defaultListAdd(targetSong)
|
||||
}
|
||||
let targetIndex = this.defaultList.list.findIndex(
|
||||
s => s.songmid === targetSong.songmid
|
||||
)
|
||||
if (targetIndex > -1) {
|
||||
this.setList({
|
||||
list: this.defaultList.list,
|
||||
listId: 'test',
|
||||
index: targetIndex,
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSearch(index) {
|
||||
const info = this.listDetail.list[index]
|
||||
this.$router.push({
|
||||
path: 'search',
|
||||
query: {
|
||||
text: `${info.name} ${info.singer}`,
|
||||
},
|
||||
})
|
||||
},
|
||||
handleToggleListPage(page) {
|
||||
this.getList(page).then(() => {
|
||||
this.$nextTick(() => {
|
||||
scrollTo(this.$refs.dom_scrollContent, 0)
|
||||
})
|
||||
})
|
||||
},
|
||||
handleToggleListDetailPage(page) {
|
||||
this.getListDetail({ id: this.selectListInfo.id, page }).then(() => {
|
||||
this.$nextTick(() => {
|
||||
scrollTo(this.$refs.dom_scrollContent, 0)
|
||||
})
|
||||
})
|
||||
},
|
||||
handleAddDownload(type) {
|
||||
this.createDownload({ musicInfo: this.musicInfo, type })
|
||||
this.isShowDownload = false
|
||||
},
|
||||
handleAddDownloadMultiple(type) {
|
||||
switch (this.source) {
|
||||
case 'kg':
|
||||
case 'wy':
|
||||
type = '128k'
|
||||
}
|
||||
this.createDownloadMultiple({ list: [...this.selectdData], type })
|
||||
this.resetSelect()
|
||||
this.isShowDownloadMultiple = false
|
||||
},
|
||||
handleItemClick(index) {
|
||||
this.setSelectListInfo(this.listData.list[index])
|
||||
this.setVisibleListDetail(true)
|
||||
this.clearListDetail()
|
||||
this.$nextTick(() => {
|
||||
this.getListDetail({ id: this.selectListInfo.id, page: 1 })
|
||||
})
|
||||
},
|
||||
handleFlowBtnClick(action) {
|
||||
switch (action) {
|
||||
case 'download':
|
||||
this.isShowDownloadMultiple = true
|
||||
break
|
||||
case 'play':
|
||||
this.testPlay()
|
||||
break
|
||||
case 'add':
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
this.resetSelect()
|
||||
break
|
||||
}
|
||||
},
|
||||
handleSongListAction({ action, data }) {
|
||||
switch (action) {
|
||||
case 'listBtnClick':
|
||||
return this.handleListBtnClick(data)
|
||||
case 'togglePage':
|
||||
return this.handleToggleListDetailPage(data)
|
||||
case 'flowBtnClick':
|
||||
return this.handleFlowBtnClick(data)
|
||||
case 'testPlay':
|
||||
return this.testPlay(data)
|
||||
case 'search':
|
||||
return this.handleSearch(data)
|
||||
}
|
||||
},
|
||||
resetSelect() {
|
||||
this.selectdData = []
|
||||
},
|
||||
hideListDetail() {
|
||||
setTimeout(() => this.setVisibleListDetail(false), 50)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../assets/styles/layout.less';
|
||||
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
.header {
|
||||
flex: none;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
|
||||
}
|
||||
.tab {
|
||||
flex: auto;
|
||||
}
|
||||
.select {
|
||||
flex: none;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.songListContent, .song-list-detail-content {
|
||||
// flex: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.songListContent {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
// position: relative;
|
||||
}
|
||||
|
||||
.song-list-header {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
height: 60px;
|
||||
}
|
||||
.song-list-header-left {
|
||||
flex: none;
|
||||
margin-left: 5px;
|
||||
width: 60px;
|
||||
position: relative;
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
.play-num {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 2px;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
text-align: right;
|
||||
.mixin-ellipsis-1;
|
||||
}
|
||||
}
|
||||
|
||||
.song-list-header-middle {
|
||||
flex: auto;
|
||||
padding: 5px 7px;
|
||||
h3 {
|
||||
.mixin-ellipsis-1;
|
||||
line-height: 1.2;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
p {
|
||||
.mixin-ellipsis-2;
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
.song-list-header-right {
|
||||
flex: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.song-list-detail-content {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.songList {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
padding: 0 15px;
|
||||
ul {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
.item {
|
||||
width: 32%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
margin-top: 15px;
|
||||
cursor: pointer;
|
||||
transition: opacity @transition-theme;
|
||||
&:hover {
|
||||
opacity: .7;
|
||||
}
|
||||
}
|
||||
.left {
|
||||
flex: none;
|
||||
width: 66px;
|
||||
height: 66px;
|
||||
display: flex;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
flex: auto;
|
||||
padding: 5px 15px 5px 7px;
|
||||
overflow: hidden;
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
text-align: justify;
|
||||
line-height: 1.2;
|
||||
.mixin-ellipsis-1;
|
||||
}
|
||||
p {
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
.mixin-ellipsis-2;
|
||||
text-align: justify;
|
||||
line-height: 1.2;
|
||||
// text-indent: 24px;
|
||||
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
.pagination {
|
||||
text-align: center;
|
||||
padding: 15px 0;
|
||||
// left: 50%;
|
||||
// transform: translateX(-50%);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user