Compare commits

..

21 Commits

Author SHA1 Message Date
lyswhut
a26bef6317 发布v0.3.0版本 2019-08-24 16:19:46 +08:00
lyswhut
21c41d5af1 新增音量调整 2019-08-24 16:18:04 +08:00
lyswhut
b270096591 优化更新弹窗功能,新增非安装版弹窗提醒 2019-08-24 14:24:07 +08:00
lyswhut
be689f088d 更新readme 2019-08-24 10:31:53 +08:00
lyswhut
2410409342 更新readme 2019-08-23 20:42:05 +08:00
lyswhut
a24d682747 重命名appveyor文件 2019-08-23 20:12:36 +08:00
lyswhut
2ada44a2fc 修复取消任务栏进度条可能导致的bug 2019-08-23 20:10:09 +08:00
lyswhut
d6c7fb8dcc 新增MAC、Linux构建并兼容Linux 2019-08-23 19:28:54 +08:00
lyswhut
bb40a8612a 去除切换到临时接口功能 2019-08-22 23:57:10 +08:00
lyswhut
1182a6eba4 删除重复部分 2019-08-22 23:52:00 +08:00
lyswhut
0d303889ef 修正readme文字无法加粗的问题 2019-08-22 23:26:17 +08:00
lyswhut
2b3aab2faf 更新到v0.2.3版本 2019-08-22 23:02:59 +08:00
lyswhut
893d20b4e9 使用临时接口时,试听列表中的下载按钮仍然能点击的Bug 2019-08-22 00:42:42 +08:00
lyswhut
32e421356f 移除专辑栏隐藏设置 2019-08-22 00:29:32 +08:00
lyswhut
9858170e61 发布0.2.2版本 2019-08-21 22:52:34 +08:00
lyswhut
16711e33e8 更新描述文本 2019-08-21 20:07:40 +08:00
lyswhut
f534e11acb 修复下载过程中出错重试5次都失败后不会自动开始下一个任务的Bug 2019-08-21 13:18:59 +08:00
lyswhut
2ff0f4b102 发布0.2.1版本 2019-08-20 21:28:06 +08:00
lyswhut
5b2a44e3bd 添加发布页面链接 2019-08-20 17:24:02 +08:00
lyswhut
0b06206d34 优化readme中的图片 2019-08-20 17:12:23 +08:00
lyswhut
cb93dfa218 完善readme 2019-08-20 16:57:43 +08:00
38 changed files with 699 additions and 176 deletions

View File

@@ -4,14 +4,14 @@ platform:
cache:
- node_modules
- '%APPDATA%\npm-cache'
# - '%USERPROFILE%\.electron'
- '%LOCALAPPDATA%\electron\Cache'
install:
- ps: Install-Product node 12 x64
- npm install
build_script:
- npm run pub:gh
- npm run publish:gh
test: off

1
.gitignore vendored
View File

@@ -34,6 +34,7 @@ build/Release
# Dependency directories
node_modules/
node_modules.bak*/
jspm_packages/
# TypeScript v1 declaration files

43
.travis.yml Normal file
View File

@@ -0,0 +1,43 @@
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:
- node_modules
- $HOME/.cache/electron
- $HOME/.cache/electron-builder
- $HOME/.npm/_prebuilds
notifications:
email: false
script:
- |
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
npm install && npm run publish:gh:linux
else
npm run publish:gh:mac
fi
before_cache:
- rm -rf $HOME/.cache/electron-builder/wine
# only run this script on pull requests and merges into
# the 'master' and 'prod' branches
branches:
only:
- master

View File

@@ -6,6 +6,54 @@ 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.3.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.2.3...v0.3.0) - 2019-08-24
### 新增
- 新增**MAC**及**Linux**版本(需要的可自行下载)
- 新增音量调整
- 新增任务栏播放进度条控制选项(现在可在设置界面关闭在任务栏显示的播放进度)
- 新增更新出错时的弹窗提示
- 从该版本起,非安装版也会有更新弹窗提醒了,但仍然需要手动下载新版本更新,版本信息可到设置页面查看
### 修复
- 强制把临时接口设置回 `messoer` 接口
## [0.2.3](https://github.com/lyswhut/lx-music-desktop/compare/v0.2.2...v0.2.3) - 2019-08-22
### 新增
- 新增任务栏程序标题改变功能(播放歌曲时任务栏标题将显示当前播放的歌曲)
### 修复
- 使用临时接口时试听列表中的下载按钮仍然能点击的Bug
- 修复某些情况下歌曲链接未能缓存的问题
### 移除
- 移除临时接口(因服务器被攻击,本接口已关闭)
- 移除列表栏设置的隐藏专辑栏选项感觉这个设置并没有什么luan用并且还会打破布局
## [0.2.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.2.1...v0.2.2) - 2019-08-21
### 修复
- 修复下载过程中出错重试5次都失败后不会自动开始下一个任务的Bug
- 修复播放到一半URL过期时不会刷新URL直接播放下一首的问题
## [0.2.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.2.0...v0.2.1) - 2019-08-20
### 优化
- 新增歌曲URL存储当URL无效时才重新获取以减少接口不稳定的影响
### 修复
- 修复歌曲加载无法加载时自动切换混乱的Bug
- 修复移除列表最后一首歌曲时播放器不停止播放的问题
## [0.2.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.1.6...v0.2.0) - 2019-08-20
### 新增

View File

@@ -1,39 +1,63 @@
# 洛雪音乐助手桌面版
<p align="center"><a href="https://github.com/lyswhut/lx-music-desktop"><img width="200" src="https://github.com/lyswhut/lx-music-desktop/blob/master/doc/images/icon.png" alt="lx-music logo"></a></p>
[![GitHub release][1]][2]
<p align="center">
<a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/release/lyswhut/lx-music-desktop" alt="Release version"></a>
<a href="https://ci.appveyor.com/project/lyswhut/lx-music-desktop"><img src="https://ci.appveyor.com/api/projects/status/flrsqd5ymp8fnte5?svg=true" alt="Build status"></a>
<a href="https://travis-ci.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/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>
<!-- [![GitHub release][1]][2]
[![Build status][3]][4]
[![GitHub Releases Download][5]][6]
[![dev branch][7]][8]
<!-- [![GitHub license][9]][10] -->
[![GitHub license][9]][10] -->
[1]: https://img.shields.io/github/release/lyswhut/lx-music-desktop
<!-- [1]: https://img.shields.io/github/release/lyswhut/lx-music-desktop
[2]: https://github.com/lyswhut/lx-music-desktop/releases
[3]: https://ci.appveyor.com/api/projects/status/flrsqd5ymp8fnte5?svg=true
[4]: https://ci.appveyor.com/project/lyswhut/lx-music-desktop
[5]: https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/latest/total
<!-- [5]: https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/total -->
[5]: https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/total
[6]: https://github.com/lyswhut/lx-music-desktop/releases
[7]: https://img.shields.io/github/package-json/v/lyswhut/lx-music-desktop/dev
[8]: https://github.com/lyswhut/lx-music-desktop/tree/dev
[9]: https://img.shields.io/github/license/lyswhut/lx-music-desktop
<!-- [10]: https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE -->
[10]: https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE -->
## 说明
<h2 align="center">洛雪音乐助手桌面版</h2>
一个基于 Electron + Vue 开发的 Windows 版音乐软件。
### 说明
一个基于 Electron + Vue 开发的音乐软件。
所用技术栈:
- Electron 6.x
- Vue 2.x
其他说明TODO
已支持的平台:
软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)
- Windows 7 及以上
- Mac OS
- Linux
感谢 <https://github.com/messoer> 提供的部分音乐API
软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)<br>
软件下载请转到:[发布页面](https://github.com/lyswhut/lx-music-desktop/releases)<br>
或者到网盘下载:`https://www.lanzous.com/b906260/` 密码:`glqw`
## 使用方法
#### 关于软件更新
软件启动时若发现新版本时会自动从本仓库下载安装包,下载完毕会弹窗提示更新。<br>
若下载未完成时软件被关闭,下次启动软件会再次自动下载。<br>
目前暂未添加跳过更新某个版本的功能。<br>
注意:**绿色版**的软件更新功能**不可用**,为了能及时地获取更新,建议使用安装版!!
### 源码使用方法
环境要求Node.js 12.x
```bash
# 开发模式
@@ -42,11 +66,19 @@ npm run dev
# 构建免安装版
npm run pack:dir
# 构建安装包
# 构建安装包windows版
npm run pack
```
## License
### UI界面
Apache License 2.0
<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>
### 致谢
感谢 [@messoer](https://github.com/messoer) 提供的部分音乐API
### 许可证
[Apache License 2.0](https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE)

View File

@@ -7,11 +7,6 @@ module.exports = {
libraryTarget: 'commonjs2',
path: path.join(__dirname, '../../dist/electron'),
},
externals: [
// suppress electron-debug warning
// see https://github.com/SimulatedGREG/electron-vue/issues/498
{ 'electron-debug': 'electron-debug' },
],
resolve: {
alias: {
common: path.join(__dirname, '../../src/common'),

BIN
doc/images/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
doc/images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

5
licenses/license_en.txt Normal file
View File

@@ -0,0 +1,5 @@
This program is only for learning to communicate!
Do not use for commercial purposes! !
All consequences of using this software are borne by the user!
By: lyswhut

5
licenses/license_zh.txt Normal file
View File

@@ -0,0 +1,5 @@
本程序仅用于学习交流使用!
请勿用于商业用途!!
使用本软件造成的一切后果由使用者承担!
By: 落雪无痕

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "lx-music-desktop",
"version": "0.1.4",
"version": "0.2.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,12 +1,40 @@
{
"name": "lx-music-desktop",
"version": "0.2.0",
"version": "0.3.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: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",
"publish": "node publish",
"pub:gh": "node build-config/pack.js && electron-builder --win -p always",
"pack": "node build-config/pack.js && electron-builder -w",
"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: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=x64 electron-builder -w=7z --x64 -p onTagOrDraft",
"publish:win:7z:x86": "cross-env TARGET=green ARCH=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: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",
"publish:linux:deb:x86": "cross-env ARCH=x86 electron-builder -l=deb --ia32 -p onTagOrDraft",
"pack:linux": "node build-config/pack.js && electron-builder -l",
"pack:dir": "node build-config/pack.js && electron-builder --dir",
"dev": "node build-config/runner-dev.js",
@@ -34,49 +62,50 @@
"files": [
"dist/electron/**/*"
],
"extraResources": [
"./licenses"
],
"win": {
"icon": "src/static/icons/lunch.ico",
"icon": "./resources/icons/256x256.ico",
"legalTrademarks": "lyswhut",
"target": [
{
"arch": [
"ia32",
"x64"
],
"target": "nsis"
}
]
"artifactName": "${productName} v${version} ${env.ARCH} ${env.TARGET}.${ext}"
},
"mac": {
"icon": "./resources/icons/512x512.png",
"category": "public.app-category.music"
},
"linux": {
"target": [
{
"target": "AppImage",
"arch": [
"x64"
]
},
{
"arch": [
"ia32",
"x64"
],
"target": "deb"
},
{
"arch": [
"x64"
],
"target": "snap"
}
],
"maintainer": "lyswhut <lyswuhut@qq.com>"
"maintainer": "lyswhut <lyswuhut@qq.com>",
"artifactName": "${productName} v${version} ${env.ARCH}.${ext}"
},
"nsis": {
"oneClick": false,
"language": "2052",
"allowToChangeInstallationDirectory": true,
"differentialPackage": true,
"license": "./license.rtf"
"license": "./licenses/license.rtf",
"shortcutName": "lx-music"
},
"dmg": {
"contents": [
{
"x": 110,
"y": 150,
"name": "lx-music"
},
{
"x": 240,
"y": 150,
"type": "link",
"path": "/Applications",
"name": "lx-music"
}
],
"title": "洛雪音乐助手 v${version}"
},
"appImage": {
"license": "./licenses/license_zh.txt",
"category": "Audio"
},
"publish": [
{
@@ -90,8 +119,15 @@
"type": "git",
"url": "git+https://github.com/lyswhut/lx-music-desktop.git"
},
"keywords": [],
"author": "lyswhut",
"keywords": [
"music-player",
"electron-app",
"vuejs2"
],
"author": {
"name": "lyswhut",
"email": "lyswuhut@qq.com"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/lyswhut/lx-music-desktop/issues"

View File

@@ -1,10 +1,11 @@
### 新增
- 新增**百度音乐**排行榜及其音乐直接试听与下载
- 新增网易云排行榜音乐直接试听与下载目前仅支持128k音质
- 新增酷狗排行榜音乐直接试听与下载目前仅支持128k音质
- 新增**MAC**及**Linux**版本(需要的可自行下载
- 新增音量调整
- 新增任务栏播放进度条控制选项(现在可在设置界面关闭在任务栏显示的播放进度
- 新增更新出错时的弹窗提示
- 从该版本起,非安装版也会有更新弹窗提醒了,但仍然需要手动下载新版本更新,版本信息可到设置页面查看
### 修复
- 修复更新弹窗历史版本描述多余的换行问题
- 修复歌曲无法播放的情况下歌词仍会播放的问题
- 强制把临时接口设置回 `messoer` 接口

View File

@@ -1,7 +1,23 @@
{
"version": "0.2.0",
"desc": "<h3>新增</h3>\n<ul>\n<li>新增<strong>百度音乐</strong>排行榜及其音乐直接试听与下载</li>\n<li>新增网易云排行榜音乐直接试听与下载目前仅支持128k音质</li>\n<li>新增酷狗排行榜音乐直接试听与下载目前仅支持128k音质</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复更新弹窗历史版本描述多余的换行问题</li>\n<li>修复歌曲无法播放的情况下歌词仍会播放的问题</li>\n</ul>\n",
"version": "0.3.0",
"desc": "<h3>新增</h3>\n<ul>\n<li>新增<strong>MAC</strong>及<strong>Linux</strong>版本(需要的可自行下载</li>\n<li>新增音量调整</li>\n<li>新增任务栏播放进度条控制选项(现在可在设置界面关闭在任务栏显示的播放进度)</li>\n<li>新增更新出错时的弹窗提示</li>\n<li>从该版本起,非安装版也会有更新弹窗提醒了,但仍然需要手动下载新版本更新,版本信息可到设置页面查看</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>强制把临时接口设置回 <code>messoer</code> 接口</li>\n</ul>\n",
"history": [
{
"version": "0.2.3",
"desc": "<h3>新增</h3>\n<ul>\n<li>新增任务栏程序标题改变功能(播放歌曲时任务栏标题将显示当前播放的歌曲)</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>使用临时接口时试听列表中的下载按钮仍然能点击的Bug</li>\n<li>修复某些情况下歌曲链接未能缓存的问题</li>\n</ul>\n<h3>移除</h3>\n<ul>\n<li>移除临时接口(因服务器被攻击,本接口已关闭)</li>\n<li>移除列表栏设置的隐藏专辑栏选项感觉这个设置并没有什么luan用并且还会打破布局</li>\n</ul>\n"
},
{
"version": "0.2.2",
"desc": "<h3>修复</h3>\n<ul>\n<li>修复下载过程中出错重试5次都失败后不会自动开始下一个任务的Bug</li>\n<li>修复播放到一半URL过期时不会刷新URL直接播放下一首的问题</li>\n</ul>\n"
},
{
"version": "0.2.1",
"desc": "<h3>优化</h3>\n<ul>\n<li>新增歌曲URL存储当URL无效时才重新获取以减少接口不稳定的影响</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复歌曲加载无法加载时自动切换混乱的Bug</li>\n<li>修复移除列表最后一首歌曲时播放器不停止播放的问题</li>\n</ul>\n"
},
{
"version": "0.2.0",
"desc": "<h3>新增</h3>\n<ul>\n<li>新增<strong>百度音乐</strong>排行榜及其音乐直接试听与下载</li>\n<li>新增网易云排行榜音乐直接试听与下载目前仅支持128k音质</li>\n<li>新增酷狗排行榜音乐直接试听与下载目前仅支持128k音质</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复更新弹窗历史版本描述多余的换行问题</li>\n<li>修复歌曲无法播放的情况下歌词仍会播放的问题</li>\n</ul>\n"
},
{
"version": "0.1.6",
"desc": "<h3>修复</h3>\n<ul>\n<li>修复列表多选音源限制Bug</li>\n</ul>\n"

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

BIN
resources/icons/512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

4
src/common/utils.js Normal file
View File

@@ -0,0 +1,4 @@
export const isLinux = process.platform == 'linux'
export const isWin = process.platform == 'win32'
export const isMac = process.platform == 'darwin'

View File

@@ -3,7 +3,7 @@ html(lang="cn")
meta(charset="UTF-8")
meta(name="viewport" content="width=device-width, initial-scale=1.0")
meta(http-equiv="X-UA-Compatible" content="ie=edge")
title= require('../package.json').name
title 洛雪音乐助手
body
#root

View File

@@ -1,10 +1,11 @@
const { app, BrowserWindow } = require('electron')
const { app, BrowserWindow, Menu } = require('electron')
const path = require('path')
require('./events')
const progressBar = require('./events/progressBar')
const trafficLight = require('./events/trafficLight')
const autoUpdate = require('./utils/autoUpdate')
const { isLinux, isMac } = require('../common/utils')
const isDev = process.env.NODE_ENV !== 'production'
@@ -33,8 +34,8 @@ function createWindow() {
useContentSize: true,
width: 920,
frame: false,
transparent: true,
icon: path.join(global.__static, 'icons/lunch.ico'),
transparent: !isLinux,
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
resizable: false,
maximizable: false,
fullscreenable: false,
@@ -58,6 +59,24 @@ function createWindow() {
if (!isDev) autoUpdate(mainWindow)
}
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() }],
},
{
label: '窗口',
role: 'window',
submenu: [{ label: '最小化', role: 'minimize' }, { label: '关闭', role: 'close' }],
},
]
Menu.setApplicationMenu(Menu.buildFromTemplate(template))
} else {
Menu.setApplicationMenu(null)
}
app.once('ready', createWindow)
app.on('window-all-closed', () => {

View File

@@ -3,6 +3,7 @@ const { autoUpdater } = require('electron-updater')
const { mainOn } = require('../../common/icp')
autoUpdater.logger = log
// autoUpdater.autoDownload = false
autoUpdater.logger.transports.file.level = 'info'
log.info('App starting...')
@@ -60,21 +61,30 @@ module.exports = win => {
autoUpdater.on('checking-for-update', () => {
sendStatusToWindow('Checking for update...')
})
autoUpdater.on('update-available', (ev, info) => {
autoUpdater.on('update-available', info => {
sendStatusToWindow('Update available.')
win.webContents.send('update-available', info)
})
autoUpdater.on('update-not-available', (ev, info) => {
autoUpdater.on('update-not-available', info => {
sendStatusToWindow('Update not available.')
setTimeout(() => { // 延迟发送事件,过早发送可能渲染进程还启动完成
win.webContents.send('update-not-available')
}, 5000)
})
autoUpdater.on('error', (ev, err) => {
autoUpdater.on('error', () => {
sendStatusToWindow('Error in auto-updater.')
setTimeout(() => { // 延迟发送事件,过早发送可能渲染进程还启动完成
win.webContents.send('update-error')
}, 6000)
})
autoUpdater.on('download-progress', (ev, progressObj) => {
autoUpdater.on('download-progress', progressObj => {
sendStatusToWindow('Download progress...')
})
autoUpdater.on('update-downloaded', (ev, info) => {
autoUpdater.on('update-downloaded', info => {
sendStatusToWindow('Update downloaded.')
win.webContents.send('update-downloaded')
setTimeout(() => { // 延迟发送事件,过早发送可能渲染进程还启动完成
win.webContents.send('update-downloaded')
}, 2000)
})
mainOn('quit-update', () => {
setTimeout(() => {

View File

@@ -1,5 +1,5 @@
<template lang="pug">
#container(v-if="isProd" :class="theme" @mouseenter="enableIgnoreMouseEvents" @mouseleave="dieableIgnoreMouseEvents")
#container(v-if="isProd && !isLinux" :class="theme" @mouseenter="enableIgnoreMouseEvents" @mouseleave="dieableIgnoreMouseEvents")
core-aside#left
#right
core-toolbar#toolbar
@@ -20,14 +20,20 @@
<script>
import { mapMutations, mapGetters, mapActions } from 'vuex'
import { rendererOn } from '../common/icp'
import { isLinux } from '../common/utils'
window.ELECTRON_DISABLE_SECURITY_WARNINGS = process.env.ELECTRON_DISABLE_SECURITY_WARNINGS
const win = require('electron').remote.getCurrentWindow()
const body = document.body
let win
let body
if (!isLinux) {
win = require('electron').remote.getCurrentWindow()
body = document.body
}
export default {
data() {
return {
isProd: process.env.NODE_ENV === 'production',
isLinux,
globalObj: {
apiSource: 'messoer',
},
@@ -42,6 +48,7 @@ export default {
}),
},
mounted() {
document.body.classList.add(this.isLinux ? 'noTransparent' : 'transparent')
this.init()
},
watch: {
@@ -53,6 +60,7 @@ export default {
},
defaultList: {
handler(n) {
// console.log(n)
this.electronStore.set('list.defaultList', n)
},
deep: true,
@@ -73,21 +81,34 @@ export default {
},
methods: {
...mapActions(['getVersionInfo']),
...mapMutations(['setNewVersion', 'setVersionVisible']),
...mapMutations(['setNewVersion', 'setVersionModalVisible']),
...mapMutations('list', ['initDefaultList']),
...mapMutations('download', ['updateDownloadList']),
...mapMutations(['setSetting']),
init() {
if (this.isProd) {
if (this.isProd && !isLinux) {
body.addEventListener('mouseenter', this.dieableIgnoreMouseEvents)
body.addEventListener('mouseleave', this.enableIgnoreMouseEvents)
}
rendererOn('update-available', (e, info) => {
// this.showUpdateModal(true)
this.setNewVersion({
version: info.version,
})
})
rendererOn('update-error', () => {
this.setVersionModalVisible({ isError: true })
this.$nextTick(() => {
this.showUpdateModal()
})
})
rendererOn('update-downloaded', () => {
this.getVersionInfo().then(body => {
this.setNewVersion(body)
this.$nextTick(() => {
this.setVersionVisible(true)
})
this.showUpdateModal()
})
rendererOn('update-not-available', () => {
if (this.setting.ignoreVersion) this.setSetting(Object.assign({}, this.setting, { ignoreVersion: null }))
this.setNewVersion({
version: this.version.version,
})
})
@@ -96,10 +117,12 @@ export default {
window.globalObj = this.globalObj
},
enableIgnoreMouseEvents() {
if (isLinux) return
win.setIgnoreMouseEvents(false)
// console.log('content enable')
},
dieableIgnoreMouseEvents() {
if (isLinux) return
// console.log('content disable')
win.setIgnoreMouseEvents(true, { forward: true })
},
@@ -110,10 +133,11 @@ export default {
},
initPlayList() {
let defaultList = this.electronStore.get('list.defaultList')
// console.log(defaultList)
if (defaultList) {
defaultList.list.forEach(m => {
m.typeUrl = {}
})
// defaultList.list.forEach(m => {
// m.typeUrl = {}
// })
this.initDefaultList(defaultList)
}
},
@@ -129,6 +153,20 @@ export default {
this.updateDownloadList(downloadList)
}
},
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
this.$nextTick(() => {
this.setVersionModalVisible({ isShow: true })
})
})
},
},
beforeDestroy() {
if (this.isProd) {
@@ -144,22 +182,30 @@ export default {
@import './assets/styles/layout.less';
body {
// background-color: #fff;
padding: @shadow-app;
user-select: none;
height: 100vh;
box-sizing: border-box;
}
.transparent {
padding: @shadow-app;
#container {
box-shadow: 0 0 @shadow-app rgba(0, 0, 0, 0.5);
border-radius: 4px;
background-color: transparent;
}
}
.noTransparent {
background-color: #fff;
}
#container {
position: relative;
display: flex;
height: 100%;
box-shadow: 0 0 @shadow-app rgba(0, 0, 0, 0.5);
// background-color: #fff;
border-radius: 4px;
overflow: hidden;
}
#left {
flex: none;
width: @width-app-left;

View File

@@ -48,5 +48,12 @@ svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/19
path(fill='currentColor' d='M112.525,95.091L26.75,45.901C11.982,37.427,0,44.369,0,61.404v98.062c0,17.025,11.982,23.969,26.75,15.492l85.781-49.177C127.294,117.305,127.294,103.565,112.525,95.091z')
// 205.857 205.857
//- path(fill='currentColor' d='M174.522,0h-26.848c-9.885,0-17.897,8.013-17.897,17.899v62.533L37.513,2.522c-3.483-2.406-7.807-2.005-11.072-2.005c-13.061,0-13.004,11.7-13.004,14.666v175.983c0,2.507-0.057,14.666,13.004,14.666c3.265,0,7.589,0.401,11.072-2.005l92.265-77.91v62.016c0,9.885,8.012,17.898,17.897,17.898h26.848c9.885,0,17.898-8.013,17.898-17.898V17.899C192.421,8.013,184.408,0,174.522,0z')
g#icon-sound
// 0 0 291.063 291.064
path(fill='currentColor' d='M26.512,204.255h18.292l106.48,67.761c12.354,7.855,22.369,2.361,22.369-12.282v-69.397c16.933-8.854,28.501-26.559,28.501-46.983c0-20.425-11.568-38.129-28.501-46.986V31.645c0-14.639-10.18-20.401-22.731-12.873L44.804,82.443H26.512C11.866,82.443,0,94.311,0,108.955v68.789C0,192.387,11.866,204.255,26.512,204.255z')
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')
</template>

View File

@@ -8,6 +8,13 @@ div(:class="$style.player")
div(:class="$style.column1")
div(:class="$style.container")
div(:class="$style.title") {{title}}
div(:class="$style.volumeContent")
div(:class="$style.volume" @click.stop='handleChangeVolume' :title="`当前音量:${volumeStr}%`")
div(:class="$style.volumeBar" :style="{ width: volumeStr + '%' }")
//- div(:class="$style.playBtn" @click='handleNext' title="音量")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 291.063 291.064' space='preserve')
use(xlink:href='#icon-sound')
div(:class="$style.playBtn" @click='handleNext' title="下一首")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
use(xlink:href='#icon-nextMusic')
@@ -41,14 +48,16 @@ div(:class="$style.player")
<script>
import Lyric from 'lrc-file-parser'
import { rendererSend } from '../../../common/icp'
import { formatPlayTime2, getRandom, checkPath } from '../../utils'
import { formatPlayTime2, getRandom, checkPath, setTitle } from '../../utils'
import { mapGetters, mapActions, mapMutations } from 'vuex'
import { requestMsg } from '../../utils/message'
export default {
data() {
return {
show: true,
audio: null,
volume: 0,
nowPlayTime: 0,
maxPlayTime: 0,
isPlay: false,
@@ -68,6 +77,8 @@ export default {
text: '',
line: 0,
},
delayNextTimeout: null,
audioErrorTime: 0,
retryNum: 0,
}
},
@@ -95,6 +106,9 @@ export default {
isAPITemp() {
return this.setting.apiSource == 'temp'
},
volumeStr() {
return parseInt(this.volume * 100)
},
},
mounted() {
this.setProgessWidth()
@@ -119,8 +133,13 @@ export default {
? n.findIndex(s => s.musicInfo.songmid === this.musicInfo.songmid)
: n.findIndex(s => s.songmid === this.musicInfo.songmid)
if (index < 0) {
this.fixPlayIndex(this.playIndex - 1)
if (n.length) this.handleNext()
// console.log(this.playIndex)
if (n.length) {
this.fixPlayIndex(this.playIndex - 1)
this.handleNext()
} else {
this.setPlayIndex(-1)
}
} else {
this.fixPlayIndex(index)
}
@@ -131,6 +150,9 @@ export default {
if (n.toFixed(2) === o.toFixed(2)) return
this.sendProgressEvent(n, 'normal')
},
volume(n) {
this.handleSaveVolume(n)
},
},
methods: {
...mapActions('player', ['getUrl', 'getPic', 'getLrc']),
@@ -139,9 +161,11 @@ export default {
'fixPlayIndex',
'resetChangePlay',
]),
...mapMutations(['setVolume']),
...mapMutations('list', ['updateMusicInfo']),
init() {
this.audio = document.createElement('audio')
window.a = this.audio = document.createElement('audio')
this.volume = this.audio.volume = this.setting.player.volume
this.audio.controls = false
this.audio.autoplay = true
this.audio.loop = this.setting.player.togglePlayMethod === 'singleLoop'
@@ -167,8 +191,9 @@ export default {
// console.log('code', this.audio.error.code)
if (!this.musicInfo.songmid) return
console.log('出错')
if (this.audio.error.code == 4 && this.retryNum < 5) {
if (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)
return
@@ -191,19 +216,21 @@ export default {
// } else {
// this.handleNext()
// }
this.status = '音频加载出错,2 两秒后切换下一首'
setTimeout(() => {
this.handleNext()
}, 2000)
this.status = '音频加载出错,5 秒后切换下一首'
this.addDelayNextTimeout()
})
this.audio.addEventListener('loadeddata', () => {
this.maxPlayTime = this.audio.duration
if (this.audioErrorTime) {
this.audio.currentTime = this.audioErrorTime
this.audioErrorTime = 0
}
if (!this.targetSong.interval && this.listId != 'download') this.updateMusicInfo({ index: this.playIndex, data: { interval: formatPlayTime2(this.maxPlayTime) } })
this.status = '音乐加载中...'
})
// this.audio.addEventListener('loadstart', () => {
// this.status = '开始加载音乐信息...'
// })
this.audio.addEventListener('loadstart', () => {
this.status = '音乐加载中...'
})
this.audio.addEventListener('canplay', () => {
console.log('加载完成开始播放')
// if (this.musicInfo.lrc) this.lyric.lrc.play(this.audio.currentTime * 1000)
@@ -241,8 +268,10 @@ export default {
},
play() {
console.log('play', this.playIndex)
this.checkDelayNextTimeout()
let targetSong = this.targetSong = this.list[this.playIndex]
this.retryNum = 0
this.audioErrorTime = 0
if (this.listId == 'download') {
if (!checkPath(targetSong.filePath) || !targetSong.isComplate || /\.ape$/.test(targetSong.filePath)) {
@@ -264,6 +293,20 @@ export default {
this.setLrc(targetSong)
}
},
checkDelayNextTimeout() {
console.log(this.delayNextTimeout)
if (this.delayNextTimeout) {
clearTimeout(this.delayNextTimeout)
this.delayNextTimeout = null
}
},
addDelayNextTimeout() {
this.checkDelayNextTimeout()
this.delayNextTimeout = setTimeout(() => {
this.delayNextTimeout = null
this.handleNext()
}, 5000)
},
handleNext() {
// if (this.list.listName === null) return
let list
@@ -276,7 +319,7 @@ export default {
}
if (!list.length) return this.setPlayIndex(-1)
let playIndex = this.list === list ? this.playIndex : list.indexOf(this.list[this.playIndex])
// console.log(playIndex)
let index
switch (this.setting.player.togglePlayMethod) {
case 'listLoop':
@@ -307,14 +350,14 @@ export default {
startPlay() {
this.isPlay = true
if (this.musicInfo.lrc) this.lyric.lrc.play(this.audio.currentTime * 1000)
this.setAppName()
this.setAppTitle()
this.sendProgressEvent(this.progress, 'normal')
},
stopPlay() {
this.isPlay = false
this.lyric.lrc.pause()
this.sendProgressEvent(this.progress, 'paused')
this.clearAppName()
this.clearAppTitle()
},
setProgess(e) {
this.audio.currentTime =
@@ -349,19 +392,13 @@ export default {
this.musicInfo.url = targetSong.typeUrl[type]
this.status = '歌曲链接获取中...'
let urlP = this.musicInfo.url && !isRefresh
? Promise.resolve()
: this.getUrl({ musicInfo: targetSong, type }).then(() => {
this.musicInfo.url = targetSong.typeUrl[type]
})
urlP.then(() => {
this.audio.src = this.musicInfo.url
return this.getUrl({ musicInfo: targetSong, type, isRefresh }).then(() => {
this.audio.src = this.musicInfo.url = targetSong.typeUrl[type]
}).catch(err => {
if (err.message == requestMsg.cancelRequest) return
this.status = err.message
setTimeout(() => {
this.handleNext()
}, 2000)
this.addDelayNextTimeout()
return Promise.reject(err)
})
},
setImg(targetSong) {
@@ -406,18 +443,27 @@ export default {
},
sendProgressEvent(status, mode) {
// console.log(status)
rendererSend('progress', {
this.setting.player.isShowTaskProgess && rendererSend('progress', {
status: status < 0.01 ? 0.01 : status,
mode: mode || 'normal',
})
},
setAppName() {
// rendererSend('appName', {
// name: `${this.musicInfo.name} - ${this.musicInfo.singer}`,
// })
setAppTitle() {
setTitle(`${this.musicInfo.name} - ${this.musicInfo.singer}`)
},
clearAppName() {
// rendererSend('appName')
clearAppTitle() {
setTitle()
},
handleChangeVolume(e) {
let val = e.offsetX / 70
if (val < 0) val = 0
if (val > 1) val = 1
if (val > 0.97) val = 1
this.volume = val
if (this.audio) this.audio.volume = this.volume
},
handleSaveVolume(volume) {
this.setVolume(volume)
},
},
}
@@ -490,6 +536,39 @@ export default {
.mixin-ellipsis-1;
}
.volume-content {
width: 100px;
display: flex;
align-items: center;
padding: 0 15px;
}
.volume {
cursor: pointer;
width: 100%;
height: 0.25em;
border-radius: 10px;
// overflow: hidden;
transition: @transition-theme;
transition-property: background-color;
background-color: @color-player-progress;
// background-color: #f5f5f5;
position: relative;
border-radius: @radius-progress-border;
}
.volume-bar {
position: absolute;
left: 0;
top: 0;
width: 0;
height: 100%;
border-radius: @radius-progress-border;
transition-duration: 0.2s;
background-color: @color-player-progress-bar2;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
}
.play-btn {
+ .play-btn {
margin-left: 10px;

View File

@@ -1,6 +1,6 @@
<template lang="pug">
div(:class="$style.checkbox")
input(:type="need ? 'radio' : 'checkbox'" :id="id" :value="value" :name="name" @change="change" v-model="bool")
input(:type="need ? 'radio' : 'checkbox'" :id="id" :disabled="disabled" :value="value" :name="name" @change="change" v-model="bool")
label(:for="id" :class="$style.content")
div(v-if="indeterminate")
svg(v-show="indeterminate" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' width="100%" viewBox='0 32 448 448' space='preserve')
@@ -34,6 +34,10 @@ export default {
default: false,
},
label: {},
disabled: {
type: Boolean,
default: false,
},
indeterminate: {
type: Boolean,
default: false,
@@ -111,6 +115,11 @@ export default {
> input {
display: none;
&[disabled] {
+ .content {
opacity: .5;
}
}
&:checked {
+ .content {
> div {

View File

@@ -0,0 +1,80 @@
<template lang="pug">
input(type="range" :class="[$style.range, min ? $style.min : '']" :disabled="disabled" v-model="val" input="handleInput" @change="handleChange")
</template>
<script>
export default {
props: {
min: {
type: Boolean,
},
disabled: {
type: Boolean,
default: false,
},
value: {
type: Number,
default: 0,
},
},
data() {
return {
val: 0,
}
},
mounted() {
this.val = this.value
},
methods: {
handleChange(e) {
this.$emit('input', this.val)
this.$emit('change', e)
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.range {
display: inline-block;
border-radius: .25em;
cursor: pointer;
color: @color-btn;
outline: none;
background: transparent;
// background-color: @color-btn-background;
&[disabled] {
opacity: .4;
}
&:hover {
background-color: @color-theme_2-hover;
}
&:active {
background-color: @color-theme_2-active;
}
}
.min {
}
// each(@themes, {
// :global(#container.@{value}) {
// .btn {
// 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}';
// }
// }
// }
// })
</style>

View File

@@ -1,7 +1,7 @@
<template lang="pug">
material-modal(:show="version.showModal" @close="handleClose")
main(:class="$style.main" v-if="version.newVersion")
h2 🚀程序更新🚀
h2 {{ version.isError ? '🌟发现新版本🌟' : '🚀程序更新🚀'}}
div.scroll(:class="$style.info")
div(:class="$style.current")
@@ -15,7 +15,20 @@ material-modal(:show="version.showModal" @close="handleClose")
h4 v{{ver.version}}
p(v-html="ver.desc")
div(:class="$style.footer")
div(:class="$style.footer" v-if="version.isError")
div(:class="$style.desc")
p 发现有新版本啦但是自动更新功能出问题了
p
| 如果你所用的软件是
strong 安装版
| 可以到QQ群830125506 反馈哦
p
| 你现在可以选择继续使用当前版本或
strong 去发布页下载新版本
div(:class="$style.btns")
material-btn(:class="$style.btn" @click.onec="handleIgnoreClick") 忽略该版本
material-btn(:class="$style.btn" @click.onec="handleOpenPageClick") 去下载新版本
div(:class="$style.footer" v-else)
div(:class="$style.desc")
p 新版本已下载完毕
p
@@ -24,18 +37,18 @@ material-modal(:show="version.showModal" @close="handleClose")
| 或稍后
strong 关闭程序时
| 自动更新~
material-btn(:class="$style.btn" @click.onec="handleClick") 立即重启更新
material-btn(:class="$style.btn" @click.onec="handleRestartClick") 立即重启更新
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
import { rendererSend } from '../../../common/icp'
import { checkVersion } from '../../utils'
import { checkVersion, openUrl } from '../../utils'
export default {
computed: {
...mapGetters(['version']),
...mapGetters(['version', 'setting']),
history() {
if (!this.version.newVersion) return []
let arr = []
@@ -48,11 +61,21 @@ export default {
},
},
methods: {
...mapMutations(['setVersionVisible']),
...mapMutations(['setVersionModalVisible', 'setSetting']),
handleClose() {
this.setVersionVisible(false)
this.setVersionModalVisible({
isShow: false,
})
},
handleClick(event) {
handleIgnoreClick(event) {
this.handleClose()
// event.target.disabled = true
this.setSetting(Object.assign({}, this.setting, { ignoreVersion: this.version.newVersion.version }))
},
handleOpenPageClick() {
openUrl('https://github.com/lyswhut/lx-music-desktop')
},
handleRestartClick(event) {
this.handleClose()
event.target.disabled = true
rendererSend('quit-update')
@@ -68,7 +91,7 @@ export default {
.main {
position: relative;
padding: 15px;
max-width: 500px;
max-width: 450px;
min-width: 300px;
display: flex;
flex-flow: column nowrap;
@@ -156,6 +179,11 @@ export default {
display: block;
width: 100%;
}
.btns {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 0 10px;
}
each(@themes, {
:global(#container.@{value}) {

View File

@@ -5,7 +5,7 @@ import { author, name } from '../../../package.json'
export default {
getVersionInfo() {
return new Promise((resolve, reject) => {
httpGet(`https://raw.githubusercontent.com/${author}/${name}/master/publish/version.json`, (err, resp, body) => {
httpGet(`https://raw.githubusercontent.com/${author.name}/${name}/master/publish/version.json`, (err, resp, body) => {
if (err) return reject(err)
resolve(body)
})

View File

@@ -70,8 +70,9 @@ const addTask = (list, type, store) => {
})
}
const refreshUrl = downloadInfo => {
return music[downloadInfo.musicInfo.source].getMusicUrl(downloadInfo.musicInfo, downloadInfo.type).promise
const getUrl = (downloadInfo, isRefresh) => {
const url = downloadInfo.musicInfo.typeUrl[downloadInfo.type]
return url && !isRefresh ? Promise.resolve({ url }) : music[downloadInfo.musicInfo.source].getMusicUrl(downloadInfo.musicInfo, downloadInfo.type).promise
}
// actions
@@ -116,12 +117,12 @@ const actions = {
// 检查是否可以开始任务
if (downloadInfo && downloadInfo != state.downloadStatus.WAITING) commit('setStatus', { downloadInfo, status: state.downloadStatus.WAITING })
let result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum)
if (!result) return downloadInfo && commit('setStatus', { downloadInfo, status: state.downloadStatus.WAITING })
if (!result) return
if (!downloadInfo) downloadInfo = result
// 开始任务
commit('setStatusText', { downloadInfo, text: '任务初始化中' })
commit('onDownload', downloadInfo)
commit('setStatusText', { downloadInfo, text: '任务初始化中' })
let msg = checkPath(rootState.setting.download.savePath)
if (msg) return commit('setStatusText', '检查下载目录出错: ' + msg)
const _this = this
@@ -137,15 +138,18 @@ const actions = {
console.log('on complate')
},
onError(err) {
console.log(err.message)
// console.log(err.code, err.message)
commit('onError', downloadInfo)
// console.log(tryNum[downloadInfo.key])
if (++tryNum[downloadInfo.key] > 5) return
if (++tryNum[downloadInfo.key] > 5) {
_this.dispatch('download/startTask')
return
}
let code
if (err.message.includes('Response status was')) {
code = err.message.replace(/Response status was (\d+)$/, '$1')
} if (err.code === 'ETIMEDOUT') {
code = 'ETIMEDOUT'
} else if (err.code === 'ETIMEDOUT' || err.code == 'ENOTFOUND') {
code = err.code
} else {
console.log('Download failed, Attempting Retry')
dls[downloadInfo.key].resume()
@@ -157,8 +161,9 @@ const actions = {
case '403':
case '410':
case 'ETIMEDOUT':
case 'ENOTFOUND':
commit('setStatusText', { downloadInfo, text: '链接失效,正在刷新链接' })
refreshUrl(downloadInfo).then(result => {
getUrl(downloadInfo, true).then(result => {
commit('updateUrl', { downloadInfo, url: result.url })
commit('setStatusText', { downloadInfo, text: '链接刷新成功' })
dls[downloadInfo.key].url = dls[downloadInfo.key].requestURL = result.url
@@ -168,9 +173,7 @@ const actions = {
console.log(err)
_this.dispatch('download/startTask')
})
return
}
_this.dispatch('download/startTask')
},
// onStateChanged(state) {
// console.log(state)
@@ -192,7 +195,7 @@ const actions = {
},
}
commit('setStatusText', { downloadInfo, text: '获取URL中...' })
let p = options.url ? Promise.resolve() : refreshUrl(downloadInfo).then(result => {
let p = options.url ? Promise.resolve() : getUrl(downloadInfo).then(result => {
commit('updateUrl', { downloadInfo, url: result.url })
if (!result.url) return Promise.reject(new Error('获取URL失败'))
options.url = result.url

View File

@@ -22,8 +22,9 @@ const getters = {
// actions
const actions = {
getUrl({ commit, state }, { musicInfo, type }) {
getUrl({ commit, state }, { musicInfo, type, isRefresh }) {
if (urlRequest && urlRequest.cancelHttp) urlRequest.cancelHttp()
if (musicInfo.typeUrl[type] && !isRefresh) return Promise.resolve()
urlRequest = music[musicInfo.source].getMusicUrl(musicInfo, type)
return urlRequest.promise.then(result => {
commit('setUrl', { musicInfo, url: result.url, type })
@@ -55,7 +56,7 @@ const actions = {
// mitations
const mutations = {
setUrl(state, datas) {
datas.musicInfo.typeUrl[datas.type] = datas.url
datas.musicInfo.typeUrl = Object.assign({}, datas.musicInfo.typeUrl, { [datas.type]: datas.url })
},
getPic(state, datas) {
datas.musicInfo.img = datas.url
@@ -72,6 +73,7 @@ const mutations = {
setPlayIndex(state, index) {
state.playIndex = index
state.changePlay = true
// console.log(state.changePlay)
},
fixPlayIndex(state, index) {
state.playIndex = index

View File

@@ -19,7 +19,11 @@ export default {
// val.desc = val.desc.replace(/\n/g, '<br>')
state.version.newVersion = val
},
setVersionVisible(state, val) {
state.version.showModal = val
setVersionModalVisible(state, { isShow, isError }) {
if (isShow !== undefined) state.version.showModal = isShow
if (isError !== undefined) state.version.isError = isError
},
setVolume(state, val) {
state.setting.player.volume = val
},
}

View File

@@ -49,6 +49,7 @@ export default {
version,
newVersion: null,
showModal: false,
isError: false,
},
userInfo: null,
setting,

View File

@@ -161,12 +161,14 @@ export const isChildren = (parent, children) => {
* @param {*} setting
*/
export const updateSetting = setting => {
const defaultVersion = '1.0.3'
const defaultVersion = '1.0.4'
const defaultSetting = {
version: defaultVersion,
player: {
togglePlayMethod: 'listLoop',
highQuality: false,
isShowTaskProgess: true,
volume: 1,
},
list: {
isShowAlbumName: true,
@@ -184,6 +186,7 @@ export const updateSetting = setting => {
sourceId: 'kw',
apiSource: 'messoer',
randomAnimate: true,
ignoreVersion: null,
}
const overwriteSetting = {
version: defaultVersion,
@@ -198,6 +201,7 @@ export const updateSetting = setting => {
objectDeepMerge(defaultSetting, overwriteSetting)
setting = defaultSetting
}
setting.apiSource = 'messoer' // 强制设置回 messoer 接口源
return setting
}
@@ -209,3 +213,10 @@ export const openUrl = url => {
shell.openExternal(url)
}
/**
* 设置标题
*/
let dom_title = document.getElementsByTagName('title')[0]
export const setTitle = title => {
dom_title.innerText = title || '洛雪音乐助手'
}

View File

@@ -1,6 +1,7 @@
export const requestMsg = {
fail: '请求异常😮,可以多试几次,若还是不行就换一首吧。。。',
unachievable: '哦No😱...接口无法访问了!已帮你切换到临时接口,重试下看能不能播放吧~',
unachievable: '哦No😱...接口无法访问了!',
// unachievable: '哦No😱...接口无法访问了!已帮你切换到临时接口,重试下看能不能播放吧~',
notConnectNetwork: '无法连接网络',
cancelRequest: '取消http请求',
}

View File

@@ -84,7 +84,7 @@ export const httpFatch = (url, options = { method: 'get' }) => {
return promise
}
if (err.message === 'socket hang up') {
window.globalObj.apiSource = 'temp'
// window.globalObj.apiSource = 'temp'
return Promise.reject(new Error(requestMsg.unachievable))
}
if (err.code === 'ENOTFOUND') return Promise.reject(new Error(requestMsg.notConnectNetwork))

View File

@@ -11,7 +11,7 @@
:indeterminate="isIndeterminate" :title="isSelectAll && !isIndeterminate ? '全不选' : '全选'")
th.nobreak(style="width: 25%;") 歌曲名
th.nobreak(style="width: 20%;") 歌手
th.nobreak(style="width: 20%;" v-if="setting.list.isShowAlbumName") 专辑
th.nobreak(style="width: 20%;") 专辑
th.nobreak(style="width: 20%;") 操作
th.nobreak(style="width: 10%;") 时长
div.scroll(:class="$style.tbody")
@@ -28,7 +28,7 @@
//- span.badge.badge-info(v-if="item._types.ape") APE
//- span.badge.badge-success(v-if="item._types.flac") FLAC
td.break(style="width: 20%;") {{item.singer}}
td.break(style="width: 20%;" v-if="setting.list.isShowAlbumName") {{item.albumName}}
td.break(style="width: 20%;") {{item.albumName}}
td(style="width: 20%; padding-left: 0; padding-right: 0;")
material-list-buttons(:index="index" @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)') 下载
@@ -137,7 +137,6 @@ export default {
this.clickIndex = -1
},
testPlay(index) {
if (this.isAPITemp && this.list[index].source != 'kw') return
this.setList({ list: this.list, listId: 'test', index })
},
handleRemove(index) {
@@ -146,16 +145,17 @@ export default {
handleListBtnClick(info) {
switch (info.action) {
case 'download':
this.musicInfo = this.list[info.index]
const minfo = this.list[info.index]
if (this.isAPITemp && minfo.source != 'kw') 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 'add':
break
case 'remove':
this.handleRemove(info.index)
break

View File

@@ -19,7 +19,7 @@ div.scroll(:class="$style.setting")
h3 音乐来源
div
material-checkbox(v-for="item in apiSources" :id="`setting_api_source_${item.id}`" @change="handleAPISourceChange(item.id)" :class="$style.gapTop"
need v-model="current_setting.apiSource" :value="item.id" :label="item.label" :key="item.id")
need v-model="current_setting.apiSource" :disabled="item.disabled" :value="item.id" :label="item.label" :key="item.id")
dt 播放设置
dd(title="都不选时播放完当前歌曲就停止播放")
@@ -31,6 +31,10 @@ div.scroll(:class="$style.setting")
h3 优先播放高品质音乐
div
material-checkbox(id="setting_player_highQuality" v-model="current_setting.player.highQuality" label="是否启用")
dd(title='在任务栏上显示当前歌曲播放进度')
h3 是否启用任务栏播放进度条
div
material-checkbox(id="setting_player_showTaskProgess" v-model="current_setting.player.isShowTaskProgess" label="是否启用")
dt 下载设置
dd(title='下载歌曲保存的路径')
h3 下载路径
@@ -45,8 +49,8 @@ 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")
dt 列表设置
dd(title='播放列表是否显示专辑栏')
//- dt 列表设置
//- dd(title='播放列表是否显示专辑栏')
h3 专辑栏
div
material-checkbox(id="setting_list_showalbum" v-model="current_setting.list.isShowAlbumName" label="是否显示专辑栏")
@@ -63,14 +67,21 @@ div.scroll(:class="$style.setting")
div
material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleImportAllData") 导入
material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleExportAllData") 导出
dt 软件更新
dd
p.small
| 最新版本{{version.newVersion ? version.newVersion.version : '未知'}}
p.small 当前版本{{version.version}}
p.small(v-if="version.newVersion")
span(v-if="isLatestVer") 软件已是最新尽情地体验吧~🥂
material-btn(v-else-if="setting.ignoreVersion" :class="[$style.btn, $style.gapLeft]" min @click="showUpdateModal") 打开更新窗口
span(v-else) 发现新版本并在努力下载中请稍等...
p.small(v-else) 检查更新中...
dt 关于洛雪音乐
dd
p.small
| 本软件完全免费代码已开源开源地址
span.hover(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop')") https://github.com/lyswhut/lx-music-desktop
p
small 当前版本
| {{version.version}}
p.small
| 本软件仅用于学习交流使用禁止将本软件用于
strong 非法用途
@@ -85,7 +96,11 @@ div.scroll(:class="$style.setting")
| 本软件的部分接口使用自 https://github.com/messoer ,非常感谢
strong @messoer
|
p.small 若有问题可 mail tolyswhut@qq.com 或到 github 提交 issue
p.small 若有问题可 mail tolyswhut@qq.com 或到 GitHub 提交 issue
p.small
| 若觉得好用的话可以去 GitHub 点个
strong star
| 支持作者哦~~🍻
p
small By
| 落雪无痕
@@ -94,12 +109,18 @@ div.scroll(:class="$style.setting")
<script>
import { mapGetters, mapMutations } from 'vuex'
import { openDirInExplorer, openSelectDir, openSaveDir, updateSetting, openUrl } from '../utils'
import { rendererSend } from '../../common/icp'
import fs from 'fs'
export default {
name: 'Setting',
computed: {
...mapGetters(['setting', 'themes', 'version']),
...mapGetters('list', ['defaultList']),
isLatestVer() {
return this.version.newVersion && this.version.version === this.version.newVersion.version
},
},
data() {
return {
@@ -108,12 +129,13 @@ export default {
player: {
togglePlayMethod: 'random',
highQuality: false,
isShowTaskProgess: true,
},
list: {
isShowAlbumName: true,
},
download: {
savePath: 'C:\\',
savePath: '',
fileName: '歌名 - 歌手',
},
themeId: 0,
@@ -142,11 +164,14 @@ export default {
apiSources: [
{
id: 'messoer',
label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)<br><span style="line-height: 1.5;"><strong>注意:</strong>本接口10秒内请求数超过100次会封10小时的IP</span>',
label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)',
disabled: false,
},
{
id: 'temp',
label: '临时接口软件的某些功能将不可用建议在messoer不可用时再切换到本选项',
// label: '临时接口软件的某些功能将不可用建议在messoer不可用时再切换到本选项',
label: '临时接口(因服务器被攻击,本接口已关闭)',
disabled: true,
},
],
musicNames: [
@@ -173,12 +198,21 @@ export default {
},
deep: true,
},
'current_setting.player.isShowTaskProgess'(n) {
if (n) return
this.$nextTick(() => {
rendererSend('progress', {
status: -1,
mode: 'normal',
})
})
},
},
mounted() {
this.init()
},
methods: {
...mapMutations(['setSetting']),
...mapMutations(['setSetting', 'setVersionModalVisible']),
...mapMutations('list', ['setDefaultList']),
init() {
this.current_setting = JSON.parse(JSON.stringify(this.setting))
@@ -332,6 +366,9 @@ export default {
window.globalObj.apiSource = id
})
},
showUpdateModal() {
this.setVersionModalVisible({ isShow: true })
},
},
}
</script>