You've already forked lx-music-desktop
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed28a59fcb | ||
|
|
adc46411b2 | ||
|
|
fcc4d666ec | ||
|
|
9d89f5d48d | ||
|
|
88c62e01ad | ||
|
|
1823598a8b | ||
|
|
3fd22988c1 | ||
|
|
a3ade4cde2 | ||
|
|
55c2286eca | ||
|
|
1afa050698 | ||
|
|
dfa15c6952 | ||
|
|
a2af321c5e | ||
|
|
fddfaf23ce | ||
|
|
ae0ee2048a | ||
|
|
6659d1fe43 | ||
|
|
f601e61f8d | ||
|
|
f8ed7a112a | ||
|
|
b0d6181bd7 | ||
|
|
82843b14b4 | ||
|
|
0df3ca3c5f | ||
|
|
c881f8e886 | ||
|
|
f1bf274de1 | ||
|
|
91e4e9c2d5 | ||
|
|
63a5f94a67 | ||
|
|
1bd8694262 | ||
|
|
501231adff | ||
|
|
3a033b66c4 | ||
|
|
46aacba037 | ||
|
|
10ef80da75 | ||
|
|
75b7897ad6 | ||
|
|
14423e0eb3 | ||
|
|
fe44581a61 | ||
|
|
0d612bd6df | ||
|
|
b7eba95ab2 | ||
|
|
59091a5ea9 | ||
|
|
31e8b466cf | ||
|
|
c97bc5edfc | ||
|
|
74f8e9544b | ||
|
|
0a5e7c44ff |
12
.travis.yml
12
.travis.yml
@@ -1,19 +1,17 @@
|
||||
sudo: true
|
||||
language: node_js
|
||||
node_js: 12
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode10.2
|
||||
language: node_js
|
||||
node_js: "12"
|
||||
env:
|
||||
- ELECTRON_CACHE=$HOME/.cache/electron
|
||||
- ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
|
||||
|
||||
- os: linux
|
||||
language: node_js
|
||||
node_js: "12"
|
||||
dist: trusty
|
||||
services: docker
|
||||
language: generic
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -26,6 +24,8 @@ notifications:
|
||||
email: false
|
||||
|
||||
script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
||||
npm install && npm run publish:gh:linux
|
||||
|
||||
47
CHANGELOG.md
47
CHANGELOG.md
@@ -6,6 +6,53 @@ Project versioning adheres to [Semantic Versioning](http://semver.org/).
|
||||
Commit convention is based on [Conventional Commits](http://conventionalcommits.org).
|
||||
Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||
|
||||
## [0.11.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.10.0...v0.11.0) - 2019-11-10
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增歌曲缓冲定时器,尝试用于解决网络正常但是歌曲缓冲过久的问题
|
||||
- 新增下载管理的任务状态分类
|
||||
- 添加**杀毒软件提示有病毒或恶意行为**的说明,可到**常见问题**拉到最后查看(常见问题可在开源地址找到)
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化更新弹窗机制及其内容描述,对于可以自动更新的版本,现在可以看到软件的下载进度了
|
||||
|
||||
## [0.10.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.9.1...v0.10.0) - 2019-11-02
|
||||
|
||||
#### 优化
|
||||
|
||||
- 大幅减少程序**播放时**对CPU与GPU的使用,经测试CPU使用减少60%以上,GPU使用减少90%以上,这应该能解决MAC系统上的温度上涨的问题
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复酷我源**搜索提示**、**排行榜**无法获取的问题
|
||||
- 修复咪咕源无法播放的问题
|
||||
|
||||
## [0.9.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.9.0...v0.9.1) - 2019-10-27
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复没有配置文件时程序启动出错的问题
|
||||
|
||||
## [0.9.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.8.2...v0.9.0) - 2019-10-27
|
||||
|
||||
#### 新增
|
||||
|
||||
- 新增窗口大小设置,若觉得软件窗口小可以到设置页调大点
|
||||
- 新增定位当前播放歌曲,点击播放栏左侧的**歌曲图片**可在播放列表定位当前播放的歌曲(该功能对播放下载列表的歌曲无效)
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复搜索提示失效的问题
|
||||
- 修复从歌单或列表点击搜索按钮搜索目标歌曲时,搜索框未聚焦仍然弹出候选搜索列表的问题
|
||||
|
||||
## [0.8.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.8.1...v0.8.2) - 2019-10-20
|
||||
|
||||
#### 修复
|
||||
|
||||
- 兼容旧版酷我源搜索列表过滤128k音质的bug(注:0.8.1版本仅修复了酷我源的歌曲过滤问题,该修复仅对以后添加的歌曲有效,如果是之前添加的歌曲仍会出现这个问题,现修复对之前旧列表数据的兼容处理)
|
||||
|
||||
## [0.8.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.8.0...v0.8.1) - 2019-10-20
|
||||
|
||||
#### 修复
|
||||
|
||||
17
FAQ.md
17
FAQ.md
@@ -4,7 +4,7 @@
|
||||
|
||||
## 软件为什么没有桌面歌词与自定义列表功能
|
||||
|
||||
洛雪音乐的最初定位不是作为播放器开发的,它主要用于**查找歌曲**,软件的播放功能仅用于试听,不建议用作为常用播放器使用,因此无桌面、界面歌词,不可自定义列表。
|
||||
洛雪音乐的最初定位不是作为播放器开发的,它主要用于**查找歌曲**,软件的播放功能仅用于试听,不建议用作为常用播放器使用,因此无桌面、界面歌词,不可自定义列表等功能。
|
||||
|
||||
## 歌曲无法试听与下载
|
||||
|
||||
@@ -53,8 +53,21 @@
|
||||
|
||||
## 安装版安装失败,提示应用未安装
|
||||
|
||||
对于部分电脑出现安装失败的问题我也不懂什么原因,,可以尝试清理下安装文件,或者重启电脑试试。
|
||||
对于部分电脑出现安装失败的问题,可以做出以下尝试:
|
||||
|
||||
- 若你之前可以安装成功,但现在安装失败,就去**控制面板-程序和功能**或用第三方卸载工具看下有没有之前的版本残留,若同时在不同路径下安装了多个版本就可能会出现该问题,这种情况卸载掉所有版本重新安装即可
|
||||
- 清理安装路径下的残留文件
|
||||
- 以管理员权限打开`cmd`,输入`sfc /scannow`回车等待检查完成重启电脑
|
||||
- 若还是不行我也没办法了。。
|
||||
|
||||
## 缺少`xxx.dll`
|
||||
|
||||
这个是电脑缺少某些dll导致的,正常的系统是没有这个问题的,解决办法需自行百度弹出的错误信息看下别人是怎么解决的。
|
||||
|
||||
## 杀毒软件提示有病毒或恶意行为
|
||||
|
||||
本人只能保证我写的代码不包含任何**恶意代码**、**搜集用户信息**的行为,并且软件代码已开源,请自行查阅,软件安装包也是由CI拉取源代码构建,构建日志:[windows包](https://ci.appveyor.com/project/lyswhut/lx-music-desktop)、[Mac/Linux包](https://travis-ci.org/lyswhut/lx-music-desktop)<br>
|
||||
尽管如此,但这不意味着软件是100%安全的的,由于软件使用了第三方依赖,当这些依赖存在恶意行为时,软件也将会受到牵连,所以我只能尽量选择使用较多人用、信任度较高的依赖。<br>
|
||||
当然,以上说明建立的前提是在你所用的安装包是从**官方渠道**下载的,或者有相关能力者还可以下载源代码自己构建安装包。
|
||||
|
||||
最后,若出现杀毒软件报毒,请自行判断选择是否继续使用本软件!
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
|
||||
所用技术栈:
|
||||
|
||||
- Electron 6.x
|
||||
- Vue 2.x
|
||||
- Electron 7
|
||||
- Vue 2
|
||||
|
||||
已支持的平台:
|
||||
|
||||
@@ -80,7 +80,7 @@ npm run pack
|
||||
### 免责声明
|
||||
|
||||
本项目**不开发或者破解直接获取音频数据**的功能,所有音频数据均来自**第三方接口**!<br>
|
||||
本软件仅用于**测试 `electron 6.x` 在各种系统上的兼容性**及用于**对比各大音乐平台歌单、排行榜等数据列表的差异性**,使用本软件产生的**任何涉及版权相关的数据**请于**24小时内删除**。<br>
|
||||
本软件仅用于**测试 `electron 7` 在各种系统上的兼容性**及用于**对比各大音乐平台歌单、排行榜等数据列表的差异性**,使用本软件产生的**任何涉及版权相关的数据**请于**24小时内删除**。<br>
|
||||
本软件仅用于学习交流使用,禁止用于商业用途,使用本软件所造成的的后果由使用者承担!<br>
|
||||
若对此有疑问请 mail to: lyswhut@qq.com
|
||||
|
||||
|
||||
3464
package-lock.json
generated
3464
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "0.8.1",
|
||||
"version": "0.11.0",
|
||||
"description": "一个免费的音乐下载助手",
|
||||
"main": "./dist/electron/main.js",
|
||||
"productName": "lx-music-desktop",
|
||||
@@ -134,29 +134,29 @@
|
||||
},
|
||||
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/core": "^7.7.2",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"@babel/polyfill": "^7.6.0",
|
||||
"@babel/preset-env": "^7.6.3",
|
||||
"autoprefixer": "^9.6.5",
|
||||
"@babel/polyfill": "^7.7.0",
|
||||
"@babel/preset-env": "^7.7.1",
|
||||
"autoprefixer": "^9.7.1",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-minify-webpack-plugin": "^0.3.1",
|
||||
"babel-preset-minify": "^0.5.1",
|
||||
"cfonts": "^2.4.5",
|
||||
"chalk": "^2.4.2",
|
||||
"chalk": "^3.0.0",
|
||||
"changelog-parser": "^2.8.0",
|
||||
"copy-webpack-plugin": "^5.0.4",
|
||||
"core-js": "^3.3.2",
|
||||
"cos-nodejs-sdk-v5": "^2.5.12",
|
||||
"copy-webpack-plugin": "^5.0.5",
|
||||
"core-js": "^3.4.0",
|
||||
"cos-nodejs-sdk-v5": "^2.5.14",
|
||||
"cross-env": "^6.0.3",
|
||||
"css-loader": "^3.2.0",
|
||||
"del": "^5.1.0",
|
||||
"electron": "^6.0.12",
|
||||
"electron-builder": "^21.2.0",
|
||||
"electron": "^7.1.1",
|
||||
"electron-builder": "^22.1.0",
|
||||
"electron-debug": "^3.0.1",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint": "^6.6.0",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"eslint-formatter-friendly": "^7.0.0",
|
||||
"eslint-loader": "^3.0.2",
|
||||
@@ -182,14 +182,14 @@
|
||||
"rimraf": "^3.0.0",
|
||||
"stylus": "^0.54.7",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"terser-webpack-plugin": "^2.1.3",
|
||||
"terser-webpack-plugin": "^2.2.1",
|
||||
"url-loader": "^2.2.0",
|
||||
"vue-loader": "^15.7.1",
|
||||
"vue-loader": "^15.7.2",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-cli": "^3.3.9",
|
||||
"webpack-dev-server": "^3.8.2",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-dev-server": "^3.9.0",
|
||||
"webpack-hot-middleware": "^2.25.0",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
@@ -197,14 +197,14 @@
|
||||
"axios": "^0.19.0",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"dnscache": "^1.0.2",
|
||||
"electron-log": "^3.0.8",
|
||||
"electron-store": "^5.0.0",
|
||||
"electron-updater": "^4.1.2",
|
||||
"electron-log": "^3.0.9",
|
||||
"electron-store": "^5.1.0",
|
||||
"electron-updater": "^4.2.0",
|
||||
"flac-metadata": "^0.1.1",
|
||||
"js-htmlencode": "^0.3.0",
|
||||
"lrc-file-parser": "^0.1.14",
|
||||
"node-downloader-helper": "^1.0.10",
|
||||
"node-id3": "^0.1.11",
|
||||
"node-id3": "^0.1.12",
|
||||
"request": "^2.88.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-electron": "^1.0.6",
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
#### 修复
|
||||
### 新增
|
||||
|
||||
- 修复酷我源搜索歌曲结果未添加128k音质导致播放128k音质时显示“该歌曲没有可播放的音频”的问题
|
||||
- 新增歌曲缓冲定时器,尝试用于解决网络正常但是歌曲缓冲过久的问题
|
||||
- 新增下载管理的任务状态分类
|
||||
- 添加**杀毒软件提示有病毒或恶意行为**的说明,可到**常见问题**拉到最后查看(常见问题可在开源地址找到)
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化更新弹窗机制及其内容描述,对于可以自动更新的版本,现在可以看到软件的下载进度了
|
||||
|
||||
@@ -1,7 +1,27 @@
|
||||
{
|
||||
"version": "0.8.1",
|
||||
"desc": "<h4>修复</h4>\n<ul>\n<li>修复酷我源搜索歌曲结果未添加128k音质导致播放128k音质时显示“该歌曲没有可播放的音频”的问题</li>\n</ul>\n",
|
||||
"version": "0.11.0",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增歌曲缓冲定时器,尝试用于解决网络正常但是歌曲缓冲过久的问题</li>\n<li>新增下载管理的任务状态分类</li>\n<li>添加<strong>杀毒软件提示有病毒或恶意行为</strong>的说明,可到<strong>常见问题</strong>拉到最后查看(常见问题可在开源地址找到)</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>优化更新弹窗机制及其内容描述,对于可以自动更新的版本,现在可以看到软件的下载进度了</li>\n</ul>\n",
|
||||
"history": [
|
||||
{
|
||||
"version": "0.10.0",
|
||||
"desc": "<h4>优化</h4>\n<ul>\n<li>大幅减少程序<strong>播放时</strong>对CPU与GPU的使用,经测试CPU使用减少60%以上,GPU使用减少90%以上,这应该能解决MAC系统上的温度上涨的问题</li>\n</ul>\n<h4>修复</h4>\n<ul>\n<li>修复酷我源<strong>搜索提示</strong>、<strong>排行榜</strong>无法获取的问题</li>\n<li>修复咪咕源无法播放的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.9.1",
|
||||
"desc": "<h4>修复</h4>\n<ul>\n<li>修复没有配置文件时程序启动出错的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.9.0",
|
||||
"desc": "<h4>新增</h4>\n<ul>\n<li>新增窗口大小设置,若觉得软件窗口小可以到设置页调大点</li>\n<li>新增定位当前播放歌曲,点击播放栏左侧的<strong>歌曲图片</strong>可在播放列表定位当前播放的歌曲(该功能对播放下载列表的歌曲无效)</li>\n</ul>\n<h4>修复</h4>\n<ul>\n<li>修复搜索提示失效的问题</li>\n<li>修复从歌单或列表点击搜索按钮搜索目标歌曲时,搜索框未聚焦仍然弹出候选搜索列表的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.8.2",
|
||||
"desc": "<h4>修复</h4>\n<ul>\n<li>兼容旧版酷我源搜索列表过滤128k音质的bug(注:0.8.1版本仅修复了酷我源的歌曲过滤问题,该修复仅对以后添加的歌曲有效,如果是之前添加的歌曲仍会出现这个问题,现修复对之前旧列表数据的兼容处理)</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.8.1",
|
||||
"desc": "<h4>修复</h4>\n<ul>\n<li>修复酷我源搜索歌曲结果未添加128k音质导致播放128k音质时显示“该歌曲没有可播放的音频”的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.8.0",
|
||||
"desc": "<h4>新增</h4>\n<ul>\n<li>新增网易云源歌曲搜索</li>\n<li>新增网易云源歌单</li>\n<li>新增各平台通过输入歌单链接或歌单ID打开歌单详情列表,目前只适配了<strong>网页版歌单链接</strong>,其他方式的歌单链接可能无法解析,但你可想办法获取歌单ID后输入打开。注:各平台歌单ID均为纯数字,若遇到链接里存在歌单ID但无法解析的歌单链接,可以到GitHub提交issue或发送邮件或加群830125506反馈!</li>\n<li>新增音量调整滑动功能,现在支持鼠标左右拖动调整音量了</li>\n</ul>\n<h4>优化</h4>\n<ul>\n<li>优化搜索框搜索体验</li>\n<li>优化音量条交互视觉效果</li>\n<li>缓存歌单详情列表数据</li>\n</ul>\n<h4>修复</h4>\n<ul>\n<li>修复QQ源歌单无法翻页Bug</li>\n<li>修复默认列表没有创建时无法显示收藏列表的Bug</li>\n<li>修复网易云128k直接试听</li>\n<li>修复歌曲音质不存在时仍然播放或下载的Bug</li>\n<li>修复调整音量时,调整的位置与鼠标点击的位置不一致的问题</li>\n</ul>\n"
|
||||
|
||||
25
src/common/config.js
Normal file
25
src/common/config.js
Normal file
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
windowSizeList: [
|
||||
{
|
||||
id: 1,
|
||||
name: '小',
|
||||
width: 920,
|
||||
height: 590,
|
||||
tabList: '645px',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '中',
|
||||
width: 1012,
|
||||
height: 650,
|
||||
tabList: '719px',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '大',
|
||||
width: 1104,
|
||||
height: 708,
|
||||
tabList: '792px',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
const { ipcMain, ipcRenderer } = require('electron')
|
||||
|
||||
|
||||
export const mainSend = (name, params) => {
|
||||
ipcMain.send(name, params)
|
||||
}
|
||||
|
||||
export const mainOn = (name, callback) => {
|
||||
ipcMain.on(name, callback)
|
||||
}
|
||||
|
||||
|
||||
export const rendererSend = (name, params) => {
|
||||
ipcRenderer.send(name, params)
|
||||
}
|
||||
|
||||
export const rendererOn = (name, callback) => {
|
||||
ipcRenderer.on(name, callback)
|
||||
}
|
||||
31
src/common/ipc.js
Normal file
31
src/common/ipc.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const { ipcMain, ipcRenderer } = require('electron')
|
||||
|
||||
|
||||
export const mainOn = (event, callback) => {
|
||||
ipcMain.on(event, callback)
|
||||
}
|
||||
export const mainOnce = (event, callback) => {
|
||||
ipcMain.once(event, callback)
|
||||
}
|
||||
|
||||
export const mainHandle = (name, callback) => {
|
||||
ipcMain.handle(name, callback)
|
||||
}
|
||||
export const mainHandleOnce = (name, callback) => {
|
||||
ipcMain.handleOnce(name, callback)
|
||||
}
|
||||
|
||||
|
||||
export const rendererSend = (name, params) => {
|
||||
ipcRenderer.send(name, params)
|
||||
}
|
||||
export const rendererSendSync = (name, params) => ipcRenderer.sendSync(name, params)
|
||||
|
||||
export const rendererInvoke = (name, params) => ipcRenderer.invoke(name, params)
|
||||
|
||||
export const rendererOn = (name, callback) => {
|
||||
ipcRenderer.on(name, callback)
|
||||
}
|
||||
export const rendererOnce = (name, callback) => {
|
||||
ipcRenderer.once(name, callback)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
const { app } = require('electron')
|
||||
const { name: defaultName } = require('../../../package.json')
|
||||
|
||||
|
||||
8
src/main/events/clearCache.js
Normal file
8
src/main/events/clearCache.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const { mainHandle } = require('../../common/ipc')
|
||||
|
||||
mainHandle('clearCache', async(event, options) => {
|
||||
if (!global.mainWindow) throw new Error('mainwindow is undefined')
|
||||
return global.mainWindow.webContents.session.clearCache()
|
||||
})
|
||||
|
||||
|
||||
7
src/main/events/getCacheSize.js
Normal file
7
src/main/events/getCacheSize.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const { mainHandle } = require('../../common/ipc')
|
||||
|
||||
mainHandle('getCacheSize', async(event, options) => {
|
||||
if (!global.mainWindow) throw new Error('mainwindow is undefined')
|
||||
return global.mainWindow.webContents.session.getCacheSize()
|
||||
})
|
||||
|
||||
@@ -4,3 +4,9 @@ require('./request')
|
||||
require('./progressBar')
|
||||
require('./trafficLight')
|
||||
require('./musicMeta')
|
||||
require('./selectDir')
|
||||
require('./setWindowSize')
|
||||
require('./showSaveDialog')
|
||||
require('./clearCache')
|
||||
require('./getCacheSize')
|
||||
require('./setIgnoreMouseEvent')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
const { setMeta } = require('../utils/musicMeta')
|
||||
|
||||
mainOn('setMusicMeta', (event, { filePath, meta }) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
|
||||
mainOn('progress', (event, params) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const request = require('request')
|
||||
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
const tasks = []
|
||||
|
||||
|
||||
13
src/main/events/restartWindow.js
Normal file
13
src/main/events/restartWindow.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
|
||||
mainOn('restartWindow', (event, name) => {
|
||||
console.log(name)
|
||||
switch (name) {
|
||||
case 'main':
|
||||
default:
|
||||
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
8
src/main/events/selectDir.js
Normal file
8
src/main/events/selectDir.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const { mainHandle } = require('../../common/ipc')
|
||||
const { dialog } = require('electron')
|
||||
|
||||
mainHandle('selectDir', async(event, options) => {
|
||||
if (!global.mainWindow) throw new Error('mainwindow is undefined')
|
||||
return dialog.showOpenDialog(global.mainWindow, options)
|
||||
})
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { dialog } = require('electron')
|
||||
|
||||
module.exports = win => {
|
||||
mainOn('selectPath', (event, params) => {
|
||||
let path = dialog.showOpenDialog(win, params.options)
|
||||
if (path === undefined) return
|
||||
event.sender.send(params.eventName, path)
|
||||
})
|
||||
}
|
||||
|
||||
8
src/main/events/setIgnoreMouseEvent.js
Normal file
8
src/main/events/setIgnoreMouseEvent.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
mainOn('setIgnoreMouseEvents', (event, isIgnored) => {
|
||||
if (!global.mainWindow) return
|
||||
isIgnored
|
||||
? global.mainWindow.setIgnoreMouseEvents(true, { forward: true })
|
||||
: global.mainWindow.setIgnoreMouseEvents(false)
|
||||
})
|
||||
7
src/main/events/setWindowSize.js
Normal file
7
src/main/events/setWindowSize.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
mainOn('setWindowSize', (event, options) => {
|
||||
if (!global.mainWindow) return
|
||||
global.mainWindow.setBounds(options)
|
||||
})
|
||||
|
||||
8
src/main/events/showSaveDialog.js
Normal file
8
src/main/events/showSaveDialog.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const { mainHandle } = require('../../common/ipc')
|
||||
const { dialog } = require('electron')
|
||||
|
||||
mainHandle('showSaveDialog', async(event, options) => {
|
||||
if (!global.mainWindow) throw new Error('mainwindow is undefined')
|
||||
return dialog.showSaveDialog(global.mainWindow, options)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// const { app } = require('electron')
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
|
||||
mainOn('min', event => {
|
||||
@@ -7,11 +7,11 @@ mainOn('min', event => {
|
||||
global.mainWindow.minimize()
|
||||
}
|
||||
})
|
||||
// mainOn('max', event => {
|
||||
// if (global.mainWindow) {
|
||||
// global.mainWindow.maximize()
|
||||
// }
|
||||
// })
|
||||
mainOn('max', event => {
|
||||
if (global.mainWindow) {
|
||||
global.mainWindow.maximize()
|
||||
}
|
||||
})
|
||||
mainOn('close', event => {
|
||||
if (global.mainWindow) {
|
||||
// global.mainWindowdow.destroy()
|
||||
|
||||
@@ -18,6 +18,7 @@ app.on('second-instance', (event, argv, cwd) => {
|
||||
require('./events')
|
||||
const autoUpdate = require('./utils/autoUpdate')
|
||||
const { isLinux, isMac } = require('../common/utils')
|
||||
const { getWindowSizeInfo } = require('./utils')
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production'
|
||||
|
||||
@@ -39,15 +40,17 @@ if (isDev) {
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
let windowSizeInfo = getWindowSizeInfo()
|
||||
/**
|
||||
* Initial window options
|
||||
*/
|
||||
mainWindow = global.mainWindow = new BrowserWindow({
|
||||
height: 590,
|
||||
height: windowSizeInfo.height,
|
||||
useContentSize: true,
|
||||
width: 920,
|
||||
width: windowSizeInfo.width,
|
||||
frame: false,
|
||||
transparent: !isLinux,
|
||||
enableRemoteModule: false,
|
||||
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const { log } = require('../../common/utils')
|
||||
const { autoUpdater } = require('electron-updater')
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
autoUpdater.logger = log
|
||||
// autoUpdater.autoDownload = false
|
||||
@@ -21,7 +21,7 @@ log.info('App starting...')
|
||||
|
||||
function sendStatusToWindow(text) {
|
||||
log.info(text)
|
||||
// global.mainWindow.webContents.send('message', text)
|
||||
// ipcMain.send('message', text)
|
||||
}
|
||||
|
||||
|
||||
@@ -90,16 +90,20 @@ module.exports = isFirstCheckedUpdate => {
|
||||
sendStatusToWindow('Update not available.')
|
||||
handleSendEvent({ type: 'update-not-available' })
|
||||
})
|
||||
autoUpdater.on('error', () => {
|
||||
autoUpdater.on('error', err => {
|
||||
sendStatusToWindow('Error in auto-updater.')
|
||||
handleSendEvent({ type: 'update-error' })
|
||||
handleSendEvent({ type: 'update-error', info: err.message })
|
||||
})
|
||||
autoUpdater.on('download-progress', progressObj => {
|
||||
sendStatusToWindow('Download progress...')
|
||||
let log_message = 'Download speed: ' + progressObj.bytesPerSecond
|
||||
log_message = log_message + ' - Downloaded ' + progressObj.percent + '%'
|
||||
log_message = log_message + ' (' + progressObj.transferred + '/' + progressObj.total + ')'
|
||||
sendStatusToWindow(log_message)
|
||||
handleSendEvent({ type: 'update-progress', info: progressObj })
|
||||
})
|
||||
autoUpdater.on('update-downloaded', info => {
|
||||
sendStatusToWindow('Update downloaded.')
|
||||
handleSendEvent({ type: 'update-downloaded' })
|
||||
handleSendEvent({ type: 'update-downloaded', info })
|
||||
})
|
||||
mainOn('quit-update', () => {
|
||||
setTimeout(() => {
|
||||
|
||||
8
src/main/utils/index.js
Normal file
8
src/main/utils/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const Store = require('electron-store')
|
||||
const { windowSizeList } = require('../../common/config')
|
||||
|
||||
exports.getWindowSizeInfo = () => {
|
||||
let electronStore = new Store()
|
||||
const { windowSizeId = 1 } = electronStore.get('setting') || {}
|
||||
return windowSizeList.find(i => i.id === windowSizeId) || windowSizeList[0]
|
||||
}
|
||||
@@ -20,20 +20,15 @@
|
||||
<script>
|
||||
import dnscache from 'dnscache'
|
||||
import { mapMutations, mapGetters, mapActions } from 'vuex'
|
||||
import { rendererOn } from '../common/icp'
|
||||
import { rendererOn, rendererSend } from '../common/ipc'
|
||||
import { isLinux } from '../common/utils'
|
||||
import music from './utils/music'
|
||||
window.ELECTRON_DISABLE_SECURITY_WARNINGS = process.env.ELECTRON_DISABLE_SECURITY_WARNINGS
|
||||
dnscache({
|
||||
enable: true,
|
||||
ttl: 21600,
|
||||
cachesize: 1000,
|
||||
})
|
||||
let win
|
||||
let body
|
||||
if (!isLinux) {
|
||||
win = require('electron').remote.getCurrentWindow()
|
||||
body = document.body
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -96,37 +91,51 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['getVersionInfo']),
|
||||
...mapMutations(['setNewVersion', 'setVersionModalVisible']),
|
||||
...mapMutations(['setNewVersion', 'setVersionModalVisible', 'setDownloadProgress']),
|
||||
...mapMutations('list', ['initList']),
|
||||
...mapMutations('download', ['updateDownloadList']),
|
||||
...mapMutations(['setSetting']),
|
||||
init() {
|
||||
if (this.isProd && !isLinux) {
|
||||
body.addEventListener('mouseenter', this.dieableIgnoreMouseEvents)
|
||||
body.addEventListener('mouseleave', this.enableIgnoreMouseEvents)
|
||||
document.body.addEventListener('mouseenter', this.dieableIgnoreMouseEvents)
|
||||
document.body.addEventListener('mouseleave', this.enableIgnoreMouseEvents)
|
||||
}
|
||||
rendererOn('update-available', (e, info) => {
|
||||
// this.showUpdateModal(true)
|
||||
this.setNewVersion({
|
||||
// console.log(info)
|
||||
this.setVersionModalVisible({ isDownloading: true })
|
||||
this.getVersionInfo().catch(() => ({
|
||||
version: info.version,
|
||||
desc: info.releaseNotes,
|
||||
})).then(body => {
|
||||
// console.log(body)
|
||||
this.setNewVersion(body)
|
||||
this.$nextTick(() => {
|
||||
this.setVersionModalVisible({ isShow: true })
|
||||
})
|
||||
})
|
||||
})
|
||||
rendererOn('update-error', () => {
|
||||
if (!this.updateTimeout) return
|
||||
this.setVersionModalVisible({ isError: true })
|
||||
rendererOn('update-error', (event, err) => {
|
||||
// console.log(err)
|
||||
this.clearUpdateTimeout()
|
||||
this.setVersionModalVisible({ isError: true })
|
||||
this.$nextTick(() => {
|
||||
this.showUpdateModal()
|
||||
})
|
||||
})
|
||||
rendererOn('update-downloaded', () => {
|
||||
rendererOn('update-progress', (event, progress) => {
|
||||
// console.log(progress)
|
||||
this.setDownloadProgress(progress)
|
||||
})
|
||||
rendererOn('update-downloaded', info => {
|
||||
// console.log(info)
|
||||
this.clearUpdateTimeout()
|
||||
this.setVersionModalVisible({ isError: false })
|
||||
this.showUpdateModal()
|
||||
this.setVersionModalVisible({ isDownloaded: true })
|
||||
this.$nextTick(() => {
|
||||
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,
|
||||
@@ -135,26 +144,29 @@ export default {
|
||||
// 更新超时定时器
|
||||
this.updateTimeout = setTimeout(() => {
|
||||
this.updateTimeout = null
|
||||
this.setVersionModalVisible({ isError: true })
|
||||
this.setVersionModalVisible({ isTimeOut: true })
|
||||
this.$nextTick(() => {
|
||||
this.showUpdateModal()
|
||||
})
|
||||
}, 180000)
|
||||
}, 60 * 30 * 1000)
|
||||
|
||||
this.initData()
|
||||
this.globalObj.apiSource = this.setting.apiSource
|
||||
this.globalObj.proxy = Object.assign({}, this.setting.network.proxy)
|
||||
window.globalObj = this.globalObj
|
||||
|
||||
// 初始化音乐sdk
|
||||
music.init()
|
||||
},
|
||||
enableIgnoreMouseEvents() {
|
||||
if (isLinux) return
|
||||
win.setIgnoreMouseEvents(false)
|
||||
rendererSend('setIgnoreMouseEvents', false)
|
||||
// console.log('content enable')
|
||||
},
|
||||
dieableIgnoreMouseEvents() {
|
||||
if (isLinux) return
|
||||
// console.log('content disable')
|
||||
win.setIgnoreMouseEvents(true, { forward: true })
|
||||
rendererSend('setIgnoreMouseEvents', true)
|
||||
},
|
||||
|
||||
initData() { // 初始化数据
|
||||
@@ -181,12 +193,18 @@ export default {
|
||||
showUpdateModal() {
|
||||
(this.version.newVersion && this.version.newVersion.history ? Promise.resolve(this.version.newVersion) : this.getVersionInfo().then(body => {
|
||||
this.setNewVersion(body)
|
||||
if (body.version !== this.setting.ignoreVersion) this.setSetting(Object.assign({}, this.setting, { ignoreVersion: null }))
|
||||
return body
|
||||
})).then(body => {
|
||||
if (body.version === this.version.version) return
|
||||
if (this.version.isError && body.version === this.setting.ignoreVersion) return
|
||||
|
||||
})).catch(() => {
|
||||
this.setVersionModalVisible({ isUnknow: true })
|
||||
let result = {
|
||||
version: '0.0.0',
|
||||
desc: null,
|
||||
}
|
||||
this.setNewVersion(result)
|
||||
return result
|
||||
}).then(result => {
|
||||
if (result.version === this.version.version) return
|
||||
// console.log(this.version)
|
||||
this.$nextTick(() => {
|
||||
this.setVersionModalVisible({ isShow: true })
|
||||
})
|
||||
@@ -201,8 +219,8 @@ export default {
|
||||
beforeDestroy() {
|
||||
this.clearUpdateTimeout()
|
||||
if (this.isProd) {
|
||||
body.removeEventListener('mouseenter', this.dieableIgnoreMouseEvents)
|
||||
body.removeEventListener('mouseleave', this.enableIgnoreMouseEvents)
|
||||
document.body.removeEventListener('mouseenter', this.dieableIgnoreMouseEvents)
|
||||
document.body.removeEventListener('mouseleave', this.enableIgnoreMouseEvents)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -413,7 +413,7 @@
|
||||
|
||||
|
||||
// Width
|
||||
@width-app-left: 180px;
|
||||
@width-app-left: 20%;
|
||||
|
||||
// Height
|
||||
@height-toolbar: 50px;
|
||||
|
||||
@@ -68,8 +68,8 @@ export default {
|
||||
}
|
||||
.logo {
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
height: 100px;
|
||||
padding: 12% 13%;
|
||||
// height: 120px;
|
||||
color: @color-theme-font;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.player")
|
||||
div(:class="$style.left")
|
||||
div(:class="$style.left" @click="handleToMusicLocation")
|
||||
img(v-if="musicInfo.img" :src="musicInfo.img" @error="imgError")
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' height='100%' viewBox='0 0 60 60' space='preserve')
|
||||
use(:xlink:href='`#${$style.iconPic}`')
|
||||
@@ -27,7 +27,7 @@ div(:class="$style.player")
|
||||
div(:class="$style.column2")
|
||||
div(:class="$style.progress")
|
||||
//- div(:class="[$style.progressBar, $style.progressBar1]" :style="{ transform: `scaleX(${progress || 0})` }")
|
||||
div(:class="[$style.progressBar, $style.progressBar2]" :style="{ transform: `scaleX(${progress || 0})` }")
|
||||
div(:class="[$style.progressBar, $style.progressBar2, isActiveTransition ? $style.barTransition : '']" @transitionend="handleTransitionEnd" :style="{ transform: `scaleX(${progress || 0})` }")
|
||||
div(:class="$style.progressMask" @click='setProgess' ref="dom_progress")
|
||||
div(:class="$style.column3")
|
||||
span {{nowPlayTimeStr}}
|
||||
@@ -48,7 +48,7 @@ div(:class="$style.player")
|
||||
|
||||
<script>
|
||||
import Lyric from 'lrc-file-parser'
|
||||
import { rendererSend } from '../../../common/icp'
|
||||
import { rendererSend } from '../../../common/ipc'
|
||||
import { formatPlayTime2, getRandom, checkPath, setTitle, clipboardWriteText, debounce } from '../../utils'
|
||||
import { mapGetters, mapActions, mapMutations } from 'vuex'
|
||||
import { requestMsg } from '../../utils/message'
|
||||
@@ -88,8 +88,11 @@ export default {
|
||||
msDownX: 0,
|
||||
msDownVolume: 0,
|
||||
},
|
||||
handleVolumeMsMoveFn: null,
|
||||
handleVolumeMsUpFn: null,
|
||||
isActiveTransition: false,
|
||||
mediaBuffer: {
|
||||
timeout: null,
|
||||
playTime: 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -125,12 +128,14 @@ export default {
|
||||
this.setVolume(volume)
|
||||
}, 300)
|
||||
|
||||
document.addEventListener('mousemove', this.handleVolumeMsMoveFn = this.handleVolumeMsMove.bind(this))
|
||||
document.addEventListener('mouseup', this.handleVolumeMsUpFn = this.handleVolumeMsUp.bind(this))
|
||||
document.addEventListener('mousemove', this.handleVolumeMsMove)
|
||||
document.addEventListener('mouseup', this.handleVolumeMsUp)
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('mousemove', this.handleVolumeMsMoveFn)
|
||||
document.removeEventListener('mouseup', this.handleVolumeMsUpFn)
|
||||
document.removeEventListener('mousemove', this.handleVolumeMsMove)
|
||||
document.removeEventListener('mouseup', this.handleVolumeMsUp)
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
},
|
||||
watch: {
|
||||
changePlay(n) {
|
||||
@@ -211,9 +216,9 @@ export default {
|
||||
if (!this.musicInfo.songmid) return
|
||||
console.log('出错')
|
||||
this.stopPlay()
|
||||
if (this.listId != 'download' && this.audio.error.code !== 1 && this.retryNum < 3) { // 若音频URL无效则尝试刷新3次URL
|
||||
if (this.listId != 'download' && this.audio.error.code !== 1 && this.retryNum < 2) { // 若音频URL无效则尝试刷新2次URL
|
||||
// console.log(this.retryNum)
|
||||
this.audioErrorTime = this.audio.currentTime // 记录出错的播放时间
|
||||
if (!this.audioErrorTime) this.audioErrorTime = this.audio.currentTime // 记录出错的播放时间
|
||||
this.retryNum++
|
||||
this.setUrl(this.list[this.playIndex], true)
|
||||
this.status = 'URL过期,正在刷新URL...'
|
||||
@@ -238,6 +243,14 @@ export default {
|
||||
})
|
||||
this.audio.addEventListener('canplay', () => {
|
||||
console.log('加载完成开始播放')
|
||||
if (this.mediaBuffer.playTime) {
|
||||
let playTime = this.mediaBuffer.playTime
|
||||
this.mediaBuffer.playTime = 0
|
||||
this.audio.currentTime = playTime
|
||||
}
|
||||
if (this.mediaBuffer.timeout) {
|
||||
this.clearBufferTimeout()
|
||||
}
|
||||
// if (this.musicInfo.lrc) this.lyric.lrc.play(this.audio.currentTime * 1000)
|
||||
this.status = '音乐加载中...'
|
||||
})
|
||||
@@ -246,10 +259,13 @@ export default {
|
||||
// // if (this.musicInfo.lyric.orgLrc) this.musicInfo.lyric.lrc.play(this.audio.currentTime * 1000)
|
||||
// this.status = '播放中...'
|
||||
// })
|
||||
// this.audio.addEventListener('emptied', () => {
|
||||
// console.log('媒介资源元素突然为空,网络错误 or 切换歌曲?')
|
||||
// this.status = '媒介资源元素突然为空,网络错误?'
|
||||
// })
|
||||
this.audio.addEventListener('emptied', () => {
|
||||
this.mediaBuffer.playTime = 0
|
||||
this.clearBufferTimeout()
|
||||
|
||||
// console.log('媒介资源元素突然为空,网络错误 or 切换歌曲?')
|
||||
// this.status = '媒介资源元素突然为空,网络错误?'
|
||||
})
|
||||
|
||||
this.audio.addEventListener('timeupdate', () => {
|
||||
this.nowPlayTime = this.audio.currentTime
|
||||
@@ -257,7 +273,9 @@ export default {
|
||||
|
||||
this.audio.addEventListener('waiting', () => {
|
||||
// this.musicInfo.lyric.lrc.pause()
|
||||
// console.log('缓冲中...')
|
||||
this.stopPlay()
|
||||
this.startBuffering()
|
||||
this.status = '缓冲中...'
|
||||
})
|
||||
|
||||
@@ -367,18 +385,33 @@ export default {
|
||||
},
|
||||
setProgess(e) {
|
||||
if (!this.audio.src) return
|
||||
this.audio.currentTime =
|
||||
(e.offsetX / this.pregessWidth) * this.maxPlayTime
|
||||
if (!this.isPlay) this.audio.play()
|
||||
this.isActiveTransition = true
|
||||
this.$nextTick(() => {
|
||||
const time = (e.offsetX / this.pregessWidth) * this.maxPlayTime
|
||||
if (this.audioErrorTime) this.audioErrorTime = time
|
||||
if (this.mediaBuffer.playTime) {
|
||||
this.clearBufferTimeout()
|
||||
this.mediaBuffer.playTime = time
|
||||
this.startBuffering()
|
||||
}
|
||||
this.audio.currentTime = time
|
||||
|
||||
if (!this.isPlay) this.audio.play()
|
||||
})
|
||||
},
|
||||
setProgessWidth() {
|
||||
this.pregessWidth = parseInt(
|
||||
window.getComputedStyle(this.$refs.dom_progress, null).width
|
||||
window.getComputedStyle(this.$refs.dom_progress, null).width,
|
||||
)
|
||||
},
|
||||
togglePlay() {
|
||||
if (!this.audio.src) return
|
||||
this.isPlay ? this.audio.pause() : this.audio.play()
|
||||
if (this.isPlay) {
|
||||
this.audio.pause()
|
||||
this.clearBufferTimeout()
|
||||
} else {
|
||||
this.audio.play()
|
||||
}
|
||||
},
|
||||
imgError(e) {
|
||||
// e.target.src = 'https://y.gtimg.cn/music/photo_new/T002R500x500M000002BMEC42fM8S3.jpg'
|
||||
@@ -489,6 +522,50 @@ export default {
|
||||
handleCopy(text) {
|
||||
clipboardWriteText(text)
|
||||
},
|
||||
handleResize() {
|
||||
this.setProgessWidth()
|
||||
},
|
||||
handleToMusicLocation() {
|
||||
if (this.listId == 'download') return
|
||||
if (this.playIndex == -1) return
|
||||
this.$router.push({
|
||||
path: 'list',
|
||||
query: {
|
||||
id: this.listId,
|
||||
scrollIndex: this.playIndex,
|
||||
},
|
||||
})
|
||||
},
|
||||
handleTransitionEnd(e) {
|
||||
// console.log(e)
|
||||
this.isActiveTransition = false
|
||||
},
|
||||
startBuffering() {
|
||||
console.log('start t')
|
||||
if (this.mediaBuffer.timeout) return
|
||||
this.mediaBuffer.timeout = setTimeout(() => {
|
||||
this.mediaBuffer.timeout = null
|
||||
if (!this.mediaBuffer.playTime) this.mediaBuffer.playTime = this.audio.currentTime
|
||||
let skipTime = this.audio.currentTime + getRandom(3, 6)
|
||||
if (skipTime > this.maxPlayTime) skipTime = (this.maxPlayTime - this.audio.currentTime) / 2
|
||||
if (skipTime - this.mediaBuffer.playTime < 1 || this.maxPlayTime - skipTime < 1) {
|
||||
this.mediaBuffer.playTime = 0
|
||||
this.handleNext()
|
||||
return
|
||||
}
|
||||
this.startBuffering()
|
||||
this.audio.currentTime = skipTime
|
||||
console.log(this.mediaBuffer.playTime)
|
||||
console.log(this.audio.currentTime)
|
||||
}, 3000)
|
||||
},
|
||||
clearBufferTimeout() {
|
||||
console.log('clear t')
|
||||
if (!this.mediaBuffer.timeout) return
|
||||
clearTimeout(this.mediaBuffer.timeout)
|
||||
this.mediaBuffer.timeout = null
|
||||
this.mediaBuffer.playTime = 0
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -517,6 +594,14 @@ export default {
|
||||
transition-property: color;
|
||||
flex: none;
|
||||
padding: 2px;
|
||||
opacity: 1;
|
||||
transition: @transition-theme;
|
||||
transition-property: opacity;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
@@ -671,21 +756,23 @@ export default {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform-origin: 0;
|
||||
transition-property: transform;
|
||||
transition-timing-function: ease-out;
|
||||
border-radius: @radius-progress-border;
|
||||
}
|
||||
.progress-bar1 {
|
||||
transition-duration: 0.6s;
|
||||
background-color: @color-player-progress-bar1;
|
||||
}
|
||||
|
||||
.progress-bar2 {
|
||||
transition-duration: 0.2s;
|
||||
background-color: @color-player-progress-bar2;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.bar-transition {
|
||||
transition-property: transform;
|
||||
transition-timing-function: ease-out;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
.column3 {
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { rendererSend } from 'common/icp'
|
||||
import { rendererSend } from 'common/ipc'
|
||||
import { mapGetters } from 'vuex'
|
||||
import music from '../../utils/music'
|
||||
import { debounce } from '../../utils'
|
||||
@@ -23,6 +23,7 @@ export default {
|
||||
visibleList: false,
|
||||
tipList: [],
|
||||
tipSearch: null,
|
||||
isFocused: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -64,10 +65,12 @@ export default {
|
||||
handleEvent({ action, data }) {
|
||||
switch (action) {
|
||||
case 'focus':
|
||||
this.isFocused = true
|
||||
if (!this.visibleList) this.visibleList = true
|
||||
if (this.searchText) this.handleTipSearch()
|
||||
break
|
||||
case 'blur':
|
||||
this.isFocused = false
|
||||
setTimeout(() => {
|
||||
if (this.visibleList) this.visibleList = false
|
||||
}, 50)
|
||||
@@ -84,7 +87,7 @@ export default {
|
||||
},
|
||||
|
||||
handleTipSearch() {
|
||||
if (!this.visibleList) this.visibleList = true
|
||||
if (!this.visibleList && this.isFocused) this.visibleList = true
|
||||
this.tipSearch()
|
||||
},
|
||||
|
||||
|
||||
@@ -2,16 +2,12 @@ import Vue from 'vue'
|
||||
import upperFirst from 'lodash/upperFirst'
|
||||
import camelCase from 'lodash/camelCase'
|
||||
|
||||
const requireComponent = require.context(
|
||||
'./', true, /\.vue$/
|
||||
)
|
||||
const requireComponent = require.context('./', true, /\.vue$/)
|
||||
|
||||
requireComponent.keys().forEach(fileName => {
|
||||
const componentConfig = requireComponent(fileName)
|
||||
|
||||
const componentName = upperFirst(
|
||||
camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, ''))
|
||||
)
|
||||
const componentName = upperFirst(camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, '')))
|
||||
|
||||
Vue.component(componentName, componentConfig.default || componentConfig)
|
||||
})
|
||||
|
||||
@@ -67,8 +67,6 @@ export default {
|
||||
} else {
|
||||
checked.splice(index, 1)
|
||||
}
|
||||
} else if (typeof this.checked == 'string') {
|
||||
checked = this.bool ? this.value : ''
|
||||
} else if (typeof this.checked == 'boolean') {
|
||||
let bool = this.bool
|
||||
if (this.indeterminate) {
|
||||
@@ -78,6 +76,8 @@ export default {
|
||||
// })
|
||||
}
|
||||
checked = bool
|
||||
} else {
|
||||
checked = this.bool ? this.value : ''
|
||||
}
|
||||
this.$emit('input', checked)
|
||||
this.$emit('change', checked)
|
||||
@@ -88,14 +88,14 @@ export default {
|
||||
bool = value.includes(this.value)
|
||||
} else {
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
bool = value === this.value
|
||||
break
|
||||
case 'boolean':
|
||||
bool = value
|
||||
break
|
||||
// case 'string':
|
||||
// case 'number':
|
||||
default:
|
||||
return
|
||||
bool = value === this.value
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
div(:class="$style.icon")
|
||||
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")
|
||||
div.scroll(:class="$style.list" :style="{ width: listStyle }" @click.stop ref="dom_list")
|
||||
div(:class="$style.tag" @click="handleClick(null)") 默认
|
||||
dl(v-for="type in list")
|
||||
dt(:class="$style.type") {{type.name}}
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
<script>
|
||||
import { isChildren } from '../../utils'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
@@ -26,6 +27,13 @@ export default {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting', 'windowSizeList']),
|
||||
listStyle() {
|
||||
let info = this.windowSizeList.find(i => i.id === this.setting.windowSizeId) || this.windowSizeList[0]
|
||||
return info.tabList
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
|
||||
@@ -1,7 +1,31 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="version.showModal" @close="handleClose")
|
||||
main(:class="$style.main" v-if="version.newVersion")
|
||||
h2 {{ version.isError ? (isUnknow ? '❓ 版本信息获取失败 ❓' : '🌟发现新版本🌟') : '🚀程序更新🚀'}}
|
||||
material-modal(:show="version.showModal" @close="handleClose" v-if="version.newVersion")
|
||||
main(:class="$style.main" v-if="version.isDownloaded")
|
||||
h2 🚀程序更新🚀
|
||||
|
||||
div.scroll(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
h3 最新版本:{{version.newVersion.version}}
|
||||
h3 当前版本:{{version.version}}
|
||||
h3 版本变化:
|
||||
p(:class="$style.desc" v-html="version.newVersion.desc")
|
||||
div(:class="[$style.history, $style.desc]" v-if="history.length")
|
||||
h3 历史版本:
|
||||
div(:class="$style.item" v-for="ver in history")
|
||||
h4 v{{ver.version}}
|
||||
p(v-html="ver.desc")
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.desc")
|
||||
p 新版本已下载完毕,
|
||||
p
|
||||
| 你可以选择
|
||||
strong 立即重启更新
|
||||
| 或稍后
|
||||
strong 关闭程序时
|
||||
| 自动更新~
|
||||
material-btn(:class="$style.btn" @click.onec="handleRestartClick") 立即重启更新
|
||||
main(:class="$style.main" v-else-if="version.isError && !version.isUnknow && version.newVersion.version != version.version")
|
||||
h2 ❌ 版本更新出错 ❌
|
||||
|
||||
div.scroll(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
@@ -15,44 +39,97 @@ material-modal(:show="version.showModal" @close="handleClose")
|
||||
h4 v{{ver.version}}
|
||||
p(v-html="ver.desc")
|
||||
|
||||
div(:class="$style.footer" v-if="version.isError")
|
||||
div(:class="$style.desc" v-if="!isUnknow")
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.desc")
|
||||
p 发现有新版本啦,但是自动更新功能出问题了,
|
||||
p
|
||||
| 你现在可以选择继续使用当前版本或
|
||||
strong 去发布页下载新版本
|
||||
| ,
|
||||
| 你可以去
|
||||
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" title="点击打开") 软件发布页
|
||||
| 或
|
||||
strong.hover.underline(@click="handleOpenUrl('https://www.lanzous.com/b906260/')" title="点击打开") 网盘
|
||||
| (密码:
|
||||
strong.hover(@click="handleCopy('glqw')" title="点击复制") glqw
|
||||
| ) 下载新版本,
|
||||
p
|
||||
| 国内Windows/MAC用户推荐到
|
||||
strong.hover.underline(@click="handleOpenUrl('https://www.lanzous.com/b906260/')") 网盘(点击打开)
|
||||
| 下载,密码:
|
||||
strong.hover(@click="handleCopy('glqw')" title="点击复制") glqw
|
||||
div(:class="$style.btns")
|
||||
material-btn(:class="$style.btn" @click.onec="handleIgnoreClick") 忽略该版本
|
||||
material-btn(:class="$style.btn" @click.onec="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop#readme')") 去软件发布页
|
||||
div(:class="$style.footer" v-else)
|
||||
div(:class="$style.desc")
|
||||
p 新版本已下载完毕,
|
||||
p
|
||||
| 你可以选择
|
||||
strong 立即重启更新
|
||||
| 或稍后
|
||||
strong 关闭程序时
|
||||
| 自动更新~
|
||||
material-btn(:class="$style.btn" @click.onec="handleRestartClick") 立即重启更新
|
||||
strong 网盘
|
||||
| 下载。
|
||||
main(:class="$style.main" v-else-if="version.isDownloading && version.isTimeOut && !version.isUnknow")
|
||||
h2 ❗️ 新版本下载超时 ❗️
|
||||
div(:class="$style.desc")
|
||||
p 你当前所在网络访问GitHub较慢,导致新版本下载超时(已经下了半个钟了😳),建议手动更新版本!
|
||||
p
|
||||
| 你可以去
|
||||
material-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" title="点击打开") 软件发布页
|
||||
| 或
|
||||
material-btn(min @click="handleOpenUrl('https://www.lanzous.com/b906260/')" title="点击打开") 网盘
|
||||
| (密码:
|
||||
strong.hover(@click="handleCopy('glqw')" title="点击复制") glqw
|
||||
| )下载新版本,
|
||||
p
|
||||
| 国内Windows/MAC用户推荐到
|
||||
strong 网盘
|
||||
| 下载。
|
||||
p 当前下载进度:{{progress}}
|
||||
main(:class="$style.main" v-else-if="version.isUnknow")
|
||||
h2 ❓ 获取最新版本信息失败 ❓
|
||||
|
||||
div.scroll(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
h3 当前版本:{{version.version}}
|
||||
div(:class="$style.desc")
|
||||
p 更新信息获取失败,可能是无法访问Github导致的,请手动检查更新!
|
||||
p
|
||||
| 检查方法:打开
|
||||
material-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" title="点击打开") 软件发布页
|
||||
| 或
|
||||
material-btn(min @click="handleOpenUrl('https://www.lanzous.com/b906260/')" title="点击打开") 网盘
|
||||
| (密码:
|
||||
strong.hover(@click="handleCopy('glqw')" title="点击复制") glqw
|
||||
| )查看它们的
|
||||
strong 版本号
|
||||
| 与当前版本({{version.version}})对比是否一样,
|
||||
p 若一样则不必理会该弹窗,直接关闭即可,否则请手动下载新版本更新。
|
||||
main(:class="$style.main" v-else)
|
||||
h2 🌟发现新版本🌟
|
||||
|
||||
div.scroll(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
h3 最新版本:{{version.newVersion.version}}
|
||||
h3 当前版本:{{version.version}}
|
||||
h3 版本变化:
|
||||
p(:class="$style.desc" v-html="version.newVersion.desc")
|
||||
div(:class="[$style.history, $style.desc]" v-if="history.length")
|
||||
h3 历史版本:
|
||||
div(:class="$style.item" v-for="ver in history")
|
||||
h4 v{{ver.version}}
|
||||
p(v-html="ver.desc")
|
||||
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.desc")
|
||||
p 发现有新版本啦,正在努力更新中,若下载太慢可以手动更新哦~
|
||||
p
|
||||
| 手动更新可以去
|
||||
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" title="点击打开") 软件发布页
|
||||
| 或
|
||||
strong.hover.underline(@click="handleOpenUrl('https://www.lanzous.com/b906260/')" title="点击打开") 网盘
|
||||
| (密码:
|
||||
strong.hover(@click="handleCopy('glqw')" title="点击复制") glqw
|
||||
| ) 下载,
|
||||
p 国内Windows/MAC用户推荐到网盘下载。
|
||||
p 当前下载进度:{{progress}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { rendererSend } from '../../../common/icp'
|
||||
import { checkVersion, openUrl, clipboardWriteText } from '../../utils'
|
||||
import { rendererSend } from '../../../common/ipc'
|
||||
import { checkVersion, openUrl, clipboardWriteText, sizeFormate } from '../../utils'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
...mapGetters(['version', 'setting']),
|
||||
history() {
|
||||
if (!this.version.newVersion) return []
|
||||
if (!this.version.newVersion || !this.version.newVersion.history) return []
|
||||
let arr = []
|
||||
let currentVer = this.version.version
|
||||
this.version.newVersion.history.forEach(ver => {
|
||||
@@ -61,8 +138,10 @@ export default {
|
||||
|
||||
return arr
|
||||
},
|
||||
isUnknow() {
|
||||
return this.version.newVersion.version == '0.0.0'
|
||||
progress() {
|
||||
return this.version.downloadProgress
|
||||
? `${this.version.downloadProgress.percent.toFixed(2)}% - ${sizeFormate(this.version.downloadProgress.transferred)}/${sizeFormate(this.version.downloadProgress.total)} - ${sizeFormate(this.version.downloadProgress.bytesPerSecond)}/s`
|
||||
: '初始化中...'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -72,11 +151,6 @@ export default {
|
||||
isShow: false,
|
||||
})
|
||||
},
|
||||
handleIgnoreClick(event) {
|
||||
this.handleClose()
|
||||
// event.target.disabled = true
|
||||
this.setSetting(Object.assign({}, this.setting, { ignoreVersion: this.version.newVersion.version }))
|
||||
},
|
||||
handleOpenUrl(url) {
|
||||
openUrl(url)
|
||||
},
|
||||
@@ -148,6 +222,10 @@ export default {
|
||||
list-style: initial;
|
||||
padding-inline-start: 30px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.history {
|
||||
@@ -175,22 +253,23 @@ export default {
|
||||
.footer {
|
||||
flex: 0 0 none;
|
||||
.desc {
|
||||
font-size: 12px;
|
||||
padding-top: 10px;
|
||||
font-size: 12px;
|
||||
color: @color-theme;
|
||||
line-height: 1.2;
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
color: @color-theme;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
margin-top: 10px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
.btns {
|
||||
display: grid;
|
||||
padding-top: 10px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 0 10px;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
|
||||
@@ -4,14 +4,13 @@ import Router from 'vue-router'
|
||||
import paths from './paths'
|
||||
|
||||
|
||||
function route(path, view, name, meta) {
|
||||
function route(path, view, name, meta, props) {
|
||||
return {
|
||||
name: name || view,
|
||||
path,
|
||||
meta,
|
||||
component: (resovle) => import(
|
||||
`../views/${view}.vue`
|
||||
).then(resovle),
|
||||
props,
|
||||
component: (resovle) => import(`../views/${view}.vue`).then(resovle),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +18,7 @@ Vue.use(Router)
|
||||
|
||||
const router = new Router({
|
||||
mode: 'hash',
|
||||
routes: paths.map(path => route(path.path, path.view, path.name, path.meta)).concat([
|
||||
routes: paths.map(path => route(path.path, path.view, path.name, path.meta, path.props)).concat([
|
||||
{ path: '*', redirect: '/search' },
|
||||
]),
|
||||
linkActiveClass: 'active-link',
|
||||
|
||||
@@ -26,6 +26,7 @@ export default [
|
||||
path: '/list',
|
||||
name: 'list',
|
||||
view: 'List',
|
||||
// props: true,
|
||||
},
|
||||
{
|
||||
path: '/download',
|
||||
|
||||
@@ -9,11 +9,7 @@ export default {
|
||||
timeout: 20000,
|
||||
}, (err, resp, body) => {
|
||||
if (err) {
|
||||
return ++retryNum > 3 ? resolve({
|
||||
version: '0.0.0',
|
||||
desc: '<h3>版本信息获取失败</h3><ul><li>更新信息获取失败,可能是无法访问Github导致的,请手动检查更新!</li><li>检查方法:去设置-关于洛雪音乐打开<strong>开源地址</strong>或<strong>网盘地址</strong>查看<strong>版本号</strong>与当前版本对比是否最新</li></ul>',
|
||||
history: [],
|
||||
}) : this.dispatch('getVersionInfo', retryNum).then(ver => resolve(ver))
|
||||
return ++retryNum > 3 ? reject() : this.dispatch('getVersionInfo', retryNum).then(ver => resolve(ver)).catch(err => reject(err))
|
||||
}
|
||||
resolve(body)
|
||||
})
|
||||
|
||||
@@ -34,4 +34,7 @@ export default {
|
||||
route(state) {
|
||||
return state.route
|
||||
},
|
||||
windowSizeList(state) {
|
||||
return state.windowSizeList
|
||||
},
|
||||
}
|
||||
|
||||
@@ -75,7 +75,12 @@ const addTask = (list, type, store) => {
|
||||
|
||||
const getUrl = (downloadInfo, isRefresh) => {
|
||||
const url = downloadInfo.musicInfo.typeUrl[downloadInfo.type]
|
||||
if (!downloadInfo.musicInfo._types[downloadInfo.type]) return Promise.reject(new Error('该歌曲没有可下载的音频'))
|
||||
if (!downloadInfo.musicInfo._types[downloadInfo.type]) {
|
||||
// 兼容旧版酷我源搜索列表过滤128k音质的bug
|
||||
if (!(downloadInfo.musicInfo.source == 'kw' && downloadInfo.type == '128k')) return Promise.reject(new Error('该歌曲没有可下载的音频'))
|
||||
|
||||
// return Promise.reject(new Error('该歌曲没有可下载的音频'))
|
||||
}
|
||||
return url && !isRefresh ? Promise.resolve({ url }) : music[downloadInfo.musicInfo.source].getMusicUrl(downloadInfo.musicInfo, downloadInfo.type).promise
|
||||
}
|
||||
|
||||
@@ -190,7 +195,7 @@ const actions = {
|
||||
// console.log(err.code, err.message)
|
||||
commit('onError', downloadInfo)
|
||||
// console.log(tryNum[downloadInfo.key])
|
||||
if (++tryNum[downloadInfo.key] > 5) {
|
||||
if (++tryNum[downloadInfo.key] > 2) {
|
||||
_this.dispatch('download/startTask')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -23,7 +23,12 @@ const getters = {
|
||||
// actions
|
||||
const actions = {
|
||||
getUrl({ commit, state }, { musicInfo, type, isRefresh }) {
|
||||
if (!musicInfo._types[type]) return Promise.reject(new Error('该歌曲没有可播放的音频'))
|
||||
if (!musicInfo._types[type]) {
|
||||
// 兼容旧版酷我源搜索列表过滤128k音质的bug
|
||||
if (!(musicInfo.source == 'kw' && type == '128k')) return Promise.reject(new Error('该歌曲没有可播放的音频'))
|
||||
|
||||
// return Promise.reject(new Error('该歌曲没有可播放的音频'))
|
||||
}
|
||||
if (urlRequest && urlRequest.cancelHttp) urlRequest.cancelHttp()
|
||||
if (musicInfo.typeUrl[type] && !isRefresh) return Promise.resolve()
|
||||
urlRequest = music[musicInfo.source].getMusicUrl(musicInfo, type)
|
||||
|
||||
@@ -22,15 +22,18 @@ export default {
|
||||
state.setting.list.scroll.locations[id] = location
|
||||
},
|
||||
setNewVersion(state, val) {
|
||||
// val.history.forEach(ver => {
|
||||
// ver.desc = ver.desc.replace(/\n/g, '<br>')
|
||||
// })
|
||||
// val.desc = val.desc.replace(/\n/g, '<br>')
|
||||
state.version.newVersion = val
|
||||
},
|
||||
setVersionModalVisible(state, { isShow, isError }) {
|
||||
setDownloadProgress(state, info) {
|
||||
state.version.downloadProgress = info
|
||||
},
|
||||
setVersionModalVisible(state, { isShow, isError, isDownloaded, isTimeOut, isDownloading, isUnknow }) {
|
||||
if (isShow !== undefined) state.version.showModal = isShow
|
||||
if (isError !== undefined) state.version.isError = isError
|
||||
if (isTimeOut !== undefined) state.version.isTimeOut = isTimeOut
|
||||
if (isDownloading !== undefined) state.version.isDownloading = isDownloading
|
||||
if (isDownloaded !== undefined) state.version.isDownloaded = isDownloaded
|
||||
if (isUnknow !== undefined) state.version.isUnknow = isUnknow
|
||||
},
|
||||
setVolume(state, val) {
|
||||
state.setting.player.volume = val
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// const isDev = process.env.NODE_ENV === 'development'
|
||||
import Store from 'electron-store'
|
||||
import { updateSetting } from '../utils'
|
||||
import { windowSizeList } from '../../common/config'
|
||||
import { version } from '../../../package.json'
|
||||
let electronStore = new Store()
|
||||
const setting = updateSetting(electronStore.get('setting'))
|
||||
@@ -61,8 +62,14 @@ export default {
|
||||
newVersion: null,
|
||||
showModal: false,
|
||||
isError: false,
|
||||
isTimeOut: false,
|
||||
isUnknow: false,
|
||||
isDownloaded: false,
|
||||
isDownloading: false,
|
||||
downloadProgress: null,
|
||||
},
|
||||
userInfo: null,
|
||||
setting,
|
||||
electronStore,
|
||||
windowSizeList,
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ export const pauseResumeTimer = (_dl, wait) => {
|
||||
setTimeout(() => {
|
||||
if (!_dl.isResumable()) {
|
||||
console.warn(
|
||||
"This URL doesn't support resume, it will start from the beginning"
|
||||
"This URL doesn't support resume, it will start from the beginning",
|
||||
)
|
||||
}
|
||||
return _dl.resume()
|
||||
}, wait)
|
||||
}, wait),
|
||||
)
|
||||
}, wait)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import fs from 'fs'
|
||||
import { shell, remote, clipboard } from 'electron'
|
||||
import { shell, clipboard } from 'electron'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
import crypto from 'crypto'
|
||||
import { rendererSend } from '../../common/icp'
|
||||
import { rendererSend, rendererInvoke } from '../../common/ipc'
|
||||
|
||||
/**
|
||||
* 获取两个数之间的随机整数,大于等于min,小于max
|
||||
@@ -86,13 +86,13 @@ export const checkPath = path => fs.existsSync(path)
|
||||
* 在资源管理器中打开目录
|
||||
* @param {*} 选项
|
||||
*/
|
||||
export const openSelectDir = options => remote.dialog.showOpenDialog(remote.getCurrentWindow(), options)
|
||||
export const selectDir = options => rendererInvoke('selectDir', options)
|
||||
|
||||
/**
|
||||
* 在资源管理器中打开目录
|
||||
* @param {*} 选项
|
||||
*/
|
||||
export const openSaveDir = options => remote.dialog.showSaveDialog(remote.getCurrentWindow(), options)
|
||||
export const openSaveDir = options => rendererInvoke('showSaveDialog', options)
|
||||
|
||||
/**
|
||||
* 在资源管理器中打开目录
|
||||
@@ -164,7 +164,7 @@ export const isChildren = (parent, children) => {
|
||||
* @param {*} setting
|
||||
*/
|
||||
export const updateSetting = setting => {
|
||||
const defaultVersion = '1.0.12'
|
||||
const defaultVersion = '1.0.13'
|
||||
const defaultSetting = {
|
||||
version: defaultVersion,
|
||||
player: {
|
||||
@@ -216,11 +216,11 @@ export const updateSetting = setting => {
|
||||
password: '',
|
||||
},
|
||||
},
|
||||
windowSizeId: 1,
|
||||
themeId: 0,
|
||||
sourceId: 'kw',
|
||||
apiSource: 'test',
|
||||
apiSource: 'temp',
|
||||
randomAnimate: true,
|
||||
ignoreVersion: null,
|
||||
}
|
||||
const overwriteSetting = {
|
||||
version: defaultVersion,
|
||||
@@ -360,12 +360,17 @@ export const asyncSetArray = (from, to, num = 100) => new Promise(resolve => {
|
||||
|
||||
/**
|
||||
* 获取缓存大小
|
||||
* @param {*} win
|
||||
*/
|
||||
export const getCacheSize = () => remote.getCurrentWindow().webContents.session.getCacheSize()
|
||||
export const getCacheSize = () => rendererInvoke('getCacheSize')
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @param {*} win
|
||||
*/
|
||||
export const clearCache = () => remote.getCurrentWindow().webContents.session.clearCache()
|
||||
export const clearCache = () => rendererInvoke('clearCache')
|
||||
|
||||
/**
|
||||
* 设置窗口大小
|
||||
* @param {*} width
|
||||
* @param {*} height
|
||||
*/
|
||||
export const setWindowSize = (width, height) => rendererSend('setWindowSize', { width, height })
|
||||
|
||||
@@ -145,9 +145,7 @@ export default {
|
||||
getList(sortId, tagId, page, tryNum = 0) {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_list = httpFetch(
|
||||
this.getListUrl(sortId, tagId, page)
|
||||
)
|
||||
this._requestObj_list = httpFetch(this.getListUrl(sortId, tagId, page))
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.error_code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
|
||||
return {
|
||||
|
||||
@@ -4,7 +4,7 @@ import tx from './tx'
|
||||
import wy from './wy'
|
||||
import mg from './mg'
|
||||
import bd from './bd'
|
||||
export default {
|
||||
const sources = {
|
||||
sources: [
|
||||
{
|
||||
name: '酷我音乐',
|
||||
@@ -38,3 +38,12 @@ export default {
|
||||
mg,
|
||||
bd,
|
||||
}
|
||||
export default {
|
||||
...sources,
|
||||
init() {
|
||||
for (let source of sources.sources) {
|
||||
let sm = sources[source.id]
|
||||
sm && sm.init && sm.init()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
userid: 2626431536,
|
||||
vip: 1,
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
if (body.error_code !== 0) return Promise.reject('图片获取失败')
|
||||
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_list = httpFetch(
|
||||
this.getSongListUrl(sortId, tagId, page)
|
||||
this.getSongListUrl(sortId, tagId, page),
|
||||
)
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getSongList(sortId, tagId, page, ++tryNum)
|
||||
@@ -120,7 +120,7 @@ export default {
|
||||
return_min: 6,
|
||||
return_max: 15,
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
return this._requestObj_listRecommend.promise.then(({ body }) => {
|
||||
if (body.status !== 1) return this.getSongListRecommend(++tryNum)
|
||||
@@ -253,7 +253,7 @@ export default {
|
||||
this.currentTagInfo.id = tagId
|
||||
this.currentTagInfo.info = Object.assign({}, info)
|
||||
return info
|
||||
})
|
||||
}),
|
||||
)
|
||||
if (!tagId && page === 1 && sortId === this.sortList[0].id) tasks.push(this.getSongListRecommend()) // 如果是所有类别,则顺便获取推荐列表
|
||||
return Promise.all(tasks).then(([list, info, recommendList]) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { httpGet, cancelHttp } from '../../request'
|
||||
import tempSearch from './tempSearch'
|
||||
import musicSearch from './musicSearch'
|
||||
import { formatSinger } from './util'
|
||||
import { formatSinger, getToken } from './util'
|
||||
import leaderboard from './leaderboard'
|
||||
import lyric from './lyric'
|
||||
import pic from './pic'
|
||||
@@ -96,6 +96,10 @@ const kw = {
|
||||
getPic(songInfo) {
|
||||
return pic.getPic(songInfo)
|
||||
},
|
||||
|
||||
init() {
|
||||
getToken()
|
||||
},
|
||||
}
|
||||
|
||||
export default kw
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { httpGet, cancelHttp } from '../../request'
|
||||
import { formatPlayTime, decodeName } from '../../index'
|
||||
import { formatSinger } from './util'
|
||||
|
||||
import { formatSinger, getToken, matchToken } from './util'
|
||||
|
||||
export default {
|
||||
list: [
|
||||
@@ -89,20 +88,29 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
getData2(url) {
|
||||
async getData2(url) {
|
||||
if (this._cancelRequestObj2 != null) {
|
||||
cancelHttp(this._cancelRequestObj2)
|
||||
this._cancelPromiseCancelFn2(new Error('取消http请求'))
|
||||
}
|
||||
let token = window.kw_token.token
|
||||
if (!token) token = await getToken()
|
||||
return new Promise((resolve, reject) => {
|
||||
this._cancelPromiseCancelFn2 = reject
|
||||
this._cancelRequestObj2 = httpGet(url, (err, resp, body) => {
|
||||
this._cancelRequestObj2 = httpGet(url, {
|
||||
headers: {
|
||||
Referer: 'http://www.kuwo.cn/',
|
||||
csrf: token,
|
||||
cookie: 'kw_token=' + token,
|
||||
},
|
||||
}, (err, resp, body) => {
|
||||
this._cancelRequestObj2 = null
|
||||
this._cancelPromiseCancelFn2 = null
|
||||
if (err) {
|
||||
console.log(err)
|
||||
reject(err)
|
||||
return reject(err)
|
||||
}
|
||||
window.kw_token.token = matchToken(resp.headers)
|
||||
resolve(body)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
import { httpGet, cancelHttp } from '../../request'
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName } from '../../index'
|
||||
import { getToken, matchToken } from './util'
|
||||
|
||||
|
||||
export default {
|
||||
regExps: {
|
||||
relWord: /RELWORD=(.+)/,
|
||||
},
|
||||
_musicTempSearchRequestObj: null,
|
||||
_musicTempSearchPromiseCancelFn: null,
|
||||
tempSearch(str) {
|
||||
requestObj: null,
|
||||
tempSearch(str, token) {
|
||||
this.cancelTempSearch()
|
||||
return new Promise((resolve, reject) => {
|
||||
this._musicTempSearchPromiseCancelFn = reject
|
||||
this._musicTempSearchRequestObj = httpGet(`http://www.kuwo.cn/api/www/search/searchKey?key=${encodeURIComponent(str)}`, (err, resp, body) => {
|
||||
this._musicTempSearchRequestObj = null
|
||||
this._musicTempSearchPromiseCancelFn = null
|
||||
if (err) {
|
||||
console.log(err)
|
||||
reject(err)
|
||||
}
|
||||
resolve(body)
|
||||
})
|
||||
this.requestObj = httpFetch(`http://www.kuwo.cn/api/www/search/searchKey?key=${encodeURIComponent(str)}`, {
|
||||
headers: {
|
||||
Referer: 'http://www.kuwo.cn/',
|
||||
csrf: token,
|
||||
cookie: 'kw_token=' + token,
|
||||
},
|
||||
})
|
||||
return this.requestObj.promise.then(({ statusCode, body, headers }) => {
|
||||
if (statusCode != 200) return Promise.reject(new Error('请求失败'))
|
||||
window.kw_token.token = matchToken(headers)
|
||||
if (body.code !== 200) return Promise.reject(new Error('请求失败'))
|
||||
return body
|
||||
})
|
||||
},
|
||||
handleResult(rawData) {
|
||||
@@ -29,12 +31,11 @@ export default {
|
||||
})
|
||||
},
|
||||
cancelTempSearch() {
|
||||
if (this._musicTempSearchRequestObj != null) {
|
||||
cancelHttp(this._musicTempSearchRequestObj)
|
||||
this._musicTempSearchPromiseCancelFn(new Error('取消http请求'))
|
||||
}
|
||||
if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp()
|
||||
},
|
||||
search(str) {
|
||||
return this.tempSearch(str).then(result => this.handleResult(result.data))
|
||||
async search(str) {
|
||||
let token = window.kw_token.token
|
||||
if (!token) token = await getToken()
|
||||
return this.tempSearch(str, token).then(result => this.handleResult(result.data))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,2 +1,34 @@
|
||||
import { httpGet } from '../../request'
|
||||
|
||||
if (!window.kw_token) {
|
||||
window.kw_token = {
|
||||
token: null,
|
||||
isGetingToken: false,
|
||||
}
|
||||
}
|
||||
|
||||
export const formatSinger = rawData => rawData.replace(/&/g, '、')
|
||||
|
||||
export const matchToken = headers => {
|
||||
try {
|
||||
return headers['set-cookie'][0].match(/kw_token=(\w+)/)[1]
|
||||
} catch (err) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const wait = time => new Promise(resolve => setTimeout(() => resolve(), time))
|
||||
|
||||
|
||||
export const getToken = () => new Promise((resolve, reject) => {
|
||||
if (window.kw_token.isGetingToken) return wait(1000).then(() => getToken().then(token => resolve(token)))
|
||||
if (window.kw_token.token) return resolve(window.kw_token.token)
|
||||
window.kw_token.isGetingToken = true
|
||||
httpGet('http://www.kuwo.cn', (err, resp) => {
|
||||
window.kw_token.isGetingToken = false
|
||||
if (err) return reject(err)
|
||||
if (resp.statusCode != 200) return reject(new Error('获取失败'))
|
||||
const token = window.kw_token.token = matchToken(resp.headers)
|
||||
resolve(token)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@ const api_test = {
|
||||
family: 4,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve({ type, url: encodeURI(body.data) }) : Promise.reject(new Error(requestMsg.fail))
|
||||
return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
|
||||
@@ -109,7 +109,7 @@ export default {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_list = httpFetch(
|
||||
this.getListUrl(sortId, tagId, page)
|
||||
this.getListUrl(sortId, tagId, page),
|
||||
)
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.download")
|
||||
//- transition
|
||||
div(:class="$style.header")
|
||||
material-tab(:class="$style.tab" :list="tabs" align="left" item-key="id" item-name="name" v-model="tabId")
|
||||
div(:class="$style.content" v-if="list.length")
|
||||
div(:class="$style.thead")
|
||||
table
|
||||
@@ -17,7 +19,7 @@ div(:class="$style.download")
|
||||
div.scroll(v-if="list.length" :class="$style.tbody")
|
||||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.key' @click="handleDoubleClick(index)" :class="isPlayList && playIndex === index ? $style.active : ''")
|
||||
tr(v-for='(item, index) in showList' :key='item.key' @click="handleDoubleClick(index)" :class="playListIndex === index ? $style.active : ''")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
td.break(style="width: 28%;") {{item.musicInfo.name}} - {{item.musicInfo.singer}}
|
||||
@@ -46,6 +48,29 @@ export default {
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
isShowDownloadMultiple: false,
|
||||
tabs: [
|
||||
{
|
||||
name: '全部任务',
|
||||
id: 'all',
|
||||
},
|
||||
{
|
||||
name: '正在下载',
|
||||
id: 'runing',
|
||||
},
|
||||
{
|
||||
name: '已暂停',
|
||||
id: 'paused',
|
||||
},
|
||||
{
|
||||
name: '出错',
|
||||
id: 'error',
|
||||
},
|
||||
{
|
||||
name: '下载完成',
|
||||
id: 'finished',
|
||||
},
|
||||
],
|
||||
tabId: 'all',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -54,6 +79,25 @@ export default {
|
||||
isPlayList() {
|
||||
return this.listId == 'download'
|
||||
},
|
||||
playListIndex() {
|
||||
if (this.listId != 'download') return
|
||||
let path = this.list[this.playIndex].filePath
|
||||
return this.showList.findIndex(i => i.filePath == path)
|
||||
},
|
||||
showList() {
|
||||
switch (this.tabId) {
|
||||
case 'runing':
|
||||
return this.list.filter(i => i.status == this.downloadStatus.RUN || i.status == this.downloadStatus.WAITING)
|
||||
case 'paused':
|
||||
return this.list.filter(i => i.status == this.downloadStatus.PAUSE)
|
||||
case 'error':
|
||||
return this.list.filter(i => i.status == this.downloadStatus.ERROR)
|
||||
case 'finished':
|
||||
return this.list.filter(i => i.status == this.downloadStatus.COMPLETED)
|
||||
default:
|
||||
return this.list
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectdData(n) {
|
||||
@@ -76,14 +120,14 @@ export default {
|
||||
...mapMutations('player', ['setList']),
|
||||
...mapMutations('download', ['pauseTask']),
|
||||
handlePauseTask(index) {
|
||||
let info = this.list[index]
|
||||
let info = this.showList[index]
|
||||
let dl = this.dls[info.key]
|
||||
dl ? dl.pause() : this.pauseTask(info)
|
||||
console.log('pause')
|
||||
},
|
||||
handleStartTask(index) {
|
||||
console.log('start')
|
||||
let info = this.list[index]
|
||||
let info = this.showList[index]
|
||||
let dl = this.dls[info.key]
|
||||
dl ? dl.resume() : this.startTask(info)
|
||||
},
|
||||
@@ -101,7 +145,7 @@ export default {
|
||||
this.clickIndex = -1
|
||||
},
|
||||
handleClick(index) {
|
||||
let info = this.list[index]
|
||||
let info = this.showList[index]
|
||||
if (info.isComplate) {
|
||||
this.handlePlay(index)
|
||||
} else if (info.status === this.downloadStatus.RUN) {
|
||||
@@ -111,8 +155,9 @@ export default {
|
||||
}
|
||||
},
|
||||
handlePlay(index) {
|
||||
if (!checkPath(this.list[index].filePath)) return
|
||||
this.setList({ list: this.list, listId: 'download', index })
|
||||
if (!checkPath(this.showList[index].filePath)) return
|
||||
let path = this.showList[index].filePath
|
||||
this.setList({ list: this.list, listId: 'download', index: this.list.findIndex(i => i.filePath === path) })
|
||||
},
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
@@ -134,7 +179,7 @@ export default {
|
||||
}
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdData = isSelect ? [...this.list] : []
|
||||
this.selectdData = isSelect ? [...this.showList] : []
|
||||
},
|
||||
resetSelect() {
|
||||
this.isSelectAll = false
|
||||
@@ -145,7 +190,7 @@ export default {
|
||||
case 'start':
|
||||
this.selectdData.forEach(item => {
|
||||
if (item.isComplate || item.status == this.downloadStatus.RUN) return
|
||||
let index = this.list.indexOf(item)
|
||||
let index = this.showList.indexOf(item)
|
||||
if (index < 0) return
|
||||
this.handleStartTask(index)
|
||||
})
|
||||
@@ -155,13 +200,13 @@ export default {
|
||||
this.selectdData.forEach(item => {
|
||||
if (item.isComplate || item.status == this.downloadStatus.PAUSE) return
|
||||
if (item.status == this.downloadStatus.RUN) return runs.push(item)
|
||||
let index = this.list.indexOf(item)
|
||||
let index = this.showList.indexOf(item)
|
||||
if (index < 0) return
|
||||
this.handlePauseTask(index)
|
||||
})
|
||||
runs.forEach(item => {
|
||||
if (item.isComplate || item.status == this.downloadStatus.PAUSE) return
|
||||
let index = this.list.indexOf(item)
|
||||
let index = this.showList.indexOf(item)
|
||||
if (index < 0) return
|
||||
this.handlePauseTask(index)
|
||||
})
|
||||
@@ -174,7 +219,7 @@ export default {
|
||||
this.resetSelect()
|
||||
},
|
||||
handleOpenFolder(index) {
|
||||
let path = this.list[index].filePath
|
||||
let path = this.showList[index].filePath
|
||||
if (!checkPath(path)) return
|
||||
openDirInExplorer(path)
|
||||
},
|
||||
@@ -188,16 +233,23 @@ export default {
|
||||
.download {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
// .noItem {
|
||||
|
||||
// }
|
||||
}
|
||||
.header {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
flex: auto;
|
||||
overflow: hidden;
|
||||
// table {
|
||||
// position: relative;
|
||||
// thead {
|
||||
|
||||
@@ -95,7 +95,7 @@ export default {
|
||||
this.listAdd({ id: 'default', musicInfo: targetSong })
|
||||
}
|
||||
let targetIndex = this.defaultList.list.findIndex(
|
||||
s => s.songmid === targetSong.songmid
|
||||
s => s.songmid === targetSong.songmid,
|
||||
)
|
||||
if (targetIndex > -1) {
|
||||
this.setList({
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
div.scroll(:class="$style.tbody" @scroll="handleScroll" ref="dom_scrollContent")
|
||||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid'
|
||||
tr(v-for='(item, index) in list' :key='item.songmid' :id="'mid_' + item.songmid"
|
||||
@click="handleDoubleClick(index)" :class="[isPlayList && playIndex === index ? $style.active : '', (isAPITemp && item.source != 'kw') ? $style.disabled : '']")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
<script>
|
||||
import { mapMutations, mapGetters, mapActions } from 'vuex'
|
||||
import { throttle, asyncSetArray } from '../utils'
|
||||
import { throttle, asyncSetArray, scrollTo } from '../utils'
|
||||
export default {
|
||||
name: 'List',
|
||||
data() {
|
||||
@@ -69,6 +69,7 @@ export default {
|
||||
isShowListAdd: false,
|
||||
isShowListAddMultiple: false,
|
||||
delayTimeout: null,
|
||||
isToggleList: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -125,9 +126,18 @@ export default {
|
||||
list() {
|
||||
this.resetSelect()
|
||||
},
|
||||
'$route.query.scrollIndex'(n) {
|
||||
if (n == null || this.isToggleList) return
|
||||
this.restoreScroll(true)
|
||||
this.isToggleList = true
|
||||
},
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (to.query.id === undefined) return
|
||||
if (to.query.id == null) return
|
||||
else if (to.query.id == this.listId) {
|
||||
if (to.query.scrollIndex != null) this.isToggleList = false
|
||||
return next()
|
||||
}
|
||||
this.delayShow = false
|
||||
this.$nextTick(() => {
|
||||
this.listId = to.query.id
|
||||
@@ -195,14 +205,29 @@ export default {
|
||||
this.delayTimeout = null
|
||||
}
|
||||
},
|
||||
restoreScroll() {
|
||||
restoreScroll(isAnimation) {
|
||||
if (!this.list.length) return
|
||||
let location = this.setting.list.scroll.locations[this.listId]
|
||||
if (this.setting.list.scroll.enable && location) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.dom_scrollContent.scrollTo(0, location)
|
||||
})
|
||||
if (this.$route.query.scrollIndex == null) {
|
||||
let location = this.setting.list.scroll.locations[this.listId]
|
||||
if (this.setting.list.scroll.enable && location) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.dom_scrollContent.scrollTo(0, location)
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
let location = this.getMusicLocation(this.$route.query.scrollIndex) - 150
|
||||
if (location < 0) location = 0
|
||||
isAnimation ? scrollTo(this.$refs.dom_scrollContent, location) : this.$refs.dom_scrollContent.scrollTo(0, location)
|
||||
this.$router.replace({
|
||||
path: 'list',
|
||||
query: {
|
||||
id: this.listId,
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDoubleClick(index) {
|
||||
if (
|
||||
@@ -292,6 +317,10 @@ export default {
|
||||
break
|
||||
}
|
||||
},
|
||||
getMusicLocation(index) {
|
||||
let dom = document.getElementById('mid_' + this.list[index].songmid)
|
||||
return dom ? dom.offsetTop : 0
|
||||
},
|
||||
// handleScroll(e) {
|
||||
// console.log(e.target.scrollTop)
|
||||
// },
|
||||
|
||||
@@ -194,7 +194,7 @@ export default {
|
||||
this.listAdd({ id: 'default', musicInfo: targetSong })
|
||||
}
|
||||
let targetIndex = this.defaultList.list.findIndex(
|
||||
s => s.songmid === targetSong.songmid
|
||||
s => s.songmid === targetSong.songmid,
|
||||
)
|
||||
if (targetIndex > -1) {
|
||||
this.setList({
|
||||
|
||||
@@ -18,9 +18,15 @@ div.scroll(:class="$style.setting")
|
||||
dd(title='选择音乐来源')
|
||||
h3 音乐来源
|
||||
div
|
||||
material-checkbox(v-for="item in apiSources" :id="`setting_api_source_${item.id}`" @change="handleAPISourceChange(item.id)" :class="$style.gapTop"
|
||||
material-checkbox(v-for="item in apiSources" :id="`setting_api_source_${item.id}`" name="setting_api_source" @change="handleAPISourceChange(item.id)" :class="$style.gapTop"
|
||||
need v-model="current_setting.apiSource" :disabled="item.disabled" :value="item.id" :label="item.label" :key="item.id")
|
||||
|
||||
dd(title='设置软件窗口尺寸')
|
||||
h3 窗口尺寸
|
||||
div
|
||||
material-checkbox(v-for="(item, index) in windowSizeList" :id="`setting_window_size_${item.id}`" name="setting_window_size" @change="handleWindowSizeChange(index)" :class="$style.gapLeft"
|
||||
need v-model="current_setting.windowSizeId" :value="item.id" :label="item.name" :key="item.id")
|
||||
|
||||
dt 播放设置
|
||||
dd(title="都不选时播放完当前歌曲就停止播放")
|
||||
h3 歌曲切换方式
|
||||
@@ -40,8 +46,8 @@ div.scroll(:class="$style.setting")
|
||||
h3 是否显示歌曲源(仅对我的音乐分类有效)
|
||||
div
|
||||
material-checkbox(id="setting_list_showSource_enable" v-model="current_setting.list.isShowSource" label="是否显示")
|
||||
dd(title='是否恢复播放列表滚动条位置')
|
||||
h3 恢复列表滚动位置(仅对我的音乐分类有效)
|
||||
dd(title='是否记住播放列表滚动条位置')
|
||||
h3 记住列表滚动位置(仅对我的音乐分类有效)
|
||||
div
|
||||
material-checkbox(id="setting_list_scroll_enable" v-model="current_setting.list.scroll.enable" label="是否启用")
|
||||
//- dd(title='播放列表是否显示专辑栏')
|
||||
@@ -114,10 +120,13 @@ div.scroll(:class="$style.setting")
|
||||
p.small
|
||||
| 最新版本:{{version.newVersion ? version.newVersion.version : '未知'}}
|
||||
p.small 当前版本:{{version.version}}
|
||||
p.small(v-if="version.newVersion")
|
||||
p.small(v-if="this.version.downloadProgress" style="line-height: 1.5;")
|
||||
| 发现新版本并在努力下载中,请稍后...⏳
|
||||
br
|
||||
| 下载进度:{{downloadProgress}}
|
||||
p(v-if="version.newVersion")
|
||||
span(v-if="isLatestVer") 软件已是最新,尽情地体验吧~🥂
|
||||
material-btn(v-else-if="setting.ignoreVersion || version.isError" :class="[$style.btn, $style.gapLeft]" min @click="showUpdateModal") 打开更新窗口 🚀
|
||||
span(v-else) 发现新版本并在努力下载中,请稍等...⏳
|
||||
material-btn(v-else :class="[$style.btn, $style.gapLeft]" min @click="showUpdateModal") 打开更新窗口 🚀
|
||||
p.small(v-else) 检查更新中...
|
||||
dt 关于洛雪音乐
|
||||
dd
|
||||
@@ -168,7 +177,7 @@ div.scroll(:class="$style.setting")
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import {
|
||||
openDirInExplorer,
|
||||
openSelectDir,
|
||||
selectDir,
|
||||
openSaveDir,
|
||||
updateSetting,
|
||||
openUrl,
|
||||
@@ -176,19 +185,27 @@ import {
|
||||
getCacheSize,
|
||||
clearCache,
|
||||
sizeFormate,
|
||||
setWindowSize,
|
||||
} from '../utils'
|
||||
import { rendererSend } from '../../common/icp'
|
||||
import { rendererSend } from '../../common/ipc'
|
||||
import fs from 'fs'
|
||||
|
||||
|
||||
export default {
|
||||
name: 'Setting',
|
||||
computed: {
|
||||
...mapGetters(['setting', 'themes', 'version']),
|
||||
...mapGetters(['setting', 'themes', 'version', 'windowSizeList']),
|
||||
...mapGetters('list', ['defaultList', 'loveList']),
|
||||
isLatestVer() {
|
||||
return this.version.newVersion && this.version.version === this.version.newVersion.version
|
||||
},
|
||||
isShowRebootBtn() {
|
||||
return this.current_setting.windowSizeId != window.currentWindowSizeId
|
||||
},
|
||||
downloadProgress() {
|
||||
return this.version.downloadProgress
|
||||
? `${this.version.downloadProgress.percent.toFixed(2)}% - ${sizeFormate(this.version.downloadProgress.transferred)}/${sizeFormate(this.version.downloadProgress.total)} - ${sizeFormate(this.version.downloadProgress.bytesPerSecond)}/s`
|
||||
: '更新初始化中...'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -225,6 +242,7 @@ export default {
|
||||
odc: {
|
||||
isAutoClearSearchInput: false,
|
||||
},
|
||||
windowSizeId: 1,
|
||||
themeId: 0,
|
||||
sourceId: 0,
|
||||
randomAnimate: true,
|
||||
@@ -314,10 +332,11 @@ export default {
|
||||
...mapMutations('list', ['setList']),
|
||||
init() {
|
||||
this.current_setting = JSON.parse(JSON.stringify(this.setting))
|
||||
if (!window.currentWindowSizeId) window.currentWindowSizeId = this.setting.windowSizeId
|
||||
this.getCacheSize()
|
||||
},
|
||||
handleChangeSavePath() {
|
||||
openSelectDir({
|
||||
selectDir({
|
||||
title: '选择歌曲保存路径',
|
||||
defaultPath: this.current_setting.download.savePath,
|
||||
properties: ['openDirectory'],
|
||||
@@ -410,7 +429,7 @@ export default {
|
||||
})
|
||||
},
|
||||
handleImportAllData() {
|
||||
openSelectDir({
|
||||
selectDir({
|
||||
title: '选择备份文件',
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
@@ -432,7 +451,7 @@ export default {
|
||||
})
|
||||
},
|
||||
handleImportSetting() {
|
||||
openSelectDir({
|
||||
selectDir({
|
||||
title: '选择配置文件',
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
@@ -454,7 +473,7 @@ export default {
|
||||
})
|
||||
},
|
||||
handleImportPlayList() {
|
||||
openSelectDir({
|
||||
selectDir({
|
||||
title: '选择列表文件',
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
@@ -502,6 +521,10 @@ export default {
|
||||
this.getCacheSize()
|
||||
})
|
||||
},
|
||||
handleWindowSizeChange(index) {
|
||||
let info = this.windowSizeList[index]
|
||||
setWindowSize(info.width, info.height)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -549,6 +572,19 @@ export default {
|
||||
|
||||
}
|
||||
|
||||
.btn-content {
|
||||
display: inline-block;
|
||||
transition: @transition-theme;
|
||||
transition-property: opacity, transform;
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
|
||||
&.hide {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
}
|
||||
|
||||
.gap-left {
|
||||
+ .gap-left {
|
||||
margin-left: 20px;
|
||||
|
||||
@@ -190,7 +190,7 @@ export default {
|
||||
this.listAdd({ id: 'default', musicInfo: targetSong })
|
||||
}
|
||||
let targetIndex = this.defaultList.list.findIndex(
|
||||
s => s.songmid === targetSong.songmid
|
||||
s => s.songmid === targetSong.songmid,
|
||||
)
|
||||
if (targetIndex > -1) {
|
||||
this.setList({
|
||||
|
||||
Reference in New Issue
Block a user