mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/lyswhut/lx-music-desktop.git
synced 2026-09-20 08:04:00 +08:00
Compare commits
315 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78c5250f1b | ||
|
|
9797d98fac | ||
|
|
43c2dc3dec | ||
|
|
50e140e606 | ||
|
|
3f88701751 | ||
|
|
7d89d53b1b | ||
|
|
09f7989cab | ||
|
|
6255cfd401 | ||
|
|
e7e4897dcd | ||
|
|
9639143893 | ||
|
|
3be3b0ca36 | ||
|
|
afc81b6308 | ||
|
|
36d140d4bd | ||
|
|
edff998be9 | ||
|
|
5a856e468e | ||
|
|
d2845f91b5 | ||
|
|
9040c13c3f | ||
|
|
7ed95ff523 | ||
|
|
aed9889a2e | ||
|
|
0090f484d8 | ||
|
|
0c576c65a8 | ||
|
|
b94cde5fbe | ||
|
|
df2582d1de | ||
|
|
f237a9aab5 | ||
|
|
12c370d7cb | ||
|
|
015c17e2dc | ||
|
|
d8a3466914 | ||
|
|
05d2ffe8fa | ||
|
|
a62d8304e2 | ||
|
|
e51ee8c1ad | ||
|
|
6d0f668f88 | ||
|
|
ed5e590859 | ||
|
|
346fa2c004 | ||
|
|
db04b0c285 | ||
|
|
07800bdb83 | ||
|
|
ad8b338bd9 | ||
|
|
031c0c263d | ||
|
|
d54053003e | ||
|
|
adb453c216 | ||
|
|
ef04e43323 | ||
|
|
9ff5147418 | ||
|
|
cdbedf3d64 | ||
|
|
3d52fa059e | ||
|
|
ef46d1a308 | ||
|
|
d57cfa90fc | ||
|
|
7aece7dd7e | ||
|
|
ccf362db41 | ||
|
|
7bd4002f09 | ||
|
|
9460b12cf9 | ||
|
|
8cac592182 | ||
|
|
83b25b0c33 | ||
|
|
1832ec753c | ||
|
|
0c4f943d72 | ||
|
|
116ee25e28 | ||
|
|
6149c2a8a8 | ||
|
|
b2e475b857 | ||
|
|
f7e4e98b01 | ||
|
|
c4a9919652 | ||
|
|
5c1fb7d4e8 | ||
|
|
b1d0a4e7ad | ||
|
|
75db995342 | ||
|
|
c318856534 | ||
|
|
cf42e1846e | ||
|
|
56a5ebbb9d | ||
|
|
7431e1e605 | ||
|
|
4b6a460e69 | ||
|
|
f6f0c2f1dc | ||
|
|
90357ae386 | ||
|
|
bdc6b08234 | ||
|
|
1ba68d67ba | ||
|
|
d0518e6dfe | ||
|
|
3be6a78568 | ||
|
|
a6b8881e30 | ||
|
|
23c057ac08 | ||
|
|
07460ba06f | ||
|
|
bcbedbe053 | ||
|
|
ba26037c7f | ||
|
|
60243215a0 | ||
|
|
9c3ab28da9 | ||
|
|
2b1076f09e | ||
|
|
241859232b | ||
|
|
456fdc0fca | ||
|
|
be84bd27d3 | ||
|
|
2e84788d53 | ||
|
|
76b3b3b23d | ||
|
|
426c88c4ed | ||
|
|
d625b0d567 | ||
|
|
e350c5f070 | ||
|
|
1e481edc67 | ||
|
|
12f02dda98 | ||
|
|
ef50d90a18 | ||
|
|
25ae72cd26 | ||
|
|
eb8f83786c | ||
|
|
cd7b075016 | ||
|
|
19068dc6b0 | ||
|
|
93ba0bd807 | ||
|
|
15a76486ef | ||
|
|
f01e367785 | ||
|
|
9b536f8dc1 | ||
|
|
664a0e4ad8 | ||
|
|
9ed64354fc | ||
|
|
f59a160249 | ||
|
|
cdd7774a73 | ||
|
|
a10777d598 | ||
|
|
a4c5670409 | ||
|
|
343c53b41c | ||
|
|
4c97bc34ce | ||
|
|
83f0ca918a | ||
|
|
bc7c3968b6 | ||
|
|
1aba217b1a | ||
|
|
a95e87a08f | ||
|
|
b75e299b2f | ||
|
|
3e63b49c3c | ||
|
|
1eaf2372bb | ||
|
|
8b8400e5be | ||
|
|
c6551c9ea3 | ||
|
|
b04c676288 | ||
|
|
01e2a2bdb2 | ||
|
|
670533807a | ||
|
|
9d1270374e | ||
|
|
353e8bd0de | ||
|
|
9ca0ec82a8 | ||
|
|
bb5fd44750 | ||
|
|
1e435b0ff8 | ||
|
|
bb080c2d18 | ||
|
|
91063075d3 | ||
|
|
ccaf485c91 | ||
|
|
125207226b | ||
|
|
393affbd90 | ||
|
|
4f06fe45d3 | ||
|
|
ba1a981c87 | ||
|
|
6d51240a27 | ||
|
|
527143405f | ||
|
|
2808fdd3c0 | ||
|
|
a2c84392f4 | ||
|
|
3fdff4e6eb | ||
|
|
dd41e00691 | ||
|
|
29bcaa9558 | ||
|
|
3be3e8546f | ||
|
|
0bbb760e61 | ||
|
|
4f238f4f62 | ||
|
|
a244c6d5e3 | ||
|
|
aa5765971e | ||
|
|
2a66edd1c5 | ||
|
|
a6e86e8d6b | ||
|
|
f30cb9da59 | ||
|
|
e94d17a922 | ||
|
|
53f5c168ad | ||
|
|
4533f7b1d5 | ||
|
|
b9398e882a | ||
|
|
66f19d72da | ||
|
|
35e85cfdcb | ||
|
|
6d6b63cce1 | ||
|
|
a7d5e77a1c | ||
|
|
0332b22c4a | ||
|
|
09a7974818 | ||
|
|
66d2f0d550 | ||
|
|
d2556fed20 | ||
|
|
49cd8536a7 | ||
|
|
b8f15bcca9 | ||
|
|
a17ba9f62c | ||
|
|
a9aa9a2e20 | ||
|
|
43da07ca4c | ||
|
|
1b22abcd50 | ||
|
|
f85c83169d | ||
|
|
ecff344473 | ||
|
|
cde380782f | ||
|
|
d557149326 | ||
|
|
ecdcb040ee | ||
|
|
e58471fe37 | ||
|
|
30e66473db | ||
|
|
5357ed3746 | ||
|
|
337f443cbf | ||
|
|
e7ad1b8496 | ||
|
|
aea01de449 | ||
|
|
b7fb75a49e | ||
|
|
57752d09cd | ||
|
|
bd395f557a | ||
|
|
2d865d8fed | ||
|
|
5bff74e7a9 | ||
|
|
a9e3723764 | ||
|
|
b811227c41 | ||
|
|
4896c4dda5 | ||
|
|
b4ee1ade2d | ||
|
|
a6e2308282 | ||
|
|
f56c42f353 | ||
|
|
5edf51810d | ||
|
|
81985b0e31 | ||
|
|
163830f1bd | ||
|
|
867ae2991c | ||
|
|
ee3d04ba23 | ||
|
|
71dd8c14f8 | ||
|
|
88dc9c2a74 | ||
|
|
98f012de4d | ||
|
|
c85a036ac6 | ||
|
|
1f8b632d95 | ||
|
|
59dd56e542 | ||
|
|
1bfa8dcb3f | ||
|
|
1b381af7a7 | ||
|
|
2bc4912416 | ||
|
|
474f0d8291 | ||
|
|
231fe54408 | ||
|
|
78bef70735 | ||
|
|
ce7247e209 | ||
|
|
1d807e2a89 | ||
|
|
749141c10e | ||
|
|
e2c7c0596c | ||
|
|
392cd72f83 | ||
|
|
340a9d937b | ||
|
|
5d7ad836db | ||
|
|
f8e449b017 | ||
|
|
bb0b59080a | ||
|
|
95b08c2406 | ||
|
|
3ef5e0e55a | ||
|
|
ae9b4bc2f5 | ||
|
|
914e738931 | ||
|
|
e4c19c0f2a | ||
|
|
54354518d0 | ||
|
|
d36e21ab56 | ||
|
|
b496e3c667 | ||
|
|
d10434285f | ||
|
|
d6c8886fdb | ||
|
|
51e3c8605c | ||
|
|
d4d6b9c9aa | ||
|
|
0c9c3c61fc | ||
|
|
0228850d6d | ||
|
|
529078dc67 | ||
|
|
aadb68ba08 | ||
|
|
c81171a39e | ||
|
|
a50ecff189 | ||
|
|
73321829ae | ||
|
|
e88c837482 | ||
|
|
2b263cae87 | ||
|
|
e93052f0cb | ||
|
|
9539083f7e | ||
|
|
8f26eb1c69 | ||
|
|
a126e5b4c8 | ||
|
|
033c3cd8e9 | ||
|
|
50d029c671 | ||
|
|
6a3f7e6150 | ||
|
|
aadfbefbe9 | ||
|
|
edbcaf0f90 | ||
|
|
207427e993 | ||
|
|
e109dd876a | ||
|
|
64ac69c48b | ||
|
|
652b06c116 | ||
|
|
654035a469 | ||
|
|
cd50e0086b | ||
|
|
66a119e9dc | ||
|
|
14ec7d48f6 | ||
|
|
5ad5b211e9 | ||
|
|
aac4b6ccfe | ||
|
|
cfc6967fdc | ||
|
|
8a0b960985 | ||
|
|
bd260c3dc5 | ||
|
|
203dff8d98 | ||
|
|
ca56089a3e | ||
|
|
a012d1b927 | ||
|
|
0af322a3a8 | ||
|
|
8d743803c8 | ||
|
|
63fed77c5b | ||
|
|
f2077dca04 | ||
|
|
cccfb6a08a | ||
|
|
fa6dead83d | ||
|
|
605418d750 | ||
|
|
8aa869b2e4 | ||
|
|
558b6e0ccf | ||
|
|
6a695368da | ||
|
|
ce89f29aeb | ||
|
|
6d935d8589 | ||
|
|
967093328f | ||
|
|
48e1da128d | ||
|
|
369de684a6 | ||
|
|
d5f65eea06 | ||
|
|
8e5deb5bf4 | ||
|
|
df653258bb | ||
|
|
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 |
9
.github/ISSUE_TEMPLATE/----.md
vendored
9
.github/ISSUE_TEMPLATE/----.md
vendored
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: 功能请求
|
||||
name: 功能请求(请先查看常见问题及搜索issue列表中有无你要提的问题)
|
||||
about: 为这个项目提出一个想法
|
||||
title: 例如:添加xxx功能、优化xxx功能
|
||||
labels: ''
|
||||
@@ -7,6 +7,11 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**解决方案检查**
|
||||
<!-- 请确保你已从以下渠道寻找过解决方案,然后将 [ ] 替换成 [x] -->
|
||||
- [ ] 我已阅读常见问题(<https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md>)
|
||||
- [ ] 我已搜索issue列表(<https://github.com/lyswhut/lx-music-desktop/issues?utf8=✓&q=>)
|
||||
|
||||
**描述您想要的解决方案**
|
||||
简洁明了地描述您要发生的事情。
|
||||
|
||||
@@ -14,4 +19,4 @@ assignees: ''
|
||||
对您考虑过的所有替代解决方案或功能的简洁明了的描述。
|
||||
|
||||
**其他内容**
|
||||
在此处添加有关功能请求的任何其他上下文或屏幕截图。
|
||||
在此处添加有关功能请求的任何其他上下文或屏幕截图(直接把图片拖到编辑框即可添加图片)。
|
||||
|
||||
9
.github/ISSUE_TEMPLATE/--bug.md
vendored
9
.github/ISSUE_TEMPLATE/--bug.md
vendored
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: 报告Bug
|
||||
name: 报告Bug(请先查看常见问题及搜索issue列表中有无你要提的问题)
|
||||
about: 创建报告以帮助我们改进
|
||||
title: 例如:音乐无法播放
|
||||
labels: ''
|
||||
@@ -7,6 +7,11 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**解决方案检查**
|
||||
<!-- 请确保你已从以下渠道寻找过解决方案,然后将 [ ] 替换成 [x] -->
|
||||
- [ ] 我已阅读常见问题(<https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md>)
|
||||
- [ ] 我已搜索issue列表(<https://github.com/lyswhut/lx-music-desktop/issues?utf8=✓&q=>)
|
||||
|
||||
**描述错误**
|
||||
清楚简洁地说明错误是什么。
|
||||
|
||||
@@ -21,7 +26,7 @@ assignees: ''
|
||||
对您期望发生的事情的简洁明了的描述。
|
||||
|
||||
**截图**
|
||||
如果适用,请添加屏幕截图以帮助解释您的问题。
|
||||
如果适用,请添加屏幕截图以帮助解释您的问题(直接把图片拖到编辑框即可添加图片)。
|
||||
|
||||
**环境:**
|
||||
-操作系统及版本:[例如:Windows 10 64位 18362.156]
|
||||
|
||||
12
.travis.yml
12
.travis.yml
@@ -1,19 +1,16 @@
|
||||
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 +23,8 @@ notifications:
|
||||
email: false
|
||||
|
||||
script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
||||
npm install && npm run publish:gh:linux
|
||||
@@ -41,3 +40,4 @@ before_cache:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- dev
|
||||
|
||||
291
CHANGELOG.md
291
CHANGELOG.md
@@ -6,6 +6,297 @@ 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.18.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.18.1...v0.18.2) - 2020-05-02
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复开启托盘时,可能导致无法自动更新的问题
|
||||
|
||||
## [0.18.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.18.0...v0.18.1) - 2020-05-02
|
||||
|
||||
### 优化
|
||||
|
||||
- win下的托盘图标使用更大的图片
|
||||
- 加长软件协议的强制停留时间
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复导入设置某些设置未立即生效的问题
|
||||
|
||||
## [0.18.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.17.0...v0.18.0) - 2020-05-01
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增FLAC格式音乐标签信息写入与封面嵌入(因128k以外的音质已失效,目前该功能用不上了)
|
||||
- 添加软件启动时是否自动聚焦搜索框的设置
|
||||
- 新增托盘设置,默认关闭,可到设置开启,感谢 @LasyIsLazy 提交的PR
|
||||
- 新增打开酷狗源用户歌单
|
||||
- 新增使用协议
|
||||
- 新增虾米音源
|
||||
- 新增新皮肤“粉妆玉琢”、“青出于黑”,可去体验下~
|
||||
- 新增“超大”、“巨大”窗口尺寸
|
||||
- 新增播放详情页(退出详情页可点击右上角退出按钮或者在播放详情页任意地方**鼠标快速右击两次**)
|
||||
|
||||
### 优化
|
||||
|
||||
- 略微加深音量条底色
|
||||
- 优化其他界面细节
|
||||
- 优化英语翻译,感谢 @CPCer
|
||||
- 优化程序的流畅度
|
||||
|
||||
### 更变
|
||||
|
||||
- 下载列表的歌曲下载、播放将随设置中的保存路径改变而改变,不再固定指向其初始位置
|
||||
- 移除列表多选框,现在多选需要键盘配合,想要多选前需按下`Shift`或`Ctrl`键然后再鼠标点击想要选中的内容即可触发多选机制,其中`Shift`键用于连续选择,`Ctrl`键用于不连续选择,`Ctrl+a`用于快速全选。例子一:想要选中1-5项,则先按下`Shift`键后,鼠标点击第一项,再点击第五项即可完成选择;例子二:想要选中1项与第3项,则先按下`Ctrl`键后,鼠标点击第一项,再点击第三项即可完成选择;例子三:想要选中当前列表的全部内容,键盘先按下`Ctrl`键不放,然后按`a`键,即可完成选择。用`Shift`或`Ctrl`选择时,鼠标点击未选中的内容会将其选中,点击已选择的内容会将其取消选择,若想全部取消选择,在不按`Shift`或`Alt`键的情况下,随意点击列表里的一项内容即可全部取消选择。(P.S:`Ctrl`键对应Mac OS上的`Command`键)
|
||||
- 现在进度条的封面图左击改为打开播放详情页,在列表定位歌曲改为右击
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复网易源某些歌曲提示没有可播放的音质的问题
|
||||
- 修复下载管理刷新URL失败时不标记任务下载失败的问题
|
||||
- 修复列表导出的文字描述,感谢 @CPCer
|
||||
- 修复歌曲切换方式无法取消勾选的问题
|
||||
- 修复打开歌单详情的情况下切到其他界面再切回来报错的问题
|
||||
- 修正播放列表浮动按钮错误的文字提示
|
||||
|
||||
### 移除
|
||||
|
||||
- 因128k以外的音质失效,So 禁止所有128k外的音质下载
|
||||
|
||||
### 其他
|
||||
|
||||
更新 Electron 到 8.2.5
|
||||
|
||||
|
||||
## [0.17.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.16.0...v0.17.0) - 2020-03-15
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增多语言设置,目前软件内置了简体中文、繁体中文、英语三种语言,欢迎提交PR翻译更多语言!
|
||||
- 新增无法打开外部歌单FAQ
|
||||
- 新增启动参数`search`,使用例子:`.\lx-music-desktop.exe -search="突然的自我 - 伍佰"`
|
||||
- 新增音频输出设置
|
||||
- 新增软件内的包括字体在内的界面内容大小调整,现在当窗口大小切换到“较小/大/较大”时,软件内的元素将会适当减小或加大,窗口大小的“小”与“中”内的元素将保持之前的大小暂不做改变
|
||||
- 新增音源别名,默认将显示别名,想要显示回原名可到设置切换(免责声明:别名仅是本软件用于描述各音源的标签,其名字归版权方所有)
|
||||
- 新增发现新版本更新失败弹窗的忽略提醒按钮,忽略提醒后,以后同一个版本再失败时将不会弹窗提醒,但仍可到设置-版本更新手动点开更新弹窗查看或恢复提醒
|
||||
- 新增热搜词,默认关闭,可到设置开启
|
||||
- 新增历史搜索记录,默认关闭,可到设置开启(右击单个历史记录标签可移除所点击的记录)
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化月里嫦娥皮肤侧栏鼠标悬浮颜色
|
||||
- 优化播放进度条的动画效果
|
||||
- 现在添加下载任务时,后面添加的任务会在列表顶部插入
|
||||
- 优化歌单打开机制,现在歌单加载失败时会提示加载失败了,并且支持直接打开企鹅、酷我手机分享出来的歌单了
|
||||
- 优化右上角最小化/关闭按钮布局
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复歌单详情处于加载状态时无法返回的问题
|
||||
- 修复鼠标右击复制列表内容时会复制音质标签的问题
|
||||
- 修复`0.6.2`及以前的版本导出的“所有数据”内的歌曲列表无法导入的问题
|
||||
- 修复下载列表在某些情况下无法取消全选的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新Electron到 8.1.1
|
||||
|
||||
## [0.16.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.15.0...v0.16.0) - 2020-02-16
|
||||
|
||||
### 新增
|
||||
|
||||
- 允许选中列表内歌曲名、歌手名、专辑名内的文字,选中后可使用键盘快捷键进行复制
|
||||
- 新增在列表可选内容区域**鼠标右击**时自动复制列表已选文字的功能
|
||||
- 新增在搜索框**鼠标右击**时自动粘贴剪贴板的文本到搜索框中
|
||||
- 任务下载失败时将显示搜索按钮,方便在其他源搜索该歌曲
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化木叶之村主题翻页器背景颜色
|
||||
- 优化各个主题音质标签颜色
|
||||
- 优化其他一些界面细节及用户交互效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复启用透明窗口鼠标不穿透的bug
|
||||
- 修复大窗口时设置的音乐来源选项不换行的问题
|
||||
- 修复某些情况下暂停任务会自动开始任务的问题
|
||||
- 修复移除暂停、错误的任务时不删除未下载完成的文件的问题
|
||||
- 修复酷狗源歌单热门标签歌单列表无法加载问题
|
||||
- 修复QQ源歌单热门标签歌单列表无法加载问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到 8.0.1
|
||||
|
||||
## [0.15.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.14.1...v0.15.0) - 2020-01-23
|
||||
|
||||
洛雪提前祝大家新年快乐、身体健康、阖家幸福!
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复歌曲下载列表无法加载的问题
|
||||
- 修复歌曲下载任务数大于最大下载任务数的问题
|
||||
- 修复某些情况下歌曲下载错误的问题
|
||||
- 修复下载列表数据没有被迁移直接被丢弃的问题
|
||||
|
||||
## [0.14.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.14.0...v0.14.1) - 2020-01-22
|
||||
|
||||
洛雪提前祝大家新年快乐、身体健康、阖家幸福!
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复由于旧版配置文件迁移出错导致的软件界面无法显示的问题
|
||||
|
||||
## [0.14.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.13.1...v0.14.0) - 2020-01-22
|
||||
|
||||
洛雪提前祝大家新年快乐、身体健康、阖家幸福!
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增各大平台歌单热门标签显示(显示在歌单界面的第一个下拉标签菜单中)
|
||||
- 恢复QQ音乐源128k音质试听
|
||||
- 新增不强制win7开启透明效果即可使用,但要配置运行参数`-nt`,例如:`.\lx-music-desktop.exe -nt`,添加方法可自行百度“给快捷方式加参数”
|
||||
- 新增“新年快乐”主题,可自行切换体验
|
||||
|
||||
### 优化
|
||||
|
||||
- 减淡各个主题的歌曲列表分隔线颜色
|
||||
- 在线音乐列表音质标签优化,当歌曲有无损音质时隐藏高品质标签
|
||||
- 更新改进的歌词播放插件,现在歌词的播放显示将更准确
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复咪咕源无法搜索的问题
|
||||
- 修复更新弹窗底部文字颜色没有适配当前主题颜色的问题
|
||||
- 修复导入设置窗口大小、代理设置不立即生效的问题
|
||||
- 修复在线音乐列表获取失败时无限循环请求的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 将软件设置与播放列表分离存储成两个文件
|
||||
- 更新 Electron 到 7.1.9
|
||||
|
||||
## [0.13.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.13.0...v0.13.1) - 2019-12-16
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复全局更新弹窗无法遮盖搜索框的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 由于electron 7.1.3 - 7.1.5 的自动更新功能存在Bug,现降级到7.1.2
|
||||
|
||||
## [0.13.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.12.1...v0.13.0) - 2019-12-15
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增搜索框搜索建议键盘上下方向键选择功能
|
||||
- 聚合搜索新增音源显示
|
||||
- 新增“离开搜索界面时清空搜索列表”设置选项,默认关闭,可到设置-强迫症设置开启
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化“信口雌黄”皮肤配色
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复存在弹出层时,搜索建议列表被弹出层覆盖的问题
|
||||
- 修复搜索、排行榜、歌单列表多选框从不定状态到选中的Bug
|
||||
|
||||
### 移除
|
||||
|
||||
- 因Q音接口失效,移除Q音源的试听与下载
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到7.1.5
|
||||
- 更新vue到2.6.11
|
||||
|
||||
## [0.12.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.12.0...v0.12.1) - 2019-12-01
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化定位歌曲时的列表滚动机制
|
||||
- 优化链接点击效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复使用酷我源下载歌曲时,当歌曲无封面时下载报错的问题
|
||||
- 修复酷我源排行榜、歌单详情列表里的歌曲音质匹配问题(原来无论歌曲有无高品、无损都会显示有)
|
||||
- 禁止外部链接在软件内打开,将所有外部链接从默认浏览器打开
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到7.1.2
|
||||
|
||||
## [0.12.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.11.0...v0.12.0) - 2019-11-17
|
||||
|
||||
由于新下载库仍然没有完成,但下载功能已经可用,so 移除之前使用的第三方下载库,暂时把新下载库的下载模块直接加入本程序,若出现下载问题欢迎反馈!
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增下载功能对代理设置的支持,现在若在软件设置了代理服务器,下载功能也将会走代理网络了
|
||||
|
||||
### 优化
|
||||
|
||||
- 新下载模块将对恢复下载的任务进行字节校验,用于解决下载进度超过100%后仍然下载的问题
|
||||
- 注意:目前仍然无法暂停处于**链接获取**状态中的任务
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复Linux deb版本`.desktop`桌面文件缺少图标的问题,新增中文名称显示、软件分类,感谢@lowy的反馈!
|
||||
- 修复下载列表歌曲状态分类列表操作Bug
|
||||
- 修复歌曲封面下载失败时仍然执行嵌入封面操作导致报错的问题
|
||||
- 跳过重复添加**相同歌曲名与扩展名的歌曲**,例如你之前下载了A歌曲的128k音质,现在想要下载它的320k音质,但由于两者都是MP3格式,会因为重名导致之前的128k音质被覆盖但列表中仍然显示两种音质的问题(但实际上都是指向后面的320k音质)
|
||||
|
||||
## [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
|
||||
|
||||
#### 修复
|
||||
|
||||
71
FAQ.md
71
FAQ.md
@@ -1,10 +1,10 @@
|
||||
# lx-music-desktop 常见问题
|
||||
|
||||
在阅读本常见问题后,仍然无法解决你的问题,请提交issue或者加企鹅群`830125506`反馈,反馈时请**注明**已阅读常见问题!
|
||||
在阅读本常见问题后,仍然无法解决你的问题,请提交issue或者加企鹅群`830125506`反馈(无事勿加,入群先看群公告),反馈时请**注明**已阅读常见问题!
|
||||
|
||||
## 软件为什么没有桌面歌词与自定义列表功能
|
||||
|
||||
洛雪音乐的最初定位不是作为播放器开发的,它主要用于**查找歌曲**,软件的播放功能仅用于试听,不建议用作为常用播放器使用,因此无桌面、界面歌词,不可自定义列表。
|
||||
洛雪音乐的最初定位不是作为播放器开发的,它主要用于**查找歌曲**,软件的播放功能仅用于试听,不建议用作为常用播放器使用,因此无桌面、界面歌词,不可自定义列表等功能。
|
||||
|
||||
## 歌曲无法试听与下载
|
||||
|
||||
@@ -12,17 +12,16 @@
|
||||
|
||||
1. 尝试更新到最新版本
|
||||
2. 尝试切换其他歌曲(或直接搜索该歌曲),若全部歌曲都无法试听与下载则进行下一步
|
||||
3. 尝试到设置-接口来源切换到其他接口
|
||||
3. 尝试到 设置-音乐来源 切换到其他接口
|
||||
4. 尝试切换网络,比如用手机开热点(目前存在某些网络无法访问接口服务器的情况)
|
||||
5. 若还不行请到这个链接查看详情:<https://github.com/lyswhut/lx-music-desktop/issues/5>
|
||||
6. 若没有在第5条链接中的第一条评论中看到接口无法使用的说明,则应该是你网络无法访问接口服务器的问题,如果接口有问题我会在那里说明。
|
||||
|
||||
想要知道是不是自己网络的问题可以看看`https://ts.tempmusic.tk`能不能在浏览器打开,浏览器显示404是正常的,如果不是404那就证明所在网络无法访问接口服务器。
|
||||
想要知道是不是自己网络的问题可以看看`http://ts.tempmusic.tk`能不能在浏览器打开,浏览器显示404是正常的,如果不是404那就证明所在网络无法访问接口服务器。
|
||||
若网页无法打开或打来不是404,则应该是DNS的问题,可以尝试以下办法:
|
||||
|
||||
1. 改成自动获取试试
|
||||
1. 将DNS改成自动获取试试
|
||||
2. 手动把DNS改一下,不要用360的DNS,可以把DNS改成`114.114.114.114`、`8.8.8.8`
|
||||
3. 软件设置里面的代理不要勾起来
|
||||
|
||||
## 软件安装包说明
|
||||
|
||||
@@ -46,15 +45,63 @@
|
||||
注意:**绿色版**的软件自动更新功能**不可用**,建议使用安装版!!<br>
|
||||
注意:**Mac版**、**Linux deb**版不支持自动更新!
|
||||
|
||||
## Windows 7 下界面异常
|
||||
## Windows 7 下界面异常(界面显示不完整)
|
||||
|
||||
当 win7 没有开启**透明效果**时界面将会显示异常,开启方法请自行百度。<br>
|
||||
对于一些开启透明效果后仍然无法正常显示界面的系统,我也不知道是什么原因导致的,只能说正常的系统是没有这个问题的,如果你知道原因导致的欢迎反馈!
|
||||
由于软件默认使用了透明窗口,根据Electron官方文档的[说明](https://electronjs.org/docs/api/frameless-window#%E5%B1%80%E9%99%90%E6%80%A7):
|
||||
> 在 windows 操作系统上, 当 DWM 被禁用时, 透明窗口将无法工作。
|
||||
|
||||
## 安装版安装失败,提示应用未安装
|
||||
因此,当 win7 没有使用**AERO**主题时界面将会显示异常,开启AERO的方法请自行百度:`win7开启aero效果`(开启后可看到任务栏变透明)。<br>
|
||||
从`0.14.0`版本起不再强制要求开启透明效果,若你实在不想开启(若非电脑配置太低,墙裂建议开启!),可通过添加运行参数`-nt`来运行程序即可,例如:`.\lx-music-desktop.exe -nt`,添加方法可自行百度“给快捷方式加参数”,该参数的作用是用来控制程序是否使用非透明窗口运行。
|
||||
|
||||
对于部分电脑出现安装失败的问题我也不懂什么原因,,可以尝试清理下安装文件,或者重启电脑试试。
|
||||
对于一些完全无法正常显示界面的情况,请阅读下面的 **软件启动后,界面无法显示**
|
||||
|
||||
## 软件启动后,界面无法显示
|
||||
|
||||
软件启动后,可以在任务栏看到软件,但软件界面在桌面上无任何显示。<br>
|
||||
原始问题看:<https://github.com/electron/electron/issues/19569#issuecomment-522231083><br>
|
||||
解决办法:下载`.NET Framework 4.7.1`或**更高**版本安装即可(建议安装最新版,若安装过程中遇到问题可尝试自行百度解决)。<br>
|
||||
微软官方下载地址:<https://dotnet.microsoft.com/download/dotnet-framework><br>
|
||||
下载`Runtime(运行时)`版即可,安装完成后可能需要重启才生效。
|
||||
|
||||
若还是不行可尝试以下操作:
|
||||
|
||||
- 更新显卡驱动
|
||||
- 尝试将绿色版的软件放在**桌面**或**我的文档**运行
|
||||
|
||||
## 安装版安装失败,提示安装程序并未成功地运行完成
|
||||
|
||||
对于部分电脑出现安装失败的问题,可以做出以下尝试:
|
||||
|
||||
- 若你之前可以安装成功,但现在安装失败,就去**控制面板-程序和功能**或用第三方卸载工具看下有没有之前的版本残留,若同时在不同路径下安装了多个版本就可能会出现该问题,这种情况卸载掉所有版本重新安装即可
|
||||
- 清理安装路径下的残留文件
|
||||
- 以管理员权限打开`cmd`,输入`sfc /scannow`回车等待检查完成重启电脑
|
||||
- 若还是不行我也没办法了。。
|
||||
|
||||
## 缺少`xxx.dll`
|
||||
|
||||
这个是电脑缺少某些dll导致的,正常的系统是没有这个问题的,解决办法需自行百度弹出的错误信息看下别人是怎么解决的。
|
||||
这个是电脑缺少某些dll导致的,正常的系统是没有这个问题的,可以尝试如下几个解决办法:
|
||||
|
||||
- 以管理员权限打开`cmd`,输入`sfc /scannow`回车等待检查完成重启电脑
|
||||
- 若上面的方法**修复、重启**电脑后仍然不行,就自行百度弹出的**错误信息**看下别人是怎么解决的
|
||||
|
||||
## 杀毒软件提示有病毒或恶意行为
|
||||
|
||||
本人只能保证我写的代码不包含任何**恶意代码**、**收集用户信息**的行为,并且软件代码已开源,请自行查阅,软件安装包也是由CI拉取源代码构建,构建日志:[windows包](https://ci.appveyor.com/project/lyswhut/lx-music-desktop)、[Mac/Linux包](https://travis-ci.org/lyswhut/lx-music-desktop)<br>
|
||||
尽管如此,但这不意味着软件是100%安全的,由于软件使用了第三方依赖,当这些依赖存在恶意行为时([供应链攻击](https://docs.microsoft.com/zh-cn/windows/security/threat-protection/intelligence/supply-chain-malware)),软件也将会受到牵连,所以我只能尽量选择使用较多人用、信任度较高的依赖。<br>
|
||||
当然,以上说明建立的前提是在你所用的安装包是从**本项目主页上写的链接**下载的,或者有相关能力者还可以下载源代码自己构建安装包。
|
||||
|
||||
从`0.17.0`起,由于加入了音频输出设备切换功能,该功能调用了 [MediaDevices.enumerateDevices()](https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/enumerateDevices),可能导致安全软件提示洛雪要访问摄像头(目前发现卡巴斯基会提示),但实际上没有用到摄像头,并且摄像头的提示灯也不会亮,你可以选择阻止访问。
|
||||
|
||||
最后,若出现杀毒软件报毒、存在恶意行为,请自行判断选择是否继续使用本软件!
|
||||
|
||||
## 软件无法联网
|
||||
|
||||
软件的排行榜、歌单、搜索列表**都**无法加载:
|
||||
|
||||
- 检查是否在设置界面开启了代理(当代理乱设置时软件将无法联网)
|
||||
- 检查软件是否被第三方软件/防火墙阻止联网
|
||||
|
||||
## 无法打开外部歌单
|
||||
|
||||
对于分享出来的歌单,若打开失败,可尝试先在浏览器中打开后,再从浏览器地址栏复制URL地址到软件打开;<br>
|
||||
或者如果你知道歌单 id 也可以直接输入歌单 id 打开。<br>
|
||||
|
||||
47
README.md
47
README.md
@@ -4,6 +4,7 @@
|
||||
<a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/release/lyswhut/lx-music-desktop" alt="Release version"></a>
|
||||
<a href="https://ci.appveyor.com/project/lyswhut/lx-music-desktop"><img src="https://ci.appveyor.com/api/projects/status/flrsqd5ymp8fnte5?svg=true" alt="Build status"></a>
|
||||
<a href="https://travis-ci.org/lyswhut/lx-music-desktop"><img src="https://travis-ci.org/lyswhut/lx-music-desktop.svg?branch=master" alt="Build status"></a>
|
||||
<a href="https://electronjs.org/releases/stable"><img src="https://img.shields.io/github/package-json/dependency-version/lyswhut/lx-music-desktop/dev/electron/master" alt="Electron version"></a>
|
||||
<!-- <a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/latest/total" alt="Downloads"></a> -->
|
||||
<a href="https://github.com/lyswhut/lx-music-desktop/tree/dev"><img src="https://img.shields.io/github/package-json/v/lyswhut/lx-music-desktop/dev" alt="Dev branch version"></a>
|
||||
<!-- <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> -->
|
||||
@@ -35,8 +36,8 @@
|
||||
|
||||
所用技术栈:
|
||||
|
||||
- Electron 6.x
|
||||
- Vue 2.x
|
||||
- Electron 8
|
||||
- Vue 2
|
||||
|
||||
已支持的平台:
|
||||
|
||||
@@ -46,12 +47,12 @@
|
||||
|
||||
软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)<br>
|
||||
软件下载请转到:[发布页面](https://github.com/lyswhut/lx-music-desktop/releases)<br>
|
||||
或者到网盘下载(网盘内有MAC、windows版):`https://www.lanzous.com/b906260/` 密码:`glqw`<br>
|
||||
使用常见问题请转至:[常见问题](https://github.com/lyswhut/lx-music-desktop#常见问题)
|
||||
或者到网盘下载(网盘内有MAC、windows版):`https://t-s.lanzous.com/b0bf2cfa/` 密码:`glqw`<br>
|
||||
使用常见问题请转至:[常见问题](https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md)
|
||||
|
||||
### 源码使用方法
|
||||
|
||||
环境要求:Node.js 12.x
|
||||
环境要求:Node.js 12.x+
|
||||
|
||||
```bash
|
||||
# 开发模式
|
||||
@@ -60,30 +61,46 @@ npm run dev
|
||||
# 构建免安装版
|
||||
npm run pack:dir
|
||||
|
||||
# 构建安装包(windows版)
|
||||
# 构建安装包(Windows版)
|
||||
npm run pack
|
||||
|
||||
# 构建安装包(Mac版)
|
||||
npm run pack:mac
|
||||
|
||||
# 构建安装包(Linux版)
|
||||
npm run pack:linux
|
||||
|
||||
```
|
||||
|
||||
### UI界面
|
||||
|
||||
<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>
|
||||
|
||||
### 启动参数
|
||||
|
||||
目前软件已支持的启动参数如下:
|
||||
|
||||
- `-search` 启动软件时自动在搜索框搜索指定的内容,例如:`-search="突然的自我 - 伍佰"`
|
||||
- `-nt` 以非透明模式启动,对于未开启AERO效果的win7系统可加此参数启动以确保界面正常显示
|
||||
|
||||
### 常见问题
|
||||
|
||||
常见问题已移至:<https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md>
|
||||
|
||||
### 致谢
|
||||
### 项目协议
|
||||
|
||||
感谢 [@messoer](https://github.com/messoer) 曾经提供的部分音乐API!
|
||||
本项目基于 [Apache License 2.0](https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE) 许可证发行,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。
|
||||
|
||||
### 免责声明
|
||||
词语约定:本协议中的“本项目”指洛雪音乐桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本项目内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。
|
||||
|
||||
本项目**不开发或者破解直接获取音频数据**的功能,所有音频数据均来自**第三方接口**!<br>
|
||||
本软件仅用于**测试 `electron 6.x` 在各种系统上的兼容性**及用于**对比各大音乐平台歌单、排行榜等数据列表的差异性**,使用本软件产生的**任何涉及版权相关的数据**请于**24小时内删除**。<br>
|
||||
本软件仅用于学习交流使用,禁止用于商业用途,使用本软件所造成的的后果由使用者承担!<br>
|
||||
若对此有疑问请 mail to: lyswhut@qq.com
|
||||
1. 本项目的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本项目不对数据的准确性负责。
|
||||
2. 使用本项目的过程中可能会产生版权数据,对于这些版权数据,本项目不拥有它们的所有权,为了避免造成侵权,使用者务必在**24小时**内清除使用本项目的过程中所产生的版权数据。
|
||||
3. 本项目内的官方音乐平台别名为本项目内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本项目更改或移除。
|
||||
4. 本项目内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本项目移除。
|
||||
5. 由于使用本项目产生的包括由于本协议或由于使用或无法使用本项目而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。
|
||||
6. 本项目完全免费,且开源发布于 GitHub 面向全世界人用作对技术的学习交流,本项目不对项目内的技术可能存在违反当地法律法规的行为作保证,**禁止在违反当地法律法规的情况下使用本项目**,对于使用者在明知或不知当地法律法规不允许的情况下使用本项目所造成的任何违法违规行为由使用者承担,本项目不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。
|
||||
|
||||
### 许可证
|
||||
若你使用了本项目,将代表你接收以上协议。
|
||||
|
||||
[Apache License 2.0](https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE)
|
||||
音乐平台不易,请尊重版权,支持正版。<br>
|
||||
若对此有疑问请 mail to: lyswhut+qq.com (请将`+`替换成`@`)
|
||||
|
||||
@@ -9,6 +9,8 @@ module.exports = {
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.join(__dirname, '../../src/main'),
|
||||
events: path.join(__dirname, '../../src/main/events'),
|
||||
common: path.join(__dirname, '../../src/common'),
|
||||
},
|
||||
extensions: ['*', '.js', '.json', '.node'],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const path = require('path')
|
||||
const merge = require('webpack-merge')
|
||||
const webpack = require('webpack')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
@@ -18,5 +19,17 @@ module.exports = merge(baseConfig, {
|
||||
__static: `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
new FriendlyErrorsPlugin({
|
||||
onErrors(severity, errors) { // Silent warning from electron-debug
|
||||
if (severity != 'warning') return
|
||||
|
||||
for (let i = errors.length; i > -1; i--) {
|
||||
const error = errors[i]
|
||||
if (error.file == './node_modules/electron-debug/index.js') errors.splice(i, 1)
|
||||
}
|
||||
// You can listen to errors transformed and prioritized by the plugin
|
||||
// severity can be 'error' or 'warning'
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ process.env.NODE_ENV = 'production'
|
||||
const chalk = require('chalk')
|
||||
const del = require('del')
|
||||
const webpack = require('webpack')
|
||||
const Multispinner = require('multispinner')
|
||||
const Spinnies = require('spinnies')
|
||||
|
||||
const mainConfig = require('./main/webpack.config.prod')
|
||||
const rendererConfig = require('./renderer/webpack.config.prod')
|
||||
@@ -15,40 +15,44 @@ const okayLog = chalk.bgGreen.white(' OKAY ') + ' '
|
||||
function build() {
|
||||
del.sync(['dist/electron', 'build'])
|
||||
|
||||
const tasks = ['main', 'renderer']
|
||||
const m = new Multispinner(tasks, {
|
||||
preText: 'building',
|
||||
postText: 'process',
|
||||
})
|
||||
|
||||
const spinners = new Spinnies({ color: 'blue' })
|
||||
spinners.add('main', { text: 'main building' })
|
||||
spinners.add('renderer', { text: 'renderer building' })
|
||||
let results = ''
|
||||
|
||||
m.on('success', () => {
|
||||
// m.on('success', () => {
|
||||
// process.stdout.write('\x1B[2J\x1B[0f')
|
||||
// console.log(`\n\n${results}`)
|
||||
// console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
|
||||
// process.exit()
|
||||
// })
|
||||
function handleSuccess() {
|
||||
process.stdout.write('\x1B[2J\x1B[0f')
|
||||
console.log(`\n\n${results}`)
|
||||
console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
|
||||
process.exit()
|
||||
})
|
||||
}
|
||||
|
||||
pack(mainConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
m.success('main')
|
||||
}).catch(err => {
|
||||
m.error('main')
|
||||
console.log(`\n ${errorLog}failed to build main process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
pack(rendererConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
m.success('renderer')
|
||||
}).catch(err => {
|
||||
m.error('renderer')
|
||||
console.log(`\n ${errorLog}failed to build renderer process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
})
|
||||
Promise.all([
|
||||
pack(mainConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
spinners.succeed('main', { text: 'main build success!' })
|
||||
}).catch(err => {
|
||||
spinners.fail('main', { text: 'main build fail :(' })
|
||||
console.log(`\n ${errorLog}failed to build main process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
}),
|
||||
pack(rendererConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
spinners.succeed('renderer', { text: 'renderer build success!' })
|
||||
}).catch(err => {
|
||||
spinners.fail('renderer', { text: 'renderer build fail :(' })
|
||||
console.log(`\n ${errorLog}failed to build renderer process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
}),
|
||||
]).then(handleSuccess)
|
||||
}
|
||||
|
||||
function pack(config) {
|
||||
|
||||
@@ -7,13 +7,12 @@ const path = require('path')
|
||||
const { spawn } = require('child_process')
|
||||
const webpack = require('webpack')
|
||||
const WebpackDevServer = require('webpack-dev-server')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const webpackHotMiddleware = require('webpack-hot-middleware')
|
||||
|
||||
const mainConfig = require('./main/webpack.config.dev')
|
||||
const rendererConfig = require('./renderer/webpack.config.dev')
|
||||
|
||||
const { logStats } = require('./utils')
|
||||
|
||||
let electronProcess = null
|
||||
let manualRestart = false
|
||||
let hotMiddleware
|
||||
@@ -31,7 +30,7 @@ function startRenderer() {
|
||||
|
||||
compiler.hooks.compilation.tap('compilation', compilation => {
|
||||
// console.log(Object.keys(compilation.hooks))
|
||||
compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
|
||||
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
|
||||
hotMiddleware.publish({ action: 'reload' })
|
||||
cb()
|
||||
})
|
||||
@@ -59,7 +58,7 @@ function startRenderer() {
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
server.listen(9080)
|
||||
@@ -73,7 +72,6 @@ function startMain() {
|
||||
const compiler = webpack(mainConfig)
|
||||
|
||||
compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
|
||||
logStats('Main', chalk.white.bold('compiling...'))
|
||||
hotMiddleware.publish({ action: 'compiling' })
|
||||
done()
|
||||
})
|
||||
@@ -137,34 +135,24 @@ function electronLog(data, color) {
|
||||
}
|
||||
}
|
||||
|
||||
function greeting() {
|
||||
/* const cols = process.stdout.columns
|
||||
let text = ''
|
||||
|
||||
if (cols > 104) text = 'electron-vue'
|
||||
else if (cols > 76) text = 'electron-|vue'
|
||||
else text = false
|
||||
|
||||
if (text) {
|
||||
say(text, {
|
||||
colors: ['yellow'],
|
||||
font: 'simple3d',
|
||||
space: false,
|
||||
})
|
||||
} else console.log(chalk.yellow.bold('\n electron-vue')) */
|
||||
console.log(chalk.blue('getting ready...') + '\n')
|
||||
}
|
||||
|
||||
function init() {
|
||||
greeting()
|
||||
const Spinnies = require('spinnies')
|
||||
const spinners = new Spinnies({ color: 'blue' })
|
||||
spinners.add('main', { text: 'main compiling' })
|
||||
spinners.add('renderer', { text: 'renderer compiling' })
|
||||
function handleSuccess(name) {
|
||||
spinners.succeed(name, { text: name + ' compile success!' })
|
||||
}
|
||||
function handleFail(name) {
|
||||
spinners.fail(name, { text: name + ' compile fail!' })
|
||||
}
|
||||
|
||||
Promise.all([startRenderer(), startMain()])
|
||||
.then(() => {
|
||||
startElectron()
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
Promise.all([
|
||||
startRenderer().then(() => handleSuccess('renderer')).catch(() => handleFail('renderer')),
|
||||
startMain().then(() => handleSuccess('main')).catch(() => handleFail('main')),
|
||||
]).then(startElectron).catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
init()
|
||||
|
||||
@@ -1,45 +1,49 @@
|
||||
{\rtf1\adeflang1025\ansi\ansicpg936\uc2\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}
|
||||
{\rtf1\adeflang1025\ansi\ansicpg936\uc2\adeff0\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi0\deflang1033\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}
|
||||
{\f13\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}
|
||||
{\f44\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}@\'cb\'ce\'cc\'e5;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\f44\fbidi \fnil\fcharset134\fprq2{\*\panose 00000000000000000000}@\'cb\'ce\'cc\'e5;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\fdbmajor\f31501\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df Light;}{\fhimajor\f31502\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df Light;}
|
||||
{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\fdbminor\f31505\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df{\*\falt DengXian};}{\fhiminor\f31506\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df{\*\falt DengXian};}
|
||||
{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f65\fbidi \fmodern\fcharset238\fprq1 Courier New CE;}{\f66\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr;}
|
||||
{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f45\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f46\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||
{\f48\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f49\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f50\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f51\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\f52\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f53\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f65\fbidi \fmodern\fcharset238\fprq1 Courier New CE;}{\f66\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr;}
|
||||
{\f68\fbidi \fmodern\fcharset161\fprq1 Courier New Greek;}{\f69\fbidi \fmodern\fcharset162\fprq1 Courier New Tur;}{\f70\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f71\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic);}
|
||||
{\f72\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic;}{\f73\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese);}{\f177\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f487\fbidi \fnil\fcharset0\fprq2 @SimSun Western;}
|
||||
{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31520\fbidi \fnil\fcharset0\fprq2 DengXian Light Western;}
|
||||
{\fdbmajor\f31518\fbidi \fnil\fcharset238\fprq2 DengXian Light CE;}{\fdbmajor\f31519\fbidi \fnil\fcharset204\fprq2 DengXian Light Cyr;}{\fdbmajor\f31521\fbidi \fnil\fcharset161\fprq2 DengXian Light Greek;}
|
||||
{\fhimajor\f31530\fbidi \fnil\fcharset0\fprq2 DengXian Light Western;}{\fhimajor\f31528\fbidi \fnil\fcharset238\fprq2 DengXian Light CE;}{\fhimajor\f31529\fbidi \fnil\fcharset204\fprq2 DengXian Light Cyr;}
|
||||
{\fhimajor\f31531\fbidi \fnil\fcharset161\fprq2 DengXian Light Greek;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||
{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||
{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
||||
{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31560\fbidi \fnil\fcharset0\fprq2 DengXian Western{\*\falt DengXian};}
|
||||
{\fdbminor\f31558\fbidi \fnil\fcharset238\fprq2 DengXian CE{\*\falt DengXian};}{\fdbminor\f31559\fbidi \fnil\fcharset204\fprq2 DengXian Cyr{\*\falt DengXian};}{\fdbminor\f31561\fbidi \fnil\fcharset161\fprq2 DengXian Greek{\*\falt DengXian};}
|
||||
{\fhiminor\f31570\fbidi \fnil\fcharset0\fprq2 DengXian Western{\*\falt DengXian};}{\fhiminor\f31568\fbidi \fnil\fcharset238\fprq2 DengXian CE{\*\falt DengXian};}{\fhiminor\f31569\fbidi \fnil\fcharset204\fprq2 DengXian Cyr{\*\falt DengXian};}
|
||||
{\fhiminor\f31571\fbidi \fnil\fcharset161\fprq2 DengXian Greek{\*\falt DengXian};}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||
{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||
{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
||||
{\f45\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f46\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f48\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f49\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\f50\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f51\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f52\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||
{\f53\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;
|
||||
\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;}
|
||||
{\*\defchp \fs21\kerning2\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
|
||||
\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052
|
||||
{\f72\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic;}{\f73\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese);}{\f177\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f385\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}
|
||||
{\f386\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f388\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f389\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f392\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}
|
||||
{\f393\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f487\fbidi \fnil\fcharset0\fprq2 @SimSun Western;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
|
||||
{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||
{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31520\fbidi \fnil\fcharset0\fprq2 DengXian Light Western;}{\fdbmajor\f31518\fbidi \fnil\fcharset238\fprq2 DengXian Light CE;}
|
||||
{\fdbmajor\f31519\fbidi \fnil\fcharset204\fprq2 DengXian Light Cyr;}{\fdbmajor\f31521\fbidi \fnil\fcharset161\fprq2 DengXian Light Greek;}{\fhimajor\f31530\fbidi \fnil\fcharset0\fprq2 DengXian Light Western;}
|
||||
{\fhimajor\f31528\fbidi \fnil\fcharset238\fprq2 DengXian Light CE;}{\fhimajor\f31529\fbidi \fnil\fcharset204\fprq2 DengXian Light Cyr;}{\fhimajor\f31531\fbidi \fnil\fcharset161\fprq2 DengXian Light Greek;}
|
||||
{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
|
||||
{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||
{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31560\fbidi \fnil\fcharset0\fprq2 DengXian Western{\*\falt DengXian};}{\fdbminor\f31558\fbidi \fnil\fcharset238\fprq2 DengXian CE{\*\falt DengXian};}
|
||||
{\fdbminor\f31559\fbidi \fnil\fcharset204\fprq2 DengXian Cyr{\*\falt DengXian};}{\fdbminor\f31561\fbidi \fnil\fcharset161\fprq2 DengXian Greek{\*\falt DengXian};}{\fhiminor\f31570\fbidi \fnil\fcharset0\fprq2 DengXian Western{\*\falt DengXian};}
|
||||
{\fhiminor\f31568\fbidi \fnil\fcharset238\fprq2 DengXian CE{\*\falt DengXian};}{\fhiminor\f31569\fbidi \fnil\fcharset204\fprq2 DengXian Cyr{\*\falt DengXian};}{\fhiminor\f31571\fbidi \fnil\fcharset161\fprq2 DengXian Greek{\*\falt DengXian};}
|
||||
{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
|
||||
\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
|
||||
\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;\chyperlink\ctint255\cshade255\red5\green99\blue193;\red96\green94\blue92;\red225\green223\blue221;\cfollowedhyperlink\ctint255\cshade255\red149\green79\blue114;}{\*\defchp
|
||||
\fs21\kerning2\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
|
||||
\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052
|
||||
\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
|
||||
\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv
|
||||
\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052
|
||||
\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs21\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052
|
||||
\snext11 \ssemihidden \sunhideused Normal Table;}{\s15\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af2\afs22\alang1025 \ltrch\fcs0
|
||||
\fs21\lang1033\langfe2052\kerning2\loch\f31505\hich\af2\dbch\af31505\cgrid\langnp1033\langfenp2052 \sbasedon0 \snext15 \slink16 \sunhideused Plain Text;}{\*\cs16 \additive \rtlch\fcs1 \af2 \ltrch\fcs0 \loch\f31505\hich\af2 \sbasedon10 \slink15 \slocked
|
||||
\'b4\'bf\'ce\'c4\'b1\'be \'d7\'d6\'b7\'fb;}}{\*\rsidtbl \rsid927107\rsid3950508\rsid11081282\rsid12910709\rsid13643782\rsid14384001}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0
|
||||
\mnaryLim1}{\info{\author lysyw}{\operator lysyw}{\creatim\yr2019\mo8\dy17\hr10\min22}{\revtim\yr2019\mo8\dy17\hr10\min22}{\version2}{\edmins0}{\nofpages1}{\nofwords8}{\nofchars49}{\nofcharsws56}{\vern111}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.co
|
||||
m/office/word/2003/wordml}}\paperw11906\paperh16838\margl2253\margr2253\margt1440\margb1440\gutter0\ltrsect
|
||||
\'b4\'bf\'ce\'c4\'b1\'be \'d7\'d6\'b7\'fb;}{\*\cs17 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf19 \sbasedon10 \sunhideused \styrsid9533173 Hyperlink;}{\*\cs18 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \cf20\chshdng0\chcfpat0\chcbpat21
|
||||
\sbasedon10 \ssemihidden \sunhideused \styrsid9533173 Unresolved Mention;}{\*\cs19 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf22 \sbasedon10 \ssemihidden \sunhideused \styrsid9533173 FollowedHyperlink;}}{\*\pgptbl {\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}}
|
||||
{\*\rsidtbl \rsid927107\rsid1398824\rsid2109456\rsid3950508\rsid4133944\rsid4355753\rsid9533173\rsid10447395\rsid11081282\rsid12910709\rsid13643782\rsid14384001\rsid15226681}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0
|
||||
\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author lysyw}{\operator lysyw}{\creatim\yr2019\mo8\dy17\hr10\min22}{\revtim\yr2020\mo4\dy28\hr13\min46}{\version8}{\edmins3}{\nofpages1}{\nofwords135}{\nofchars772}{\nofcharsws906}{\vern1}}
|
||||
{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw11906\paperh16838\margl2253\margr2253\margt1440\margb1440\gutter0\ltrsect
|
||||
\deftab420\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\formshade\horzdoc\dgmargin\dghspace180\dgvspace156
|
||||
\dghorigin2253\dgvorigin1440\dghshow0\dgvshow2\jcompress\lnongrid
|
||||
\viewkind1\viewscale100\splytwnine\ftnlytwnine\htmautsp\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct\asianbrkrule\rsidroot3950508\newtblstyruls
|
||||
\viewkind1\viewscale120\splytwnine\ftnlytwnine\htmautsp\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct\asianbrkrule\rsidroot3950508\newtblstyruls
|
||||
\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat {\upr{\*\fchars
|
||||
!%),.:\'3b>?]\'7d\'a1\'e9\'a1\'a7\'a1\'e3\'a1\'a4\'a1\'a6\'a1\'a5\'a8\'44\'a1\'ac\'a1\'af\'a1\'b1\'a1\'ad\'a1\'eb\'a1\'e4\'a1\'e5?\'a1\'e6\'a1\'c3\'a1\'a2\'a1\'a3\'a1\'a8\'a1\'b5\'a1\'b7\'a1\'b9\'a1\'bb\'a1\'bf\'a1\'b3\'a1\'bd\'a8\'95\'a6\'e1\'a6\'e3\'a6\'e7\'a6\'e5\'a6\'eb\'a9\'77\'a9\'79\'a9\'7b\'a3\'a1\'a3\'a2\'a3\'a5\'a3\'a7\'a3\'a9\'a3\'ac\'a3\'ae\'a3\'ba\'a3\'bb\'a3\'bf\'a3\'dd\'a3\'e0\'a3\'fc\'a3\'fd\'a1\'ab\'a1\'e9
|
||||
}{\*\ud\uc0{\*\fchars
|
||||
@@ -49,18 +53,67 @@ $([\'7b{\uc2\u163 \'a1\'ea\u165 \'a3\'a4\'a1\'a4\'a1\'ae\'a1\'b0\'a1\'b4\'a1\'b6
|
||||
\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\headery851\footery992\colsx425\endnhere\sectlinegrid312\sectspecifyl\sectrsid2109456\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang
|
||||
{\pntxta \dbch .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta \dbch )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl6
|
||||
\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl9
|
||||
\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}\pard\plain \ltrpar\s15\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid12910709 \rtlch\fcs1 \af2\afs22\alang1025 \ltrch\fcs0
|
||||
\fs21\lang1033\langfe2052\kerning2\loch\af31505\hich\af2\dbch\af31505\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'b3\'cc\'d0\'f2
|
||||
\'bd\'f6\'d3\'c3\'d3\'da\'d1\'a7\'cf\'b0\'bd\'bb\'c1\'f7\'ca\'b9\'d3\'c3\'a3\'a1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'c7\'eb\'ce\'f0\'d3\'c3\'d3\'da\'c9\'cc\'d2\'b5\'d3\'c3\'cd\'be\'a3\'a1\'a3\'a1}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'d4\'ec\'b3\'c9\'b5\'c4\'d2\'bb\'c7\'d0\'ba\'f3\'b9\'fb\'d3\'c9\'ca\'b9\'d3\'c3\'d5\'df
|
||||
\'b3\'d0\'b5\'a3\'a3\'a1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
\par
|
||||
\par \hich\af13\dbch\af13\loch\f13 By: }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'c2\'e4\'d1\'a9\'ce\'de\'ba\'db}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
\par
|
||||
\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}\pard\plain \ltrpar\s15\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid1398824 \rtlch\fcs1 \af2\afs22\alang1025 \ltrch\fcs0
|
||||
\fs21\lang1033\langfe2052\kerning2\loch\af31505\hich\af2\dbch\af31505\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'a3\'a8
|
||||
\'c8\'ed\'bc\'fe\'a3\'a9\'bb\'f9\'d3\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid4133944 \hich\af13\dbch\af13\loch\f13 Apache License 2.0}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'d0\'ed\'bf\'c9\'d6\'a4\'b7\'a2
|
||||
\'d0\'d0\'a3\'ac\'d4\'da\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'c7\'b0\'a3\'ac\'c4\'e3\'a3\'a8\'ca\'b9\'d3\'c3\'d5\'df\'a3\'a9\'d0\'e8\'c7\'a9\'ca\'f0\'b1\'be\'d0\'ad\'d2\'e9\'b2\'c5\'bf\'c9\'bc\'cc\'d0\'f8\'ca\'b9\'d3\'c3\'a3\'ac\'d2\'d4\'cf\'c2
|
||||
\'d0\'ad\'d2\'e9\'ca\'c7\'b6\'d4\'d3\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 Apache Li\hich\af13\dbch\af13\loch\f13 cense 2.0 }{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'b5\'c4\'b2\'b9\'b3\'e4\'a3\'ac\'c8\'e7\'d3\'d0\'b3\'e5\'cd\'bb\'a3\'ac\'d2\'d4\'d2\'d4\'cf\'c2\'d0\'ad\'d2\'e9\'ce\'aa\'d7\'bc\'a1\'a3}{\rtlch\fcs1 \af13
|
||||
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15226681
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid10447395\charrsid1398824
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'b4\'ca\'d3\'ef\'d4\'bc\'b6\'a8\'a3\'ba\'b1\'be\'d0\'ad\'d2\'e9\'d6\'d0\'b5\'c4\'a1\'b0\'b1\'be\'c8\'ed\'bc\'fe\'a1\'b1\'d6\'b8
|
||||
\'c2\'e5\'d1\'a9\'d2\'f4\'c0\'d6\'d7\'c0\'c3\'e6\'b0\'e6\'cf\'ee\'c4\'bf\'a3\'bb\'a1\'b0\'ca\'b9\'d3\'c3\'d5\'df\'a1\'b1\'d6\'b8\'c7\'a9\'ca\'f0\'b1\'be\'d0\'ad\'d2\'e9\'b5\'c4\'ca\'b9\'d3\'c3\'d5\'df\'a3\'bb\'a1\'b0\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6
|
||||
\'c6\'bd\'cc\'a8\'a1\'b1\'d6\'b8\'b6\'d4\'b1\'be\'c8\'ed\'bc\'fe\'c4\'da\'d6\'c3\'b5\'c4\'b0\'fc\'c0\'a8\'bf\'e1\'ce\'d2\'a1\'a2\'bf\'e1\'b9\'b7\'a1\'a2\'df\'e4\'b9\'be\'b5\'c8\'d2\'f4\'c0\'d6\'d4\'b4\'b5\'c4\'b9\'d9\'b7\'bd\'c6\'bd\'cc\'a8\'cd\'b3
|
||||
\'b3\'c6\'a3\'bb\'a1\'b0\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a1\'b1\'d6\'b8\'b0\'fc\'c0\'a8\'b5\'ab\'b2\'bb\'cf\'de\'d3\'da\'cd\'bc\'cf\'f1\'a1\'a2\'d2\'f4\'c6\'b5\'a1\'a2\'c3\'fb\'d7\'d6\'b5\'c8\'d4\'da\'c4\'da\'b5\'c4\'cb\'fb\'c8\'cb\'d3\'b5\'d3\'d0
|
||||
\'cb\'f9\'ca\'f4\'b0\'e6\'c8\'a8\'b5\'c4\'ca\'fd\'be\'dd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par
|
||||
\par \hich\af13\dbch\af13\loch\f13 1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'b1\'be\'c8\'ed\'bc\'fe\'b5\'c4\'ca\'fd\'be\'dd\'c0\'b4\'d4\'b4\'d4\'ad\'c0\'ed\'ca\'c7
|
||||
\'b4\'d3\'b8\'f7\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b5\'c4\'b9\'ab\'bf\'aa\'b7\'fe\'ce\'f1\'c6\'f7\'d6\'d0\'c0\'ad\'c8\'a1\'ca\'fd\'be\'dd\'a3\'ac\'be\'ad\'b9\'fd\'b6\'d4\'ca\'fd\'be\'dd\'bc\'f2\'b5\'a5\'b5\'d8\'c9\'b8\'d1\'a1\'d3\'eb
|
||||
\'ba\'cf\'b2\'a2\'ba\'f3\'bd\'f8\'d0\'d0\'d5\'b9\'ca\'be\'a3\'ac\'d2\'f2\'b4\'cb\'b1\'be\'c8\'ed\'bc\'fe\'b2\'bb\'b6\'d4\'ca\'fd\'be\'dd\'b5\'c4\'d7\'bc\'c8\'b7\'d0\'d4\'b8\'ba\'d4\'f0\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par \hich\af13\dbch\af13\loch\f13 2}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'b5\'c4\'b9\'fd\'b3\'cc\'d6\'d0\'bf\'c9\'c4\'dc
|
||||
\'bb\'e1\'b2\'fa\'c9\'fa\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a3\'ac\'b6\'d4\'d3\'da\'d5\'e2\'d0\'a9\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a3\'ac\'b1\'be\'c8\'ed\'bc\'fe\'b2\'bb\'d3\'b5\'d3\'d0\'cb\'fc\loch\af13\hich\af13\dbch\f13 \'c3\'c7\'b5\'c4\'cb\'f9\'d3\'d0
|
||||
\'c8\'a8\'a3\'ac\'ce\'aa\'c1\'cb\'b1\'dc\'c3\'e2\'d4\'ec\'b3\'c9\'c7\'d6\'c8\'a8\'a3\'ac\'ca\'b9\'d3\'c3\'d5\'df\'ce\'f1\'b1\'d8\'d4\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\hich\af13\dbch\af13\loch\f13 24}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'d0\'a1\'ca\'b1\'c4\'da\'c7\'e5\'b3\'fd\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'b5\'c4\'b9\'fd
|
||||
\'b3\'cc\'d6\'d0\'cb\'f9\'b2\'fa\'c9\'fa\'b5\'c4\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par \hich\af13\dbch\af13\loch\f13 3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'b1\'be\'c8\'ed\'bc\'fe\'c4\'da\'b5\'c4\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8
|
||||
\'b1\'f0\'c3\'fb\'ce\'aa\'b1\'be\'c8\'ed\'bc\'fe\'c4\'da\'b6\'d4\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b5\'c4\'d2\'bb\'b8\'f6\'b3\'c6\'ba\'f4\'a3\'ac\'b2\'bb\'b0\'fc\'ba\'ac\'b6\'f1\'d2\'e2\'a3\'ac\'c8\'e7\'b9\'fb\'b9\'d9\'b7\'bd\'d2\'f4
|
||||
\'c0\'d6\'c6\'bd\'cc\'a8\'be\'f5\'b5\'c3\'b2\'bb\'cd\'d7\'a3\'ac\'bf\'c9\'c1\'aa\'cf\'b5\'b1\'be\'c8\'ed\'bc\'fe\'b8\'fc\'b8\'c4\'bb\'f2\'d2\'c6\'b3\'fd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
|
||||
\par \hich\af13\dbch\af13\loch\f13 4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'b1\'be\'c8\'ed\'bc\'fe\'c4\'da\'ca\'b9\'d3\'c3\'b5\'c4\'b2\'bf\'b7\'d6\'b0\'fc\'c0\'a8
|
||||
\'b5\'ab\'b2\'bb\'cf\'de\'d3\'da\'d7\'d6\'cc\'e5\'a1\'a2\'cd\'bc\'c6\'ac\'b5\'c8\'d7\'ca\'d4\'b4\'c0\'b4\'d4\'b4\'d3\'da\'bb\'a5\'c1\'aa\'cd\'f8\'a3\'ac\'c8\'e7\'b9\'fb\'b3\'f6\'cf\'d6\'c7\'d6\'c8\'a8\'bf\'c9\'c1\'aa\'cf\'b5\'b1\'be\'c8\'ed\'bc\'fe
|
||||
\'d2\'c6\'b3\'fd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par \hich\af13\dbch\af13\loch\f13 5}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'d3\'c9\'d3\'da\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'b2\'fa\'c9\'fa\'b5\'c4\'b0\'fc
|
||||
\'c0\'a8\'d3\'c9\'d3\'da\'b1\'be\'d0\'ad\'d2\'e9\'bb\'f2\'d3\'c9\'d3\'da\'ca\'b9\'d3\'c3\'bb\'f2\'ce\'de\'b7\'a8\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'b6\'f8\'d2\'fd\'c6\'f0\'b5\'c4\'c8\'ce\'ba\'ce\'d0\'d4\'d6\'ca\'b5\'c4\'c8\'ce\'ba\'ce\'d6\'b1
|
||||
\'bd\'d3\'a1\'a2\'bc\'e4\'bd\'d3\'a1\'a2\'cc\'d8\'ca\'e2\'a1\'a2\'c5\'bc\'c8\'bb\'bb\'f2\'bd\'e1\'b9\'fb\'d0\'d4\'cb\'f0\'ba\'a6\'a3\'a8\'b0\'fc\'c0\'a8\'b5\'ab\'b2\'bb\'cf\'de\'d3\'da\'d2\'f2\'c9\'cc\'d3\'fe\'cb\'f0\'ca\'a7\'a1\'a2\'cd\'a3\'b9\'a4
|
||||
\'a1\'a2\'bc\'c6\'cb\'e3\'bb\'fa\'b9\'ca\'d5\'cf\'bb\'f2\'b9\'ca\'d5\'cf\'d2\'fd\'c6\'f0\'b5\'c4\'cb\'f0\'ba\'a6\'c5\'e2\'b3\'a5\'a3\'ac\'bb\'f2\'c8\'ce\'ba\'ce\'bc\'b0\loch\af13\hich\af13\dbch\f13 \'cb\'f9\'d3\'d0\'c6\'e4\'cb\'fb\'c9\'cc\'d2\'b5\'cb\'f0
|
||||
\'ba\'a6\'bb\'f2\'cb\'f0\'ca\'a7\'a3\'a9\'d3\'c9\'ca\'b9\'d3\'c3\'d5\'df\'b8\'ba\'d4\'f0\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par \hich\af13\dbch\af13\loch\f13 6}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'b1\'be\'cf\'ee\'c4\'bf\'cd\'ea\'c8\'ab\'c3\'e2\'b7\'d1\'a3\'ac\'c7\'d2\'bf\'aa\'d4\'b4
|
||||
\'b7\'a2\'b2\'bc\'d3\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 GitHub }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\loch\af13\hich\af13\dbch\f13 \'c3\'e6\'cf\'f2\'c8\'ab\'ca\'c0\'bd\'e7\'c8\'cb\'d3\'c3\'d7\'f7\'b6\'d4\'bc\'bc\'ca\'f5\'b5\'c4\'d1\'a7\'cf\'b0\'bd\'bb\'c1\'f7\'a3\'ac\'b1\'be\'c8\'ed\'bc\'fe\'b2\'bb\'b6\'d4\'cf\'ee\'c4\'bf\'c4\'da\'b5\'c4\'bc\'bc\'ca\'f5
|
||||
\'bf\'c9\'c4\'dc\'b4\'e6\'d4\'da\'ce\'a5\'b7\'b4\'b5\'b1\'b5\'d8\'b7\'a8\'c2\'c9\'b7\'a8\'b9\'e6\'b5\'c4\'d0\'d0\'ce\'aa\'d7\'f7\'b1\'a3\'d6\'a4\'a3\'ac\'bd\'fb\'d6\'b9\'d4\'da\'ce\'a5\'b7\'b4\'b5\'b1\'b5\'d8\'b7\'a8\'c2\'c9\'b7\'a8\'b9\'e6\'b5\'c4
|
||||
\'c7\'e9\'bf\'f6\'cf\'c2\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'a3\'ac\'b6\'d4\'d3\'da\'ca\'b9\'d3\'c3\'d5\'df\'d4\'da\'c3\'f7\'d6\'aa\'bb\'f2\'b2\'bb\'d6\'aa\'b5\'b1\'b5\'d8\'b7\'a8\'c2\'c9\'b7\'a8\'b9\'e6\'b2\'bb\'d4\'ca\'d0\'ed\'b5\'c4\'c7\'e9
|
||||
\'bf\'f6\'cf\'c2\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'cb\'f9\'d4\'ec\'b3\'c9\'b5\'c4\'c8\'ce\'ba\'ce\'ce\'a5\'b7\'a8\'ce\'a5\'b9\'e6\'d0\'d0\'ce\'aa\'d3\'c9\'ca\'b9\'d3\'c3\'d5\'df\'b3\'d0\'b5\'a3\'a3\'ac\'b1\'be\'c8\'ed\'bc\'fe\'b2\'bb\'b3\'d0
|
||||
\'b5\'a3\'d3\'c9\'b4\'cb\'d4\'ec\'b3\'c9\'b5\'c4\'c8\'ce\'ba\'ce\'d6\'b1\'bd\'d3\'a1\'a2\'bc\'e4\'bd\'d3\'a1\'a2\'cc\'d8\'ca\'e2\'a1\'a2\'c5\'bc\'c8\'bb\'bb\'f2\'bd\'e1\'b9\'fb\'d0\'d4\'d4\'f0\'c8\'ce\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15226681
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid10447395\charrsid1398824
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 * }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13
|
||||
\'c8\'f4\'d0\'ad\'d2\'e9\'b8\'fc\'d0\'c2\'a3\'ac\'cb\'a1\'b2\'bb\'c1\'ed\'d0\'d0\'cd\'a8\'d6\'aa\'a3\'ac\'bf\'c9\'b5\'bd\'bf\'aa\'d4\'b4\'b5\'d8\'d6\'b7\'b2\'e9\'bf\'b4\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid15226681
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 * }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13
|
||||
\'b1\'be\'c8\'ed\'bc\'fe\'b5\'c4\'b3\'f5\'d6\'d4\'ca\'c7\'b0\'ef\'d6\'fa\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'bc\'f2\'bb\'af\'ca\'fd\'be\'dd\'ba\'f3\'b4\'fa\'ce\'aa\'d5\'b9\'ca\'be\'a3\'ac\'b0\'ef\'d6\'fa\'ca\'b9\'d3\'c3\'d5\'df\'b8\'f9
|
||||
\'be\'dd\'b8\'e8\'c7\'fa\loch\af13\hich\af13\dbch\f13 \'c3\'fb\'a1\'a2\'d2\'d5\'ca\'f5\'bc\'d2\'b5\'c8\'b9\'d8\'bc\'fc\'d7\'d6\'bf\'ec\'cb\'d9\'b5\'d8\'b6\'a8\'ce\'bb\'cb\'f9\'d0\'e8\'c4\'da\'c8\'dd\'cb\'f9\'d4\'da\'b5\'c4\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8
|
||||
\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid15226681
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 * }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13
|
||||
\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b2\'bb\'d2\'d7\'a3\'ac\'bd\'a8\'d2\'e9\'b5\'bd\'b6\'d4\'d3\'a6\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'d6\'a7\'b3\'d6\'d5\'fd\'b0\'e6\'d7\'ca\'d4\'b4\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid12910709
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid9533173\charrsid15226681
|
||||
\par }\pard \ltrpar\s15\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid12910709 {\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \hich\af13\dbch\af13\loch\f13 By: }{
|
||||
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'c2\'e4\'d1\'a9\'ce\'de\'ba\'db}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
|
||||
\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a
|
||||
9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad
|
||||
5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6
|
||||
@@ -114,7 +167,7 @@ e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8
|
||||
617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
|
||||
6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
|
||||
656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
|
||||
{\*\latentstyles\lsdstimax377\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;
|
||||
{\*\latentstyles\lsdstimax376\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1;
|
||||
@@ -143,18 +196,8 @@ e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 2;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 4;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 7;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 7;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Contemporary;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Elegant;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Professional;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;
|
||||
\lsdpriority39 \lsdlocked0 Table Grid;\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;
|
||||
\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;
|
||||
\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;
|
||||
\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List;\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;
|
||||
\lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;
|
||||
@@ -202,8 +245,8 @@ e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8
|
||||
\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5;
|
||||
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6;
|
||||
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link Error;}}{\*\datastore 0105000002000000180000004d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link;}}{\*\datastore 01050000
|
||||
02000000180000004d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000
|
||||
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
@@ -212,8 +255,8 @@ fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000908a
|
||||
0599a254d501feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
|
||||
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000b026
|
||||
8d59201dd601feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000105000000000000}}
|
||||
@@ -1,5 +1,18 @@
|
||||
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!
|
||||
This project (software) is issued based on the Apache License 2.0 license. Before using this software, you (users) need to sign this agreement before you can continue to use it. The following agreement is a supplement to the Apache License 2.0. In case of conflict, use the following agreement Shall prevail.
|
||||
|
||||
|
||||
Terms agreed: "this software" in this agreement refers to the Luo Xue Music desktop version of the project; "user" refers to the user who signed this agreement; "official music platform" refers to the built-in software including Kuwo, Kugou, Migu The official platforms of music sources, etc. are collectively referred to; "copyright data" refers to data including but not limited to images, audio, names, etc. that others own the copyright.
|
||||
|
||||
1. The principle of the data source of this software is to pull data from the public servers of each official music platform. After simply filtering and merging the data for display, this software is not responsible for the accuracy of the data.
|
||||
2. Copyright data may be generated during the use of this software. For this copyright data, the software does not own their ownership. In order to avoid infringement, users must clear the copyright generated during the use of this software within 24 hours data.
|
||||
3. The alias of the official music platform in this software is a name for the official music platform in the software. It does not contain maliciousness. If the official music platform feels inappropriate, you can contact the software to change or remove it.
|
||||
4. The parts used in this software include but are not limited to fonts, pictures and other resources from the Internet. If there is infringement, you can contact this software to remove it.
|
||||
5. Any direct, indirect, special, accidental or consequential damage of any nature arising from the use of this software, including this agreement or the use or inability to use this software (including but not limited to due to loss of goodwill, work stoppage, Compensation for computer failure or damage caused by the failure, or any and all other commercial damage or loss) is the responsibility of the user.
|
||||
6. This project is completely free, and the open source is published on GitHub. It is used by people all over the world to learn and exchange technology. This software does not guarantee that the technology in the project may violate local laws and regulations. It is prohibited to violate local laws and regulations. Using this software, the user shall be responsible for any violations caused by the user's use of the software without knowing or not permitted by local laws and regulations. The software shall not be responsible for any direct, indirect, special, accidental Or consequential responsibility.
|
||||
|
||||
|
||||
* If the agreement is updated without prior notice, you can check it at the open source address.
|
||||
* The original intention of this software is to help the official music platform to simplify the data generation for display, and to help users quickly locate the music platform where the desired content is based on the song title, artist and other keywords.
|
||||
* Music platform is not easy, it is recommended to support genuine resources to the corresponding music platform.
|
||||
|
||||
By: lyswhut
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
本程序仅用于学习交流使用!
|
||||
请勿用于商业用途!!
|
||||
使用本软件造成的一切后果由使用者承担!
|
||||
本项目(软件)基于Apache License 2.0 许可证发行,在使用本软件前,你(使用者)需签署本协议才可继续使用,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。
|
||||
|
||||
|
||||
词语约定:本协议中的“本软件”指洛雪音乐桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本软件内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。
|
||||
|
||||
1、本软件的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本软件不对数据的准确性负责。
|
||||
2、使用本软件的过程中可能会产生版权数据,对于这些版权数据,本软件不拥有它们的所有权,为了避免造成侵权,使用者务必在24小时内清除使用本软件的过程中所产生的版权数据。
|
||||
3、本软件内的官方音乐平台别名为本软件内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本软件更改或移除。
|
||||
4、本软件内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本软件移除。
|
||||
5、由于使用本软件产生的包括由于本协议或由于使用或无法使用本软件而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。
|
||||
6、本项目完全免费,且开源发布于 GitHub 面向全世界人用作对技术的学习交流,本软件不对项目内的技术可能存在违反当地法律法规的行为作保证,禁止在违反当地法律法规的情况下使用本软件,对于使用者在明知或不知当地法律法规不允许的情况下使用本软件所造成的任何违法违规行为由使用者承担,本软件不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。
|
||||
|
||||
|
||||
* 若协议更新,恕不另行通知,可到开源地址查看。
|
||||
* 本软件的初衷是帮助官方音乐平台简化数据后代为展示,帮助使用者根据歌曲名、艺术家等关键字快速地定位所需内容所在的音乐平台。
|
||||
* 音乐平台不易,建议到对应音乐平台支持正版资源。
|
||||
|
||||
By: 落雪无痕
|
||||
|
||||
13311
package-lock.json
generated
13311
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
164
package.json
164
package.json
@@ -1,15 +1,17 @@
|
||||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "0.8.1",
|
||||
"version": "0.18.2",
|
||||
"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=win_安装版 ARCH=x64_x86 electron-builder -w=nsis --x64 --ia32",
|
||||
"pack:win:portable": "npm run pack:win:portable:x64_x86 && npm run pack:win:portable:x64 && npm run pack:win:portable:x86",
|
||||
"pack:win:portable:x64_x86": "cross-env TARGET=便携版 ARCH=x64_x86 electron-builder -w=portable --x64 --ia32",
|
||||
"pack:win": "npm run pack:win:setup:x86_64 && npm run pack:win:7z",
|
||||
"pack:win:setup:x86_64": "cross-env TARGET=win_安装版 ARCH=x86_64 electron-builder -w=nsis --x64 --ia32",
|
||||
"pack:win:setup:x64": "cross-env TARGET=win_安装版 ARCH=x64 electron-builder -w=nsis --x64",
|
||||
"pack:win:setup:x86": "cross-env TARGET=win_安装版 ARCH=x86 electron-builder -w=nsis --ia32",
|
||||
"pack:win:portable": "npm run pack:win:portable:x86_64 && npm run pack:win:portable:x64 && npm run pack:win:portable:x86",
|
||||
"pack:win:portable:x86_64": "cross-env TARGET=便携版 ARCH=x86_64 electron-builder -w=portable --x64 --ia32",
|
||||
"pack:win:portable:x64": "cross-env TARGET=便携版 ARCH=x64 electron-builder -w=portable --x64",
|
||||
"pack:win:portable:x86": "cross-env TARGET=便携版 ARCH=x86 electron-builder -w=portable --ia32",
|
||||
"pack:win:7z": "npm run pack:win:7z:x64 && npm run pack:win:7z:x86",
|
||||
@@ -18,9 +20,9 @@
|
||||
"publish": "node publish",
|
||||
"publish:gh": "node build-config/pack.js && npm run publish:win",
|
||||
"publish:win": "npm run publish:win:7z && npm run publish:win:setup",
|
||||
"publish:win:setup": "cross-env TARGET=Setup ARCH=x64_x86 electron-builder -w=nsis --x64 --ia32 -p onTagOrDraft",
|
||||
"publish:win:portable": "npm run publish:win:portable:x64_x86 && npm run publish:win:portable:x64 && npm run publish:win:portable:x86",
|
||||
"publish:win:portable:x64_x86": "cross-env TARGET=portable ARCH=x64_x86 electron-builder -w=portable --x64 --ia32 -p onTagOrDraft",
|
||||
"publish:win:setup": "cross-env TARGET=Setup ARCH=x86_64 electron-builder -w=nsis --x64 --ia32 -p onTagOrDraft",
|
||||
"publish:win:portable": "npm run publish:win:portable:x86_64 && npm run publish:win:portable:x64 && npm run publish:win:portable:x86",
|
||||
"publish:win:portable:x86_64": "cross-env TARGET=portable ARCH=x86_64 electron-builder -w=portable --x64 --ia32 -p onTagOrDraft",
|
||||
"publish:win:portable:x64": "cross-env TARGET=portable ARCH=x64 electron-builder -w=portable --x64 -p onTagOrDraft",
|
||||
"publish:win:portable:x86": "cross-env TARGET=portable ARCH=x86 electron-builder -w=portable --ia32 -p onTagOrDraft",
|
||||
"publish:win:7z": "npm run publish:win:7z:x64 && npm run publish:win:7z:x86",
|
||||
@@ -36,6 +38,7 @@
|
||||
"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:mac": "node build-config/pack.js && electron-builder -m=dmg",
|
||||
"pack:dir": "node build-config/pack.js && electron-builder --dir",
|
||||
"dev": "node build-config/runner-dev.js",
|
||||
"clean:electron": "rimraf dist/electron",
|
||||
@@ -49,7 +52,7 @@
|
||||
"lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-formatter-friendly --fix src"
|
||||
},
|
||||
"browserslist": [
|
||||
"Chrome >= 76"
|
||||
"Electron 8.2.5"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
@@ -71,12 +74,17 @@
|
||||
"artifactName": "${productName} v${version} ${env.ARCH} ${env.TARGET}.${ext}"
|
||||
},
|
||||
"mac": {
|
||||
"icon": "./resources/icons/512x512.png",
|
||||
"icon": "./resources/icons/512x512.icns",
|
||||
"category": "public.app-category.music"
|
||||
},
|
||||
"linux": {
|
||||
"maintainer": "lyswhut <lyswuhut@qq.com>",
|
||||
"artifactName": "${productName} v${version} ${env.ARCH}.${ext}"
|
||||
"maintainer": "lyswhut <lyswhut@qq.com>",
|
||||
"artifactName": "${productName} v${version} ${env.ARCH}.${ext}",
|
||||
"icon": "./resources/icons",
|
||||
"category": "Utility;AudioVideo;Audio;Player;Music;",
|
||||
"desktop": {
|
||||
"Name[zh_CN]": "洛雪音乐助手"
|
||||
}
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
@@ -87,31 +95,40 @@
|
||||
"shortcutName": "lx-music"
|
||||
},
|
||||
"dmg": {
|
||||
"window": {
|
||||
"width": 600,
|
||||
"height": 400
|
||||
},
|
||||
"contents": [
|
||||
{
|
||||
"x": 110,
|
||||
"y": 150,
|
||||
"x": 106,
|
||||
"y": 252,
|
||||
"name": "lx-music"
|
||||
},
|
||||
{
|
||||
"x": 240,
|
||||
"y": 150,
|
||||
"x": 490,
|
||||
"y": 252,
|
||||
"type": "link",
|
||||
"path": "/Applications",
|
||||
"name": "lx-music"
|
||||
"path": "/Applications"
|
||||
}
|
||||
],
|
||||
"title": "洛雪音乐助手 v${version}"
|
||||
},
|
||||
"appImage": {
|
||||
"license": "./licenses/license_zh.txt",
|
||||
"category": "Audio"
|
||||
"category": "Utility;AudioVideo;Audio;Player;Music;"
|
||||
},
|
||||
"publish": [
|
||||
{
|
||||
"provider": "github",
|
||||
"owner": "lyswhut",
|
||||
"repo": "lx-music-desktop"
|
||||
},
|
||||
{
|
||||
"package": "lx-music-desktop",
|
||||
"repo": "lx-music-desktop",
|
||||
"user": "lyswhut",
|
||||
"provider": "bintray"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -126,7 +143,7 @@
|
||||
],
|
||||
"author": {
|
||||
"name": "lyswhut",
|
||||
"email": "lyswuhut@qq.com"
|
||||
"email": "lyswhut@qq.com"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
@@ -134,83 +151,84 @@
|
||||
},
|
||||
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"@babel/polyfill": "^7.6.0",
|
||||
"@babel/preset-env": "^7.6.3",
|
||||
"autoprefixer": "^9.6.5",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-loader": "^8.0.6",
|
||||
"@babel/core": "^7.9.6",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/polyfill": "^7.8.7",
|
||||
"@babel/preset-env": "^7.9.6",
|
||||
"autoprefixer": "^9.7.6",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-minify-webpack-plugin": "^0.3.1",
|
||||
"babel-preset-minify": "^0.5.1",
|
||||
"cfonts": "^2.4.5",
|
||||
"chalk": "^2.4.2",
|
||||
"browserslist": "^4.12.0",
|
||||
"cfonts": "^2.8.1",
|
||||
"chalk": "^4.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",
|
||||
"cross-env": "^6.0.3",
|
||||
"css-loader": "^3.2.0",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"core-js": "^3.6.5",
|
||||
"cos-nodejs-sdk-v5": "^2.5.20",
|
||||
"cross-env": "^7.0.2",
|
||||
"css-loader": "^3.5.3",
|
||||
"del": "^5.1.0",
|
||||
"electron": "^6.0.12",
|
||||
"electron-builder": "^21.2.0",
|
||||
"electron": "^8.2.5",
|
||||
"electron-builder": "^22.6.0",
|
||||
"electron-debug": "^3.0.1",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"electron-devtools-installer": "^3.0.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
"eslint-formatter-friendly": "^7.0.0",
|
||||
"eslint-loader": "^3.0.2",
|
||||
"eslint-plugin-html": "^6.0.0",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-node": "^10.0.0",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-html": "^6.0.2",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"file-loader": "^4.2.0",
|
||||
"file-loader": "^6.0.0",
|
||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"less": "^3.10.3",
|
||||
"less-loader": "^5.0.0",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"less": "^3.11.1",
|
||||
"less-loader": "^6.0.0",
|
||||
"markdown-it": "^10.0.0",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"multispinner": "^0.2.1",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-pxtorem": "^5.1.1",
|
||||
"pug": "^2.0.4",
|
||||
"pug-loader": "^2.4.0",
|
||||
"pug-plain-loader": "^1.0.0",
|
||||
"raw-loader": "^3.1.0",
|
||||
"rimraf": "^3.0.0",
|
||||
"raw-loader": "^4.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"spinnies": "^0.5.1",
|
||||
"stylus": "^0.54.7",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"terser-webpack-plugin": "^2.1.3",
|
||||
"url-loader": "^2.2.0",
|
||||
"vue-loader": "^15.7.1",
|
||||
"terser-webpack-plugin": "^2.3.6",
|
||||
"url-loader": "^4.1.0",
|
||||
"vue-loader": "^15.9.1",
|
||||
"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",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.3",
|
||||
"webpack-hot-middleware": "^2.25.0",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"crypto-js": "^4.0.0",
|
||||
"dnscache": "^1.0.2",
|
||||
"electron-log": "^3.0.8",
|
||||
"electron-store": "^5.0.0",
|
||||
"electron-updater": "^4.1.2",
|
||||
"flac-metadata": "^0.1.1",
|
||||
"electron-log": "^4.1.1",
|
||||
"electron-store": "^5.1.1",
|
||||
"electron-updater": "^4.3.1",
|
||||
"image-size": "^0.8.3",
|
||||
"js-htmlencode": "^0.3.0",
|
||||
"lrc-file-parser": "^0.1.14",
|
||||
"node-downloader-helper": "^1.0.10",
|
||||
"node-id3": "^0.1.11",
|
||||
"request": "^2.88.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-electron": "^1.0.6",
|
||||
"vue-router": "^3.1.3",
|
||||
"vuex": "^3.1.1",
|
||||
"vuex-electron": "^1.0.3",
|
||||
"lrc-file-parser": "^1.0.3",
|
||||
"mousetrap": "^1.6.5",
|
||||
"needle": "^2.4.1",
|
||||
"node-id3": "^0.1.16",
|
||||
"request": "^2.88.2",
|
||||
"vue": "^2.6.11",
|
||||
"vue-i18n": "^8.17.4",
|
||||
"vue-router": "^3.1.6",
|
||||
"vuex": "^3.3.0",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,33 @@
|
||||
const autoprefixer = require('autoprefixer')
|
||||
const pxtorem = require('postcss-pxtorem')
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
pxtorem({
|
||||
rootValue: 16,
|
||||
unitPrecision: 5,
|
||||
propList: [
|
||||
'font', 'font-size',
|
||||
'line-height',
|
||||
'letter-spacing',
|
||||
'padding', 'margin',
|
||||
'padding-left', 'padding-right',
|
||||
'padding-top', 'padding-bottom',
|
||||
'margin-left', 'margin-right',
|
||||
'margin-top', 'margin-bottom',
|
||||
'height', 'width',
|
||||
'max-width', 'max-height',
|
||||
'min-width', 'min-height',
|
||||
'flex', '::-webkit-scrollbar',
|
||||
'top', 'left', 'bottom', 'right',
|
||||
'border-radius',
|
||||
],
|
||||
selectorBlackList: ['html', 'ignore-to-rem'],
|
||||
replace: true,
|
||||
mediaQuery: false,
|
||||
minPixelValue: 0,
|
||||
exclude: [/node_modules/i],
|
||||
}),
|
||||
autoprefixer(),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#### 修复
|
||||
### 修复
|
||||
|
||||
- 修复酷我源搜索歌曲结果未添加128k音质导致播放128k音质时显示“该歌曲没有可播放的音频”的问题
|
||||
- 修复开启托盘时,可能导致无法自动更新的问题
|
||||
|
||||
@@ -1,7 +1,75 @@
|
||||
{
|
||||
"version": "0.8.1",
|
||||
"desc": "<h4>修复</h4>\n<ul>\n<li>修复酷我源搜索歌曲结果未添加128k音质导致播放128k音质时显示“该歌曲没有可播放的音频”的问题</li>\n</ul>\n",
|
||||
"version": "0.18.2",
|
||||
"desc": "<h3>修复</h3>\n<ul>\n<li>修复开启托盘时,可能导致无法自动更新的问题</li>\n</ul>\n",
|
||||
"history": [
|
||||
{
|
||||
"version": "0.18.1",
|
||||
"desc": "<h3>优化</h3>\n<ul>\n<li>win下的托盘图标使用更大的图片</li>\n<li>加长软件协议的强制停留时间</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复导入设置某些设置未立即生效的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.18.0",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增FLAC格式音乐标签信息写入与封面嵌入(因128k以外的音质已失效,目前该功能用不上了)</li>\n<li>添加软件启动时是否自动聚焦搜索框的设置</li>\n<li>新增托盘设置,默认关闭,可到设置开启,感谢 @LasyIsLazy 提交的PR</li>\n<li>新增打开酷狗源用户歌单</li>\n<li>新增使用协议</li>\n<li>新增虾米音源</li>\n<li>新增新皮肤“粉妆玉琢”、“青出于黑”,可去体验下~</li>\n<li>新增“超大”、“巨大”窗口尺寸</li>\n<li>新增播放详情页(退出详情页可点击右上角退出按钮或者在播放详情页任意地方<strong>鼠标快速右击两次</strong>)</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>略微加深音量条底色</li>\n<li>优化其他界面细节</li>\n<li>优化英语翻译,感谢 @CPCer</li>\n<li>优化程序的流畅度</li>\n</ul>\n<h3>更变</h3>\n<ul>\n<li>下载列表的歌曲下载、播放将随设置中的保存路径改变而改变,不再固定指向其初始位置</li>\n<li>移除列表多选框,现在多选需要键盘配合,想要多选前需按下<code>Shift</code>或<code>Ctrl</code>键然后再鼠标点击想要选中的内容即可触发多选机制,其中<code>Shift</code>键用于连续选择,<code>Ctrl</code>键用于不连续选择,<code>Ctrl+a</code>用于快速全选。例子一:想要选中1-5项,则先按下<code>Shift</code>键后,鼠标点击第一项,再点击第五项即可完成选择;例子二:想要选中1项与第3项,则先按下<code>Ctrl</code>键后,鼠标点击第一项,再点击第三项即可完成选择;例子三:想要选中当前列表的全部内容,键盘先按下<code>Ctrl</code>键不放,然后按<code>a</code>键,即可完成选择。用<code>Shift</code>或<code>Ctrl</code>选择时,鼠标点击未选中的内容会将其选中,点击已选择的内容会将其取消选择,若想全部取消选择,在不按<code>Shift</code>或<code>Alt</code>键的情况下,随意点击列表里的一项内容即可全部取消选择。(P.S:<code>Ctrl</code>键对应Mac OS上的<code>Command</code>键)</li>\n<li>现在进度条的封面图左击改为打开播放详情页,在列表定位歌曲改为右击</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复网易源某些歌曲提示没有可播放的音质的问题</li>\n<li>修复下载管理刷新URL失败时不标记任务下载失败的问题</li>\n<li>修复列表导出的文字描述,感谢 @CPCer</li>\n<li>修复歌曲切换方式无法取消勾选的问题</li>\n<li>修复打开歌单详情的情况下切到其他界面再切回来报错的问题</li>\n<li>修正播放列表浮动按钮错误的文字提示</li>\n</ul>\n<h3>移除</h3>\n<ul>\n<li>因128k以外的音质失效,So 禁止所有128k外的音质下载</li>\n</ul>\n<h3>其他</h3>\n<p>更新 Electron 到 8.2.5</p>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.17.0",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增多语言设置,目前软件内置了简体中文、繁体中文、英语三种语言,欢迎提交PR翻译更多语言!</li>\n<li>新增无法打开外部歌单FAQ</li>\n<li>新增启动参数<code>search</code>,使用例子:<code>.\\lx-music-desktop.exe -search="突然的自我 - 伍佰"</code></li>\n<li>新增音频输出设置</li>\n<li>新增软件内的包括字体在内的界面内容大小调整,现在当窗口大小切换到“较小/大/较大”时,软件内的元素将会适当减小或加大,窗口大小的“小”与“中”内的元素将保持之前的大小暂不做改变</li>\n<li>新增音源别名,默认将显示别名,想要显示回原名可到设置切换(免责声明:别名仅是本软件用于描述各音源的标签,其名字归版权方所有)</li>\n<li>新增发现新版本更新失败弹窗的忽略提醒按钮,忽略提醒后,以后同一个版本再失败时将不会弹窗提醒,但仍可到设置-版本更新手动点开更新弹窗查看或恢复提醒</li>\n<li>新增热搜词,默认关闭,可到设置开启</li>\n<li>新增历史搜索记录,默认关闭,可到设置开启(右击单个历史记录标签可移除所点击的记录)</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>优化月里嫦娥皮肤侧栏鼠标悬浮颜色</li>\n<li>优化播放进度条的动画效果</li>\n<li>现在添加下载任务时,后面添加的任务会在列表顶部插入</li>\n<li>优化歌单打开机制,现在歌单加载失败时会提示加载失败了,并且支持直接打开企鹅、酷我手机分享出来的歌单了</li>\n<li>优化右上角最小化/关闭按钮布局</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复歌单详情处于加载状态时无法返回的问题</li>\n<li>修复鼠标右击复制列表内容时会复制音质标签的问题</li>\n<li>修复<code>0.6.2</code>及以前的版本导出的“所有数据”内的歌曲列表无法导入的问题</li>\n<li>修复下载列表在某些情况下无法取消全选的问题</li>\n</ul>\n<h3>其他</h3>\n<ul>\n<li>更新Electron到 8.1.1</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.16.0",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>允许选中列表内歌曲名、歌手名、专辑名内的文字,选中后可使用键盘快捷键进行复制</li>\n<li>新增在列表可选内容区域<strong>鼠标右击</strong>时自动复制列表已选文字的功能</li>\n<li>新增在搜索框<strong>鼠标右击</strong>时自动粘贴剪贴板的文本到搜索框中</li>\n<li>任务下载失败时将显示搜索按钮,方便在其他源搜索该歌曲</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>优化木叶之村主题翻页器背景颜色</li>\n<li>优化各个主题音质标签颜色</li>\n<li>优化其他一些界面细节及用户交互效果</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复启用透明窗口鼠标不穿透的bug</li>\n<li>修复大窗口时设置的音乐来源选项不换行的问题</li>\n<li>修复某些情况下暂停任务会自动开始任务的问题</li>\n<li>修复移除暂停、错误的任务时不删除未下载完成的文件的问题</li>\n<li>修复酷狗源歌单热门标签歌单列表无法加载问题</li>\n<li>修复QQ源歌单热门标签歌单列表无法加载问题</li>\n</ul>\n<h3>其他</h3>\n<ul>\n<li>更新electron到 8.0.1</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.15.0",
|
||||
"desc": "<p>洛雪提前祝大家新年快乐、身体健康、阖家幸福!</p>\n<h3>修复</h3>\n<ul>\n<li>修复歌曲下载列表无法加载的问题</li>\n<li>修复歌曲下载任务数大于最大下载任务数的问题</li>\n<li>修复某些情况下歌曲下载错误的问题</li>\n<li>修复下载列表数据没有被迁移直接被丢弃的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.14.1",
|
||||
"desc": "<p>洛雪提前祝大家新年快乐、身体健康、阖家幸福!</p>\n<h3>修复</h3>\n<ul>\n<li>修复由于旧版配置文件迁移出错导致的软件界面无法显示的问题</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.14.0",
|
||||
"desc": "<p>洛雪提前祝大家新年快乐、身体健康、阖家幸福!</p>\n<h3>新增</h3>\n<ul>\n<li>新增各大平台歌单热门标签显示(显示在歌单界面的第一个下拉标签菜单中)</li>\n<li>恢复QQ音乐源128k音质试听</li>\n<li>新增不强制win7开启透明效果即可使用,但要配置运行参数<code>-nt</code>,例如:<code>.\\lx-music-desktop.exe -nt</code>,添加方法可自行百度“给快捷方式加参数”</li>\n<li>新增“新年快乐”主题,可自行切换体验</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>减淡各个主题的歌曲列表分隔线颜色</li>\n<li>在线音乐列表音质标签优化,当歌曲有无损音质时隐藏高品质标签</li>\n<li>更新改进的歌词播放插件,现在歌词的播放显示将更准确</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复咪咕源无法搜索的问题</li>\n<li>修复更新弹窗底部文字颜色没有适配当前主题颜色的问题</li>\n<li>修复导入设置窗口大小、代理设置不立即生效的问题</li>\n<li>修复在线音乐列表获取失败时无限循环请求的问题</li>\n</ul>\n<h3>其他</h3>\n<ul>\n<li>将软件设置与播放列表分离存储成两个文件</li>\n<li>更新 Electron 到 7.1.9</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.13.1",
|
||||
"desc": "<h3>修复</h3>\n<ul>\n<li>修复全局更新弹窗无法遮盖搜索框的问题</li>\n</ul>\n<h3>其他</h3>\n<ul>\n<li>由于electron 7.1.3 - 7.1.5 的自动更新功能存在Bug,现降级到7.1.2</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.13.0",
|
||||
"desc": "<h3>新增</h3>\n<ul>\n<li>新增搜索框搜索建议键盘上下方向键选择功能</li>\n<li>聚合搜索新增音源显示</li>\n<li>新增“离开搜索界面时清空搜索列表”设置选项,默认关闭,可到设置-强迫症设置开启</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>优化“信口雌黄”皮肤配色</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复存在弹出层时,搜索建议列表被弹出层覆盖的问题</li>\n<li>修复搜索、排行榜、歌单列表多选框从不定状态到选中的Bug</li>\n</ul>\n<h3>移除</h3>\n<ul>\n<li>因Q音接口失效,移除Q音源的试听与下载</li>\n</ul>\n<h3>其他</h3>\n<ul>\n<li>更新electron到7.1.5</li>\n<li>更新vue到2.6.11</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.12.1",
|
||||
"desc": "<h3>优化</h3>\n<ul>\n<li>优化定位歌曲时的列表滚动机制</li>\n<li>优化链接点击效果</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复使用酷我源下载歌曲时,当歌曲无封面时下载报错的问题</li>\n<li>修复酷我源排行榜、歌单详情列表里的歌曲音质匹配问题(原来无论歌曲有无高品、无损都会显示有)</li>\n<li>禁止外部链接在软件内打开,将所有外部链接从默认浏览器打开</li>\n</ul>\n<h3>其他</h3>\n<ul>\n<li>更新electron到7.1.2</li>\n</ul>\n"
|
||||
},
|
||||
{
|
||||
"version": "0.12.0",
|
||||
"desc": "<p>由于新下载库仍然没有完成,但下载功能已经可用,so 移除之前使用的第三方下载库,暂时把新下载库的下载模块直接加入本程序,若出现下载问题欢迎反馈!</p>\n<h3>新增</h3>\n<ul>\n<li>新增下载功能对代理设置的支持,现在若在软件设置了代理服务器,下载功能也将会走代理网络了</li>\n</ul>\n<h3>优化</h3>\n<ul>\n<li>新下载模块将对恢复下载的任务进行字节校验,用于解决下载进度超过100%后仍然下载的问题</li>\n<li>注意:目前仍然无法暂停处于<strong>链接获取</strong>状态中的任务</li>\n</ul>\n<h3>修复</h3>\n<ul>\n<li>修复Linux deb版本<code>.desktop</code>桌面文件缺少图标的问题,新增中文名称显示、软件分类,感谢@lowy的反馈!</li>\n<li>修复下载列表歌曲状态分类列表操作Bug</li>\n<li>修复歌曲封面下载失败时仍然执行嵌入封面操作导致报错的问题</li>\n<li>跳过重复添加<strong>相同歌曲名与扩展名的歌曲</strong>,例如你之前下载了A歌曲的128k音质,现在想要下载它的320k音质,但由于两者都是MP3格式,会因为重名导致之前的128k音质被覆盖但列表中仍然显示两种音质的问题(但实际上都是指向后面的320k音质)</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"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
|
||||
56
src/common/config.js
Normal file
56
src/common/config.js
Normal file
@@ -0,0 +1,56 @@
|
||||
module.exports = {
|
||||
windowSizeList: [
|
||||
{
|
||||
id: 0,
|
||||
name: 'smaller',
|
||||
width: 828,
|
||||
height: 530,
|
||||
fontSize: '14px',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: 'small',
|
||||
width: 920,
|
||||
height: 590,
|
||||
fontSize: '16px',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'medium',
|
||||
width: 1012,
|
||||
height: 650,
|
||||
fontSize: '16px',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'big',
|
||||
width: 1104,
|
||||
height: 708,
|
||||
fontSize: '17px',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'larger',
|
||||
width: 1198,
|
||||
height: 766,
|
||||
fontSize: '18px',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'oversized',
|
||||
width: 1380,
|
||||
height: 886,
|
||||
fontSize: '18px',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'huge',
|
||||
width: 1656,
|
||||
height: 1062,
|
||||
fontSize: '19px',
|
||||
},
|
||||
],
|
||||
navigationUrlWhiteList: [
|
||||
/^https:\/\/www\.xiami\.com/,
|
||||
],
|
||||
}
|
||||
12
src/common/error.js
Normal file
12
src/common/error.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const { log } = require('./utils')
|
||||
|
||||
process.on('uncaughtException', function(err) {
|
||||
console.error('An uncaught error occurred!')
|
||||
console.error(err)
|
||||
log.error(err)
|
||||
})
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.error('Unhandled Rejection at: Promise ', p)
|
||||
console.error(' reason: ', reason)
|
||||
log.error(reason)
|
||||
})
|
||||
@@ -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')
|
||||
|
||||
|
||||
exports.mainOn = (event, callback) => {
|
||||
ipcMain.on(event, callback)
|
||||
}
|
||||
exports.mainOnce = (event, callback) => {
|
||||
ipcMain.once(event, callback)
|
||||
}
|
||||
|
||||
exports.mainHandle = (name, callback) => {
|
||||
ipcMain.handle(name, callback)
|
||||
}
|
||||
exports.mainHandleOnce = (name, callback) => {
|
||||
ipcMain.handleOnce(name, callback)
|
||||
}
|
||||
|
||||
|
||||
exports.rendererSend = (name, params) => {
|
||||
ipcRenderer.send(name, params)
|
||||
}
|
||||
exports.rendererSendSync = (name, params) => ipcRenderer.sendSync(name, params)
|
||||
|
||||
exports.rendererInvoke = (name, params) => ipcRenderer.invoke(name, params)
|
||||
|
||||
exports.rendererOn = (name, callback) => {
|
||||
ipcRenderer.on(name, callback)
|
||||
}
|
||||
exports.rendererOnce = (name, callback) => {
|
||||
ipcRenderer.once(name, callback)
|
||||
}
|
||||
5
src/main/events/_name.js
Normal file
5
src/main/events/_name.js
Normal file
@@ -0,0 +1,5 @@
|
||||
exports.tray = {
|
||||
create: 'create',
|
||||
destroy: 'destroy',
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
global.lx_event = {}
|
||||
|
||||
require('./request')
|
||||
// require('./appName')
|
||||
require('./progressBar')
|
||||
require('./trafficLight')
|
||||
require('./musicMeta')
|
||||
const Tray = require('./tray')
|
||||
|
||||
if (!global.lx_event.tray) global.lx_event.tray = new Tray()
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// const { app } = require('electron')
|
||||
const { mainOn } = require('../../common/icp')
|
||||
|
||||
|
||||
mainOn('min', event => {
|
||||
if (global.mainWindow) {
|
||||
global.mainWindow.minimize()
|
||||
}
|
||||
})
|
||||
// mainOn('max', event => {
|
||||
// if (global.mainWindow) {
|
||||
// global.mainWindow.maximize()
|
||||
// }
|
||||
// })
|
||||
mainOn('close', event => {
|
||||
if (global.mainWindow) {
|
||||
// global.mainWindowdow.destroy()
|
||||
// console.log('close')
|
||||
// app.quit()
|
||||
global.mainWindow.close()
|
||||
}
|
||||
})
|
||||
14
src/main/events/tray.js
Normal file
14
src/main/events/tray.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { EventEmitter } = require('events')
|
||||
const { tray: TRAY_EVENT_NAME } = require('./_name')
|
||||
|
||||
class Tray extends EventEmitter {
|
||||
create() {
|
||||
this.emit(TRAY_EVENT_NAME.create)
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.emit(TRAY_EVENT_NAME.destroy)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Tray
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, Menu } = require('electron')
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
// 单例应用程序
|
||||
@@ -7,31 +7,72 @@ if (!app.requestSingleInstanceLock()) {
|
||||
return
|
||||
}
|
||||
app.on('second-instance', (event, argv, cwd) => {
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) mainWindow.restore()
|
||||
mainWindow.focus()
|
||||
if (global.mainWindow) {
|
||||
if (global.mainWindow.isMinimized()) {
|
||||
global.mainWindow.restore()
|
||||
} else if (global.mainWindow.isVisible()) {
|
||||
global.mainWindow.focus()
|
||||
} else {
|
||||
global.mainWindow.show()
|
||||
}
|
||||
} else {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
const isDev = global.isDev = process.env.NODE_ENV !== 'production'
|
||||
const { navigationUrlWhiteList } = require('../common/config')
|
||||
|
||||
app.on('web-contents-created', (event, contents) => {
|
||||
contents.on('will-navigate', (event, navigationUrl) => {
|
||||
if (isDev) return console.log('navigation to url:', navigationUrl)
|
||||
if (!navigationUrlWhiteList.some(url => url.test(navigationUrl))) return event.preventDefault()
|
||||
console.log('navigation to url:', navigationUrl)
|
||||
})
|
||||
contents.on('new-window', async(event, navigationUrl) => {
|
||||
event.preventDefault()
|
||||
if (/^devtools/.test(navigationUrl)) return
|
||||
console.log(navigationUrl)
|
||||
await shell.openExternal(navigationUrl)
|
||||
})
|
||||
contents.on('will-attach-webview', (event, webPreferences, params) => {
|
||||
// Strip away preload scripts if unused or verify their location is legitimate
|
||||
delete webPreferences.preload
|
||||
delete webPreferences.preloadURL
|
||||
|
||||
// Disable Node.js integration
|
||||
webPreferences.nodeIntegration = false
|
||||
|
||||
// Verify URL being loaded
|
||||
if (!navigationUrlWhiteList.some(url => url.test(params.src))) {
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// https://github.com/electron/electron/issues/22691
|
||||
app.commandLine.appendSwitch('wm-window-animations-disabled')
|
||||
|
||||
// https://github.com/electron/electron/issues/18397
|
||||
app.allowRendererProcessReuse = !isDev
|
||||
|
||||
const { getAppSetting, parseEnv, getWindowSizeInfo } = require('./utils')
|
||||
|
||||
global.envParams = parseEnv()
|
||||
|
||||
require('../common/error')
|
||||
require('./events')
|
||||
require('./rendererEvents')
|
||||
const winEvent = require('./rendererEvents/winEvent')
|
||||
const autoUpdate = require('./utils/autoUpdate')
|
||||
const { isLinux, isMac } = require('../common/utils')
|
||||
const { isMac, isLinux } = require('../common/utils')
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production'
|
||||
|
||||
/**
|
||||
* Set `__static` path to static files in production
|
||||
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
|
||||
*/
|
||||
|
||||
let mainWindow
|
||||
let winURL
|
||||
let isFirstCheckedUpdate = true
|
||||
|
||||
if (isDev) {
|
||||
global.__static = path.join(__dirname, '../static')
|
||||
// eslint-disable-next-line no-undef
|
||||
global.__static = __static
|
||||
winURL = 'http://localhost:9080'
|
||||
} else {
|
||||
global.__static = path.join(__dirname, '/static')
|
||||
@@ -39,19 +80,22 @@ if (isDev) {
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
const windowSizeInfo = getWindowSizeInfo(global.appSetting)
|
||||
/**
|
||||
* Initial window options
|
||||
*/
|
||||
mainWindow = global.mainWindow = new BrowserWindow({
|
||||
height: 590,
|
||||
global.mainWindow = new BrowserWindow({
|
||||
height: windowSizeInfo.height,
|
||||
useContentSize: true,
|
||||
width: 920,
|
||||
width: windowSizeInfo.width,
|
||||
frame: false,
|
||||
transparent: !isLinux,
|
||||
transparent: !isLinux && !global.envParams.nt,
|
||||
enableRemoteModule: false,
|
||||
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
fullscreenable: false,
|
||||
show: false,
|
||||
webPreferences: {
|
||||
// contextIsolation: true,
|
||||
webSecurity: !isDev,
|
||||
@@ -59,72 +103,42 @@ function createWindow() {
|
||||
},
|
||||
})
|
||||
|
||||
mainWindow.loadURL(winURL)
|
||||
|
||||
mainWindow.on('close', () => {
|
||||
mainWindow.setProgressBar(-1)
|
||||
})
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = global.mainWindow = null
|
||||
})
|
||||
global.mainWindow.loadURL(winURL)
|
||||
|
||||
winEvent(global.mainWindow)
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
if (!isDev) {
|
||||
autoUpdate(isFirstCheckedUpdate)
|
||||
isFirstCheckedUpdate = false
|
||||
}
|
||||
if (!isDev) autoUpdate()
|
||||
}
|
||||
|
||||
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: '退出', accelerator: 'Command+Q', click: () => app.quit() },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '窗口',
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{ label: '最小化', role: 'minimize' },
|
||||
{ label: '关闭', role: 'close' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
submenu: [
|
||||
{ label: '撤销', accelerator: 'CmdOrCtrl+Z', role: 'undo' },
|
||||
{ label: '恢复', accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ label: '剪切', accelerator: 'CmdOrCtrl+X', role: 'cut' },
|
||||
{ label: '复制', accelerator: 'CmdOrCtrl+C', role: 'copy' },
|
||||
{ label: '粘贴', accelerator: 'CmdOrCtrl+V', role: 'paste' },
|
||||
{ label: '选择全部', accelerator: 'CmdOrCtrl+A', role: 'selectAll' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template))
|
||||
} else {
|
||||
Menu.setApplicationMenu(null)
|
||||
function init() {
|
||||
global.appSetting = getAppSetting()
|
||||
createWindow()
|
||||
global.lx_event.tray.create()
|
||||
}
|
||||
|
||||
app.on('ready', createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (!isMac) app.quit()
|
||||
})
|
||||
app.on('ready', init)
|
||||
|
||||
app.on('activate', () => {
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
if (global.mainWindow) {
|
||||
if (global.mainWindow.isMinimized()) {
|
||||
global.mainWindow.restore()
|
||||
} else if (global.mainWindow.isVisible()) {
|
||||
global.mainWindow.focus()
|
||||
} else {
|
||||
global.mainWindow.show()
|
||||
}
|
||||
} else if (global.mainWindow === null) {
|
||||
init()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (isMac) {
|
||||
global.lx_event.tray.destroy()
|
||||
} else {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
require('./modules')
|
||||
|
||||
50
src/main/modules/appMenu.js
Normal file
50
src/main/modules/appMenu.js
Normal file
@@ -0,0 +1,50 @@
|
||||
const { app, Menu } = require('electron')
|
||||
const { isMac } = require('../../common/utils')
|
||||
|
||||
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: '退出',
|
||||
accelerator: 'Command+Q',
|
||||
click() {
|
||||
global.isQuitting = true
|
||||
app.quit()
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '窗口',
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{ label: '最小化', role: 'minimize' },
|
||||
{ label: '关闭', role: 'close' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
submenu: [
|
||||
{ label: '撤销', accelerator: 'CmdOrCtrl+Z', role: 'undo' },
|
||||
{ label: '恢复', accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ label: '剪切', accelerator: 'CmdOrCtrl+X', role: 'cut' },
|
||||
{ label: '复制', accelerator: 'CmdOrCtrl+C', role: 'copy' },
|
||||
{ label: '粘贴', accelerator: 'CmdOrCtrl+V', role: 'paste' },
|
||||
{ label: '选择全部', accelerator: 'CmdOrCtrl+A', role: 'selectAll' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template))
|
||||
} else {
|
||||
Menu.setApplicationMenu(null)
|
||||
}
|
||||
2
src/main/modules/index.js
Normal file
2
src/main/modules/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
require('./appMenu')
|
||||
require('./tray')
|
||||
50
src/main/modules/tray.js
Normal file
50
src/main/modules/tray.js
Normal file
@@ -0,0 +1,50 @@
|
||||
const { app, Tray, Menu } = require('electron')
|
||||
const { isWin } = require('../../common/utils')
|
||||
const { tray: TRAY_EVENT_NAME } = require('../events/_name')
|
||||
const path = require('path')
|
||||
global.lx_event.tray.on(TRAY_EVENT_NAME.create, () => {
|
||||
createTray()
|
||||
})
|
||||
global.lx_event.tray.on(TRAY_EVENT_NAME.destroy, () => {
|
||||
destroyTray()
|
||||
})
|
||||
|
||||
const createTray = () => {
|
||||
if ((global.tray && !global.tray.isDestroyed()) || !global.appSetting.tray || !global.appSetting.tray.isShow) return
|
||||
|
||||
const iconPath = path.join(global.__static, 'images/tray', isWin ? 'trayTemplate@2x.ico' : 'trayTemplate.png')
|
||||
|
||||
// 托盘
|
||||
global.tray = new Tray(iconPath)
|
||||
|
||||
global.tray.setToolTip('洛雪音乐助手')
|
||||
if (isWin) createMenu(global.tray)
|
||||
global.tray.setIgnoreDoubleClickEvents(true)
|
||||
global.tray.on('click', () => {
|
||||
const mainWindow = global.mainWindow
|
||||
if (!mainWindow) return
|
||||
mainWindow.isVisible()
|
||||
? mainWindow.focus()
|
||||
: mainWindow.show()
|
||||
})
|
||||
}
|
||||
|
||||
const destroyTray = () => {
|
||||
if (!global.tray) return
|
||||
global.tray.destroy()
|
||||
global.tray = null
|
||||
}
|
||||
|
||||
const createMenu = tray => {
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: '退出',
|
||||
click() {
|
||||
global.isQuitting = true
|
||||
app.quit()
|
||||
},
|
||||
},
|
||||
])
|
||||
tray.setContextMenu(contextMenu)
|
||||
}
|
||||
|
||||
@@ -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/rendererEvents/clearCache.js
Normal file
8
src/main/rendererEvents/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/rendererEvents/getCacheSize.js
Normal file
7
src/main/rendererEvents/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()
|
||||
})
|
||||
|
||||
6
src/main/rendererEvents/getEnvParams.js
Normal file
6
src/main/rendererEvents/getEnvParams.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const { mainHandle } = require('../../common/ipc')
|
||||
|
||||
mainHandle('getEnvParams', async(event, options) => {
|
||||
return global.envParams
|
||||
})
|
||||
|
||||
17
src/main/rendererEvents/index.js
Normal file
17
src/main/rendererEvents/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
// require('./request')
|
||||
// require('./appName')
|
||||
require('./progressBar')
|
||||
require('./trafficLight')
|
||||
require('./musicMeta')
|
||||
require('./selectDir')
|
||||
require('./setWindowSize')
|
||||
require('./showSaveDialog')
|
||||
require('./clearCache')
|
||||
require('./getCacheSize')
|
||||
require('./setIgnoreMouseEvent')
|
||||
require('./getEnvParams')
|
||||
require('./tray')
|
||||
require('./updateSetting')
|
||||
|
||||
require('./xm_verify')
|
||||
@@ -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/rendererEvents/restartWindow.js
Normal file
13
src/main/rendererEvents/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/rendererEvents/selectDir.js
Normal file
8
src/main/rendererEvents/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)
|
||||
})
|
||||
|
||||
8
src/main/rendererEvents/setIgnoreMouseEvent.js
Normal file
8
src/main/rendererEvents/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/rendererEvents/setWindowSize.js
Normal file
7
src/main/rendererEvents/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/rendererEvents/showSaveDialog.js
Normal file
8
src/main/rendererEvents/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)
|
||||
})
|
||||
|
||||
18
src/main/rendererEvents/trafficLight.js
Normal file
18
src/main/rendererEvents/trafficLight.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const { app } = require('electron')
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
mainOn('min', event => {
|
||||
if (global.mainWindow) {
|
||||
global.mainWindow.minimize()
|
||||
}
|
||||
})
|
||||
mainOn('max', event => {
|
||||
if (global.mainWindow) {
|
||||
global.mainWindow.maximize()
|
||||
}
|
||||
})
|
||||
mainOn('close', (event, isForce) => {
|
||||
if (isForce) return app.exit(0)
|
||||
global.isTrafficLightClose = true
|
||||
if (global.mainWindow) global.mainWindow.close()
|
||||
})
|
||||
12
src/main/rendererEvents/tray.js
Normal file
12
src/main/rendererEvents/tray.js
Normal file
@@ -0,0 +1,12 @@
|
||||
// const { app } = require('electron')
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
mainOn('changeTray', (event, setting) => {
|
||||
global.appSetting.tray = setting
|
||||
if (setting.isToTray) {
|
||||
global.lx_event.tray.create()
|
||||
} else {
|
||||
global.lx_event.tray.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
7
src/main/rendererEvents/updateSetting.js
Normal file
7
src/main/rendererEvents/updateSetting.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const { mainOn } = require('../../common/ipc')
|
||||
|
||||
|
||||
mainOn('updateAppSetting', (event, setting) => {
|
||||
if (!setting) return
|
||||
global.appSetting = setting
|
||||
})
|
||||
28
src/main/rendererEvents/winEvent.js
Normal file
28
src/main/rendererEvents/winEvent.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const { isMac } = require('../../common/utils')
|
||||
global.isQuitting = false
|
||||
global.isTrafficLightClose = false // 是否点击软件上的关闭按钮关闭
|
||||
|
||||
module.exports = mainWindow => {
|
||||
mainWindow.on('close', event => {
|
||||
if (global.isQuitting || !global.appSetting.tray.isToTray || (isMac && !global.isTrafficLightClose)) {
|
||||
mainWindow.setProgressBar(-1)
|
||||
return
|
||||
}
|
||||
|
||||
if (global.isTrafficLightClose) global.isTrafficLightClose = false
|
||||
event.preventDefault()
|
||||
mainWindow.hide()
|
||||
})
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = global.mainWindow = null
|
||||
})
|
||||
|
||||
// mainWindow.on('restore', () => {
|
||||
// mainWindow.webContents.send('restore')
|
||||
// })
|
||||
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show()
|
||||
})
|
||||
}
|
||||
4
src/main/rendererEvents/xm_verify/index.js
Normal file
4
src/main/rendererEvents/xm_verify/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const { isMac } = require('../../../common/utils')
|
||||
|
||||
// mac下的 BrowserView 无法拖动验证栏,改用 BrowserWindow
|
||||
require(isMac ? './xm_verify_win' : './xm_verify_view')
|
||||
4
src/main/rendererEvents/xm_verify/xm_verify.js
Normal file
4
src/main/rendererEvents/xm_verify/xm_verify.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const { isMac } = require('../../../common/utils')
|
||||
|
||||
// mac下的 BrowserView 无法拖动验证栏,改用 BrowserWindow
|
||||
require(isMac ? './xm_verify_win' : './xm_verify_view')
|
||||
66
src/main/rendererEvents/xm_verify/xm_verify_view.js
Normal file
66
src/main/rendererEvents/xm_verify/xm_verify_view.js
Normal file
@@ -0,0 +1,66 @@
|
||||
const { BrowserView } = require('electron')
|
||||
const { mainHandle } = require('../../../common/ipc')
|
||||
const { getWindowSizeInfo } = require('../../utils')
|
||||
|
||||
let view
|
||||
let isActioned = false
|
||||
let rejectFn
|
||||
|
||||
const closeView = async() => {
|
||||
if (!view) return
|
||||
// await view.webContents.session.clearCache()
|
||||
if (global.mainWindow) global.mainWindow.removeBrowserView(view)
|
||||
await view.webContents.session.clearStorageData()
|
||||
view.destroy()
|
||||
view = null
|
||||
}
|
||||
|
||||
mainHandle('xm_verify_open', (event, url) => new Promise((resolve, reject) => {
|
||||
if (!global.mainWindow) return reject(new Error('mainwindow is undefined'))
|
||||
if (view) {
|
||||
global.mainWindow.removeBrowserView(view)
|
||||
view.destroy()
|
||||
}
|
||||
|
||||
rejectFn = reject
|
||||
|
||||
isActioned = false
|
||||
|
||||
view = new BrowserView({
|
||||
webPreferences: {
|
||||
enableRemoteModule: false,
|
||||
disableHtmlFullscreenWindowResize: true,
|
||||
},
|
||||
})
|
||||
view.webContents.on('did-finish-load', () => {
|
||||
if (/punish\?/.test(view.webContents.getURL())) return
|
||||
let ses = view.webContents.session
|
||||
ses.cookies.get({ name: 'x5sec' })
|
||||
.then(async([x5sec]) => {
|
||||
isActioned = true
|
||||
await closeView()
|
||||
if (!x5sec) return reject(new Error('get x5sec failed'))
|
||||
resolve(x5sec.value)
|
||||
}).catch(async err => {
|
||||
isActioned = true
|
||||
await closeView()
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
|
||||
global.mainWindow.setBrowserView(view)
|
||||
const windowSizeInfo = getWindowSizeInfo(global.appSetting)
|
||||
view.setBounds({ x: (windowSizeInfo.width - 380) / 2, y: ((windowSizeInfo.height - 320 + 52) / 2), width: 380, height: 320 })
|
||||
view.webContents.loadURL(url, {
|
||||
httpReferrer: 'https://www.xiami.com/',
|
||||
})
|
||||
// view.webContents.openDevTools()
|
||||
}))
|
||||
|
||||
mainHandle('xm_verify_close', async() => {
|
||||
await closeView()
|
||||
if (!rejectFn) return
|
||||
if (!isActioned) rejectFn(new Error('canceled verify'))
|
||||
rejectFn = null
|
||||
})
|
||||
|
||||
77
src/main/rendererEvents/xm_verify/xm_verify_win.js
Normal file
77
src/main/rendererEvents/xm_verify/xm_verify_win.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const { BrowserWindow } = require('electron')
|
||||
const { mainHandle } = require('../../../common/ipc')
|
||||
const { getWindowSizeInfo } = require('../../utils')
|
||||
|
||||
let win
|
||||
|
||||
const closeWin = async() => {
|
||||
if (!win) return
|
||||
// await win.webContents.session.clearCache()
|
||||
// if (global.mainWindow) global.mainWindow.removeBrowserView(win)
|
||||
if (win.isDestroyed()) {
|
||||
win = null
|
||||
return
|
||||
}
|
||||
await win.webContents.session.clearStorageData()
|
||||
win.destroy()
|
||||
win = null
|
||||
}
|
||||
|
||||
mainHandle('xm_verify_open', (event, url) => new Promise((resolve, reject) => {
|
||||
if (!global.mainWindow) return reject(new Error('mainwindow is undefined'))
|
||||
if (win) win.destroy()
|
||||
|
||||
let isActioned = false
|
||||
|
||||
const mainWindowSizeInfo = global.mainWindow.getBounds()
|
||||
const windowSizeInfo = getWindowSizeInfo(global.appSetting)
|
||||
win = new BrowserWindow({
|
||||
parent: global.mainWindow,
|
||||
width: 460,
|
||||
height: 370,
|
||||
resizable: false,
|
||||
// transparent: true,
|
||||
x: mainWindowSizeInfo.x + (windowSizeInfo.width - 460) / 2,
|
||||
y: mainWindowSizeInfo.y + (windowSizeInfo.height - 320 + 52) / 2,
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
// movable: false,
|
||||
// frame: false,
|
||||
// modal: true,
|
||||
webPreferences: {
|
||||
enableRemoteModule: false,
|
||||
disableHtmlFullscreenWindowResize: true,
|
||||
},
|
||||
})
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
if (/punish\?/.test(win.webContents.getURL())) return
|
||||
let ses = win.webContents.session
|
||||
ses.cookies.get({ name: 'x5sec' })
|
||||
.then(async([x5sec]) => {
|
||||
isActioned = true
|
||||
await closeWin()
|
||||
if (!x5sec) return reject(new Error('get x5sec failed'))
|
||||
resolve(x5sec.value)
|
||||
}).catch(async err => {
|
||||
isActioned = true
|
||||
await closeWin()
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
|
||||
win.webContents.loadURL(url, {
|
||||
httpReferrer: 'https://www.xiami.com/',
|
||||
})
|
||||
|
||||
win.on('closed', async() => {
|
||||
await closeWin()
|
||||
if (isActioned) return
|
||||
reject(new Error('canceled verify'))
|
||||
})
|
||||
|
||||
// win.webContents.openDevTools()
|
||||
}))
|
||||
|
||||
mainHandle('xm_verify_close', async() => {
|
||||
await closeWin()
|
||||
})
|
||||
@@ -1,10 +1,13 @@
|
||||
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
|
||||
autoUpdater.logger.transports.file.level = 'info'
|
||||
|
||||
let isFirstCheckedUpdate = true
|
||||
|
||||
log.info('App starting...')
|
||||
|
||||
|
||||
@@ -21,7 +24,7 @@ log.info('App starting...')
|
||||
|
||||
function sendStatusToWindow(text) {
|
||||
log.info(text)
|
||||
// global.mainWindow.webContents.send('message', text)
|
||||
// ipcMain.send('message', text)
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +70,7 @@ const handleSendEvent = action => {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = isFirstCheckedUpdate => {
|
||||
module.exports = () => {
|
||||
if (!isFirstCheckedUpdate) {
|
||||
if (waitEvent.length) {
|
||||
waitEvent.forEach((event, index) => {
|
||||
@@ -79,6 +82,8 @@ module.exports = isFirstCheckedUpdate => {
|
||||
}
|
||||
return
|
||||
}
|
||||
isFirstCheckedUpdate = false
|
||||
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
sendStatusToWindow('Checking for update...')
|
||||
})
|
||||
@@ -88,20 +93,26 @@ module.exports = isFirstCheckedUpdate => {
|
||||
})
|
||||
autoUpdater.on('update-not-available', info => {
|
||||
sendStatusToWindow('Update not available.')
|
||||
handleSendEvent({ type: 'update-not-available' })
|
||||
handleSendEvent({ type: 'update-not-available', info })
|
||||
})
|
||||
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', () => {
|
||||
global.isQuitting = true
|
||||
|
||||
setTimeout(() => {
|
||||
autoUpdater.quitAndInstall(true, true)
|
||||
}, 1000)
|
||||
|
||||
281
src/main/utils/flac-metadata/index.js
Normal file
281
src/main/utils/flac-metadata/index.js
Normal file
@@ -0,0 +1,281 @@
|
||||
// Fork from https://github.com/claus/flac-metadata
|
||||
// 在 flac-metadata 的基础上修复与改进标签与封面写入逻辑
|
||||
|
||||
|
||||
const Transform = require('stream').Transform
|
||||
|
||||
const MetaDataBlock = require('./lib/MetaDataBlock')
|
||||
const MetaDataBlockStreamInfo = require('./lib/MetaDataBlockStreamInfo')
|
||||
const MetaDataBlockVorbisComment = require('./lib/MetaDataBlockVorbisComment')
|
||||
const MetaDataBlockPicture = require('./lib/MetaDataBlockPicture')
|
||||
|
||||
const STATE_IDLE = 0
|
||||
const STATE_MARKER = 1
|
||||
const STATE_MDB_HEADER = 2
|
||||
const STATE_MDB = 3
|
||||
const STATE_PASS_THROUGH = 4
|
||||
|
||||
class Processor extends Transform {
|
||||
constructor(options) {
|
||||
super(options)
|
||||
// MDB types
|
||||
this.MDB_TYPE_STREAMINFO = 0
|
||||
this.MDB_TYPE_PADDING = 1
|
||||
this.MDB_TYPE_APPLICATION = 2
|
||||
this.MDB_TYPE_SEEKTABLE = 3
|
||||
this.MDB_TYPE_VORBIS_COMMENT = 4
|
||||
this.MDB_TYPE_CUESHEET = 5
|
||||
this.MDB_TYPE_PICTURE = 6
|
||||
this.MDB_TYPE_INVALID = 127
|
||||
|
||||
this.state = STATE_IDLE
|
||||
|
||||
this.isFlac = false
|
||||
|
||||
this.buf = null
|
||||
this.bufPos = 0
|
||||
|
||||
this.mdb = null
|
||||
this.mdbLen = 0
|
||||
this.mdbLast = false
|
||||
this.mdbPush = false
|
||||
this.mdbLastWritten = false
|
||||
|
||||
this.parseMetaDataBlocks = false
|
||||
|
||||
this.waitWriteVorbis = null
|
||||
this.waitWritePicture = null
|
||||
this.tasks = 0
|
||||
|
||||
if (!(this instanceof Processor)) return new Processor(options)
|
||||
if (options && !!options.parseMetaDataBlocks) { this.parseMetaDataBlocks = true }
|
||||
}
|
||||
|
||||
writeMeta({ vorbis, picture }) {
|
||||
if (vorbis != null) {
|
||||
this.waitWriteVorbis = vorbis
|
||||
this.tasks++
|
||||
}
|
||||
if (picture != null) {
|
||||
this.waitWritePicture = picture
|
||||
this.tasks++
|
||||
}
|
||||
}
|
||||
|
||||
// clearMeta() {
|
||||
// this.mdbLastWritten = true
|
||||
// }
|
||||
|
||||
readMeta(callback) {
|
||||
this.parseMetaDataBlocks = true
|
||||
this.readCallBack = callback
|
||||
}
|
||||
|
||||
_transform(chunk, enc, done) {
|
||||
let chunkPos = 0
|
||||
let chunkLen = chunk.length
|
||||
let isChunkProcessed = false
|
||||
let _this = this
|
||||
|
||||
function _safePush(minCapacity, persist, validate) {
|
||||
let slice
|
||||
let chunkAvailable = chunkLen - chunkPos
|
||||
let isDone = (chunkAvailable + this.bufPos >= minCapacity)
|
||||
validate = (typeof validate === 'function') ? validate : function() { return true }
|
||||
if (isDone) {
|
||||
// Enough data available
|
||||
if (persist) {
|
||||
// Persist the entire block so it can be parsed
|
||||
if (this.bufPos > 0) {
|
||||
// Part of this block's data is in backup buffer, copy rest over
|
||||
chunk.copy(this.buf, this.bufPos, chunkPos, chunkPos + minCapacity - this.bufPos)
|
||||
slice = this.buf.slice(0, minCapacity)
|
||||
} else {
|
||||
// Entire block fits in current chunk
|
||||
slice = chunk.slice(chunkPos, chunkPos + minCapacity)
|
||||
}
|
||||
} else {
|
||||
slice = chunk.slice(chunkPos, chunkPos + minCapacity - this.bufPos)
|
||||
}
|
||||
// Push block after validation
|
||||
validate(slice, isDone) && _this.push(slice)
|
||||
chunkPos += minCapacity - this.bufPos
|
||||
this.bufPos = 0
|
||||
this.buf = null
|
||||
} else {
|
||||
// Not enough data available
|
||||
if (persist) {
|
||||
// Copy/append incomplete block to backup buffer
|
||||
this.buf = this.buf || Buffer.alloc(minCapacity)
|
||||
chunk.copy(this.buf, this.bufPos, chunkPos, chunkLen)
|
||||
} else {
|
||||
// Push incomplete block after validation
|
||||
slice = chunk.slice(chunkPos, chunkLen)
|
||||
validate(slice, isDone) && _this.push(slice)
|
||||
}
|
||||
this.bufPos += chunkLen - chunkPos
|
||||
}
|
||||
return isDone
|
||||
};
|
||||
let safePush = _safePush.bind(this)
|
||||
|
||||
while (!isChunkProcessed) {
|
||||
switch (this.state) {
|
||||
case STATE_IDLE:
|
||||
this.state = STATE_MARKER
|
||||
break
|
||||
case STATE_MARKER:
|
||||
if (safePush(4, true, this._validateMarker.bind(this))) {
|
||||
this.state = this.isFlac ? STATE_MDB_HEADER : STATE_PASS_THROUGH
|
||||
} else {
|
||||
isChunkProcessed = true
|
||||
}
|
||||
break
|
||||
case STATE_MDB_HEADER:
|
||||
if (safePush(4, true, this._validateMDBHeader.bind(this))) {
|
||||
this.state = STATE_MDB
|
||||
} else {
|
||||
isChunkProcessed = true
|
||||
}
|
||||
break
|
||||
case STATE_MDB:
|
||||
if (safePush(this.mdbLen, this.parseMetaDataBlocks, this._validateMDB.bind(this))) {
|
||||
if (this.mdb.isLast) {
|
||||
// This MDB has the isLast flag set to true.
|
||||
// Ignore all following MDBs.
|
||||
this.mdbLastWritten = true
|
||||
}
|
||||
this.readCallBack && this.readCallBack(this.mdb)
|
||||
if (this.mdbLast) {
|
||||
this._writeVorbisComment()
|
||||
this._writePicture()
|
||||
this.state = STATE_PASS_THROUGH
|
||||
} else {
|
||||
this.state = STATE_MDB_HEADER
|
||||
}
|
||||
} else {
|
||||
isChunkProcessed = true
|
||||
}
|
||||
break
|
||||
case STATE_PASS_THROUGH:
|
||||
safePush(chunkLen - chunkPos, false)
|
||||
isChunkProcessed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
_validateMarker(slice, isDone) {
|
||||
this.isFlac = (slice.toString('utf8', 0) === 'fLaC')
|
||||
// TODO: completely bail out if file is not a FLAC?
|
||||
return true
|
||||
}
|
||||
|
||||
_validateMDBHeader(slice, isDone) {
|
||||
// Parse MDB header
|
||||
let header = slice.readUInt32BE(0)
|
||||
let type = (header >>> 24) & 0x7f
|
||||
this.mdbLast = (((header >>> 24) & 0x80) !== 0)
|
||||
this.mdbLen = header & 0xffffff
|
||||
// Create appropriate MDB object
|
||||
// (data is injected later in _validateMDB, if parseMetaDataBlocks option is set to true)
|
||||
switch (type) {
|
||||
case this.MDB_TYPE_STREAMINFO:
|
||||
this.mdb = new MetaDataBlockStreamInfo(this.mdbLast)
|
||||
break
|
||||
case this.MDB_TYPE_VORBIS_COMMENT:
|
||||
if (this.waitWriteVorbis) {
|
||||
this._writeVorbisComment(slice, header)
|
||||
this.mdbPush = false
|
||||
return this.mdbPush
|
||||
} else {
|
||||
this.mdb = new MetaDataBlockVorbisComment(this.mdbLast)
|
||||
this.readCallback && this.readCallback(this.mdb)
|
||||
}
|
||||
break
|
||||
case this.MDB_TYPE_PICTURE:
|
||||
if (this.waitWritePicture) {
|
||||
this._writePicture(slice, header)
|
||||
this.mdbPush = false
|
||||
return this.mdbPush
|
||||
} else {
|
||||
this.mdb = new MetaDataBlockPicture(this.mdbLast)
|
||||
this.readCallback && this.readCallback(this.mdb)
|
||||
}
|
||||
break
|
||||
case this.MDB_TYPE_PADDING:
|
||||
case this.MDB_TYPE_APPLICATION:
|
||||
case this.MDB_TYPE_SEEKTABLE:
|
||||
case this.MDB_TYPE_CUESHEET:
|
||||
case this.MDB_TYPE_INVALID:
|
||||
default:
|
||||
this.mdb = new MetaDataBlock(this.mdbLast, type)
|
||||
break
|
||||
}
|
||||
|
||||
// this.emit('preprocess', this.mdb)
|
||||
|
||||
if (this.mdbLastWritten) {
|
||||
// A previous MDB had the isLast flag set to true.
|
||||
// Ignore all following MDBs.
|
||||
this.mdb.remove()
|
||||
} else {
|
||||
if (this.mdbLast && this.tasks > 0) {
|
||||
header &= 0x7fffffff
|
||||
slice.writeUInt32BE(header >>> 0, 0)
|
||||
}
|
||||
// The consumer may change the MDB's isLast flag in the preprocess handler.
|
||||
// Here that flag is updated in the MDB header.
|
||||
}
|
||||
this.mdbPush = !this.mdb.removed
|
||||
return this.mdbPush
|
||||
}
|
||||
|
||||
_validateMDB(slice, isDone) {
|
||||
// Parse the MDB if parseMetaDataBlocks option is set to true
|
||||
if (this.parseMetaDataBlocks && isDone) {
|
||||
this.mdb.parse(slice)
|
||||
}
|
||||
return this.mdbPush
|
||||
}
|
||||
|
||||
_flush(done) {
|
||||
// All chunks have been processed
|
||||
// Clean up
|
||||
this.state = STATE_IDLE
|
||||
this.mdbLastWritten = false
|
||||
this.isFlac = false
|
||||
this.bufPos = 0
|
||||
this.buf = null
|
||||
this.mdb = null
|
||||
done()
|
||||
}
|
||||
|
||||
_writeVorbisComment() {
|
||||
if (this.waitWriteVorbis == null) return
|
||||
let isLast = this.mdbLast && this.tasks === 1
|
||||
this.tasks--
|
||||
this.push(MetaDataBlockVorbisComment.create(isLast, this.waitWriteVorbis.vendor, this.waitWriteVorbis.comments).publish())
|
||||
this.waitWriteVorbis = null
|
||||
}
|
||||
|
||||
_writePicture() {
|
||||
if (this.waitWritePicture == null) return
|
||||
let isLast = this.mdbLast && this.tasks === 1
|
||||
this.tasks--
|
||||
this.push(
|
||||
MetaDataBlockPicture.create(
|
||||
isLast, this.waitWritePicture.pictureType,
|
||||
this.waitWritePicture.mimeType, this.waitWritePicture.description,
|
||||
this.waitWritePicture.width, this.waitWritePicture.height,
|
||||
this.waitWritePicture.bitsPerPixel, this.waitWritePicture.colors,
|
||||
this.waitWritePicture.pictureData,
|
||||
).publish(),
|
||||
)
|
||||
this.waitWritePicture = null
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Processor
|
||||
25
src/main/utils/flac-metadata/lib/MetaDataBlock.js
Normal file
25
src/main/utils/flac-metadata/lib/MetaDataBlock.js
Normal file
@@ -0,0 +1,25 @@
|
||||
class MetaDataBlock {
|
||||
constructor(isLast, type) {
|
||||
this.isLast = isLast
|
||||
this.type = type
|
||||
this.error = null
|
||||
this.hasData = false
|
||||
this.removed = false
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.removed = true
|
||||
}
|
||||
|
||||
parse(buffer) {
|
||||
}
|
||||
|
||||
toString() {
|
||||
let str = '[MetaDataBlock]'
|
||||
str += ' type: ' + this.type
|
||||
str += ', isLast: ' + this.isLast
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MetaDataBlock
|
||||
130
src/main/utils/flac-metadata/lib/MetaDataBlockPicture.js
Normal file
130
src/main/utils/flac-metadata/lib/MetaDataBlockPicture.js
Normal file
@@ -0,0 +1,130 @@
|
||||
const MetaDataBlock = require('./MetaDataBlock')
|
||||
|
||||
class MetaDataBlockPicture extends MetaDataBlock {
|
||||
constructor(isLast) {
|
||||
super(isLast, 6)
|
||||
|
||||
this.pictureType = 0
|
||||
this.mimeType = ''
|
||||
this.description = ''
|
||||
this.width = 0
|
||||
this.height = 0
|
||||
this.bitsPerPixel = 0
|
||||
this.colors = 0
|
||||
this.pictureData = null
|
||||
}
|
||||
|
||||
static create(isLast, pictureType, mimeType, description, width, height, bitsPerPixel, colors, pictureData) {
|
||||
let mdb = new MetaDataBlockPicture(isLast)
|
||||
mdb.pictureType = pictureType
|
||||
mdb.mimeType = mimeType
|
||||
mdb.description = description
|
||||
mdb.width = width
|
||||
mdb.height = height
|
||||
mdb.bitsPerPixel = bitsPerPixel
|
||||
mdb.colors = colors
|
||||
mdb.pictureData = pictureData
|
||||
mdb.hasData = true
|
||||
return mdb
|
||||
}
|
||||
|
||||
|
||||
parse(buffer) {
|
||||
try {
|
||||
let pos = 0
|
||||
|
||||
this.pictureType = buffer.readUInt32BE(pos)
|
||||
pos += 4
|
||||
|
||||
let mimeTypeLength = buffer.readUInt32BE(pos)
|
||||
this.mimeType = buffer.toString('utf8', pos + 4, pos + 4 + mimeTypeLength)
|
||||
pos += 4 + mimeTypeLength
|
||||
|
||||
let descriptionLength = buffer.readUInt32BE(pos)
|
||||
this.description = buffer.toString('utf8', pos + 4, pos + 4 + descriptionLength)
|
||||
pos += 4 + descriptionLength
|
||||
|
||||
this.width = buffer.readUInt32BE(pos)
|
||||
this.height = buffer.readUInt32BE(pos + 4)
|
||||
this.bitsPerPixel = buffer.readUInt32BE(pos + 8)
|
||||
this.colors = buffer.readUInt32BE(pos + 12)
|
||||
pos += 16
|
||||
|
||||
let pictureDataLength = buffer.readUInt32BE(pos)
|
||||
this.pictureData = Buffer.alloc(pictureDataLength)
|
||||
buffer.copy(this.pictureData, 0, pos + 4, pictureDataLength)
|
||||
|
||||
this.hasData = true
|
||||
} catch (e) {
|
||||
this.error = e
|
||||
this.hasData = false
|
||||
}
|
||||
}
|
||||
|
||||
publish() {
|
||||
let pos = 0
|
||||
let size = this.getSize()
|
||||
let buffer = Buffer.alloc(4 + size)
|
||||
|
||||
let header = size
|
||||
header |= (this.type << 24)
|
||||
header |= (this.isLast ? 0x80000000 : 0)
|
||||
buffer.writeUInt32BE(header >>> 0, pos)
|
||||
pos += 4
|
||||
|
||||
buffer.writeUInt32BE(this.pictureType, pos)
|
||||
pos += 4
|
||||
|
||||
let mimeTypeLen = Buffer.byteLength(this.mimeType)
|
||||
buffer.writeUInt32BE(mimeTypeLen, pos)
|
||||
buffer.write(this.mimeType, pos + 4)
|
||||
pos += 4 + mimeTypeLen
|
||||
|
||||
let descriptionLen = Buffer.byteLength(this.description)
|
||||
buffer.writeUInt32BE(descriptionLen, pos)
|
||||
buffer.write(this.description, pos + 4)
|
||||
pos += 4 + descriptionLen
|
||||
|
||||
buffer.writeUInt32BE(this.width, pos)
|
||||
buffer.writeUInt32BE(this.height, pos + 4)
|
||||
buffer.writeUInt32BE(this.bitsPerPixel, pos + 8)
|
||||
buffer.writeUInt32BE(this.colors, pos + 12)
|
||||
pos += 16
|
||||
|
||||
buffer.writeUInt32BE(this.pictureData.length, pos)
|
||||
this.pictureData.copy(buffer, pos + 4)
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
getSize() {
|
||||
let size = 4
|
||||
size += 4 + Buffer.byteLength(this.mimeType)
|
||||
size += 4 + Buffer.byteLength(this.description)
|
||||
size += 16
|
||||
size += 4 + this.pictureData.length
|
||||
return size
|
||||
}
|
||||
|
||||
toString() {
|
||||
let str = '[MetaDataBlockPicture]'
|
||||
str += ' type: ' + this.type
|
||||
str += ', isLast: ' + this.isLast
|
||||
if (this.error) {
|
||||
str += '\n ERROR: ' + this.error
|
||||
}
|
||||
if (this.hasData) {
|
||||
str += '\n pictureType: ' + this.pictureType
|
||||
str += '\n mimeType: ' + this.mimeType
|
||||
str += '\n description: ' + this.description
|
||||
str += '\n width: ' + this.width
|
||||
str += '\n height: ' + this.height
|
||||
str += '\n bitsPerPixel: ' + this.bitsPerPixel
|
||||
str += '\n colors: ' + this.colors
|
||||
str += '\n pictureData: ' + (this.pictureData ? this.pictureData.length : '<null>')
|
||||
}
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MetaDataBlockPicture
|
||||
84
src/main/utils/flac-metadata/lib/MetaDataBlockStreamInfo.js
Normal file
84
src/main/utils/flac-metadata/lib/MetaDataBlockStreamInfo.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const MetaDataBlock = require('./MetaDataBlock')
|
||||
|
||||
function pad(n, width) {
|
||||
n = '' + n
|
||||
return (n.length >= width) ? n : new Array(width - n.length + 1).join('0') + n
|
||||
}
|
||||
|
||||
class MetaDataBlockStreamInfo extends MetaDataBlock {
|
||||
constructor(isLast) {
|
||||
super(isLast, 0)
|
||||
|
||||
this.minBlockSize = 0
|
||||
this.maxBlockSize = 0
|
||||
this.minFrameSize = 0
|
||||
this.maxFrameSize = 0
|
||||
this.sampleRate = 0
|
||||
this.channels = 0
|
||||
this.bitsPerSample = 0
|
||||
this.samples = 0
|
||||
this.checksum = null
|
||||
this.duration = 0
|
||||
this.durationStr = '0:00.000'
|
||||
}
|
||||
|
||||
remove() {
|
||||
console.error("WARNING: Can't remove StreamInfo block!")
|
||||
}
|
||||
|
||||
parse(buffer) {
|
||||
try {
|
||||
let pos = 0
|
||||
|
||||
this.minBlockSize = buffer.readUInt16BE(pos)
|
||||
this.maxBlockSize = buffer.readUInt16BE(pos + 2)
|
||||
this.minFrameSize = (buffer.readUInt8(pos + 4) << 16) | buffer.readUInt16BE(pos + 5)
|
||||
this.maxFrameSize = (buffer.readUInt8(pos + 7) << 16) | buffer.readUInt16BE(pos + 8)
|
||||
|
||||
let tmp = buffer.readUInt32BE(pos + 10)
|
||||
this.sampleRate = tmp >>> 12
|
||||
this.channels = (tmp >>> 9) & 0x07
|
||||
this.bitsPerSample = (tmp >>> 4) & 0x1f
|
||||
this.samples = +((tmp & 0x0f) << 4) + buffer.readUInt32BE(pos + 14)
|
||||
|
||||
this.checksum = Buffer.alloc(16)
|
||||
buffer.copy(this.checksum, 0, 18, 34)
|
||||
|
||||
this.duration = this.samples / this.sampleRate
|
||||
|
||||
let minutes = '' + Math.floor(this.duration / 60)
|
||||
let seconds = pad(Math.floor(this.duration % 60), 2)
|
||||
let milliseconds = pad(Math.round(((this.duration % 60) - Math.floor(this.duration % 60)) * 1000), 3)
|
||||
this.durationStr = minutes + ':' + seconds + '.' + milliseconds
|
||||
|
||||
this.hasData = true
|
||||
} catch (e) {
|
||||
this.error = e
|
||||
this.hasData = false
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
let str = '[MetaDataBlockStreamInfo]'
|
||||
str += ' type: ' + this.type
|
||||
str += ', isLast: ' + this.isLast
|
||||
if (this.error) {
|
||||
str += '\n ERROR: ' + this.error
|
||||
}
|
||||
if (this.hasData) {
|
||||
str += '\n minBlockSize: ' + this.minBlockSize
|
||||
str += '\n maxBlockSize: ' + this.maxBlockSize
|
||||
str += '\n minFrameSize: ' + this.minFrameSize
|
||||
str += '\n maxFrameSize: ' + this.maxFrameSize
|
||||
str += '\n samples: ' + this.samples
|
||||
str += '\n sampleRate: ' + this.sampleRate
|
||||
str += '\n channels: ' + (this.channels + 1)
|
||||
str += '\n bitsPerSample: ' + (this.bitsPerSample + 1)
|
||||
str += '\n duration: ' + this.durationStr
|
||||
str += '\n checksum: ' + (this.checksum ? this.checksum.toString('hex') : '<null>')
|
||||
}
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MetaDataBlockStreamInfo
|
||||
105
src/main/utils/flac-metadata/lib/MetaDataBlockVorbisComment.js
Normal file
105
src/main/utils/flac-metadata/lib/MetaDataBlockVorbisComment.js
Normal file
@@ -0,0 +1,105 @@
|
||||
const MetaDataBlock = require('./MetaDataBlock')
|
||||
|
||||
class MetaDataBlockVorbisComment extends MetaDataBlock {
|
||||
constructor(isLast) {
|
||||
super(isLast, 4)
|
||||
|
||||
this.vendor = ''
|
||||
this.comments = []
|
||||
}
|
||||
|
||||
static create(isLast, vendor, comments) {
|
||||
let mdb = new MetaDataBlockVorbisComment(isLast)
|
||||
mdb.vendor = vendor
|
||||
mdb.comments = comments
|
||||
mdb.hasData = true
|
||||
return mdb
|
||||
}
|
||||
|
||||
parse(buffer) {
|
||||
try {
|
||||
let pos = 0
|
||||
|
||||
let vendorLen = buffer.readUInt32LE(pos)
|
||||
let vendor = buffer.toString('utf8', pos + 4, pos + 4 + vendorLen)
|
||||
this.vendor = vendor
|
||||
pos += 4 + vendorLen
|
||||
|
||||
let commentCount = buffer.readUInt32LE(pos)
|
||||
pos += 4
|
||||
|
||||
while (commentCount-- > 0) {
|
||||
let commentLen = buffer.readUInt32LE(pos)
|
||||
let comment = buffer.toString('utf8', pos + 4, pos + 4 + commentLen)
|
||||
this.comments.push(comment)
|
||||
pos += 4 + commentLen
|
||||
}
|
||||
|
||||
this.hasData = true
|
||||
} catch (e) {
|
||||
this.error = e
|
||||
this.hasData = false
|
||||
}
|
||||
}
|
||||
|
||||
publish() {
|
||||
let pos = 0
|
||||
let size = this.getSize()
|
||||
let buffer = Buffer.alloc(4 + size)
|
||||
|
||||
let header = size
|
||||
header |= (this.type << 24)
|
||||
header |= (this.isLast ? 0x80000000 : 0)
|
||||
buffer.writeUInt32BE(header >>> 0, pos)
|
||||
pos += 4
|
||||
let vendorLen = Buffer.byteLength(this.vendor)
|
||||
buffer.writeUInt32LE(vendorLen, pos)
|
||||
buffer.write(this.vendor, pos + 4)
|
||||
pos += 4 + vendorLen
|
||||
|
||||
let commentCount = this.comments.length
|
||||
buffer.writeUInt32LE(commentCount, pos)
|
||||
pos += 4
|
||||
|
||||
for (let i = 0; i < commentCount; i++) {
|
||||
let comment = this.comments[i]
|
||||
let commentLen = Buffer.byteLength(comment)
|
||||
buffer.writeUInt32LE(commentLen, pos)
|
||||
buffer.write(comment, pos + 4)
|
||||
pos += 4 + commentLen
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
getSize() {
|
||||
let size = 8 + Buffer.byteLength(this.vendor)
|
||||
for (let i = 0; i < this.comments.length; i++) {
|
||||
size += 4 + Buffer.byteLength(this.comments[i])
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
toString() {
|
||||
let str = '[MetaDataBlockVorbisComment]'
|
||||
str += ' type: ' + this.type
|
||||
str += ', isLast: ' + this.isLast
|
||||
if (this.error) {
|
||||
str += '\n ERROR: ' + this.error
|
||||
}
|
||||
if (this.hasData) {
|
||||
str += '\n vendor: ' + this.vendor
|
||||
if (this.comments.length) {
|
||||
str += '\n comments:'
|
||||
for (let i = 0; i < this.comments.length; i++) {
|
||||
str += '\n ' + this.comments[i].split('=').join(': ')
|
||||
}
|
||||
} else {
|
||||
str += '\n comments: none'
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MetaDataBlockVorbisComment
|
||||
@@ -1,38 +1,94 @@
|
||||
const fs = require('fs')
|
||||
const flac = require('flac-metadata')
|
||||
const fsPromises = fs.promises
|
||||
const path = require('path')
|
||||
const getImgSize = require('image-size')
|
||||
const request = require('request')
|
||||
|
||||
module.exports = (filenPath, meta) => {
|
||||
const reader = fs.createReadStream(filenPath)
|
||||
const tempPath = filenPath + '.lxmtemp'
|
||||
const writer = fs.createWriteStream(tempPath)
|
||||
const processor = new flac.Processor()
|
||||
if (meta.APIC) delete meta.APIC
|
||||
const FlacProcessor = require('./flac-metadata')
|
||||
|
||||
const comments = []
|
||||
for (const key in meta) {
|
||||
comments.push(`${key.toUpperCase()}=${meta[key]}`)
|
||||
const extReg = /^(\.(?:jpe?g|png)).*$/
|
||||
const vendor = 'reference libFLAC 1.2.1 20070917'
|
||||
|
||||
const writeMeta = async(filePath, meta, picPath) => {
|
||||
const comments = Object.keys(meta).map(key => `${key.toUpperCase()}=${meta[key] || ''}`)
|
||||
const data = {
|
||||
vorbis: {
|
||||
vendor,
|
||||
comments,
|
||||
},
|
||||
}
|
||||
const vendor = 'lx-music-desktop'
|
||||
|
||||
processor.on('preprocess', function(mdb) {
|
||||
// Remove existing VORBIS_COMMENT block, if any.
|
||||
if (mdb.type === flac.Processor.MDB_TYPE_VORBIS_COMMENT) {
|
||||
mdb.remove()
|
||||
if (picPath) {
|
||||
const apicData = await fsPromises.readFile(picPath)
|
||||
let imgSize = getImgSize(apicData)
|
||||
let mime_type
|
||||
let bitsPerPixel
|
||||
if (apicData[0] == 0xff && apicData[1] == 0xd8 && apicData[2] == 0xff) {
|
||||
mime_type = 'image/jpeg'
|
||||
bitsPerPixel = 24
|
||||
} else {
|
||||
mime_type = 'image/png'
|
||||
bitsPerPixel = 32
|
||||
}
|
||||
// Inject new VORBIS_COMMENT block.
|
||||
if (mdb.removed || mdb.isLast) {
|
||||
let mdbVorbis = flac.data.MetaDataBlockVorbisComment.create(mdb.isLast, vendor, comments)
|
||||
this.push(mdbVorbis.publish())
|
||||
data.picture = {
|
||||
pictureType: 3,
|
||||
mimeType: mime_type,
|
||||
description: '',
|
||||
width: imgSize.width,
|
||||
height: imgSize.height,
|
||||
bitsPerPixel,
|
||||
colors: 0,
|
||||
pictureData: apicData,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
reader.pipe(processor).pipe(writer).on('finish', () => {
|
||||
fs.unlink(filenPath, err => {
|
||||
const reader = fs.createReadStream(filePath)
|
||||
const tempPath = filePath + '.lxmtemp'
|
||||
const writer = fs.createWriteStream(tempPath)
|
||||
const flacProcessor = new FlacProcessor()
|
||||
flacProcessor.writeMeta(data)
|
||||
|
||||
reader.pipe(flacProcessor).pipe(writer).on('finish', () => {
|
||||
fs.unlink(filePath, err => {
|
||||
if (err) return console.log(err.message)
|
||||
fs.rename(tempPath, filenPath, err => {
|
||||
fs.rename(tempPath, filePath, err => {
|
||||
if (err) console.log(err.message)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = (filePath, meta) => {
|
||||
if (!meta.APIC) return writeMeta(filePath, meta)
|
||||
const picUrl = meta.APIC
|
||||
delete meta.APIC
|
||||
if (!/^http/.test(picUrl)) {
|
||||
return writeMeta(filePath, meta)
|
||||
}
|
||||
let picPath = filePath.replace(/\.flac$/, '') + path.extname(picUrl).replace(extReg, '$1')
|
||||
|
||||
request(picUrl)
|
||||
.on('response', respones => {
|
||||
if (respones.statusCode !== 200 && respones.statusCode != 206) return writeMeta(filePath, meta)
|
||||
respones
|
||||
.pipe(fs.createWriteStream(picPath))
|
||||
.on('finish', () => {
|
||||
if (respones.complete) {
|
||||
writeMeta(filePath, meta, picPath)
|
||||
} else {
|
||||
writeMeta(filePath, meta)
|
||||
}
|
||||
fs.unlink(picPath, err => {
|
||||
if (err) console.log(err.message)
|
||||
})
|
||||
})
|
||||
.on('error', err => {
|
||||
if (err) console.log(err.message)
|
||||
writeMeta(filePath, meta)
|
||||
})
|
||||
})
|
||||
.on('error', err => {
|
||||
if (err) console.log(err.message)
|
||||
writeMeta(filePath, meta)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
35
src/main/utils/index.js
Normal file
35
src/main/utils/index.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const Store = require('electron-store')
|
||||
const { windowSizeList } = require('../../common/config')
|
||||
|
||||
exports.getWindowSizeInfo = ({ windowSizeId = 1 } = {}) => {
|
||||
return windowSizeList.find(i => i.id === windowSizeId) || windowSizeList[0]
|
||||
}
|
||||
|
||||
exports.getAppSetting = () => {
|
||||
let electronStore = new Store()
|
||||
const defaultSetting = {
|
||||
windowSizeId: 1,
|
||||
tray: {
|
||||
isShow: false,
|
||||
isToTray: false,
|
||||
},
|
||||
}
|
||||
return Object.assign(defaultSetting, electronStore.get('setting') || {})
|
||||
}
|
||||
|
||||
exports.parseEnv = () => {
|
||||
const params = {}
|
||||
const rx = /^-\w+/
|
||||
for (let param of process.argv) {
|
||||
if (!rx.test(param)) continue
|
||||
param = param.substring(1)
|
||||
let index = param.indexOf('=')
|
||||
if (index < 0) {
|
||||
params[param] = true
|
||||
} else {
|
||||
params[param.substring(0, index)] = param.substring(index + 1)
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
@@ -6,12 +6,40 @@ const extReg = /^(\.(?:jpe?g|png)).*$/
|
||||
|
||||
module.exports = (filePath, meta) => {
|
||||
if (!meta.APIC) return NodeID3.write(meta, filePath)
|
||||
if (!/^http/.test(meta.APIC)) {
|
||||
delete meta.APIC
|
||||
return NodeID3.write(meta, filePath)
|
||||
}
|
||||
let picPath = filePath.replace(/\.mp3$/, '') + path.extname(meta.APIC).replace(extReg, '$1')
|
||||
request(meta.APIC).pipe(fs.createWriteStream(picPath)).on('finish', () => {
|
||||
meta.APIC = picPath
|
||||
NodeID3.write(meta, filePath)
|
||||
fs.unlink(picPath, err => {
|
||||
if (err) console.log(err.message)
|
||||
request(meta.APIC)
|
||||
.on('response', respones => {
|
||||
if (respones.statusCode !== 200 && respones.statusCode != 206) {
|
||||
delete meta.APIC
|
||||
NodeID3.write(meta, filePath)
|
||||
return
|
||||
}
|
||||
respones
|
||||
.pipe(fs.createWriteStream(picPath))
|
||||
.on('finish', () => {
|
||||
if (respones.complete) {
|
||||
meta.APIC = picPath
|
||||
NodeID3.write(meta, filePath)
|
||||
} else {
|
||||
delete meta.APIC
|
||||
NodeID3.write(meta, filePath)
|
||||
}
|
||||
fs.unlink(picPath, err => {
|
||||
if (err) console.log(err.message)
|
||||
})
|
||||
}).on('error', err => {
|
||||
if (err) console.log(err.message)
|
||||
delete meta.APIC
|
||||
NodeID3.write(meta, filePath)
|
||||
})
|
||||
})
|
||||
.on('error', err => {
|
||||
if (err) console.log(err.message)
|
||||
delete meta.APIC
|
||||
NodeID3.write(meta, filePath)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,160 +1,219 @@
|
||||
<template lang="pug">
|
||||
#container(v-if="isProd && !isLinux" :class="theme" @mouseenter="enableIgnoreMouseEvents" @mouseleave="dieableIgnoreMouseEvents")
|
||||
#container(v-if="isProd && !isNt" :class="[theme, nd ? 'nd' : '']" @mouseenter="enableIgnoreMouseEvents" @mouseleave="dieableIgnoreMouseEvents")
|
||||
core-aside#left
|
||||
#right
|
||||
core-toolbar#toolbar
|
||||
core-view#view
|
||||
core-player#player
|
||||
core-icons
|
||||
material-xm-verify-modal(v-show="globalObj.xm.isShowVerify" :show="globalObj.xm.isShowVerify" :bg-close="false" @close="handleXMVerifyModalClose")
|
||||
material-version-modal(v-show="version.showModal")
|
||||
#container(v-else :class="theme")
|
||||
material-pact-modal(v-show="!setting.isAgreePact || globalObj.isShowPact")
|
||||
#container(v-else :class="[theme, nd ? 'nd' : '']")
|
||||
core-aside#left
|
||||
#right
|
||||
core-toolbar#toolbar
|
||||
core-view#view
|
||||
core-player#player
|
||||
core-icons
|
||||
material-xm-verify-modal(v-show="globalObj.xm.isShowVerify" :show="globalObj.xm.isShowVerify" :bg-close="false" @close="handleXMVerifyModalClose")
|
||||
material-version-modal(v-show="version.showModal")
|
||||
material-pact-modal(v-show="!setting.isAgreePact || globalObj.isShowPact")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dnscache from 'dnscache'
|
||||
import { mapMutations, mapGetters, mapActions } from 'vuex'
|
||||
import { rendererOn } from '../common/icp'
|
||||
import { rendererOn, rendererSend, rendererInvoke } from '../common/ipc'
|
||||
import { isLinux } from '../common/utils'
|
||||
import music from './utils/music'
|
||||
import { throttle, openUrl } from './utils'
|
||||
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() {
|
||||
return {
|
||||
isProd: process.env.NODE_ENV === 'production',
|
||||
isLinux,
|
||||
isNt: false,
|
||||
globalObj: {
|
||||
apiSource: 'test',
|
||||
proxy: {},
|
||||
isShowPact: false,
|
||||
qualityList: {},
|
||||
xm: {
|
||||
isShowVerify: false,
|
||||
},
|
||||
},
|
||||
updateTimeout: null,
|
||||
envParams: {
|
||||
nt: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['electronStore', 'setting', 'theme', 'version']),
|
||||
...mapGetters('player', ['isShowPlayerDetail']),
|
||||
...mapGetters(['setting', 'theme', 'version', 'windowSizeActive']),
|
||||
...mapGetters('list', ['defaultList', 'loveList']),
|
||||
...mapGetters('download', {
|
||||
downloadList: 'list',
|
||||
downloadStatus: 'downloadStatus',
|
||||
}),
|
||||
...mapGetters('search', {
|
||||
searchHistoryList: 'historyList',
|
||||
}),
|
||||
nd() {
|
||||
return this.isShowPlayerDetail
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.saveSetting = throttle(n => {
|
||||
window.electronStore_config.set('setting', n)
|
||||
rendererSend('updateAppSetting', n)
|
||||
})
|
||||
this.saveDefaultList = throttle(n => {
|
||||
window.electronStore_list.set('defaultList', n)
|
||||
}, 500)
|
||||
this.saveLoveList = throttle(n => {
|
||||
window.electronStore_list.set('loveList', n)
|
||||
}, 500)
|
||||
this.saveDownloadList = throttle(n => {
|
||||
window.electronStore_list.set('downloadList', n)
|
||||
}, 1000)
|
||||
this.saveSearchHistoryList = throttle(n => {
|
||||
window.electronStore_data.set('searchHistoryList', n)
|
||||
}, 500)
|
||||
},
|
||||
mounted() {
|
||||
document.body.classList.add(this.isLinux ? 'noTransparent' : 'transparent')
|
||||
document.body.classList.add(this.isNt ? 'noTransparent' : 'transparent')
|
||||
window.eventHub.$emit('bindKey')
|
||||
this.init()
|
||||
},
|
||||
watch: {
|
||||
setting: {
|
||||
handler(n) {
|
||||
this.electronStore.set('setting', n)
|
||||
this.saveSetting(n)
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
defaultList: {
|
||||
handler(n) {
|
||||
// console.log(n)
|
||||
this.electronStore.set('list.defaultList', n)
|
||||
this.saveDefaultList(n)
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
loveList: {
|
||||
handler(n) {
|
||||
// console.log(n)
|
||||
this.electronStore.set('list.loveList', n)
|
||||
this.saveLoveList(n)
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
downloadList: {
|
||||
handler(n) {
|
||||
this.electronStore.set('download.list', n)
|
||||
this.saveDownloadList(n)
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
searchHistoryList(n) {
|
||||
this.saveSearchHistoryList(n)
|
||||
},
|
||||
'globalObj.apiSource'(n) {
|
||||
this.globalObj.qualityList = music.supportQuality[n]
|
||||
if (n != this.setting.apiSource) {
|
||||
this.setSetting(Object.assign({}, this.setting, {
|
||||
apiSource: n,
|
||||
}))
|
||||
}
|
||||
},
|
||||
'windowSizeActive.fontSize'(n) {
|
||||
document.documentElement.style.fontSize = n
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['getVersionInfo']),
|
||||
...mapMutations(['setNewVersion', 'setVersionModalVisible']),
|
||||
...mapMutations(['setNewVersion', 'setVersionModalVisible', 'setDownloadProgress', 'setSetting']),
|
||||
...mapMutations('list', ['initList']),
|
||||
...mapMutations('download', ['updateDownloadList']),
|
||||
...mapMutations(['setSetting']),
|
||||
init() {
|
||||
if (this.isProd && !isLinux) {
|
||||
body.addEventListener('mouseenter', this.dieableIgnoreMouseEvents)
|
||||
body.addEventListener('mouseleave', this.enableIgnoreMouseEvents)
|
||||
}
|
||||
document.documentElement.style.fontSize = this.windowSizeActive.fontSize
|
||||
|
||||
rendererInvoke('getEnvParams').then(this.handleEnvParamsInit)
|
||||
|
||||
document.body.addEventListener('click', this.handleBodyClick, true)
|
||||
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', () => {
|
||||
this.clearUpdateTimeout()
|
||||
this.setVersionModalVisible({ isError: false })
|
||||
this.showUpdateModal()
|
||||
rendererOn('update-progress', (event, progress) => {
|
||||
// console.log(progress)
|
||||
this.setDownloadProgress(progress)
|
||||
})
|
||||
rendererOn('update-not-available', () => {
|
||||
if (!this.updateTimeout) return
|
||||
if (this.setting.ignoreVersion) this.setSetting(Object.assign({}, this.setting, { ignoreVersion: null }))
|
||||
rendererOn('update-downloaded', info => {
|
||||
// console.log(info)
|
||||
this.clearUpdateTimeout()
|
||||
this.setVersionModalVisible({ isDownloaded: true })
|
||||
this.$nextTick(() => {
|
||||
this.showUpdateModal()
|
||||
})
|
||||
})
|
||||
rendererOn('update-not-available', (e, info) => {
|
||||
this.clearUpdateTimeout()
|
||||
this.setNewVersion({
|
||||
version: this.version.version,
|
||||
version: info.version,
|
||||
desc: info.releaseNotes,
|
||||
})
|
||||
this.setVersionModalVisible({ isLatestVer: true })
|
||||
})
|
||||
// 更新超时定时器
|
||||
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.qualityList = music.supportQuality[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)
|
||||
if (this.isNt) return
|
||||
rendererSend('setIgnoreMouseEvents', false)
|
||||
// console.log('content enable')
|
||||
},
|
||||
dieableIgnoreMouseEvents() {
|
||||
if (isLinux) return
|
||||
if (this.isNt) return
|
||||
// console.log('content disable')
|
||||
win.setIgnoreMouseEvents(true, { forward: true })
|
||||
rendererSend('setIgnoreMouseEvents', true)
|
||||
},
|
||||
|
||||
initData() { // 初始化数据
|
||||
@@ -162,12 +221,12 @@ export default {
|
||||
this.initDownloadList() // 初始化下载列表
|
||||
},
|
||||
initPlayList() {
|
||||
let defaultList = this.electronStore.get('list.defaultList')
|
||||
let loveList = this.electronStore.get('list.loveList')
|
||||
let defaultList = window.electronStore_list.get('defaultList')
|
||||
let loveList = window.electronStore_list.get('loveList')
|
||||
this.initList({ defaultList, loveList })
|
||||
},
|
||||
initDownloadList() {
|
||||
let downloadList = this.electronStore.get('download.list')
|
||||
let downloadList = window.electronStore_list.get('downloadList')
|
||||
if (downloadList) {
|
||||
downloadList.forEach(item => {
|
||||
if (item.status == this.downloadStatus.RUN || item.status == this.downloadStatus.WAITING) {
|
||||
@@ -179,14 +238,31 @@ 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
|
||||
(this.version.newVersion && this.version.newVersion.history
|
||||
? Promise.resolve(this.version.newVersion)
|
||||
: this.getVersionInfo().then(body => {
|
||||
this.setNewVersion(body)
|
||||
return body
|
||||
})
|
||||
).catch(() => {
|
||||
if (this.version.newVersion) return this.version.newVersion
|
||||
this.setVersionModalVisible({ isUnknow: true })
|
||||
let result = {
|
||||
version: '0.0.0',
|
||||
desc: null,
|
||||
}
|
||||
this.setNewVersion(result)
|
||||
return result
|
||||
}).then(result => {
|
||||
let newVer = result.version.replace(/\./g, '')
|
||||
let currentVer = this.version.version.replace(/\./g, '')
|
||||
let len = Math.max(newVer.length, currentVer.length)
|
||||
newVer.padStart(len, '0')
|
||||
currentVer.padStart(len, '0')
|
||||
if (parseInt(newVer) <= parseInt(currentVer)) return this.setVersionModalVisible({ isLatestVer: true })
|
||||
|
||||
if (result.version === this.setting.ignoreVersion) return
|
||||
// console.log(this.version)
|
||||
this.$nextTick(() => {
|
||||
this.setVersionModalVisible({ isShow: true })
|
||||
})
|
||||
@@ -197,13 +273,45 @@ export default {
|
||||
clearTimeout(this.updateTimeout)
|
||||
this.updateTimeout = null
|
||||
},
|
||||
handleBodyClick(event) {
|
||||
if (event.target.tagName != 'A') return
|
||||
if (event.target.host == window.location.host) return
|
||||
event.preventDefault()
|
||||
if (/^https?:\/\//.test(event.target.href)) openUrl(event.target.href)
|
||||
},
|
||||
handleEnvParamsInit(envParams) {
|
||||
this.envParams = envParams
|
||||
this.isNt = isLinux || this.envParams.nt
|
||||
if (this.isNt) {
|
||||
document.body.classList.remove('transparent')
|
||||
document.body.classList.add('noTransparent')
|
||||
}
|
||||
if (this.isProd && !this.isNt) {
|
||||
document.body.addEventListener('mouseenter', this.dieableIgnoreMouseEvents)
|
||||
document.body.addEventListener('mouseleave', this.enableIgnoreMouseEvents)
|
||||
}
|
||||
|
||||
if (this.envParams.search != null) {
|
||||
this.$router.push({
|
||||
path: 'search',
|
||||
query: {
|
||||
text: this.envParams.search,
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
handleXMVerifyModalClose() {
|
||||
music.xm.closeVerifyModal()
|
||||
},
|
||||
},
|
||||
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)
|
||||
}
|
||||
document.body.removeEventListener('click', this.handleBodyClick)
|
||||
window.eventHub.$emit('unbindKey')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 181 KiB |
BIN
src/renderer/assets/images/xnkl.jpg
Normal file
BIN
src/renderer/assets/images/xnkl.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 262 KiB |
382
src/renderer/assets/styles/animate.less
vendored
382
src/renderer/assets/styles/animate.less
vendored
@@ -1,3 +1,321 @@
|
||||
// https://daneden.github.io/animate.css/
|
||||
|
||||
@keyframes bounce {
|
||||
from,
|
||||
20%,
|
||||
53%,
|
||||
80%,
|
||||
to {
|
||||
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
40%,
|
||||
43% {
|
||||
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
-webkit-transform: translate3d(0, -30px, 0);
|
||||
transform: translate3d(0, -30px, 0);
|
||||
}
|
||||
|
||||
70% {
|
||||
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
-webkit-transform: translate3d(0, -15px, 0);
|
||||
transform: translate3d(0, -15px, 0);
|
||||
}
|
||||
|
||||
90% {
|
||||
-webkit-transform: translate3d(0, -4px, 0);
|
||||
transform: translate3d(0, -4px, 0);
|
||||
}
|
||||
}
|
||||
@keyframes flash {
|
||||
from,
|
||||
50%,
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
25%,
|
||||
75% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
|
||||
@keyframes pulse {
|
||||
from {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.05, 1.05, 1.05);
|
||||
transform: scale3d(1.05, 1.05, 1.05);
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
@keyframes rubberBand {
|
||||
from {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
30% {
|
||||
-webkit-transform: scale3d(1.25, 0.75, 1);
|
||||
transform: scale3d(1.25, 0.75, 1);
|
||||
}
|
||||
|
||||
40% {
|
||||
-webkit-transform: scale3d(0.75, 1.25, 1);
|
||||
transform: scale3d(0.75, 1.25, 1);
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.15, 0.85, 1);
|
||||
transform: scale3d(1.15, 0.85, 1);
|
||||
}
|
||||
|
||||
65% {
|
||||
-webkit-transform: scale3d(0.95, 1.05, 1);
|
||||
transform: scale3d(0.95, 1.05, 1);
|
||||
}
|
||||
|
||||
75% {
|
||||
-webkit-transform: scale3d(1.05, 0.95, 1);
|
||||
transform: scale3d(1.05, 0.95, 1);
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
@keyframes shake {
|
||||
from,
|
||||
to {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
10%,
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
-webkit-transform: translate3d(-10px, 0, 0);
|
||||
transform: translate3d(-10px, 0, 0);
|
||||
}
|
||||
|
||||
20%,
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
-webkit-transform: translate3d(10px, 0, 0);
|
||||
transform: translate3d(10px, 0, 0);
|
||||
}
|
||||
}
|
||||
@keyframes headShake {
|
||||
0% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
6.5% {
|
||||
-webkit-transform: translateX(-6px) rotateY(-9deg);
|
||||
transform: translateX(-6px) rotateY(-9deg);
|
||||
}
|
||||
|
||||
18.5% {
|
||||
-webkit-transform: translateX(5px) rotateY(7deg);
|
||||
transform: translateX(5px) rotateY(7deg);
|
||||
}
|
||||
|
||||
31.5% {
|
||||
-webkit-transform: translateX(-3px) rotateY(-5deg);
|
||||
transform: translateX(-3px) rotateY(-5deg);
|
||||
}
|
||||
|
||||
43.5% {
|
||||
-webkit-transform: translateX(2px) rotateY(3deg);
|
||||
transform: translateX(2px) rotateY(3deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
@keyframes swing {
|
||||
20% {
|
||||
-webkit-transform: rotate3d(0, 0, 1, 15deg);
|
||||
transform: rotate3d(0, 0, 1, 15deg);
|
||||
}
|
||||
|
||||
40% {
|
||||
-webkit-transform: rotate3d(0, 0, 1, -10deg);
|
||||
transform: rotate3d(0, 0, 1, -10deg);
|
||||
}
|
||||
|
||||
60% {
|
||||
-webkit-transform: rotate3d(0, 0, 1, 5deg);
|
||||
transform: rotate3d(0, 0, 1, 5deg);
|
||||
}
|
||||
|
||||
80% {
|
||||
-webkit-transform: rotate3d(0, 0, 1, -5deg);
|
||||
transform: rotate3d(0, 0, 1, -5deg);
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: rotate3d(0, 0, 1, 0deg);
|
||||
transform: rotate3d(0, 0, 1, 0deg);
|
||||
}
|
||||
}
|
||||
@keyframes tada {
|
||||
from {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
10%,
|
||||
20% {
|
||||
-webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
|
||||
30%,
|
||||
50%,
|
||||
70%,
|
||||
90% {
|
||||
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
||||
}
|
||||
|
||||
40%,
|
||||
60%,
|
||||
80% {
|
||||
-webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
|
||||
@keyframes wobble {
|
||||
from {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
15% {
|
||||
-webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
|
||||
transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
|
||||
}
|
||||
|
||||
30% {
|
||||
-webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
|
||||
transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
|
||||
}
|
||||
|
||||
45% {
|
||||
-webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
|
||||
transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
|
||||
60% {
|
||||
-webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
|
||||
transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
|
||||
}
|
||||
|
||||
75% {
|
||||
-webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
|
||||
transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
|
||||
}
|
||||
|
||||
to {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
@keyframes jello {
|
||||
from,
|
||||
11.1%,
|
||||
to {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
22.2% {
|
||||
-webkit-transform: skewX(-12.5deg) skewY(-12.5deg);
|
||||
transform: skewX(-12.5deg) skewY(-12.5deg);
|
||||
}
|
||||
|
||||
33.3% {
|
||||
-webkit-transform: skewX(6.25deg) skewY(6.25deg);
|
||||
transform: skewX(6.25deg) skewY(6.25deg);
|
||||
}
|
||||
|
||||
44.4% {
|
||||
-webkit-transform: skewX(-3.125deg) skewY(-3.125deg);
|
||||
transform: skewX(-3.125deg) skewY(-3.125deg);
|
||||
}
|
||||
|
||||
55.5% {
|
||||
-webkit-transform: skewX(1.5625deg) skewY(1.5625deg);
|
||||
transform: skewX(1.5625deg) skewY(1.5625deg);
|
||||
}
|
||||
|
||||
66.6% {
|
||||
-webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);
|
||||
transform: skewX(-0.78125deg) skewY(-0.78125deg);
|
||||
}
|
||||
|
||||
77.7% {
|
||||
-webkit-transform: skewX(0.390625deg) skewY(0.390625deg);
|
||||
transform: skewX(0.390625deg) skewY(0.390625deg);
|
||||
}
|
||||
|
||||
88.8% {
|
||||
-webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
|
||||
transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
|
||||
}
|
||||
}
|
||||
@keyframes heartBeat {
|
||||
0% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
14% {
|
||||
-webkit-transform: scale(1.3);
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
28% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
42% {
|
||||
-webkit-transform: scale(1.3);
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
70% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes flipInX {
|
||||
from {
|
||||
@@ -533,8 +851,26 @@
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
}
|
||||
@keyframes jackInTheBox {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.1) rotate(30deg);
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: rotate(3deg);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.flipInX {
|
||||
backface-visibility: visible !important;
|
||||
@@ -600,6 +936,11 @@
|
||||
.slideInUp {
|
||||
animation-name: slideInUp;
|
||||
}
|
||||
.jackInTheBox {
|
||||
-webkit-animation-name: jackInTheBox;
|
||||
animation-name: jackInTheBox;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.flipOutX {
|
||||
@@ -673,6 +1014,47 @@
|
||||
animation-name: slideOutUp;
|
||||
}
|
||||
|
||||
|
||||
.bounce {
|
||||
animation-name: bounce;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
.flash {
|
||||
animation-name: flash;
|
||||
}
|
||||
.pulse {
|
||||
animation-name: pulse;
|
||||
}
|
||||
.rubberBand {
|
||||
animation-name: rubberBand;
|
||||
}
|
||||
.shake {
|
||||
animation-name: shake;
|
||||
}
|
||||
.headShake {
|
||||
animation-timing-function: ease-in-out;
|
||||
animation-name: headShake;
|
||||
}
|
||||
.swing {
|
||||
transform-origin: top center;
|
||||
animation-name: swing;
|
||||
}
|
||||
.tada {
|
||||
animation-name: tada;
|
||||
}
|
||||
.wobble {
|
||||
animation-name: wobble;
|
||||
}
|
||||
.jello {
|
||||
animation-name: jello;
|
||||
transform-origin: center;
|
||||
}
|
||||
.heartBeat {
|
||||
animation-name: heartBeat;
|
||||
animation-duration: 1.3s;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
.animated {
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: both;
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.nobreak {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -20,12 +24,19 @@
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.select {
|
||||
user-select: text;
|
||||
}
|
||||
.no-select {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
overflow: hidden;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
th {
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
@@ -42,21 +53,28 @@ table {
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&.active {
|
||||
background-color: @color-theme_2-active;
|
||||
}
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
td {
|
||||
padding: 5px;
|
||||
padding: 6px;
|
||||
position: relative;
|
||||
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
font-size: 13px;
|
||||
line-height: 1.3;
|
||||
line-height: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 0.25em 0.4em;
|
||||
@@ -91,6 +109,14 @@ table {
|
||||
color: #fff;
|
||||
background-color: #32bc63;
|
||||
}
|
||||
&.badge-theme-success {
|
||||
color: @color-badge-success-font;
|
||||
background-color: @color-badge-success;
|
||||
}
|
||||
&.badge-theme-info {
|
||||
color: @color-badge-info-font;
|
||||
background-color: @color-badge-info;
|
||||
}
|
||||
}
|
||||
|
||||
small {
|
||||
@@ -112,7 +138,17 @@ svg {
|
||||
transition-property: fill;
|
||||
}
|
||||
|
||||
.hover {
|
||||
input, textarea {
|
||||
&::placeholder {
|
||||
color: @color-theme_2-font-label;
|
||||
}
|
||||
}
|
||||
::selection {
|
||||
color: @color-theme_2;
|
||||
background: @color-btn;
|
||||
}
|
||||
|
||||
.hover, a {
|
||||
cursor: pointer;
|
||||
transition: color .2s ease;
|
||||
&:hover {
|
||||
@@ -124,6 +160,7 @@ svg {
|
||||
}
|
||||
|
||||
.scroll {
|
||||
overflow: auto;
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
@@ -150,7 +187,7 @@ svg {
|
||||
|
||||
each(@themes, {
|
||||
#container.@{value} {
|
||||
.hover {
|
||||
.hover, a {
|
||||
&:hover {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
@@ -179,8 +216,32 @@ each(@themes, {
|
||||
&:hover {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
}
|
||||
&.active {
|
||||
background-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
&::placeholder {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
}
|
||||
::selection {
|
||||
color: ~'@{color-@{value}-theme_2}';
|
||||
background: ~'@{color-@{value}-btn}';
|
||||
}
|
||||
|
||||
.badge {
|
||||
&.badge-theme-success {
|
||||
color: ~'@{color-@{value}-badge-success-font}';
|
||||
background-color: ~'@{color-@{value}-badge-success}';
|
||||
}
|
||||
&.badge-theme-info {
|
||||
color: ~'@{color-@{value}-badge-info-font}';
|
||||
background-color: ~'@{color-@{value}-badge-info}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
@import './colors.less';
|
||||
|
||||
@themes: green, yellow, blue, red, purple, orange, grey, midAutumn, dhHyrz;
|
||||
@themes: green, yellow, blue, red, pink, purple, orange, grey, ming, mid_autumn, naruto, happy_new_year;
|
||||
|
||||
|
||||
// Colors
|
||||
// @color-theme: #03a678;
|
||||
@color-theme: #4daf7c;
|
||||
@color-theme-bgimg: none;
|
||||
@color-theme-bgposition: center center;
|
||||
@color-theme-bgposition: center;
|
||||
@color-theme-bgsize: auto auto;
|
||||
@color-theme-hover: fadeout(lighten(@color-theme, 10%), 30%);
|
||||
@color-theme-active: fadeout(darken(@color-theme, 20%), 60%);
|
||||
@@ -17,13 +17,13 @@
|
||||
@color-theme_2: rgba(255, 255, 255, .9);
|
||||
@color-theme_2-background_1: #fff;
|
||||
@color-theme_2-background_2: fadeout(@color-theme_2-background_1, 2%);
|
||||
@color-theme_2-hover: fadeout(lighten(@color-theme, 10%), 70%);
|
||||
@color-theme_2-active: fadeout(darken(@color-theme, 5%), 70%);
|
||||
@color-theme_2-hover: fadeout(lighten(@color-theme, 10%), 80%);
|
||||
@color-theme_2-active: fadeout(lighten(@color-theme, 10%), 70%);
|
||||
@color-theme_2-font: darken(@color-theme_2, 70%);
|
||||
@color-theme_2-font-label: fadeout(@color-theme_2-font, 50%);
|
||||
@color-theme_2-font-label: fadeout(@color-theme_2-font, 40%);
|
||||
@color-theme_2-line: lighten(@color-theme, 35%);
|
||||
@color-theme-sidebar: @color-theme;
|
||||
@color-btn: fadeout(darken(@color-theme, 5%), 15%);
|
||||
@color-btn: lighten(@color-theme, 5%);
|
||||
@color-btn-background: fadeout(lighten(@color-theme, 35%), 70%);
|
||||
|
||||
@color-pagination-background: fadeout(lighten(@color-theme, 45%), 30%);
|
||||
@@ -46,20 +46,33 @@
|
||||
@color-player-progress-bar1: darken(@color-theme_2, 12%);
|
||||
@color-player-progress-bar2: lighten(@color-theme, 12%);
|
||||
@color-player-status-text: lighten(@color-theme_2-font, 10%);
|
||||
@color-player-detail-play-btn: lighten(@color-theme, 7%);
|
||||
|
||||
@color-tab-btn-background: fadeout(lighten(@color-theme, 10%), 80%);
|
||||
@color-tab-btn-background-hover: @color-theme_2-hover;
|
||||
@color-tab-border-top: fadeout(lighten(@color-theme, 5%), 50%);
|
||||
@color-tab-border-bottom: lighten(@color-theme, 5%);
|
||||
|
||||
@color-hideBtn: #3bc2b2;
|
||||
@color-minBtn: #85c43b;
|
||||
@color-maxBtn: #e7aa36;
|
||||
@color-closeBtn: #ea6e4d;
|
||||
@color-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-minBtn-hover: fadeout(@color-minBtn, 10%);
|
||||
@color-maxBtn-hover: fadeout(@color-maxBtn, 10%);
|
||||
@color-closeBtn-hover: fadeout(@color-closeBtn, 10%);
|
||||
@color-green-badge-success: #32bc63;
|
||||
@color-green-badge-success-font: #fff;
|
||||
@color-green-badge-info: #4baed5;
|
||||
@color-green-badge-info-font: #fff;
|
||||
@color-badge-success: @color-theme;
|
||||
@color-badge-success-font: #fff;
|
||||
@color-badge-info: #4baed5;
|
||||
@color-badge-info-font: #fff;
|
||||
|
||||
|
||||
@color-green-theme: #4daf7c;
|
||||
@color-green-theme-bgimg: none;
|
||||
@color-green-theme-bgposition: center center;
|
||||
@color-green-theme-bgposition: center;
|
||||
@color-green-theme-bgsize: auto auto;
|
||||
@color-green-theme-hover: fadeout(lighten(@color-green-theme, 10%), 30%);
|
||||
@color-green-theme-active: fadeout(darken(@color-green-theme, 20%), 60%);
|
||||
@@ -68,13 +81,13 @@
|
||||
@color-green-theme_2: #fff;
|
||||
@color-green-theme_2-background_1: #fff;
|
||||
@color-green-theme_2-background_2: fadeout(@color-green-theme_2-background_1, 2%);
|
||||
@color-green-theme_2-hover: fadeout(lighten(@color-green-theme, 10%), 70%);
|
||||
@color-green-theme_2-active: fadeout(darken(@color-green-theme, 5%), 70%);
|
||||
@color-green-theme_2-hover: fadeout(lighten(@color-green-theme, 10%), 80%);
|
||||
@color-green-theme_2-active: fadeout(lighten(@color-green-theme, 10%), 70%);
|
||||
@color-green-theme_2-font: darken(@color-green-theme_2, 70%);
|
||||
@color-green-theme_2-font-label: fadeout(@color-green-theme_2-font, 50%);
|
||||
@color-green-theme_2-line: lighten(@color-green-theme, 35%);
|
||||
@color-green-theme_2-font-label: fadeout(@color-green-theme_2-font, 40%);
|
||||
@color-green-theme_2-line: lighten(@color-green-theme, 45%);
|
||||
@color-green-theme-sidebar: @color-green-theme;
|
||||
@color-green-btn: fadeout(darken(@color-green-theme, 5%), 15%);
|
||||
@color-green-btn: lighten(@color-green-theme, 5%);
|
||||
@color-green-btn-background: fadeout(lighten(@color-green-theme, 35%), 70%);
|
||||
@color-green-pagination-background: fadeout(lighten(@color-green-theme, 45%), 30%);
|
||||
@color-green-pagination-hover: fadeout(lighten(@color-green-theme, 10%), 70%);
|
||||
@@ -91,15 +104,28 @@
|
||||
@color-green-player-progress-bar1: darken(@color-green-theme_2, 12%);
|
||||
@color-green-player-progress-bar2: lighten(@color-green-theme, 12%);
|
||||
@color-green-player-status-text: lighten(@color-green-theme_2-font, 10%);
|
||||
@color-green-player-detail-play-btn: lighten(@color-green-theme, 7%);
|
||||
@color-green-tab-btn-background: fadeout(lighten(@color-green-theme, 10%), 80%);
|
||||
@color-green-tab-btn-background-hover: @color-green-theme_2-hover;
|
||||
@color-green-tab-border-top: fadeout(lighten(@color-green-theme, 5%), 50%);
|
||||
@color-green-tab-border-bottom: lighten(@color-green-theme, 5%);
|
||||
@color-green-hideBtn: #3bc2b2;
|
||||
@color-green-minBtn: #85c43b;
|
||||
@color-green-maxBtn: #e7aa36;
|
||||
@color-green-closeBtn: #ea6e4d;
|
||||
@color-green-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-green-minBtn-hover: fadeout(@color-green-minBtn, 10%);
|
||||
@color-green-maxBtn-hover: fadeout(@color-green-maxBtn, 10%);
|
||||
@color-green-closeBtn-hover: fadeout(@color-green-closeBtn, 10%);
|
||||
@color-green-badge-success: lighten(@color-green-theme, 7%);
|
||||
@color-green-badge-success-font: #fff;
|
||||
@color-green-badge-info: #66a2bd;
|
||||
@color-green-badge-info-font: #fff;
|
||||
|
||||
|
||||
@color-yellow-theme: #f2d35b;
|
||||
@color-yellow-theme: #e9d460;
|
||||
@color-yellow-theme-bgimg: none;
|
||||
@color-yellow-theme-bgposition: center center;
|
||||
@color-yellow-theme-bgposition: center;
|
||||
@color-yellow-theme-bgsize: auto auto;
|
||||
@color-yellow-theme-hover: fadeout(lighten(@color-yellow-theme, 10%), 30%);
|
||||
@color-yellow-theme-active: fadeout(darken(@color-yellow-theme, 20%), 60%);
|
||||
@@ -109,36 +135,49 @@
|
||||
@color-yellow-theme_2-background_1: #fff;
|
||||
@color-yellow-theme_2-background_2: fadeout(@color-yellow-theme_2-background_1, 2%);
|
||||
@color-yellow-theme_2-hover: fadeout(lighten(@color-yellow-theme, 10%), 70%);
|
||||
@color-yellow-theme_2-active: fadeout(darken(@color-yellow-theme, 5%), 70%);
|
||||
@color-yellow-theme_2-active: fadeout(lighten(@color-yellow-theme, 10%), 60%);
|
||||
@color-yellow-theme_2-font: darken(@color-yellow-theme_2, 70%);
|
||||
@color-yellow-theme_2-font-label: fadeout(@color-yellow-theme_2-font, 50%);
|
||||
@color-yellow-theme_2-line: lighten(@color-yellow-theme, 35%);
|
||||
@color-yellow-theme_2-font-label: fadeout(@color-yellow-theme_2-font, 40%);
|
||||
@color-yellow-theme_2-line: lighten(@color-yellow-theme, 28%);
|
||||
@color-yellow-theme-sidebar: @color-yellow-theme;
|
||||
@color-yellow-btn: fadeout(darken(@color-yellow-theme, 5%), 15%);
|
||||
@color-yellow-btn-background: fadeout(lighten(@color-yellow-theme, 25%), 70%);
|
||||
@color-yellow-btn: darken(@color-yellow-theme, 5%);
|
||||
@color-yellow-btn-background: fadeout(lighten(@color-yellow-theme, 25%), 60%);
|
||||
@color-yellow-pagination-background: fadeout(lighten(@color-yellow-theme, 30%), 30%);
|
||||
@color-yellow-pagination-hover: fadeout(lighten(@color-yellow-theme, 5%), 70%);
|
||||
@color-yellow-pagination-active: fadeout(darken(@color-yellow-theme, 5%), 70%);
|
||||
@color-yellow-pagination-select: fadeout(lighten(@color-yellow-theme, 5%), 50%);
|
||||
@color-yellow-search-form-background: fadeout(lighten(@color-yellow-theme, 35%), 10%);
|
||||
@color-yellow-search-list-hover: fadeout(darken(@color-yellow-theme, 10%), 70%);
|
||||
@color-yellow-scrollbar-track: fadeout(@color-yellow-theme, 80%);
|
||||
@color-yellow-scrollbar-thumb: fadeout(@color-yellow-theme, 60%);
|
||||
@color-yellow-scrollbar-thumb-hover: fadeout(@color-yellow-theme, 40%);
|
||||
@color-yellow-search-form-background: fadeout(lighten(@color-yellow-theme, 25%), 10%);
|
||||
@color-yellow-search-list-hover: fadeout(darken(@color-yellow-theme, 10%), 60%);
|
||||
@color-yellow-scrollbar-track: fadeout(@color-yellow-theme, 60%);
|
||||
@color-yellow-scrollbar-thumb: fadeout(@color-yellow-theme, 45%);
|
||||
@color-yellow-scrollbar-thumb-hover: fadeout(@color-yellow-theme, 30%);
|
||||
@color-yellow-player-pic-c1: fadeout(@color-yellow-theme_2, 50%);
|
||||
@color-yellow-player-pic-c2: darken(@color-yellow-theme_2, 30%);
|
||||
@color-yellow-player-progress: darken(@color-yellow-theme_2, 6%);
|
||||
@color-yellow-player-progress-bar1: darken(@color-yellow-theme_2, 12%);
|
||||
@color-yellow-player-progress-bar2: lighten(@color-yellow-theme, 12%);
|
||||
@color-yellow-player-progress-bar2: lighten(@color-yellow-theme, 2%);
|
||||
@color-yellow-player-status-text: lighten(@color-yellow-theme_2-font, 10%);
|
||||
@color-yellow-tab-btn-background: fadeout(lighten(@color-yellow-theme, 10%), 80%);
|
||||
@color-yellow-player-detail-play-btn: lighten(@color-yellow-theme, 7%);
|
||||
@color-yellow-tab-btn-background: fadeout(lighten(@color-yellow-theme, 10%), 70%);
|
||||
@color-yellow-tab-btn-background-hover: @color-yellow-theme_2-hover;
|
||||
@color-yellow-tab-border-top: fadeout(lighten(@color-yellow-theme, 5%), 50%);
|
||||
@color-yellow-tab-border-bottom: lighten(@color-yellow-theme, 5%);
|
||||
@color-yellow-tab-border-top: fadeout(lighten(@color-yellow-theme, 5%), 40%);
|
||||
@color-yellow-tab-border-bottom: @color-yellow-theme;
|
||||
@color-yellow-hideBtn: #3bc2b2;
|
||||
@color-yellow-minBtn: #85c43b;
|
||||
@color-yellow-maxBtn: #e7aa36;
|
||||
@color-yellow-closeBtn: #ea6e4d;
|
||||
@color-yellow-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-yellow-minBtn-hover: fadeout(@color-yellow-minBtn, 10%);
|
||||
@color-yellow-maxBtn-hover: fadeout(@color-yellow-maxBtn, 10%);
|
||||
@color-yellow-closeBtn-hover: fadeout(@color-yellow-closeBtn, 10%);
|
||||
@color-yellow-badge-success: lighten(@color-yellow-theme, 10%);
|
||||
@color-yellow-badge-success-font: #fff;
|
||||
@color-yellow-badge-info: #7cd295;
|
||||
@color-yellow-badge-info-font: #fff;
|
||||
|
||||
@color-orange-theme: #f5ab35;
|
||||
@color-orange-theme-bgimg: none;
|
||||
@color-orange-theme-bgposition: center center;
|
||||
@color-orange-theme-bgposition: center;
|
||||
@color-orange-theme-bgsize: auto auto;
|
||||
@color-orange-theme-hover: fadeout(lighten(@color-orange-theme, 10%), 30%);
|
||||
@color-orange-theme-active: fadeout(darken(@color-orange-theme, 20%), 60%);
|
||||
@@ -147,19 +186,19 @@
|
||||
@color-orange-theme_2: #fff;
|
||||
@color-orange-theme_2-background_1: #fff;
|
||||
@color-orange-theme_2-background_2: fadeout(@color-orange-theme_2-background_1, 2%);
|
||||
@color-orange-theme_2-hover: fadeout(lighten(@color-orange-theme, 10%), 70%);
|
||||
@color-orange-theme_2-hover: fadeout(darken(@color-orange-theme, 5%), 80%);
|
||||
@color-orange-theme_2-active: fadeout(darken(@color-orange-theme, 5%), 70%);
|
||||
@color-orange-theme_2-font: darken(@color-orange-theme_2, 70%);
|
||||
@color-orange-theme_2-font-label: fadeout(@color-orange-theme_2-font, 50%);
|
||||
@color-orange-theme_2-line: lighten(@color-orange-theme, 35%);
|
||||
@color-orange-theme_2-font-label: fadeout(@color-orange-theme_2-font, 40%);
|
||||
@color-orange-theme_2-line: lighten(@color-orange-theme, 36%);
|
||||
@color-orange-theme-sidebar: @color-orange-theme;
|
||||
@color-orange-btn: fadeout(darken(@color-orange-theme, 5%), 15%);
|
||||
@color-orange-btn-background: fadeout(lighten(@color-orange-theme, 35%), 70%);
|
||||
@color-orange-pagination-background: fadeout(lighten(@color-orange-theme, 35%), 30%);
|
||||
@color-orange-btn: lighten(@color-orange-theme, 5%);
|
||||
@color-orange-btn-background: fadeout(lighten(@color-orange-theme, 25%), 60%);
|
||||
@color-orange-pagination-background: fadeout(lighten(@color-orange-theme, 25%), 40%);
|
||||
@color-orange-pagination-hover: fadeout(lighten(@color-orange-theme, 10%), 70%);
|
||||
@color-orange-pagination-active: fadeout(darken(@color-orange-theme, 10%), 70%);
|
||||
@color-orange-pagination-select: fadeout(lighten(@color-orange-theme, 10%), 50%);
|
||||
@color-orange-search-form-background: fadeout(lighten(@color-orange-theme, 35%), 10%);
|
||||
@color-orange-search-form-background: fadeout(lighten(@color-orange-theme, 30%), 10%);
|
||||
@color-orange-search-list-hover: fadeout(darken(@color-orange-theme, 10%), 70%);
|
||||
@color-orange-scrollbar-track: fadeout(@color-orange-theme, 80%);
|
||||
@color-orange-scrollbar-thumb: fadeout(@color-orange-theme, 60%);
|
||||
@@ -170,14 +209,27 @@
|
||||
@color-orange-player-progress-bar1: darken(@color-orange-theme_2, 12%);
|
||||
@color-orange-player-progress-bar2: lighten(@color-orange-theme, 12%);
|
||||
@color-orange-player-status-text: lighten(@color-orange-theme_2-font, 10%);
|
||||
@color-orange-player-detail-play-btn: lighten(@color-orange-theme, 7%);
|
||||
@color-orange-tab-btn-background: fadeout(lighten(@color-orange-theme, 10%), 80%);
|
||||
@color-orange-tab-btn-background-hover: @color-orange-theme_2-hover;
|
||||
@color-orange-tab-border-top: fadeout(lighten(@color-orange-theme, 5%), 50%);
|
||||
@color-orange-tab-border-bottom: lighten(@color-orange-theme, 5%);
|
||||
@color-orange-hideBtn: #3bc2b2;
|
||||
@color-orange-minBtn: #85c43b;
|
||||
@color-orange-maxBtn: #e7aa36;
|
||||
@color-orange-closeBtn: #ea6e4d;
|
||||
@color-orange-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-orange-minBtn-hover: fadeout(@color-orange-minBtn, 10%);
|
||||
@color-orange-maxBtn-hover: fadeout(@color-orange-maxBtn, 10%);
|
||||
@color-orange-closeBtn-hover: fadeout(@color-orange-closeBtn, 10%);
|
||||
@color-orange-badge-success: lighten(@color-orange-theme, 10%);
|
||||
@color-orange-badge-success-font: #fff;
|
||||
@color-orange-badge-info: #9ed458;
|
||||
@color-orange-badge-info-font: #fff;
|
||||
|
||||
@color-blue-theme: #3498db;
|
||||
@color-blue-theme-bgimg: none;
|
||||
@color-blue-theme-bgposition: center center;
|
||||
@color-blue-theme-bgposition: center;
|
||||
@color-blue-theme-bgsize: auto auto;
|
||||
@color-blue-theme-hover: fadeout(lighten(@color-blue-theme, 10%), 30%);
|
||||
@color-blue-theme-active: fadeout(darken(@color-blue-theme, 20%), 60%);
|
||||
@@ -186,14 +238,14 @@
|
||||
@color-blue-theme_2: #fff;
|
||||
@color-blue-theme_2-background_1: #fff;
|
||||
@color-blue-theme_2-background_2: fadeout(@color-blue-theme_2-background_1, 2%);
|
||||
@color-blue-theme_2-hover: fadeout(lighten(@color-blue-theme, 10%), 70%);
|
||||
@color-blue-theme_2-active: fadeout(darken(@color-blue-theme, 5%), 70%);
|
||||
@color-blue-theme_2-hover: fadeout(lighten(@color-blue-theme, 10%), 80%);
|
||||
@color-blue-theme_2-active: fadeout(lighten(@color-blue-theme, 10%), 70%);
|
||||
@color-blue-theme_2-font: darken(@color-blue-theme_2, 70%);
|
||||
@color-blue-theme_2-font-label: fadeout(@color-blue-theme_2-font, 50%);
|
||||
@color-blue-theme_2-line: lighten(@color-blue-theme, 35%);
|
||||
@color-blue-theme_2-font-label: fadeout(@color-blue-theme_2-font, 40%);
|
||||
@color-blue-theme_2-line: lighten(@color-blue-theme, 42%);
|
||||
@color-blue-theme-sidebar: @color-blue-theme;
|
||||
@color-blue-btn: fadeout(darken(@color-blue-theme, 5%), 15%);
|
||||
@color-blue-btn-background: fadeout(lighten(@color-blue-theme, 35%), 70%);
|
||||
@color-blue-btn: lighten(@color-blue-theme, 5%);
|
||||
@color-blue-btn-background: fadeout(lighten(@color-blue-theme, 35%), 50%);
|
||||
@color-blue-pagination-background: fadeout(lighten(@color-blue-theme, 40%), 30%);
|
||||
@color-blue-pagination-hover: fadeout(lighten(@color-blue-theme, 15%), 70%);
|
||||
@color-blue-pagination-active: fadeout(darken(@color-blue-theme, 15%), 70%);
|
||||
@@ -209,29 +261,42 @@
|
||||
@color-blue-player-progress-bar1: darken(@color-blue-theme_2, 12%);
|
||||
@color-blue-player-progress-bar2: lighten(@color-blue-theme, 12%);
|
||||
@color-blue-player-status-text: lighten(@color-blue-theme_2-font, 10%);
|
||||
@color-blue-player-detail-play-btn: lighten(@color-blue-theme, 7%);
|
||||
@color-blue-tab-btn-background: fadeout(lighten(@color-blue-theme, 10%), 80%);
|
||||
@color-blue-tab-btn-background-hover: @color-blue-theme_2-hover;
|
||||
@color-blue-tab-border-top: fadeout(lighten(@color-blue-theme, 5%), 50%);
|
||||
@color-blue-tab-border-bottom: lighten(@color-blue-theme, 5%);
|
||||
@color-blue-hideBtn: #3bc2b2;
|
||||
@color-blue-minBtn: #85c43b;
|
||||
@color-blue-maxBtn: #e7aa36;
|
||||
@color-blue-closeBtn: #ea6e4d;
|
||||
@color-blue-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-blue-minBtn-hover: fadeout(@color-blue-minBtn, 10%);
|
||||
@color-blue-maxBtn-hover: fadeout(@color-blue-maxBtn, 10%);
|
||||
@color-blue-closeBtn-hover: fadeout(@color-blue-closeBtn, 10%);
|
||||
@color-blue-badge-success: #5cbf9b;
|
||||
@color-blue-badge-success-font: #fff;
|
||||
@color-blue-badge-info: lighten(@color-blue-theme, 10%);
|
||||
@color-blue-badge-info-font: #fff;
|
||||
|
||||
@color-red-theme: #d64541;
|
||||
@color-red-theme-bgimg: none;
|
||||
@color-red-theme-bgposition: center center;
|
||||
@color-red-theme-bgposition: center;
|
||||
@color-red-theme-bgsize: auto auto;
|
||||
@color-red-theme-hover: fadeout(lighten(@color-red-theme, 10%), 30%);
|
||||
@color-red-theme-active: fadeout(darken(@color-red-theme, 20%), 60%);
|
||||
@color-red-theme-font: #fff;
|
||||
@color-red-theme-font-label: lighten(@color-red-theme, 35%);
|
||||
@color-red-theme_2: #fff;
|
||||
@color-red-theme_2-hover: fadeout(lighten(@color-red-theme, 10%), 70%);
|
||||
@color-red-theme_2-active: fadeout(darken(@color-red-theme, 5%), 70%);
|
||||
@color-red-theme_2-hover: fadeout(lighten(@color-red-theme, 10%), 80%);
|
||||
@color-red-theme_2-active: fadeout(lighten(@color-red-theme, 10%), 70%);
|
||||
@color-red-theme_2-background_1: #fff;
|
||||
@color-red-theme_2-background_2: fadeout(@color-red-theme_2-background_1, 2%);
|
||||
@color-red-theme_2-font: darken(@color-red-theme_2, 70%);
|
||||
@color-red-theme_2-font-label: fadeout(@color-red-theme_2-font, 50%);
|
||||
@color-red-theme_2-line: lighten(@color-red-theme, 35%);
|
||||
@color-red-theme_2-font-label: fadeout(@color-red-theme_2-font, 40%);
|
||||
@color-red-theme_2-line: lighten(@color-red-theme, 42%);
|
||||
@color-red-theme-sidebar: @color-red-theme;
|
||||
@color-red-btn: fadeout(darken(@color-red-theme, 5%), 15%);
|
||||
@color-red-btn: lighten(@color-red-theme, 5%);
|
||||
@color-red-btn-background: fadeout(lighten(@color-red-theme, 35%), 70%);
|
||||
@color-red-pagination-background: fadeout(lighten(@color-red-theme, 40%), 30%);
|
||||
@color-red-pagination-hover: fadeout(lighten(@color-red-theme, 15%), 70%);
|
||||
@@ -248,16 +313,81 @@
|
||||
@color-red-player-progress-bar1: darken(@color-red-theme_2, 12%);
|
||||
@color-red-player-progress-bar2: lighten(@color-red-theme, 12%);
|
||||
@color-red-player-status-text: lighten(@color-red-theme_2-font, 10%);
|
||||
@color-red-player-detail-play-btn: lighten(@color-red-theme, 7%);
|
||||
@color-red-tab-border-top: fadeout(lighten(@color-red-theme, 25%), 70%);
|
||||
@color-red-tab-border-bottom: lighten(@color-red-theme, 35%);
|
||||
@color-red-tab-btn-background: fadeout(lighten(@color-red-theme, 10%), 80%);
|
||||
@color-red-tab-btn-background-hover: @color-red-theme_2-hover;
|
||||
@color-red-tab-border-top: fadeout(lighten(@color-red-theme, 5%), 50%);
|
||||
@color-red-tab-border-bottom: lighten(@color-red-theme, 5%);
|
||||
@color-red-hideBtn: #3bc2b2;
|
||||
@color-red-minBtn: #85c43b;
|
||||
@color-red-maxBtn: #e7aa36;
|
||||
@color-red-closeBtn: #ea6e4d;
|
||||
@color-red-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-red-minBtn-hover: fadeout(@color-red-minBtn, 10%);
|
||||
@color-red-maxBtn-hover: fadeout(@color-red-maxBtn, 10%);
|
||||
@color-red-closeBtn-hover: fadeout(@color-red-closeBtn, 10%);
|
||||
@color-red-badge-success: lighten(@color-red-theme, 10%);
|
||||
@color-red-badge-success-font: #fff;
|
||||
@color-red-badge-info: #dfbb6b;
|
||||
@color-red-badge-info-font: #fff;
|
||||
|
||||
@color-pink-theme: #f1828d;
|
||||
@color-pink-theme-bgimg: none;
|
||||
@color-pink-theme-bgposition: center;
|
||||
@color-pink-theme-bgsize: auto auto;
|
||||
@color-pink-theme-hover: fadeout(lighten(@color-pink-theme, 10%), 30%);
|
||||
@color-pink-theme-active: fadeout(darken(@color-pink-theme, 20%), 60%);
|
||||
@color-pink-theme-font: #fff;
|
||||
@color-pink-theme-font-label: lighten(@color-pink-theme, 35%);
|
||||
@color-pink-theme_2: #fff;
|
||||
@color-pink-theme_2-background_1: #fff;
|
||||
@color-pink-theme_2-background_2: fadeout(@color-pink-theme_2-background_1, 2%);
|
||||
@color-pink-theme_2-hover: fadeout(lighten(@color-pink-theme, 10%), 75%);
|
||||
@color-pink-theme_2-active: fadeout(lighten(@color-pink-theme, 10%), 60%);
|
||||
@color-pink-theme_2-font: darken(@color-pink-theme_2, 70%);
|
||||
@color-pink-theme_2-font-label: fadeout(@color-pink-theme_2-font, 40%);
|
||||
@color-pink-theme_2-line: lighten(@color-pink-theme, 25%);
|
||||
@color-pink-theme-sidebar: @color-pink-theme;
|
||||
@color-pink-btn: darken(@color-pink-theme, 3%);
|
||||
@color-pink-btn-background: fadeout(lighten(@color-pink-theme, 20%), 50%);
|
||||
@color-pink-pagination-background: fadeout(lighten(@color-pink-theme, 23%), 25%);
|
||||
@color-pink-pagination-hover: fadeout(lighten(@color-pink-theme, 5%), 70%);
|
||||
@color-pink-pagination-active: fadeout(darken(@color-pink-theme, 5%), 70%);
|
||||
@color-pink-pagination-select: fadeout(lighten(@color-pink-theme, 5%), 50%);
|
||||
@color-pink-search-form-background: fadeout(lighten(@color-pink-theme, 20%), 10%);
|
||||
@color-pink-search-list-hover: fadeout(darken(@color-pink-theme, 10%), 60%);
|
||||
@color-pink-scrollbar-track: fadeout(@color-pink-theme, 60%);
|
||||
@color-pink-scrollbar-thumb: fadeout(@color-pink-theme, 45%);
|
||||
@color-pink-scrollbar-thumb-hover: fadeout(@color-pink-theme, 30%);
|
||||
@color-pink-player-pic-c1: fadeout(@color-pink-theme_2, 50%);
|
||||
@color-pink-player-pic-c2: darken(@color-pink-theme_2, 30%);
|
||||
@color-pink-player-progress: darken(@color-pink-theme_2, 6%);
|
||||
@color-pink-player-progress-bar1: darken(@color-pink-theme_2, 12%);
|
||||
@color-pink-player-progress-bar2: lighten(@color-pink-theme, 2%);
|
||||
@color-pink-player-status-text: lighten(@color-pink-theme_2-font, 10%);
|
||||
@color-pink-player-detail-play-btn: lighten(@color-pink-theme, 7%);
|
||||
@color-pink-tab-btn-background: fadeout(lighten(@color-pink-theme, 10%), 70%);
|
||||
@color-pink-tab-btn-background-hover: @color-pink-theme_2-hover;
|
||||
@color-pink-tab-border-top: fadeout(lighten(@color-pink-theme, 5%), 40%);
|
||||
@color-pink-tab-border-bottom: @color-pink-theme;
|
||||
@color-pink-hideBtn: #3bc2b2;
|
||||
@color-pink-minBtn: #85c43b;
|
||||
@color-pink-maxBtn: #e7aa36;
|
||||
@color-pink-closeBtn: #ea6e4d;
|
||||
@color-pink-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-pink-minBtn-hover: fadeout(@color-pink-minBtn, 10%);
|
||||
@color-pink-maxBtn-hover: fadeout(@color-pink-maxBtn, 10%);
|
||||
@color-pink-closeBtn-hover: fadeout(@color-pink-closeBtn, 10%);
|
||||
@color-pink-badge-success: lighten(@color-pink-theme, 10%);
|
||||
@color-pink-badge-success-font: #fff;
|
||||
@color-pink-badge-info: #f5b684;
|
||||
@color-pink-badge-info-font: #fff;
|
||||
|
||||
@color-purple-theme: #9b59b6;
|
||||
@color-purple-theme-bgimg: none;
|
||||
@color-purple-theme-bgposition: center center;
|
||||
@color-purple-theme-bgposition: center;
|
||||
@color-purple-theme-bgsize: auto auto;
|
||||
@color-purple-theme-hover: fadeout(lighten(@color-purple-theme, 10%), 30%);
|
||||
@color-purple-theme-active: fadeout(darken(@color-purple-theme, 20%), 60%);
|
||||
@@ -266,13 +396,13 @@
|
||||
@color-purple-theme_2: #fff;
|
||||
@color-purple-theme_2-background_1: #fff;
|
||||
@color-purple-theme_2-background_2: fadeout(@color-purple-theme_2-background_1, 2%);
|
||||
@color-purple-theme_2-hover: fadeout(lighten(@color-purple-theme, 10%), 70%);
|
||||
@color-purple-theme_2-active: fadeout(darken(@color-purple-theme, 5%), 70%);
|
||||
@color-purple-theme_2-hover: fadeout(lighten(@color-purple-theme, 10%), 80%);
|
||||
@color-purple-theme_2-active: fadeout(lighten(@color-purple-theme, 10%), 70%);
|
||||
@color-purple-theme_2-font: darken(@color-purple-theme_2, 70%);
|
||||
@color-purple-theme_2-font-label: fadeout(@color-purple-theme_2-font, 50%);
|
||||
@color-purple-theme_2-line: lighten(@color-purple-theme, 35%);
|
||||
@color-purple-theme_2-font-label: fadeout(@color-purple-theme_2-font, 40%);
|
||||
@color-purple-theme_2-line: lighten(@color-purple-theme, 43%);
|
||||
@color-purple-theme-sidebar: @color-purple-theme;
|
||||
@color-purple-btn: fadeout(darken(@color-purple-theme, 5%), 15%);
|
||||
@color-purple-btn: lighten(@color-purple-theme, 5%);
|
||||
@color-purple-btn-background: fadeout(lighten(@color-purple-theme, 35%), 70%);
|
||||
@color-purple-pagination-background: fadeout(lighten(@color-purple-theme, 40%), 30%);
|
||||
@color-purple-pagination-hover: fadeout(lighten(@color-purple-theme, 15%), 70%);
|
||||
@@ -289,14 +419,27 @@
|
||||
@color-purple-player-progress-bar1: darken(@color-purple-theme_2, 12%);
|
||||
@color-purple-player-progress-bar2: lighten(@color-purple-theme, 12%);
|
||||
@color-purple-player-status-text: lighten(@color-purple-theme_2-font, 10%);
|
||||
@color-purple-player-detail-play-btn: lighten(@color-purple-theme, 7%);
|
||||
@color-purple-tab-btn-background: fadeout(lighten(@color-purple-theme, 10%), 80%);
|
||||
@color-purple-tab-btn-background-hover: @color-purple-theme_2-hover;
|
||||
@color-purple-tab-border-top: fadeout(lighten(@color-purple-theme, 5%), 50%);
|
||||
@color-purple-tab-border-bottom: lighten(@color-purple-theme, 5%);
|
||||
@color-purple-hideBtn: #3bc2b2;
|
||||
@color-purple-minBtn: #85c43b;
|
||||
@color-purple-maxBtn: #e7aa36;
|
||||
@color-purple-closeBtn: #ea6e4d;
|
||||
@color-purple-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-purple-minBtn-hover: fadeout(@color-purple-minBtn, 10%);
|
||||
@color-purple-maxBtn-hover: fadeout(@color-purple-maxBtn, 10%);
|
||||
@color-purple-closeBtn-hover: fadeout(@color-purple-closeBtn, 10%);
|
||||
@color-purple-badge-success: lighten(@color-purple-theme, 15%);
|
||||
@color-purple-badge-success-font: #fff;
|
||||
@color-purple-badge-info: #e5a39f;
|
||||
@color-purple-badge-info-font: #fff;
|
||||
|
||||
@color-grey-theme: #6c7a89;
|
||||
@color-grey-theme-bgimg: none;
|
||||
@color-grey-theme-bgposition: center center;
|
||||
@color-grey-theme-bgposition: center;
|
||||
@color-grey-theme-bgsize: auto auto;
|
||||
@color-grey-theme-hover: fadeout(lighten(@color-grey-theme, 10%), 30%);
|
||||
@color-grey-theme-active: fadeout(darken(@color-grey-theme, 20%), 60%);
|
||||
@@ -305,13 +448,13 @@
|
||||
@color-grey-theme_2: #fff;
|
||||
@color-grey-theme_2-background_1: #fff;
|
||||
@color-grey-theme_2-background_2: fadeout(@color-grey-theme_2-background_1, 2%);
|
||||
@color-grey-theme_2-hover: fadeout(lighten(@color-grey-theme, 10%), 70%);
|
||||
@color-grey-theme_2-active: fadeout(darken(@color-grey-theme, 5%), 70%);
|
||||
@color-grey-theme_2-hover: fadeout(lighten(@color-grey-theme, 10%), 80%);
|
||||
@color-grey-theme_2-active: fadeout(lighten(@color-grey-theme, 10%), 70%);
|
||||
@color-grey-theme_2-font: darken(@color-grey-theme_2, 70%);
|
||||
@color-grey-theme_2-font-label: fadeout(@color-grey-theme_2-font, 50%);
|
||||
@color-grey-theme_2-line: lighten(@color-grey-theme, 35%);
|
||||
@color-grey-theme_2-font-label: fadeout(@color-grey-theme_2-font, 40%);
|
||||
@color-grey-theme_2-line: lighten(@color-grey-theme, 47%);
|
||||
@color-grey-theme-sidebar: @color-grey-theme;
|
||||
@color-grey-btn: fadeout(darken(@color-grey-theme, 5%), 15%);
|
||||
@color-grey-btn: lighten(@color-grey-theme, 5%);
|
||||
@color-grey-btn-background: fadeout(lighten(@color-grey-theme, 35%), 70%);
|
||||
@color-grey-pagination-background: fadeout(lighten(@color-grey-theme, 45%), 30%);
|
||||
@color-grey-pagination-hover: fadeout(lighten(@color-grey-theme, 10%), 70%);
|
||||
@@ -328,92 +471,239 @@
|
||||
@color-grey-player-progress-bar1: darken(@color-grey-theme_2, 12%);
|
||||
@color-grey-player-progress-bar2: lighten(@color-grey-theme, 12%);
|
||||
@color-grey-player-status-text: lighten(@color-grey-theme_2-font, 10%);
|
||||
@color-grey-player-detail-play-btn: lighten(@color-grey-theme, 7%);
|
||||
@color-grey-tab-btn-background: fadeout(lighten(@color-grey-theme, 10%), 80%);
|
||||
@color-grey-tab-btn-background-hover: @color-grey-theme_2-hover;
|
||||
@color-grey-tab-border-top: fadeout(lighten(@color-grey-theme, 5%), 50%);
|
||||
@color-grey-tab-border-bottom: lighten(@color-grey-theme, 5%);
|
||||
@color-grey-hideBtn: #3bc2b2;
|
||||
@color-grey-minBtn: #85c43b;
|
||||
@color-grey-maxBtn: #e7aa36;
|
||||
@color-grey-closeBtn: #ea6e4d;
|
||||
@color-grey-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-grey-minBtn-hover: fadeout(@color-grey-minBtn, 10%);
|
||||
@color-grey-maxBtn-hover: fadeout(@color-grey-maxBtn, 10%);
|
||||
@color-grey-closeBtn-hover: fadeout(@color-grey-closeBtn, 10%);
|
||||
@color-grey-badge-success: lighten(@color-grey-theme, 15%);
|
||||
@color-grey-badge-success-font: #fff;
|
||||
@color-grey-badge-info: #b19b9f;
|
||||
@color-grey-badge-info-font: #fff;
|
||||
|
||||
@color-midAutumn-theme: rgba(74, 55, 82, 1);
|
||||
@color-midAutumn-theme-bgimg: url(../images/jqbg.jpg);
|
||||
@color-midAutumn-theme-bgposition: center center;
|
||||
@color-midAutumn-theme-bgsize: auto 100%;
|
||||
@color-midAutumn-theme-hover: fadeout(lighten(@color-midAutumn-theme, 10%), 30%);
|
||||
@color-midAutumn-theme-active: fadeout(lighten(@color-midAutumn-theme, 15%), 60%);
|
||||
@color-midAutumn-theme-font: rgba(246, 233, 255, 0.9);
|
||||
@color-midAutumn-theme-font-label: fadeout(lighten(@color-midAutumn-theme, 20%), 20%);
|
||||
@color-midAutumn-theme_2: rgba(255, 255, 255, .93);
|
||||
@color-midAutumn-theme_2-background_1: #eeedef;
|
||||
@color-midAutumn-theme_2-background_2: fadeout(@color-midAutumn-theme_2-background_1, 2%);
|
||||
@color-midAutumn-theme_2-hover: fadeout(lighten(@color-midAutumn-theme, 10%), 65%);
|
||||
@color-midAutumn-theme_2-active: fadeout(darken(@color-midAutumn-theme, 5%), 70%);
|
||||
@color-midAutumn-theme_2-font: darken(@color-midAutumn-theme_2, 70%);
|
||||
@color-midAutumn-theme_2-font-label: lighten(@color-midAutumn-theme, 40%);
|
||||
@color-midAutumn-theme_2-line: lighten(@color-midAutumn-theme, 54%);
|
||||
@color-midAutumn-theme-sidebar: rgba(255, 255, 255, 0);
|
||||
@color-midAutumn-btn: fadeout(darken(@color-midAutumn-theme, 5%), 15%);
|
||||
@color-midAutumn-btn-background: fadeout(lighten(@color-midAutumn-theme, 35%), 70%);
|
||||
@color-midAutumn-pagination-background: fadeout(lighten(@color-midAutumn-theme, 45%), 50%);
|
||||
@color-midAutumn-pagination-hover: fadeout(lighten(@color-midAutumn-theme, 10%), 70%);
|
||||
@color-midAutumn-pagination-active: fadeout(darken(@color-midAutumn-theme, 10%), 70%);
|
||||
@color-midAutumn-pagination-select: fadeout(lighten(@color-midAutumn-theme, 10%), 55%);
|
||||
@color-midAutumn-search-form-background: fadeout(lighten(@color-midAutumn-theme, 50%), 10%);
|
||||
@color-midAutumn-search-list-hover: fadeout(darken(@color-midAutumn-theme, 10%), 70%);
|
||||
@color-midAutumn-scrollbar-track: fadeout(@color-midAutumn-theme, 80%);
|
||||
@color-midAutumn-scrollbar-thumb: fadeout(@color-midAutumn-theme, 60%);
|
||||
@color-midAutumn-scrollbar-thumb-hover: fadeout(@color-midAutumn-theme, 40%);
|
||||
@color-midAutumn-player-pic-c1: fadeout(@color-midAutumn-theme_2, 50%);
|
||||
@color-midAutumn-player-pic-c2: darken(@color-midAutumn-theme_2, 30%);
|
||||
@color-midAutumn-player-progress: darken(@color-midAutumn-theme_2, 6%);
|
||||
@color-midAutumn-player-progress-bar1: darken(@color-midAutumn-theme_2, 12%);
|
||||
@color-midAutumn-player-progress-bar2: lighten(@color-midAutumn-theme, 12%);
|
||||
@color-midAutumn-player-status-text: lighten(@color-midAutumn-theme_2-font, 10%);
|
||||
@color-midAutumn-tab-btn-background: fadeout(lighten(@color-midAutumn-theme, 10%), 80%);
|
||||
@color-midAutumn-tab-btn-background-hover: @color-midAutumn-theme_2-hover;
|
||||
@color-midAutumn-tab-border-top: fadeout(lighten(@color-midAutumn-theme, 5%), 50%);
|
||||
@color-midAutumn-tab-border-bottom: lighten(@color-midAutumn-theme, 5%);
|
||||
|
||||
@color-dhHyrz-theme: rgb(87, 144, 167);
|
||||
@color-dhHyrz-theme-bgimg: url(../images/hzwbg.jpeg);
|
||||
@color-dhHyrz-theme-bgposition: center center;
|
||||
@color-dhHyrz-theme-bgsize: auto 100%;
|
||||
@color-dhHyrz-theme-hover: fadeout(lighten(@color-dhHyrz-theme, 10%), 45%);
|
||||
@color-dhHyrz-theme-active: fadeout(lighten(@color-dhHyrz-theme, 15%), 60%);
|
||||
@color-dhHyrz-theme-font: rgba(67, 118, 148, 0.9);
|
||||
@color-dhHyrz-theme-font-label: fadeout(darken(@color-dhHyrz-theme, 20%), 20%);
|
||||
@color-dhHyrz-theme_2: rgba(255, 255, 255, 0.8);
|
||||
@color-dhHyrz-theme_2-background_1: #e9faff;
|
||||
@color-dhHyrz-theme_2-background_2: fadeout(@color-dhHyrz-theme_2-background_1, 2%);
|
||||
@color-dhHyrz-theme_2-hover: fadeout(lighten(@color-dhHyrz-theme, 10%), 65%);
|
||||
@color-dhHyrz-theme_2-active: fadeout(darken(@color-dhHyrz-theme, 5%), 70%);
|
||||
@color-dhHyrz-theme_2-font: darken(@color-dhHyrz-theme_2, 80%);
|
||||
@color-dhHyrz-theme_2-font-label: lighten(@color-dhHyrz-theme, 10%);
|
||||
@color-dhHyrz-theme_2-line: lighten(@color-dhHyrz-theme, 36%);
|
||||
@color-dhHyrz-theme-sidebar: rgba(255, 255, 255, .3);
|
||||
@color-dhHyrz-btn: fadeout(darken(@color-dhHyrz-theme, 5%), 15%);
|
||||
@color-dhHyrz-btn-background: fadeout(lighten(@color-dhHyrz-theme, 35%), 70%);
|
||||
@color-dhHyrz-pagination-background: fadeout(lighten(@color-dhHyrz-theme, 45%), 50%);
|
||||
@color-dhHyrz-pagination-hover: fadeout(lighten(@color-dhHyrz-theme, 10%), 70%);
|
||||
@color-dhHyrz-pagination-active: fadeout(darken(@color-dhHyrz-theme, 10%), 70%);
|
||||
@color-dhHyrz-pagination-select: fadeout(lighten(@color-dhHyrz-theme, 10%), 55%);
|
||||
@color-dhHyrz-search-form-background: fadeout(lighten(@color-dhHyrz-theme, 30%), 20%);
|
||||
@color-dhHyrz-search-list-hover: fadeout(darken(@color-dhHyrz-theme, 10%), 50%);
|
||||
@color-dhHyrz-scrollbar-track: fadeout(@color-dhHyrz-theme, 80%);
|
||||
@color-dhHyrz-scrollbar-thumb: fadeout(@color-dhHyrz-theme, 60%);
|
||||
@color-dhHyrz-scrollbar-thumb-hover: fadeout(@color-dhHyrz-theme, 40%);
|
||||
@color-dhHyrz-player-pic-c1: fadeout(@color-dhHyrz-theme_2, 50%);
|
||||
@color-dhHyrz-player-pic-c2: darken(@color-dhHyrz-theme_2, 30%);
|
||||
@color-dhHyrz-player-progress: darken(@color-dhHyrz-theme_2, 6%);
|
||||
@color-dhHyrz-player-progress-bar1: darken(@color-dhHyrz-theme_2, 12%);
|
||||
@color-dhHyrz-player-progress-bar2: lighten(@color-dhHyrz-theme, 12%);
|
||||
@color-dhHyrz-player-status-text: lighten(@color-dhHyrz-theme_2-font, 10%);
|
||||
@color-dhHyrz-tab-btn-background: fadeout(lighten(@color-dhHyrz-theme, 10%), 80%);
|
||||
@color-dhHyrz-tab-btn-background-hover: @color-dhHyrz-theme_2-hover;
|
||||
@color-dhHyrz-tab-border-top: fadeout(lighten(@color-dhHyrz-theme, 5%), 50%);
|
||||
@color-dhHyrz-tab-border-bottom: lighten(@color-dhHyrz-theme, 5%);
|
||||
@color-ming-theme: #336e7b;
|
||||
@color-ming-theme-bgimg: none;
|
||||
@color-ming-theme-bgposition: center;
|
||||
@color-ming-theme-bgsize: auto auto;
|
||||
@color-ming-theme-hover: fadeout(lighten(@color-ming-theme, 7%), 30%);
|
||||
@color-ming-theme-active: fadeout(darken(@color-ming-theme, 20%), 60%);
|
||||
@color-ming-theme-font: #fff;
|
||||
@color-ming-theme-font-label: lighten(@color-ming-theme, 35%);
|
||||
@color-ming-theme_2: #fff;
|
||||
@color-ming-theme_2-hover: fadeout(lighten(@color-ming-theme, 10%), 85%);
|
||||
@color-ming-theme_2-active: fadeout(lighten(@color-ming-theme, 10%), 75%);
|
||||
@color-ming-theme_2-background_1: #fff;
|
||||
@color-ming-theme_2-background_2: fadeout(@color-ming-theme_2-background_1, 2%);
|
||||
@color-ming-theme_2-font: darken(@color-ming-theme_2, 70%);
|
||||
@color-ming-theme_2-font-label: fadeout(@color-ming-theme_2-font, 40%);
|
||||
@color-ming-theme_2-line: lighten(@color-ming-theme, 60%);
|
||||
@color-ming-theme-sidebar: @color-ming-theme;
|
||||
@color-ming-btn: lighten(@color-ming-theme, 5%);
|
||||
@color-ming-btn-background: fadeout(lighten(@color-ming-theme, 35%), 75%);
|
||||
@color-ming-pagination-background: fadeout(lighten(@color-ming-theme, 50%), 35%);
|
||||
@color-ming-pagination-hover: fadeout(lighten(@color-ming-theme, 15%), 70%);
|
||||
@color-ming-pagination-active: fadeout(darken(@color-ming-theme, 15%), 70%);
|
||||
@color-ming-pagination-select: fadeout(lighten(@color-ming-theme, 15%), 50%);
|
||||
@color-ming-search-form-background: fadeout(lighten(@color-ming-theme, 45%), 15%);
|
||||
@color-ming-search-list-hover: fadeout(darken(@color-ming-theme, 10%), 70%);
|
||||
@color-ming-scrollbar-track: fadeout(@color-ming-theme, 80%);
|
||||
@color-ming-scrollbar-thumb: fadeout(@color-ming-theme, 60%);
|
||||
@color-ming-scrollbar-thumb-hover: fadeout(@color-ming-theme, 40%);
|
||||
@color-ming-player-pic-c1: fadeout(@color-ming-theme_2, 50%);
|
||||
@color-ming-player-pic-c2: darken(@color-ming-theme_2, 30%);
|
||||
@color-ming-player-progress: darken(@color-ming-theme_2, 6%);
|
||||
@color-ming-player-progress-bar1: darken(@color-ming-theme_2, 12%);
|
||||
@color-ming-player-progress-bar2: lighten(@color-ming-theme, 12%);
|
||||
@color-ming-player-status-text: lighten(@color-ming-theme_2-font, 10%);
|
||||
@color-ming-player-detail-play-btn: lighten(@color-ming-theme, 10%);
|
||||
@color-ming-tab-border-top: fadeout(lighten(@color-ming-theme, 25%), 70%);
|
||||
@color-ming-tab-border-bottom: lighten(@color-ming-theme, 35%);
|
||||
@color-ming-tab-btn-background: fadeout(lighten(@color-ming-theme, 10%), 80%);
|
||||
@color-ming-tab-btn-background-hover: @color-ming-theme_2-hover;
|
||||
@color-ming-tab-border-top: fadeout(lighten(@color-ming-theme, 5%), 50%);
|
||||
@color-ming-tab-border-bottom: lighten(@color-ming-theme, 5%);
|
||||
@color-ming-hideBtn: #3bc2b2;
|
||||
@color-ming-minBtn: #85c43b;
|
||||
@color-ming-maxBtn: #e7aa36;
|
||||
@color-ming-closeBtn: #ea6e4d;
|
||||
@color-ming-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-ming-minBtn-hover: fadeout(@color-ming-minBtn, 10%);
|
||||
@color-ming-maxBtn-hover: fadeout(@color-ming-maxBtn, 10%);
|
||||
@color-ming-closeBtn-hover: fadeout(@color-ming-closeBtn, 10%);
|
||||
@color-ming-badge-success: lighten(@color-ming-theme, 10%);
|
||||
@color-ming-badge-success-font: #fff;
|
||||
@color-ming-badge-info: #6376a2;
|
||||
@color-ming-badge-info-font: #fff;
|
||||
|
||||
@color-mid_autumn-theme: rgba(74, 55, 82, 1);
|
||||
@color-mid_autumn-theme-bgimg: url(../images/jqbg.jpg);
|
||||
@color-mid_autumn-theme-bgposition: center;
|
||||
@color-mid_autumn-theme-bgsize: auto 100%;
|
||||
@color-mid_autumn-theme-hover: fadeout(lighten(@color-mid_autumn-theme, 10%), 40%);
|
||||
@color-mid_autumn-theme-active: fadeout(lighten(@color-mid_autumn-theme, 15%), 60%);
|
||||
@color-mid_autumn-theme-font: rgba(246, 233, 255, 0.9);
|
||||
@color-mid_autumn-theme-font-label: fadeout(lighten(@color-mid_autumn-theme, 20%), 20%);
|
||||
@color-mid_autumn-theme_2: rgba(255, 255, 255, .93);
|
||||
@color-mid_autumn-theme_2-background_1: #eeedef;
|
||||
@color-mid_autumn-theme_2-background_2: fadeout(@color-mid_autumn-theme_2-background_1, 2%);
|
||||
@color-mid_autumn-theme_2-hover: fadeout(lighten(@color-mid_autumn-theme, 15%), 80%);
|
||||
@color-mid_autumn-theme_2-active: fadeout(lighten(@color-mid_autumn-theme, 15%), 70%);
|
||||
@color-mid_autumn-theme_2-font: darken(@color-mid_autumn-theme_2, 70%);
|
||||
@color-mid_autumn-theme_2-font-label: desaturate(lighten(@color-mid_autumn-theme, 30%), 45%);
|
||||
@color-mid_autumn-theme_2-line: lighten(@color-mid_autumn-theme, 63%);
|
||||
@color-mid_autumn-theme-sidebar: rgba(255, 255, 255, 0);
|
||||
@color-mid_autumn-btn: lighten(@color-mid_autumn-theme, 10%);
|
||||
@color-mid_autumn-btn-background: fadeout(lighten(@color-mid_autumn-theme, 35%), 70%);
|
||||
@color-mid_autumn-pagination-background: fadeout(lighten(@color-mid_autumn-theme, 45%), 50%);
|
||||
@color-mid_autumn-pagination-hover: fadeout(lighten(@color-mid_autumn-theme, 10%), 70%);
|
||||
@color-mid_autumn-pagination-active: fadeout(darken(@color-mid_autumn-theme, 10%), 70%);
|
||||
@color-mid_autumn-pagination-select: fadeout(lighten(@color-mid_autumn-theme, 10%), 55%);
|
||||
@color-mid_autumn-search-form-background: fadeout(lighten(@color-mid_autumn-theme, 50%), 10%);
|
||||
@color-mid_autumn-search-list-hover: fadeout(darken(@color-mid_autumn-theme, 10%), 70%);
|
||||
@color-mid_autumn-scrollbar-track: fadeout(@color-mid_autumn-theme, 80%);
|
||||
@color-mid_autumn-scrollbar-thumb: fadeout(@color-mid_autumn-theme, 60%);
|
||||
@color-mid_autumn-scrollbar-thumb-hover: fadeout(@color-mid_autumn-theme, 40%);
|
||||
@color-mid_autumn-player-pic-c1: fadeout(@color-mid_autumn-theme_2, 50%);
|
||||
@color-mid_autumn-player-pic-c2: darken(@color-mid_autumn-theme_2, 30%);
|
||||
@color-mid_autumn-player-progress: darken(@color-mid_autumn-theme_2, 10%);
|
||||
@color-mid_autumn-player-progress-bar1: darken(@color-mid_autumn-theme_2, 12%);
|
||||
@color-mid_autumn-player-progress-bar2: lighten(@color-mid_autumn-theme, 12%);
|
||||
@color-mid_autumn-player-status-text: lighten(@color-mid_autumn-theme_2-font, 10%);
|
||||
@color-mid_autumn-player-detail-play-btn: lighten(@color-mid_autumn-theme, 7%);
|
||||
@color-mid_autumn-tab-btn-background: fadeout(lighten(@color-mid_autumn-theme, 10%), 80%);
|
||||
@color-mid_autumn-tab-btn-background-hover: @color-mid_autumn-theme_2-hover;
|
||||
@color-mid_autumn-tab-border-top: fadeout(lighten(@color-mid_autumn-theme, 5%), 50%);
|
||||
@color-mid_autumn-tab-border-bottom: lighten(@color-mid_autumn-theme, 5%);
|
||||
@color-mid_autumn-hideBtn: #3bc2b2;
|
||||
@color-mid_autumn-minBtn: #85c43b;
|
||||
@color-mid_autumn-maxBtn: #e7aa36;
|
||||
@color-mid_autumn-closeBtn: #ea6e4d;
|
||||
@color-mid_autumn-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-mid_autumn-minBtn-hover: fadeout(@color-mid_autumn-minBtn, 10%);
|
||||
@color-mid_autumn-maxBtn-hover: fadeout(@color-mid_autumn-maxBtn, 10%);
|
||||
@color-mid_autumn-closeBtn-hover: fadeout(@color-mid_autumn-closeBtn, 10%);
|
||||
@color-mid_autumn-badge-success: lighten(@color-mid_autumn-theme, 25%);
|
||||
@color-mid_autumn-badge-success-font: #fff;
|
||||
@color-mid_autumn-badge-info: #af9479;
|
||||
@color-mid_autumn-badge-info-font: #fff;
|
||||
|
||||
@color-naruto-theme: rgb(87, 144, 167);
|
||||
@color-naruto-theme-bgimg: url(../images/myzcbg.jpeg);
|
||||
@color-naruto-theme-bgposition: center;
|
||||
@color-naruto-theme-bgsize: auto 100%;
|
||||
@color-naruto-theme-hover: fadeout(lighten(@color-naruto-theme, 10%), 45%);
|
||||
@color-naruto-theme-active: fadeout(lighten(@color-naruto-theme, 15%), 60%);
|
||||
@color-naruto-theme-font: rgba(67, 118, 148, 0.9);
|
||||
@color-naruto-theme-font-label: fadeout(darken(@color-naruto-theme, 20%), 20%);
|
||||
@color-naruto-theme_2: rgba(255, 255, 255, 0.8);
|
||||
@color-naruto-theme_2-background_1: #e9faff;
|
||||
@color-naruto-theme_2-background_2: fadeout(@color-naruto-theme_2-background_1, 2%);
|
||||
@color-naruto-theme_2-hover: fadeout(lighten(@color-naruto-theme, 10%), 75%);
|
||||
@color-naruto-theme_2-active: fadeout(lighten(@color-naruto-theme, 10%), 65%);
|
||||
@color-naruto-theme_2-font: darken(@color-naruto-theme_2, 80%);
|
||||
@color-naruto-theme_2-font-label: desaturate(lighten(@color-naruto-theme, 10%), 45%);
|
||||
@color-naruto-theme_2-line: fadeout(lighten(@color-naruto-theme, 36%), 70%);
|
||||
@color-naruto-theme-sidebar: rgba(255, 255, 255, .3);
|
||||
@color-naruto-btn: lighten(@color-naruto-theme, 2%);
|
||||
@color-naruto-btn-background: fadeout(lighten(@color-naruto-theme, 35%), 70%);
|
||||
@color-naruto-pagination-background: fadeout(lighten(@color-naruto-theme, 20%), 70%);
|
||||
@color-naruto-pagination-hover: fadeout(lighten(@color-naruto-theme, 10%), 60%);
|
||||
@color-naruto-pagination-active: fadeout(darken(@color-naruto-theme, 10%), 70%);
|
||||
@color-naruto-pagination-select: fadeout(lighten(@color-naruto-theme, 10%), 50%);
|
||||
@color-naruto-search-form-background: fadeout(lighten(@color-naruto-theme, 30%), 20%);
|
||||
@color-naruto-search-list-hover: fadeout(darken(@color-naruto-theme, 10%), 50%);
|
||||
@color-naruto-scrollbar-track: fadeout(@color-naruto-theme, 80%);
|
||||
@color-naruto-scrollbar-thumb: fadeout(@color-naruto-theme, 60%);
|
||||
@color-naruto-scrollbar-thumb-hover: fadeout(@color-naruto-theme, 40%);
|
||||
@color-naruto-player-pic-c1: fadeout(@color-naruto-theme_2, 50%);
|
||||
@color-naruto-player-pic-c2: darken(@color-naruto-theme_2, 30%);
|
||||
@color-naruto-player-progress: darken(@color-naruto-theme_2, 10%);
|
||||
@color-naruto-player-progress-bar1: darken(@color-naruto-theme_2, 12%);
|
||||
@color-naruto-player-progress-bar2: lighten(@color-naruto-theme, 12%);
|
||||
@color-naruto-player-status-text: lighten(@color-naruto-theme_2-font, 10%);
|
||||
@color-naruto-player-detail-play-btn: lighten(@color-naruto-theme, 7%);
|
||||
@color-naruto-tab-btn-background: fadeout(lighten(@color-naruto-theme, 10%), 80%);
|
||||
@color-naruto-tab-btn-background-hover: @color-naruto-theme_2-hover;
|
||||
@color-naruto-tab-border-top: fadeout(lighten(@color-naruto-theme, 5%), 50%);
|
||||
@color-naruto-tab-border-bottom: lighten(@color-naruto-theme, 5%);
|
||||
@color-naruto-hideBtn: #3bc2b2;
|
||||
@color-naruto-minBtn: #85c43b;
|
||||
@color-naruto-maxBtn: #e7aa36;
|
||||
@color-naruto-closeBtn: #ea6e4d;
|
||||
@color-naruto-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-naruto-minBtn-hover: fadeout(@color-naruto-minBtn, 10%);
|
||||
@color-naruto-maxBtn-hover: fadeout(@color-naruto-maxBtn, 10%);
|
||||
@color-naruto-closeBtn-hover: fadeout(@color-naruto-closeBtn, 10%);
|
||||
@color-naruto-badge-success: #7fb575;
|
||||
@color-naruto-badge-success-font: #fff;
|
||||
@color-naruto-badge-info: lighten(@color-naruto-theme, 10%);
|
||||
@color-naruto-badge-info-font: #fff;
|
||||
|
||||
@color-happy_new_year-theme: rgb(252, 57, 57);
|
||||
@color-happy_new_year-theme-bgimg: url(../images/xnkl.jpg);
|
||||
@color-happy_new_year-theme-bgposition: center;
|
||||
@color-happy_new_year-theme-bgsize: auto 100%;
|
||||
@color-happy_new_year-theme-hover: fadeout(lighten(@color-happy_new_year-theme, 10%), 45%);
|
||||
@color-happy_new_year-theme-active: fadeout(lighten(@color-happy_new_year-theme, 15%), 60%);
|
||||
@color-happy_new_year-theme-font: rgba(255, 255, 255, 0.9);
|
||||
@color-happy_new_year-theme-font-label: fadeout(lighten(@color-happy_new_year-theme, 20%), 20%);
|
||||
@color-happy_new_year-theme_2: rgba(255, 199, 199, 0.8);
|
||||
@color-happy_new_year-theme_2-background_1: #f2a4a4;
|
||||
@color-happy_new_year-theme_2-background_2: fadeout(@color-happy_new_year-theme_2-background_1, 2%);
|
||||
@color-happy_new_year-theme_2-hover: fadeout(lighten(@color-happy_new_year-theme, 10%), 65%);
|
||||
@color-happy_new_year-theme_2-active: fadeout(lighten(@color-happy_new_year-theme, 10%), 55%);
|
||||
@color-happy_new_year-theme_2-font: darken(@color-happy_new_year-theme_2, 90%);
|
||||
@color-happy_new_year-theme_2-font-label: desaturate(darken(@color-happy_new_year-theme, 5%), 50%);
|
||||
@color-happy_new_year-theme_2-line: fadeout(lighten(@color-happy_new_year-theme, 16%), 70%);
|
||||
@color-happy_new_year-theme-sidebar: rgba(119, 37, 18, 0.1);
|
||||
@color-happy_new_year-btn: desaturate(@color-happy_new_year-theme, 10%);
|
||||
@color-happy_new_year-btn-background: fadeout(lighten(@color-happy_new_year-theme, 15%), 60%);
|
||||
@color-happy_new_year-pagination-background: fadeout(lighten(@color-happy_new_year-theme, 15%), 40%);
|
||||
@color-happy_new_year-pagination-hover: fadeout(lighten(@color-happy_new_year-theme, 10%), 70%);
|
||||
@color-happy_new_year-pagination-active: fadeout(darken(@color-happy_new_year-theme, 10%), 70%);
|
||||
@color-happy_new_year-pagination-select: fadeout(lighten(@color-happy_new_year-theme, 10%), 55%);
|
||||
@color-happy_new_year-search-form-background: fadeout(lighten(@color-happy_new_year-theme, 15%), 20%);
|
||||
@color-happy_new_year-search-list-hover: fadeout(darken(@color-happy_new_year-theme, 10%), 50%);
|
||||
@color-happy_new_year-scrollbar-track: fadeout(@color-happy_new_year-theme, 80%);
|
||||
@color-happy_new_year-scrollbar-thumb: fadeout(@color-happy_new_year-theme, 60%);
|
||||
@color-happy_new_year-scrollbar-thumb-hover: fadeout(@color-happy_new_year-theme, 40%);
|
||||
@color-happy_new_year-player-pic-c1: fadeout(@color-happy_new_year-theme_2, 50%);
|
||||
@color-happy_new_year-player-pic-c2: darken(@color-happy_new_year-theme_2, 30%);
|
||||
@color-happy_new_year-player-progress: darken(@color-happy_new_year-theme_2, 10%);
|
||||
@color-happy_new_year-player-progress-bar1: darken(@color-happy_new_year-theme_2, 12%);
|
||||
@color-happy_new_year-player-progress-bar2: lighten(@color-happy_new_year-theme, 9%);
|
||||
@color-happy_new_year-player-status-text: lighten(@color-happy_new_year-theme_2-font, 10%);
|
||||
@color-happy_new_year-player-detail-play-btn: lighten(@color-happy_new_year-theme, 7%);
|
||||
@color-happy_new_year-tab-btn-background: fadeout(lighten(@color-happy_new_year-theme, 10%), 80%);
|
||||
@color-happy_new_year-tab-btn-background-hover: @color-happy_new_year-theme_2-hover;
|
||||
@color-happy_new_year-tab-border-top: fadeout(lighten(@color-happy_new_year-theme, 5%), 50%);
|
||||
@color-happy_new_year-tab-border-bottom: lighten(@color-happy_new_year-theme, 5%);
|
||||
@color-happy_new_year-hideBtn: #64a130;
|
||||
@color-happy_new_year-minBtn: #c4943b;
|
||||
@color-happy_new_year-maxBtn: #e7aa36;
|
||||
@color-happy_new_year-closeBtn: #ea6e4d;
|
||||
@color-happy_new_year-hideBtn-hover: fadeout(@color-hideBtn, 10%);
|
||||
@color-happy_new_year-minBtn-hover: fadeout(@color-happy_new_year-minBtn, 10%);
|
||||
@color-happy_new_year-maxBtn-hover: fadeout(@color-happy_new_year-maxBtn, 10%);
|
||||
@color-happy_new_year-closeBtn-hover: fadeout(@color-happy_new_year-closeBtn, 10%);
|
||||
@color-happy_new_year-badge-success: @color-happy_new_year-theme;
|
||||
@color-happy_new_year-badge-success-font: #fff;
|
||||
@color-happy_new_year-badge-info: #c4943b;
|
||||
@color-happy_new_year-badge-info-font: #fff;
|
||||
|
||||
|
||||
|
||||
// Width
|
||||
@width-app-left: 180px;
|
||||
@width-app-left: 20%;
|
||||
|
||||
// Height
|
||||
@height-toolbar: 50px;
|
||||
@@ -428,3 +718,5 @@
|
||||
@radius-progress-border: 5px;
|
||||
|
||||
@transition-theme: .4s ease;
|
||||
|
||||
@form-radius: 3px;
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.aside")
|
||||
div(:class="$style.logo")
|
||||
div(:class="['animated', logoAnimate, $style.logo]")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' height='100%' viewBox='0 0 127 61' space='preserve')
|
||||
use(xlink:href='#icon-logo')
|
||||
|
||||
div(:class="$style.menu")
|
||||
dl
|
||||
dt 在线音乐
|
||||
dt {{$t('core.aside.online_music')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="search") 搜索
|
||||
router-link(:active-class="$style.active" to="search") {{$t('core.aside.search')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="songList") 歌单
|
||||
router-link(:active-class="$style.active" to="songList") {{$t('core.aside.song_list')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="leaderboard") 排行榜
|
||||
router-link(:active-class="$style.active" to="leaderboard") {{$t('core.aside.leaderboard')}}
|
||||
dl
|
||||
dt 我的音乐
|
||||
dt {{$t('core.aside.my_music')}}
|
||||
dd
|
||||
router-link(:active-class="($route.query.id === defaultList.id || $route.query.id == '') ? $style.active : ''" :to="`list?id=${defaultList.id || ''}`") {{defaultList.name}}
|
||||
router-link(:active-class="$route.query.id === loveList.id ? $style.active : ''" :to="`list?id=${loveList.id}`") {{loveList.name}}
|
||||
router-link(:active-class="($route.query.id === defaultList.id || $route.query.id == '') ? $style.active : ''" :to="`list?id=${defaultList.id || ''}`") {{$t('core.aside.default_list')}}
|
||||
router-link(:active-class="$route.query.id === loveList.id ? $style.active : ''" :to="`list?id=${loveList.id}`") {{$t('core.aside.love_list')}}
|
||||
router-link(:active-class="$route.query.id === item.id ? $style.active : ''" v-for="item in userList" :to="`list?id=${item._id}`" :key="item._id") {{item.name}}
|
||||
dl
|
||||
dt 其他
|
||||
dt {{$t('core.aside.other')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="download") 下载管理
|
||||
router-link(:active-class="$style.active" to="download") {{$t('core.aside.download')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="setting") 设置
|
||||
router-link(:active-class="$style.active" to="setting") {{$t('core.aside.setting')}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
// import { getRandom } from '../../utils'
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
@@ -41,12 +42,34 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
active: 'search',
|
||||
animates: [
|
||||
'bounce',
|
||||
// 'flash',
|
||||
// 'pulse',
|
||||
'rubberBand',
|
||||
// 'shake',
|
||||
// 'headShake',
|
||||
'swing',
|
||||
'tada',
|
||||
// 'wobble',
|
||||
'jello',
|
||||
// 'heartBeat',
|
||||
],
|
||||
logoAnimate: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('list', ['defaultList', 'loveList', 'userList']),
|
||||
},
|
||||
methods: {},
|
||||
// mounted() {
|
||||
// this.logoAnimate = this.animates[getRandom(0, this.animates.length)]
|
||||
// },
|
||||
// methods: {
|
||||
// handleMouseEnter() {
|
||||
// console.log('object')
|
||||
// this.logoAnimate = this.animates[getRandom(0, this.animates.length)]
|
||||
// },
|
||||
// },
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -66,12 +89,18 @@ export default {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
:global(.nd) {
|
||||
.aside {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
height: 100px;
|
||||
padding: 12% 13%;
|
||||
// height: 120px;
|
||||
color: @color-theme-font;
|
||||
flex: none;
|
||||
// -webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.menu {
|
||||
@@ -115,6 +144,9 @@ export default {
|
||||
&:hover:not(.active) {
|
||||
background-color: @color-theme-hover;
|
||||
}
|
||||
&:hover:not(.active) {
|
||||
background-color: @color-theme-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,6 +173,9 @@ each(@themes, {
|
||||
&:hover:not(.active) {
|
||||
background-color: ~'@{color-@{value}-theme-hover}';
|
||||
}
|
||||
&:active:not(.active) {
|
||||
background-color: ~'@{color-@{value}-theme-active}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/19
|
||||
g#icon-addTo
|
||||
path(fill='currentColor' d='M37.059,16H26V4.941C26,2.224,23.718,0,21,0s-5,2.224-5,4.941V16H4.941C2.224,16,0,18.282,0,21s2.224,5,4.941,5H16v11.059C16,39.776,18.282,42,21,42s5-2.224,5-4.941V26h11.059C39.776,26,42,23.718,42,21S39.776,16,37.059,16z')
|
||||
g#icon-delete
|
||||
// 0 0 212.982 212.982
|
||||
path(fill='currentColor' d='M131.804,106.491l75.936-75.936c6.99-6.99,6.99-18.323,0-25.312c-6.99-6.99-18.322-6.99-25.312,0l-75.937,75.937L30.554,5.242c-6.99-6.99-18.322-6.99-25.312,0c-6.989,6.99-6.989,18.323,0,25.312l75.937,75.936L5.242,182.427c-6.989,6.99-6.989,18.323,0,25.312c6.99,6.99,18.322,6.99,25.312,0l75.937-75.937l75.937,75.937c6.989,6.99,18.322,6.99,25.312,0c6.99-6.99,6.99-18.322,0-25.312L131.804,106.491z')
|
||||
g#icon-left
|
||||
// 451.847 451.847
|
||||
@@ -69,5 +70,14 @@ svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/19
|
||||
g#icon-down
|
||||
// 0 0 451.847 451.847
|
||||
path(fill='currentColor' d='M225.923,354.706c-8.098,0-16.195-3.092-22.369-9.263L9.27,151.157c-12.359-12.359-12.359-32.397,0-44.751c12.354-12.354,32.388-12.354,44.748,0l171.905,171.915l171.906-171.909c12.359-12.354,32.391-12.354,44.744,0c12.365,12.354,12.365,32.392,0,44.751L248.292,345.449C242.115,351.621,234.018,354.706,225.923,354.706z')
|
||||
g#icon-back
|
||||
// 0 0 512 512
|
||||
path(fill='currentColor' d='M511.563,434.259c-1.728-142.329-124.42-258.242-277.087-263.419V95.999c0-17.645-14.342-31.999-31.974-31.999 c-7.931,0-15.591,3.042-21.524,8.562c0,0-134.828,124.829-173.609,163.755C2.623,241.109,0,248.088,0,255.994 c0,7.906,2.623,14.885,7.369,19.687c38.781,38.915,173.609,163.745,173.609,163.745c5.933,5.521,13.593,8.562,21.524,8.562 c17.631,0,31.974-14.354,31.974-31.999v-74.591c153.479,2.156,255.792,50.603,255.792,95.924c0,5.896,4.767,10.666,10.658,10.666 c0.167,0.021,0.333,0.01,0.416,0c5.891,0,10.658-4.771,10.658-10.666C512,436.259,511.854,435.228,511.563,434.259z')
|
||||
g#icon-refresh
|
||||
// 0 0 512 512
|
||||
path(fill='currentColor' d='M440.65 12.57l4 82.77A247.16 247.16 0 0 0 255.83 8C134.73 8 33.91 94.92 12.29 209.82A12 12 0 0 0 24.09 224h49.05a12 12 0 0 0 11.67-9.26 175.91 175.91 0 0 1 317-56.94l-101.46-4.86a12 12 0 0 0-12.57 12v47.41a12 12 0 0 0 12 12H500a12 12 0 0 0 12-12V12a12 12 0 0 0-12-12h-47.37a12 12 0 0 0-11.98 12.57zM255.83 432a175.61 175.61 0 0 1-146-77.8l101.8 4.87a12 12 0 0 0 12.57-12v-47.4a12 12 0 0 0-12-12H12a12 12 0 0 0-12 12V500a12 12 0 0 0 12 12h47.35a12 12 0 0 0 12-12.6l-4.15-82.57A247.17 247.17 0 0 0 255.83 504c121.11 0 221.93-86.92 243.55-201.82a12 12 0 0 0-11.8-14.18h-49.05a12 12 0 0 0-11.67 9.26A175.86 175.86 0 0 1 255.83 432z')
|
||||
g#icon-eraser
|
||||
// 0 0 512 512
|
||||
path(fill='currentColor' d='M497.941 273.941c18.745-18.745 18.745-49.137 0-67.882l-160-160c-18.745-18.745-49.136-18.746-67.883 0l-256 256c-18.745 18.745-18.745 49.137 0 67.882l96 96A48.004 48.004 0 0 0 144 480h356c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12H355.883l142.058-142.059zm-302.627-62.627l137.373 137.373L265.373 416H150.628l-80-80 124.686-124.686z')
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,38 +1,45 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.player")
|
||||
div(:class="$style.left")
|
||||
div(:class="$style.left" @contextmenu="handleToMusicLocation" @click="showPlayerDetail")
|
||||
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}`')
|
||||
div(:class="$style.right")
|
||||
div(:class="$style.right" v-if="!isShowPlayerDetail")
|
||||
div(:class="$style.column1")
|
||||
div(:class="$style.container")
|
||||
div(:class="$style.title" @click="handleCopy(title)" :title="title + '(点击复制)'") {{title}}
|
||||
div(:class="$style.title" @click="handleCopy(title)" :title="title + $t('core.player.copy_title')") {{title}}
|
||||
div(:class="$style.volumeContent")
|
||||
div(:class="$style.volume")
|
||||
div(:class="$style.volumeBar" :style="{ transform: `scaleX(${volume || 0})` }")
|
||||
div(:class="$style.volumeMask" @mousedown="handleVolumeMsDown" ref="dom_volumeMask" :title="`当前音量:${parseInt(volume * 100)}%`")
|
||||
div(:class="$style.volumeMask" @mousedown="handleVolumeMsDown" ref="dom_volumeMask" :title="`${$t('core.player.volume')}${parseInt(volume * 100)}%`")
|
||||
|
||||
//- 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="下一首")
|
||||
div(:class="$style.playBtn" @click='handleNext' :title="$t('core.player.next')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
div(:class="$style.playBtn" :title="isPlay ? '暂停' : '播放'" @click='togglePlay')
|
||||
div(:class="$style.playBtn" :title="isPlay ? $t('core.player.pause') : $t('core.player.play')" @click='togglePlay')
|
||||
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
div(:class="$style.column2")
|
||||
div(:class="$style.progress")
|
||||
div(:class="$style.progress" v-if="!isShowPlayerDetail")
|
||||
//- 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.progressMask" @click='setProgess' ref="dom_progress")
|
||||
div(:class="[$style.progressBar, $style.progressBar2, isActiveTransition ? $style.barTransition : '']" @transitionend="handleTransitionEnd" :style="{ transform: `scaleX(${progress || 0})` }")
|
||||
div(:class="$style.progressMask" @click='handleSetProgress' ref="dom_progress")
|
||||
div(:class="$style.column3")
|
||||
span {{nowPlayTimeStr}}
|
||||
span(:class="$style.statusText") {{status}}
|
||||
span(:class="$style.statusText") {{statusText}}
|
||||
span {{maxPlayTimeStr}}
|
||||
//- transition(enter-active-class="animated lightSpeedIn"
|
||||
transition(enter-active-class="animated lightSpeedIn"
|
||||
leave-active-class="animated slideOutDown")
|
||||
core-player-detail(v-if="isShowPlayerDetail" :musicInfo="musicInfo"
|
||||
:lyric="lyric" :list="list" :listId="listId"
|
||||
:playInfo="{ nowPlayTimeStr, maxPlayTimeStr, progress, nowPlayTime, status }"
|
||||
:isPlay="isPlay" @action="handlePlayDetailAction")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' style="display: none;")
|
||||
defs
|
||||
g(:id="$style.iconPic")
|
||||
@@ -48,11 +55,12 @@ div(:class="$style.player")
|
||||
|
||||
<script>
|
||||
import Lyric from 'lrc-file-parser'
|
||||
import { rendererSend } from '../../../common/icp'
|
||||
import { formatPlayTime2, getRandom, checkPath, setTitle, clipboardWriteText, debounce } from '../../utils'
|
||||
import { rendererSend } from '../../../common/ipc'
|
||||
import { formatPlayTime2, getRandom, checkPath, setTitle, clipboardWriteText, debounce, assertApiSupport } from '../../utils'
|
||||
import { mapGetters, mapActions, mapMutations } from 'vuex'
|
||||
import { requestMsg } from '../../utils/message'
|
||||
import { isMac } from '../../../common/utils'
|
||||
import path from 'path'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -63,19 +71,21 @@ export default {
|
||||
nowPlayTime: 0,
|
||||
maxPlayTime: 0,
|
||||
isPlay: false,
|
||||
status: '^-^',
|
||||
status: '',
|
||||
statusText: '^-^',
|
||||
musicInfo: {
|
||||
songmid: null,
|
||||
img: null,
|
||||
lrc: null,
|
||||
url: null,
|
||||
name: '^',
|
||||
singer: '^',
|
||||
name: '',
|
||||
singer: '',
|
||||
album: '',
|
||||
},
|
||||
targetSong: null,
|
||||
pregessWidth: 0,
|
||||
lyric: {
|
||||
lrc: null,
|
||||
lines: [],
|
||||
text: '',
|
||||
line: 0,
|
||||
},
|
||||
@@ -88,20 +98,23 @@ export default {
|
||||
msDownX: 0,
|
||||
msDownVolume: 0,
|
||||
},
|
||||
handleVolumeMsMoveFn: null,
|
||||
handleVolumeMsUpFn: null,
|
||||
isActiveTransition: false,
|
||||
mediaBuffer: {
|
||||
timeout: null,
|
||||
playTime: 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
...mapGetters('player', ['list', 'playIndex', 'changePlay', 'listId']),
|
||||
...mapGetters('player', ['list', 'playIndex', 'changePlay', 'listId', 'isShowPlayerDetail']),
|
||||
// pic() {
|
||||
// return this.musicInfo.img ? this.musicInfo.img : ''
|
||||
// },
|
||||
title() {
|
||||
return this.musicInfo.name
|
||||
? `${this.musicInfo.name} - ${this.musicInfo.singer}`
|
||||
: ''
|
||||
: '^-^'
|
||||
},
|
||||
nowPlayTimeStr() {
|
||||
return this.nowPlayTime ? formatPlayTime2(this.nowPlayTime) : '00:00'
|
||||
@@ -112,25 +125,24 @@ export default {
|
||||
progress() {
|
||||
return this.nowPlayTime / this.maxPlayTime || 0
|
||||
},
|
||||
isAPITemp() {
|
||||
return this.setting.apiSource == 'temp'
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
this.$nextTick(() => {
|
||||
this.setProgessWidth()
|
||||
this.setProgressWidth()
|
||||
})
|
||||
this.handleSaveVolume = debounce(volume => {
|
||||
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) {
|
||||
@@ -145,6 +157,9 @@ export default {
|
||||
'setting.player.togglePlayMethod'(n) {
|
||||
this.audio.loop = n === 'singleLoop'
|
||||
},
|
||||
'setting.player.mediaDeviceId'(n) {
|
||||
this.setMediaDevice()
|
||||
},
|
||||
list(n, o) {
|
||||
if (n === o) {
|
||||
let index = this.listId == 'download'
|
||||
@@ -171,6 +186,9 @@ export default {
|
||||
volume(n) {
|
||||
this.handleSaveVolume(n)
|
||||
},
|
||||
nowPlayTime(n, o) {
|
||||
if (Math.abs(n - o) > 2) this.isActiveTransition = true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('player', ['getUrl', 'getPic', 'getLrc']),
|
||||
@@ -178,11 +196,14 @@ export default {
|
||||
'setPlayIndex',
|
||||
'fixPlayIndex',
|
||||
'resetChangePlay',
|
||||
'visiblePlayerDetail',
|
||||
]),
|
||||
...mapMutations(['setVolume']),
|
||||
...mapMutations('list', ['updateMusicInfo']),
|
||||
...mapMutations(['setMediaDeviceId']),
|
||||
init() {
|
||||
this.audio = document.createElement('audio')
|
||||
this.setMediaDevice()
|
||||
this.volume = this.audio.volume = this.setting.player.volume
|
||||
this.audio.controls = false
|
||||
this.audio.autoplay = true
|
||||
@@ -191,19 +212,20 @@ export default {
|
||||
|
||||
this.audio.addEventListener('playing', () => {
|
||||
console.log('开始播放')
|
||||
this.status = '播放中...'
|
||||
this.statusText = this.$t('core.player.playing')
|
||||
this.status = ''
|
||||
this.startPlay()
|
||||
})
|
||||
this.audio.addEventListener('pause', () => {
|
||||
console.log('暂停播放')
|
||||
this.lyric.lrc.pause()
|
||||
window.lrc.pause()
|
||||
this.stopPlay()
|
||||
this.status = '暂停播放'
|
||||
// this.status = this.statusText = this.$t('core.player.stop')
|
||||
})
|
||||
this.audio.addEventListener('ended', () => {
|
||||
console.log('播放完毕')
|
||||
this.stopPlay()
|
||||
this.status = '播放完毕'
|
||||
this.status = this.statusText = this.$t('core.player.end')
|
||||
this.handleNext()
|
||||
})
|
||||
this.audio.addEventListener('error', () => {
|
||||
@@ -211,17 +233,17 @@ 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...'
|
||||
this.status = this.statusText = this.$t('core.player.refresh_url')
|
||||
return
|
||||
}
|
||||
|
||||
this.sendProgressEvent(this.progress, 'error')
|
||||
this.status = '音频加载出错,5 秒后切换下一首'
|
||||
this.status = this.statusText = this.$t('core.player.error')
|
||||
this.addDelayNextTimeout()
|
||||
})
|
||||
this.audio.addEventListener('loadeddata', () => {
|
||||
@@ -231,25 +253,36 @@ export default {
|
||||
this.audioErrorTime = 0
|
||||
}
|
||||
if (!this.targetSong.interval && this.listId != 'download') this.updateMusicInfo({ id: 'default', index: this.playIndex, data: { interval: formatPlayTime2(this.maxPlayTime) } })
|
||||
this.status = '音乐加载中...'
|
||||
this.status = this.statusText = this.$t('core.player.loading')
|
||||
})
|
||||
this.audio.addEventListener('loadstart', () => {
|
||||
this.status = '音乐加载中...'
|
||||
this.status = this.statusText = this.$t('core.player.loading')
|
||||
})
|
||||
this.audio.addEventListener('canplay', () => {
|
||||
console.log('加载完成开始播放')
|
||||
// if (this.musicInfo.lrc) this.lyric.lrc.play(this.audio.currentTime * 1000)
|
||||
this.status = '音乐加载中...'
|
||||
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) window.lrc.play(this.audio.currentTime * 1000)
|
||||
this.status = this.statusText = this.$t('core.player.loading')
|
||||
})
|
||||
// this.audio.addEventListener('canplaythrough', () => {
|
||||
// console.log('音乐加载完毕')
|
||||
// // 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.status = this.statusText = '播放中...'
|
||||
// })
|
||||
this.audio.addEventListener('emptied', () => {
|
||||
this.mediaBuffer.playTime = 0
|
||||
this.clearBufferTimeout()
|
||||
|
||||
// console.log('媒介资源元素突然为空,网络错误 or 切换歌曲?')
|
||||
// this.status = this.statusText = '媒介资源元素突然为空,网络错误?'
|
||||
})
|
||||
|
||||
this.audio.addEventListener('timeupdate', () => {
|
||||
this.nowPlayTime = this.audio.currentTime
|
||||
@@ -257,21 +290,28 @@ export default {
|
||||
|
||||
this.audio.addEventListener('waiting', () => {
|
||||
// this.musicInfo.lyric.lrc.pause()
|
||||
// console.log('缓冲中...')
|
||||
this.stopPlay()
|
||||
this.status = '缓冲中...'
|
||||
this.startBuffering()
|
||||
this.status = this.statusText = this.$t('core.player.buffering')
|
||||
})
|
||||
|
||||
this.lyric.lrc = new Lyric({
|
||||
window.lrc = new Lyric({
|
||||
onPlay: (line, text) => {
|
||||
this.lyric.text = text
|
||||
this.lyric.line = line
|
||||
this.status = text
|
||||
this.statusText = text
|
||||
// console.log(line, text)
|
||||
},
|
||||
offset: 150,
|
||||
onSetLyric: lines => { // listening lyrics seting event
|
||||
// console.log(lines) // lines is array of all lyric text
|
||||
this.lyric.lines = lines
|
||||
this.lyric.line = 0
|
||||
},
|
||||
offset: 100,
|
||||
})
|
||||
},
|
||||
play() {
|
||||
async play() {
|
||||
console.log('play', this.playIndex)
|
||||
this.checkDelayNextTimeout()
|
||||
let targetSong = this.targetSong = this.list[this.playIndex]
|
||||
@@ -279,21 +319,24 @@ export default {
|
||||
this.audioErrorTime = 0
|
||||
|
||||
if (this.listId == 'download') {
|
||||
console.log(targetSong.filePath)
|
||||
if (!checkPath(targetSong.filePath) || !targetSong.isComplate || /\.ape$/.test(targetSong.filePath)) {
|
||||
const filePath = path.join(this.setting.download.savePath, targetSong.fileName)
|
||||
// console.log(filePath)
|
||||
if (!await checkPath(filePath) || !targetSong.isComplate || /\.ape$/.test(filePath)) {
|
||||
return this.list.length == 1 ? null : this.handleNext()
|
||||
}
|
||||
this.musicInfo.songmid = targetSong.musicInfo.songmid
|
||||
this.musicInfo.singer = targetSong.musicInfo.singer
|
||||
this.musicInfo.name = targetSong.musicInfo.name
|
||||
this.audio.src = targetSong.filePath
|
||||
// console.log(targetSong.filePath)
|
||||
this.musicInfo.album = targetSong.albumName
|
||||
this.audio.src = filePath
|
||||
// console.log(filePath)
|
||||
this.setImg(targetSong.musicInfo)
|
||||
this.setLrc(targetSong.musicInfo)
|
||||
} else {
|
||||
this.musicInfo.songmid = targetSong.songmid
|
||||
this.musicInfo.singer = targetSong.singer
|
||||
this.musicInfo.name = targetSong.name
|
||||
this.musicInfo.album = targetSong.albumName
|
||||
this.setUrl(targetSong)
|
||||
this.setImg(targetSong)
|
||||
this.setLrc(targetSong)
|
||||
@@ -313,98 +356,132 @@ export default {
|
||||
this.handleNext()
|
||||
}, 5000)
|
||||
},
|
||||
handleNext() {
|
||||
async filterList() {
|
||||
// if (this.list.listName === null) return
|
||||
let list
|
||||
if (this.listId == 'download') {
|
||||
list = this.list.filter(s => !(!checkPath(s.filePath) || !s.isComplate || /\.ape$/.test(s.filePath)))
|
||||
} else if (this.isAPITemp) {
|
||||
list = this.list.filter(s => s.source == 'kw')
|
||||
list = []
|
||||
for (const item of this.list) {
|
||||
const filePath = path.join(this.setting.download.savePath, item.fileName)
|
||||
if (!await checkPath(filePath) || !item.isComplate || /\.ape$/.test(filePath)) continue
|
||||
list.push(item)
|
||||
}
|
||||
} else {
|
||||
list = this.list
|
||||
list = this.list.filter(s => this.assertApiSupport(s.source))
|
||||
}
|
||||
if (!list.length) return this.setPlayIndex(-1)
|
||||
let playIndex = this.list === list ? this.playIndex : list.indexOf(this.list[this.playIndex])
|
||||
return list
|
||||
},
|
||||
async handlePrev() {
|
||||
// console.log(playIndex)
|
||||
let list = await this.filterList()
|
||||
if (!list.length) return this.setPlayIndex(-1)
|
||||
let playIndex = list.indexOf(this.list[this.playIndex])
|
||||
let index
|
||||
switch (this.setting.player.togglePlayMethod) {
|
||||
case 'listLoop':
|
||||
index = this.hanldeListLoop(list, playIndex)
|
||||
break
|
||||
case 'random':
|
||||
index = this.hanldeListRandom(list, playIndex)
|
||||
break
|
||||
case 'listLoop':
|
||||
case 'list':
|
||||
index = this.hanldeListNext(list, playIndex)
|
||||
index = playIndex === 0 ? list.length - 1 : playIndex - 1
|
||||
break
|
||||
default:
|
||||
return
|
||||
}
|
||||
if (index < 0) return
|
||||
if (this.list !== list) index = this.list.indexOf(list[index])
|
||||
index = this.list.indexOf(list[index])
|
||||
this.setPlayIndex(index)
|
||||
},
|
||||
hanldeListLoop(list, index) {
|
||||
return index === list.length - 1 ? 0 : index + 1
|
||||
},
|
||||
hanldeListNext(list, index) {
|
||||
return index === list.length - 1 ? -1 : index + 1
|
||||
async handleNext() {
|
||||
// if (this.list.listName === null) return
|
||||
let list = await this.filterList()
|
||||
if (!list.length) return this.setPlayIndex(-1)
|
||||
let playIndex = list.indexOf(this.list[this.playIndex])
|
||||
// console.log(playIndex)
|
||||
let index
|
||||
switch (this.setting.player.togglePlayMethod) {
|
||||
case 'listLoop':
|
||||
index = playIndex === list.length - 1 ? 0 : playIndex + 1
|
||||
break
|
||||
case 'random':
|
||||
index = this.hanldeListRandom(list, playIndex)
|
||||
break
|
||||
case 'list':
|
||||
index = playIndex === list.length - 1 ? -1 : playIndex + 1
|
||||
break
|
||||
default:
|
||||
return
|
||||
}
|
||||
if (index < 0) return
|
||||
index = this.list.indexOf(list[index])
|
||||
this.setPlayIndex(index)
|
||||
},
|
||||
hanldeListRandom(list, index) {
|
||||
return getRandom(0, list.length)
|
||||
},
|
||||
startPlay() {
|
||||
this.isPlay = true
|
||||
if (this.musicInfo.lrc) this.lyric.lrc.play(this.audio.currentTime * 1000)
|
||||
if (this.musicInfo.lrc) window.lrc.play(this.audio.currentTime * 1000)
|
||||
this.setAppTitle()
|
||||
this.sendProgressEvent(this.progress, 'normal')
|
||||
},
|
||||
stopPlay() {
|
||||
this.isPlay = false
|
||||
this.lyric.lrc.pause()
|
||||
window.lrc.pause()
|
||||
this.sendProgressEvent(this.progress, 'paused')
|
||||
this.clearAppTitle()
|
||||
},
|
||||
setProgess(e) {
|
||||
handleSetProgress(event) {
|
||||
this.setProgress(event.offsetX / this.pregessWidth)
|
||||
},
|
||||
setProgress(pregress) {
|
||||
if (!this.audio.src) return
|
||||
this.audio.currentTime =
|
||||
(e.offsetX / this.pregessWidth) * this.maxPlayTime
|
||||
const time = pregress * 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() {
|
||||
setProgressWidth() {
|
||||
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'
|
||||
this.musicInfo.img = null
|
||||
},
|
||||
getPlayType(highQuality, songInfo) {
|
||||
switch (songInfo.source) {
|
||||
case 'wy':
|
||||
case 'tx':
|
||||
// case 'kg':
|
||||
return '128k'
|
||||
}
|
||||
let type = '128k'
|
||||
if (highQuality && songInfo._types['320k']) type = '320k'
|
||||
let list = window.globalObj.qualityList[songInfo.source]
|
||||
if (highQuality && songInfo._types['320k'] && list && list.includes('320k')) type = '320k'
|
||||
return type
|
||||
},
|
||||
setUrl(targetSong, isRefresh) {
|
||||
setUrl(targetSong, isRefresh, isRetryed = false) {
|
||||
let type = this.getPlayType(this.setting.player.highQuality, targetSong)
|
||||
this.musicInfo.url = targetSong.typeUrl[type]
|
||||
this.status = '歌曲链接获取中...'
|
||||
this.status = this.statusText = this.$t('core.player.geting_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
|
||||
if (!isRetryed) return this.setUrl(targetSong, isRefresh, true)
|
||||
this.status = this.statusText = err.message
|
||||
this.addDelayNextTimeout()
|
||||
return Promise.reject(err)
|
||||
})
|
||||
@@ -429,25 +506,28 @@ export default {
|
||||
|
||||
lrcP
|
||||
.then(() => {
|
||||
this.lyric.lrc.setLyric(this.musicInfo.lrc)
|
||||
if (this.isPlay && (this.musicInfo.url || this.listId == 'download')) this.lyric.lrc.play(this.audio.currentTime * 1000)
|
||||
window.lrc.setLyric(this.musicInfo.lrc)
|
||||
if (this.isPlay && (this.musicInfo.url || this.listId == 'download')) window.lrc.play(this.audio.currentTime * 1000)
|
||||
})
|
||||
.catch(() => {
|
||||
this.status = '歌词获取失败'
|
||||
this.status = this.statusText = this.$t('core.player.lyric_error')
|
||||
})
|
||||
},
|
||||
handleRemoveMusic() {
|
||||
this.stopPlay()
|
||||
this.audio.src = null
|
||||
this.audio.removeAttribute('src')
|
||||
this.status = '^-^'
|
||||
this.statusText = '^-^'
|
||||
this.musicInfo.img = null
|
||||
this.musicInfo.name = this.musicInfo.singer = '^'
|
||||
this.status = this.musicInfo.name = this.musicInfo.singer = ''
|
||||
this.musicInfo.songmid = null
|
||||
this.musicInfo.lrc = null
|
||||
this.musicInfo.url = null
|
||||
this.nowPlayTime = 0
|
||||
this.maxPlayTime = 0
|
||||
this.lyric.lines = []
|
||||
this.lyric.line = 0
|
||||
this.lyric.text = 0
|
||||
},
|
||||
sendProgressEvent(status, mode) {
|
||||
// console.log(status)
|
||||
@@ -464,7 +544,6 @@ export default {
|
||||
},
|
||||
handleVolumeMsDown(e) {
|
||||
this.volumeEvent.isMsDown = true
|
||||
this.volumeEvent.isMsMoved = false
|
||||
this.volumeEvent.msDownX = e.clientX
|
||||
|
||||
let val = e.offsetX / 70
|
||||
@@ -489,6 +568,86 @@ export default {
|
||||
handleCopy(text) {
|
||||
clipboardWriteText(text)
|
||||
},
|
||||
handleResize() {
|
||||
this.setProgressWidth()
|
||||
},
|
||||
handleToMusicLocation() {
|
||||
if (this.listId == 'download') return
|
||||
if (this.playIndex == -1) return
|
||||
this.$router.push({
|
||||
path: 'list',
|
||||
query: {
|
||||
id: this.listId,
|
||||
scrollIndex: this.playIndex,
|
||||
},
|
||||
})
|
||||
},
|
||||
showPlayerDetail() {
|
||||
this.visiblePlayerDetail(true)
|
||||
},
|
||||
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
|
||||
},
|
||||
async setMediaDevice() {
|
||||
let mediaDeviceId = this.setting.player.mediaDeviceId
|
||||
if (!mediaDeviceId) return
|
||||
const devices = await navigator.mediaDevices.enumerateDevices()
|
||||
let device = devices.find(device => device.deviceId === mediaDeviceId)
|
||||
if (!device) return this.setMediaDeviceId('default')
|
||||
// console.log(device)
|
||||
this.audio.setSinkId(device.deviceId).catch((err) => {
|
||||
console.log(err)
|
||||
this.setMediaDeviceId('default')
|
||||
})
|
||||
},
|
||||
handlePlayDetailAction({ type, data }) {
|
||||
switch (type) {
|
||||
case 'prev':
|
||||
this.handlePrev()
|
||||
break
|
||||
case 'togglePlay':
|
||||
this.togglePlay()
|
||||
break
|
||||
case 'next':
|
||||
this.handleNext()
|
||||
break
|
||||
case 'progress':
|
||||
this.setProgress(data)
|
||||
break
|
||||
case 'volume':
|
||||
break
|
||||
}
|
||||
},
|
||||
assertApiSupport(source) {
|
||||
return assertApiSupport(source)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -505,18 +664,27 @@ export default {
|
||||
border-top: 2px solid @color-theme;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
z-index: 1;
|
||||
z-index: 2;
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
.left {
|
||||
width: @height-player;
|
||||
width: @height-player - 2;
|
||||
height: @height-player - 2;
|
||||
color: @color-theme;
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
flex: none;
|
||||
padding: 2px;
|
||||
opacity: 1;
|
||||
transition: @transition-theme;
|
||||
transition-property: opacity;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
@@ -532,7 +700,7 @@ export default {
|
||||
.right {
|
||||
flex: auto;
|
||||
// margin-left: 10px;
|
||||
padding: 5px 10px;
|
||||
padding: 5px 10px 5px 8px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
@@ -581,7 +749,7 @@ export default {
|
||||
// overflow: hidden;
|
||||
transition: @transition-theme;
|
||||
transition-property: background-color;
|
||||
background-color: @color-player-progress;
|
||||
background-color: @color-player-progress-bar1;
|
||||
// background-color: #f5f5f5;
|
||||
position: relative;
|
||||
border-radius: @radius-progress-border;
|
||||
@@ -671,21 +839,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;
|
||||
@@ -744,12 +914,11 @@ each(@themes, {
|
||||
}
|
||||
}
|
||||
.volume {
|
||||
background-color: ~'@{color-@{value}-player-progress}';
|
||||
background-color: ~'@{color-@{value}-player-progress-bar1}';
|
||||
}
|
||||
|
||||
.volume-bar {
|
||||
background-color: ~'@{color-@{value}-theme}';
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
|
||||
@@ -761,7 +930,6 @@ each(@themes, {
|
||||
}
|
||||
.progress-bar2 {
|
||||
background-color: ~'@{color-@{value}-player-progress-bar2}';
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.column3 {
|
||||
|
||||
705
src/renderer/components/core/PlayerDetail.vue
Normal file
705
src/renderer/components/core/PlayerDetail.vue
Normal file
@@ -0,0 +1,705 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.container" @contextmenu="handleContextMenu")
|
||||
//- div(:class="$style.bg" :style="bgStyle")
|
||||
//- div(:class="$style.bg2")
|
||||
div(:class="$style.header")
|
||||
div(:class="$style.control")
|
||||
button(type="button" :class="$style.hide" :title="$t('core.player.hide_detail')" @click="visiblePlayerDetail(false)")
|
||||
button(type="button" :class="$style.min" :title="$t('core.toolbar.min')" @click="min")
|
||||
//- button(type="button" :class="$style.max" @click="max")
|
||||
button(type="button" :class="$style.close" :title="$t('core.toolbar.close')" @click="close")
|
||||
|
||||
div(:class="$style.main")
|
||||
div(:class="$style.left")
|
||||
div(:class="$style.info")
|
||||
div(:class="$style.img")
|
||||
img(:src="musicInfo.img" v-if="musicInfo.img")
|
||||
div(:class="$style.description")
|
||||
p {{$t('core.player.name')}}{{musicInfo.name}}
|
||||
p {{$t('core.player.singer')}}{{musicInfo.singer}}
|
||||
p(v-if="musicInfo.album") {{$t('core.player.album')}}{{musicInfo.album}}
|
||||
//- div(:class="$style.list")
|
||||
ul
|
||||
|
||||
div(:class="$style.right")
|
||||
div(:class="[$style.lyric, lyricEvent.isMsDown ? $style.draging : null]" @mousedown="handleLyricMouseDown" ref="dom_lyric")
|
||||
div(:class="$style.lyricSpace")
|
||||
p(v-for="(info, index) in lyric.lines" :key="index" :class="lyric.line == index ? $style.lrcActive : null") {{info.text}}
|
||||
div(:class="$style.lyricSpace")
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.left")
|
||||
div(:class="$style.progressContainer")
|
||||
div(:class="$style.progressContent")
|
||||
div(:class="$style.progress")
|
||||
//- div(:class="[$style.progressBar, $style.progressBar1]" :style="{ transform: `scaleX(${progress || 0})` }")
|
||||
div(:class="[$style.progressBar, $style.progressBar2, isActiveTransition ? $style.barTransition : '']" @transitionend="handleTransitionEnd" :style="{ transform: `scaleX(${playInfo.progress || 0})` }")
|
||||
div(:class="$style.progressMask" @click='setProgress' ref="dom_progress")
|
||||
div(:class="$style.timeLabel")
|
||||
span(style="margin-left: 15px") {{playInfo.status}}
|
||||
div
|
||||
span {{playInfo.nowPlayTimeStr}}
|
||||
span(style="margin: 0 5px;") /
|
||||
span {{playInfo.maxPlayTimeStr}}
|
||||
div(:class="$style.playControl")
|
||||
//- div(:class="$style.playBtn")
|
||||
//- div(:class="$style.playBtn")
|
||||
div(:class="$style.playBtn" @click="$emit('action', { type: 'prev' })" style="transform: rotate(180deg);" :title="$t('core.player.prev')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
div(:class="$style.playBtn" :title="isPlay ? $t('core.player.pause') : $t('core.player.play')" @click="$emit('action', { type: 'togglePlay' })")
|
||||
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
div(:class="$style.playBtn" @click="$emit('action', { type: 'next' })" :title="$t('core.player.next')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { rendererSend } from 'common/ipc'
|
||||
import { scrollTo } from '../../utils'
|
||||
|
||||
let cancelScrollFn = null
|
||||
|
||||
export default {
|
||||
props: {
|
||||
musicInfo: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
songmid: null,
|
||||
img: null,
|
||||
lrc: null,
|
||||
url: null,
|
||||
name: '^',
|
||||
singer: '^',
|
||||
}
|
||||
},
|
||||
},
|
||||
lyric: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
line: 0,
|
||||
text: '',
|
||||
lines: [],
|
||||
}
|
||||
},
|
||||
},
|
||||
playInfo: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
nowPlayTimeStr: '00:00',
|
||||
maxPlayTimeStr: '00:00',
|
||||
progress: 0,
|
||||
nowPlayTime: 0,
|
||||
status: 0,
|
||||
}
|
||||
},
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
listId: {
|
||||
type: String,
|
||||
default() {
|
||||
return ''
|
||||
},
|
||||
},
|
||||
isPlay: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'musicInfo.img': {
|
||||
handler(n) {
|
||||
if (n) {
|
||||
this.bgStyle.backgroundImage = `url(${n})`
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
'lyric.lines': {
|
||||
handler() {
|
||||
this.$nextTick(() => {
|
||||
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('p')
|
||||
this.handleScrollLrc()
|
||||
})
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
'lyric.line': {
|
||||
handler(n) {
|
||||
this.handleScrollLrc()
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
'playInfo.nowPlayTime'(n, o) {
|
||||
if (Math.abs(n - o) > 2) this.isActiveTransition = true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bgStyle: {
|
||||
backgroundImage: null,
|
||||
},
|
||||
dom_lines: [],
|
||||
isActiveTransition: false,
|
||||
pregessWidth: 0,
|
||||
clickTime: 0,
|
||||
volumeEvent: {
|
||||
isMsDown: false,
|
||||
msDownX: 0,
|
||||
msDownValue: 0,
|
||||
},
|
||||
lyricEvent: {
|
||||
isMsDown: false,
|
||||
msDownY: 0,
|
||||
msDownScrollY: 0,
|
||||
isStopScroll: false,
|
||||
timeout: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.setProgressWidth()
|
||||
})
|
||||
document.addEventListener('mousemove', this.handleMouseMsMove)
|
||||
document.addEventListener('mouseup', this.handleMouseMsUp)
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.clearLyricScrollTimeout()
|
||||
document.removeEventListener('mousemove', this.handleMouseMsMove)
|
||||
document.removeEventListener('mouseup', this.handleMouseMsUp)
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('player', ['isShowPlayerDetail']),
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('player', [
|
||||
'visiblePlayerDetail',
|
||||
]),
|
||||
handleResize() {
|
||||
this.setProgressWidth()
|
||||
},
|
||||
handleScrollLrc() {
|
||||
if (!this.dom_lines.length) return
|
||||
if (cancelScrollFn) {
|
||||
cancelScrollFn()
|
||||
cancelScrollFn = null
|
||||
}
|
||||
if (this.lyricEvent.isStopScroll) return
|
||||
let dom_p = this.dom_lines[this.lyric.line]
|
||||
cancelScrollFn = scrollTo(this.$refs.dom_lyric, dom_p ? (dom_p.offsetTop - this.$refs.dom_lyric.clientHeight * 0.38) : 0)
|
||||
},
|
||||
handleTransitionEnd() {
|
||||
this.isActiveTransition = false
|
||||
},
|
||||
setProgress(event) {
|
||||
this.$emit('action', {
|
||||
type: 'progress',
|
||||
data: event.offsetX / this.pregessWidth,
|
||||
})
|
||||
},
|
||||
setProgressWidth() {
|
||||
this.pregessWidth = parseInt(
|
||||
window.getComputedStyle(this.$refs.dom_progress, null).width,
|
||||
)
|
||||
},
|
||||
handleContextMenu() {
|
||||
if (window.performance.now() - this.clickTime > 400) {
|
||||
this.clickTime = window.performance.now()
|
||||
return
|
||||
}
|
||||
this.clickTime = 0
|
||||
this.visiblePlayerDetail(false)
|
||||
},
|
||||
handleLyricMouseDown(e) {
|
||||
// console.log(e)
|
||||
this.lyricEvent.isMsDown = true
|
||||
this.lyricEvent.msDownY = e.clientY
|
||||
this.lyricEvent.msDownScrollY = this.$refs.dom_lyric.scrollTop
|
||||
},
|
||||
handleMouseMsUp(e) {
|
||||
this.lyricEvent.isMsDown = this.volumeEvent.isMsDown = false
|
||||
},
|
||||
handleMouseMsMove(e) {
|
||||
if (this.lyricEvent.isMsDown) {
|
||||
if (!this.lyricEvent.isStopScroll) this.lyricEvent.isStopScroll = true
|
||||
if (cancelScrollFn) {
|
||||
cancelScrollFn()
|
||||
cancelScrollFn = null
|
||||
}
|
||||
this.$refs.dom_lyric.scrollTop = this.lyricEvent.msDownScrollY + this.lyricEvent.msDownY - e.clientY
|
||||
this.startLyricScrollTimeout()
|
||||
}
|
||||
|
||||
// if (this.volumeEvent.isMsDown) {
|
||||
// let val = this.volumeEvent.msDownValue + (e.clientX - this.volumeEvent.msDownX) / 70
|
||||
// this.volume = val < 0 ? 0 : val > 1 ? 1 : val
|
||||
// if (this.audio) this.audio.volume = this.volume
|
||||
// }
|
||||
|
||||
// console.log(val)
|
||||
},
|
||||
startLyricScrollTimeout() {
|
||||
this.clearLyricScrollTimeout()
|
||||
this.lyricEvent.timeout = setTimeout(() => {
|
||||
this.lyricEvent.timeout = null
|
||||
this.lyricEvent.isStopScroll = false
|
||||
if (!this.isPlay) return
|
||||
this.handleScrollLrc()
|
||||
}, 3000)
|
||||
},
|
||||
clearLyricScrollTimeout() {
|
||||
if (!this.lyricEvent.timeout) return
|
||||
clearTimeout(this.lyricEvent.timeout)
|
||||
this.lyricEvent.timeout = null
|
||||
},
|
||||
min() {
|
||||
rendererSend('min')
|
||||
},
|
||||
max() {
|
||||
rendererSend('max')
|
||||
},
|
||||
close() {
|
||||
rendererSend('close')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
@control-btn-width: @height-toolbar * .5;
|
||||
|
||||
.container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #fff;
|
||||
z-index: 10;
|
||||
// -webkit-app-region: drag;
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
color: @color-theme_2-font;
|
||||
border-left: 12px solid @color-theme;
|
||||
}
|
||||
.bg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-size: 110% 110%;
|
||||
filter: blur(60px);
|
||||
z-index: -1;
|
||||
}
|
||||
.bg2 {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
background-color: rgba(255, 255, 255, .8);
|
||||
}
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
flex: 0 0 @height-toolbar;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
.control {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @height-toolbar;
|
||||
-webkit-app-region: no-drag;
|
||||
padding: 0 @control-btn-width * 0.6;
|
||||
&:hover {
|
||||
button:before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
width: @control-btn-width;
|
||||
height: @control-btn-width;
|
||||
background: none;
|
||||
border: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
+ button {
|
||||
margin-left: @control-btn-width * .4;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
border-radius: 50%;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
transition: opacity @transition-theme;
|
||||
}
|
||||
|
||||
&.hide:after {
|
||||
background-color: @color-hideBtn;
|
||||
}
|
||||
&.min:after {
|
||||
background-color: @color-minBtn;
|
||||
}
|
||||
&.max:after {
|
||||
background-color: @color-maxBtn;
|
||||
}
|
||||
&.close:after {
|
||||
background-color: @color-closeBtn;
|
||||
}
|
||||
|
||||
&.hide:hover:after {
|
||||
background-color: @color-hideBtn-hover;
|
||||
}
|
||||
&.min:hover:after {
|
||||
background-color: @color-minBtn-hover;
|
||||
opacity: 1;
|
||||
}
|
||||
&.max:hover:after {
|
||||
background-color: @color-maxBtn-hover;
|
||||
}
|
||||
&.close:hover:after {
|
||||
background-color: @color-closeBtn-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hide {
|
||||
&:before {
|
||||
content: '∨';
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.min {
|
||||
&:before {
|
||||
content: ' ';
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
left: @control-btn-width / 2 - 4;
|
||||
top: @control-btn-width / 2 - 1;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.close {
|
||||
&:before {
|
||||
content: '×';
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: auto;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
padding: 0 30px;
|
||||
}
|
||||
.left {
|
||||
flex: 0 0 40%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.info {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
.img {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
border: 5px solid @color-theme-hover;
|
||||
// border: 5px solid #fff;
|
||||
}
|
||||
}
|
||||
.description {
|
||||
width: 300px;
|
||||
padding: 15px 0;
|
||||
overflow: hidden;
|
||||
p {
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 0 0 60%;
|
||||
// padding: 0 30px;
|
||||
position: relative;
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(0deg,rgba(255,255,255,0) 0%,#fff 95%);
|
||||
pointer-events: none;
|
||||
}
|
||||
&:after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(-180deg,rgba(255,255,255,0) 0%,#fff 95%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.lyric {
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
cursor: grab;
|
||||
&.draging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
p {
|
||||
padding: 8px 0;
|
||||
line-height: 1.2;
|
||||
overflow-wrap: break-word;
|
||||
transition: @transition-theme;
|
||||
transition-property: color, font-size;
|
||||
}
|
||||
}
|
||||
.lyric-space {
|
||||
height: 70%;
|
||||
}
|
||||
.lrc-active {
|
||||
color: @color-theme;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.footer {
|
||||
flex: 0 0 100px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.left {
|
||||
flex: auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
padding-top: 13px;
|
||||
}
|
||||
.progress-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
padding: 3px 0;
|
||||
}
|
||||
.progress-content {
|
||||
position: relative;
|
||||
height: 15px;
|
||||
padding: 5px 0;
|
||||
width: 100%;
|
||||
}
|
||||
.progress {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 0.2rem;
|
||||
// overflow: hidden;
|
||||
transition: @transition-theme;
|
||||
transition-property: background-color;
|
||||
background-color: @color-player-progress;
|
||||
// background-color: #f5f5f5;
|
||||
position: relative;
|
||||
border-radius: @radius-progress-border;
|
||||
}
|
||||
.progress-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.progress-bar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform-origin: 0;
|
||||
border-top-right-radius: @radius-progress-border;
|
||||
border-bottom-right-radius: @radius-progress-border;
|
||||
}
|
||||
.progress-bar1 {
|
||||
background-color: @color-player-progress-bar1;
|
||||
}
|
||||
.progress-bar2 {
|
||||
background-color: @color-player-progress-bar2;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
|
||||
border-top-right-radius: 20px;
|
||||
border-bottom-right-radius: 20px;
|
||||
}
|
||||
|
||||
.bar-transition {
|
||||
transition-property: transform;
|
||||
transition-timing-function: ease-out;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
.time-label {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.play-control {
|
||||
flex: none;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 0 25px;
|
||||
color: @color-btn;
|
||||
}
|
||||
.play-btn {
|
||||
height: 40%;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
flex: none;
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
color: @color-player-detail-play-btn;
|
||||
transition: opacity 0.1s ease;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
|
||||
+.play-btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
svg {
|
||||
fill: currentColor;
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.container {
|
||||
border-left-color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
.control {
|
||||
button {
|
||||
// &.hide:after {
|
||||
// background-color: ~'@{color-@{value}-hideBtn}';
|
||||
// }
|
||||
&.hide:after {
|
||||
background-color: ~'@{color-@{value}-hideBtn}';
|
||||
}
|
||||
&.min:after {
|
||||
background-color: ~'@{color-@{value}-minBtn}';
|
||||
}
|
||||
&.max:after {
|
||||
background-color: ~'@{color-@{value}-maxBtn}';
|
||||
}
|
||||
&.close:after {
|
||||
background-color: ~'@{color-@{value}-closeBtn}';
|
||||
}
|
||||
|
||||
&.hide:hover:after {
|
||||
background-color: ~'@{color-@{value}-hideBtn-hover}';
|
||||
}
|
||||
&.min:hover:after {
|
||||
background-color: ~'@{color-@{value}-minBtn-hover}';
|
||||
}
|
||||
&.max:hover:after {
|
||||
background-color: ~'@{color-@{value}-maxBtn-hover}';
|
||||
}
|
||||
&.close:hover:after {
|
||||
background-color: ~'@{color-@{value}-closeBtn-hover}';
|
||||
}
|
||||
}
|
||||
}
|
||||
.img {
|
||||
img {
|
||||
border-color: ~'@{color-@{value}-theme-hover}';
|
||||
}
|
||||
}
|
||||
.lrc-active {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
.progress {
|
||||
background-color: ~'@{color-@{value}-player-progress}';
|
||||
}
|
||||
.progress-bar1 {
|
||||
background-color: ~'@{color-@{value}-player-progress-bar1}';
|
||||
}
|
||||
.progress-bar2 {
|
||||
background-color: ~'@{color-@{value}-player-progress-bar2}';
|
||||
}
|
||||
.play-btn {
|
||||
color: ~'@{color-@{value}-player-detail-play-btn}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -6,14 +6,14 @@
|
||||
@event="handleEvent" :list="tipList" :visibleList="visibleList"
|
||||
v-model="searchText")
|
||||
div(:class="$style.control")
|
||||
button(type="button" :class="$style.min" title="最小化" @click="min")
|
||||
button(type="button" :class="$style.min" :title="$t('core.toolbar.min')" @click="min")
|
||||
//- button(type="button" :class="$style.max" @click="max")
|
||||
button(type="button" :class="$style.close" title="关闭" @click="close")
|
||||
button(type="button" :class="$style.close" :title="$t('core.toolbar.close')" @click="close")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { rendererSend } from 'common/icp'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { rendererSend } from 'common/ipc'
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import music from '../../utils/music'
|
||||
import { debounce } from '../../utils'
|
||||
export default {
|
||||
@@ -23,6 +23,7 @@ export default {
|
||||
visibleList: false,
|
||||
tipList: [],
|
||||
tipSearch: null,
|
||||
isFocused: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -33,15 +34,21 @@ export default {
|
||||
source() {
|
||||
return this.setting.search.tempSearchSource
|
||||
},
|
||||
isAutoClearInput() {
|
||||
isAutoClearSearchInput() {
|
||||
return this.setting.odc.isAutoClearSearchInput
|
||||
},
|
||||
isAutoClearSearchList() {
|
||||
return this.setting.odc.isAutoClearSearchList
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
route(n) {
|
||||
if (this.isAutoClearInput && n.name != 'search' && this.searchText) this.searchText = ''
|
||||
if (n.name != 'search') {
|
||||
if (this.isAutoClearSearchInput && this.searchText) this.searchText = ''
|
||||
if (this.isAutoClearSearchList) this.clearSearchList()
|
||||
}
|
||||
},
|
||||
'storeSearchText'(n) {
|
||||
storeSearchText(n) {
|
||||
if (n !== this.searchText) this.searchText = n
|
||||
},
|
||||
searchText(n) {
|
||||
@@ -61,13 +68,18 @@ export default {
|
||||
}, 50)
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('search', {
|
||||
clearSearchList: 'clearList',
|
||||
}),
|
||||
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 +96,7 @@ export default {
|
||||
},
|
||||
|
||||
handleTipSearch() {
|
||||
if (!this.visibleList) this.visibleList = true
|
||||
if (!this.visibleList && this.isFocused) this.visibleList = true
|
||||
this.tipSearch()
|
||||
},
|
||||
|
||||
@@ -117,6 +129,8 @@ export default {
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
@control-btn-width: @height-toolbar * .5;
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
height: @height-toolbar;
|
||||
@@ -124,9 +138,14 @@ export default {
|
||||
align-items: center;
|
||||
padding-left: 15px;
|
||||
-webkit-app-region: drag;
|
||||
z-index: 1;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
}
|
||||
:global(.nd) {
|
||||
.toolbar {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
}
|
||||
.input {
|
||||
-webkit-app-region: no-drag;
|
||||
position: absolute;
|
||||
@@ -149,8 +168,10 @@ export default {
|
||||
|
||||
.control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
-webkit-app-region: no-drag;
|
||||
padding: 0 @control-btn-width * 0.6;
|
||||
&:hover {
|
||||
button:before {
|
||||
opacity: 1;
|
||||
@@ -159,7 +180,8 @@ export default {
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
width: @height-toolbar;
|
||||
width: @control-btn-width;
|
||||
height: @control-btn-width;
|
||||
background: none;
|
||||
border: none;
|
||||
display: flex;
|
||||
@@ -168,6 +190,9 @@ export default {
|
||||
outline: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
+ button {
|
||||
margin-left: @control-btn-width * 0.4;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: ' ';
|
||||
@@ -196,14 +221,14 @@ export default {
|
||||
}
|
||||
|
||||
&.min:hover:after {
|
||||
background-color: lighten(@color-minBtn, 10%);
|
||||
background-color: @color-minBtn-hover;
|
||||
opacity: 1;
|
||||
}
|
||||
&.max:hover:after {
|
||||
background-color: lighten(@color-maxBtn, 10%);
|
||||
background-color: @color-maxBtn-hover;
|
||||
}
|
||||
&.close:hover:after {
|
||||
background-color: lighten(@color-closeBtn, 10%);
|
||||
background-color: @color-closeBtn-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,8 +237,8 @@ export default {
|
||||
content: ' ';
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
left: @height-toolbar / 2 - 4;
|
||||
top: @height-toolbar / 2 - 1;
|
||||
left: @control-btn-width / 2 - 4;
|
||||
top: @control-btn-width / 2 - 1;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
@@ -228,4 +253,31 @@ export default {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.control {
|
||||
button {
|
||||
&.min:after {
|
||||
background-color: ~'@{color-@{value}-minBtn}';
|
||||
}
|
||||
&.max:after {
|
||||
background-color: ~'@{color-@{value}-maxBtn}';
|
||||
}
|
||||
&.close:after {
|
||||
background-color: ~'@{color-@{value}-closeBtn}';
|
||||
}
|
||||
&.min:hover:after {
|
||||
background-color: ~'@{color-@{value}-minBtn-hover}';
|
||||
}
|
||||
&.max:hover:after {
|
||||
background-color: ~'@{color-@{value}-maxBtn-hover}';
|
||||
}
|
||||
&.close:hover:after {
|
||||
background-color: ~'@{color-@{value}-closeBtn-hover}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
|
||||
@@ -13,6 +13,7 @@ div(:class="$style.view")
|
||||
|
||||
.view {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
> * {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template lang="pug">
|
||||
button(:class="[$style.btn, min ? $style.min : '']" :disabled="disabled" @click="$emit('click', $event)")
|
||||
button(:class="[$style.btn, min ? $style.min : null]" :disabled="disabled" @click="$emit('click', $event)")
|
||||
slot
|
||||
</template>
|
||||
|
||||
@@ -24,13 +24,14 @@ export default {
|
||||
.btn {
|
||||
display: inline-block;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
border-radius: @form-radius;
|
||||
cursor: pointer;
|
||||
padding: 8px 15px;
|
||||
color: @color-btn;
|
||||
outline: none;
|
||||
transition: background-color 0.2s ease;
|
||||
background-color: @color-btn-background;
|
||||
font-size: 14px;
|
||||
&[disabled] {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
label: {},
|
||||
label: {
|
||||
type: String,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -67,17 +69,25 @@ export default {
|
||||
} else {
|
||||
checked.splice(index, 1)
|
||||
}
|
||||
} else if (typeof this.checked == 'string') {
|
||||
checked = this.bool ? this.value : ''
|
||||
} else if (typeof this.checked == 'boolean') {
|
||||
} else {
|
||||
let bool = this.bool
|
||||
if (this.indeterminate) {
|
||||
bool = true
|
||||
// this.$nextTick(() => {
|
||||
this.bool = true
|
||||
// })
|
||||
switch (typeof this.checked) {
|
||||
case 'boolean':
|
||||
if (this.indeterminate) {
|
||||
bool = true
|
||||
this.$nextTick(() => {
|
||||
this.bool = bool
|
||||
})
|
||||
}
|
||||
checked = bool
|
||||
break
|
||||
case 'number':
|
||||
checked = this.value
|
||||
break
|
||||
default:
|
||||
checked = bool ? this.value : ''
|
||||
break
|
||||
}
|
||||
checked = bool
|
||||
}
|
||||
this.$emit('input', checked)
|
||||
this.$emit('change', checked)
|
||||
@@ -88,14 +98,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +122,6 @@ export default {
|
||||
.checkbox {
|
||||
display: inline-block;
|
||||
// font-size: 56px;
|
||||
|
||||
}
|
||||
.input {
|
||||
display: none;
|
||||
@@ -149,6 +158,7 @@ export default {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
color: @color-theme;
|
||||
margin-top: .25em;
|
||||
// border: 1px solid #ccc;
|
||||
&:after {
|
||||
position: absolute;
|
||||
@@ -159,13 +169,14 @@ export default {
|
||||
right: 0;
|
||||
border: 1px solid @color-theme_2-font-label;
|
||||
transition: border-color 0.2s ease;
|
||||
border-radius: 15%;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
transition: 0.3s ease;
|
||||
transition-property: transform;
|
||||
transform: scale(0);
|
||||
border-radius: 2px;
|
||||
// opacity: 0;
|
||||
}
|
||||
|
||||
@@ -173,6 +184,7 @@ export default {
|
||||
flex: auto;
|
||||
line-height: 1;
|
||||
margin-left: 5px;
|
||||
line-height: 1.5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
||||
| {{ info.name }}
|
||||
br
|
||||
| {{ info.singer }}
|
||||
material-btn(:class="$style.btn" :title="!checkSource(type.type) && '腾讯、网易音源仅支持下载128k音质'" :disabled="!checkSource(type.type)" :key="type.type" @click="handleClick(type.type)" v-for="type in info.types") {{getTypeName(type.type)}} {{ type.type.toUpperCase() }}{{ type.size && ` - ${type.size.toUpperCase()}` }}
|
||||
material-btn(:class="$style.btn" :title="!checkSource(type.type) && $t('material.download_modal.btn_tip')" :disabled="!checkSource(type.type)" :key="type.type" @click="handleClick(type.type)" v-for="type in info.types") {{getTypeName(type.type)}} {{ type.type.toUpperCase() }}{{ type.size && ` - ${type.size.toUpperCase()}` }}
|
||||
|
||||
</template>
|
||||
|
||||
@@ -29,6 +29,9 @@ export default {
|
||||
info() {
|
||||
return this.musicInfo || {}
|
||||
},
|
||||
qualityList() {
|
||||
return window.globalObj.qualityList[this.musicInfo.source]
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClick(type) {
|
||||
@@ -41,23 +44,17 @@ export default {
|
||||
switch (type) {
|
||||
case 'flac':
|
||||
case 'ape':
|
||||
return '无损音质'
|
||||
case 'wav':
|
||||
return this.$t('material.download_modal.lossless')
|
||||
case '320k':
|
||||
return '高品音质'
|
||||
return this.$t('material.download_modal.high_quality')
|
||||
case '192k':
|
||||
case '128k':
|
||||
return '普通音质'
|
||||
return this.$t('material.download_modal.normal')
|
||||
}
|
||||
},
|
||||
checkSource(type) {
|
||||
switch (this.musicInfo.source) {
|
||||
case 'wy':
|
||||
case 'tx':
|
||||
return type == '128k'
|
||||
|
||||
default:
|
||||
return true
|
||||
}
|
||||
return this.qualityList.includes(type)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
||||
main(:class="$style.main")
|
||||
h2
|
||||
| 已选择 {{list.length}} 首歌曲
|
||||
| {{$t('material.download_multiple_modal.tip', { len: list.length })}}
|
||||
br
|
||||
| 请选择要优先下载的音质
|
||||
material-btn(:class="$style.btn" @click="handleClick('128k')") 普通音质 - 128K
|
||||
material-btn(:class="$style.btn" @click="handleClick('320k')") 高品音质 - 320K
|
||||
| {{$t('material.download_multiple_modal.tip2')}}
|
||||
material-btn(:class="$style.btn" @click="handleClick('128k')") {{$t('material.download_multiple_modal.normal')}} - 128K
|
||||
material-btn(:class="$style.btn" @click="handleClick('320k')") {{$t('material.download_multiple_modal.high_quality')}} - 320K
|
||||
//- material-btn(:class="$style.btn" @click="handleClick('ape')") 无损音质 - APE
|
||||
material-btn(:class="$style.btn" @click="handleClick('flac')") 无损音质 - FLAC
|
||||
material-btn(:class="$style.btn" @click="handleClick('flac')") {{$t('material.download_multiple_modal.lossless')}} - FLAC/WAV
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<template lang="pug">
|
||||
transition(enter-active-class="animated-fast zoomIn" leave-active-class="animated zoomOut")
|
||||
div(:class="$style.btns" v-show="show")
|
||||
button(type="button" v-if="playBtn" title="播放" @click.stop="handleClick('play')")
|
||||
button(type="button" v-if="playBtn" :title="$t('material.flow_btn.play')" @click.stop="handleClick('play')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 287.386 287.386' space='preserve')
|
||||
use(xlink:href='#icon-testPlay')
|
||||
button(type="button" v-if="addBtn" title="添加" @click.stop="handleClick('add')")
|
||||
button(type="button" v-if="addBtn" :title="$t('material.flow_btn.add')" @click.stop="handleClick('add')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve')
|
||||
use(xlink:href='#icon-addTo')
|
||||
button(type="button" v-if="downloadBtn" title="下载" @click.stop="handleClick('download')")
|
||||
button(type="button" v-if="downloadBtn" :title="$t('material.flow_btn.download')" @click.stop="handleClick('download')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 475.078 475.077' space='preserve')
|
||||
use(xlink:href='#icon-download')
|
||||
button(type="button" v-if="startBtn" title="开始" @click.stop="handleClick('start')")
|
||||
button(type="button" v-if="startBtn" :title="$t('material.flow_btn.start')" @click.stop="handleClick('start')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
button(type="button" v-if="pauseBtn" title="暂停" @click.stop="handleClick('pause')")
|
||||
button(type="button" v-if="pauseBtn" :title="$t('material.flow_btn.pause')" @click.stop="handleClick('pause')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
button(type="button" v-if="removeBtn" title="移除" @click.stop="handleClick('remove')")
|
||||
button(type="button" v-if="removeBtn" :title="$t('material.flow_btn.remove')" @click.stop="handleClick('remove')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
|
||||
use(xlink:href='#icon-delete')
|
||||
|
||||
@@ -78,10 +78,10 @@ export default {
|
||||
button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
margin-right: 5px;
|
||||
border-radius: @form-radius;
|
||||
margin-right: 2px;
|
||||
cursor: pointer;
|
||||
padding: 4px 7px;
|
||||
padding: 6px 10px;
|
||||
color: @color-btn;
|
||||
outline: none;
|
||||
transition: background-color 0.2s ease;
|
||||
@@ -91,7 +91,7 @@ export default {
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 1.2em;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -49,7 +49,7 @@ export default {
|
||||
.input {
|
||||
display: inline-block;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
border-radius: @form-radius;
|
||||
padding: 7px 8px;
|
||||
color: @color-btn;
|
||||
outline: none;
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.btns")
|
||||
button(type="button" v-if="playBtn" title="播放" @click.stop="handleClick('play')")
|
||||
button(type="button" v-if="playBtn" :title="$t('material.list_buttons.play')" @click.stop="handleClick('play')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 287.386 287.386' space='preserve')
|
||||
use(xlink:href='#icon-testPlay')
|
||||
button(type="button" v-if="listAddBtn" title="添加到..." @click.stop="handleClick('listAdd')")
|
||||
button(type="button" v-if="listAddBtn" :title="$t('material.list_buttons.add_to')" @click.stop="handleClick('listAdd')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve')
|
||||
use(xlink:href='#icon-addTo')
|
||||
button(type="button" v-if="downloadBtn" title="下载" @click.stop="handleClick('download')")
|
||||
button(type="button" v-if="downloadBtn" :title="$t('material.list_buttons.download')" @click.stop="handleClick('download')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 475.078 475.077' space='preserve')
|
||||
use(xlink:href='#icon-download')
|
||||
button(type="button" title="添加" v-if="userInfo" @click.stop="handleClick('add')")
|
||||
button(type="button" :title="$t('material.list_buttons.add')" v-if="userInfo" @click.stop="handleClick('add')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve')
|
||||
use(xlink:href='#icon-addTo')
|
||||
button(type="button" v-if="startBtn" title="开始" @click.stop="handleClick('start')")
|
||||
button(type="button" v-if="startBtn" :title="$t('material.list_buttons.start')" @click.stop="handleClick('start')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
button(type="button" v-if="pauseBtn" title="暂停" @click.stop="handleClick('pause')")
|
||||
button(type="button" v-if="pauseBtn" :title="$t('material.list_buttons.pause')" @click.stop="handleClick('pause')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
button(type="button" v-if="fileBtn" title="定位文件" @click.stop="handleClick('file')")
|
||||
button(type="button" v-if="fileBtn" :title="$t('material.list_buttons.file')" @click.stop="handleClick('file')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='-61 0 512 512' space='preserve')
|
||||
use(xlink:href='#icon-musicFile')
|
||||
button(type="button" v-if="removeBtn" title="移除" @click.stop="handleClick('remove')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
|
||||
use(xlink:href='#icon-delete')
|
||||
button(type="button" v-if="searchBtn" title="搜索" @click.stop="handleClick('search')")
|
||||
button(type="button" v-if="searchBtn" :title="$t('material.list_buttons.search')" @click.stop="handleClick('search')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 30.239 30.239' space='preserve')
|
||||
use(xlink:href='#icon-search')
|
||||
button(type="button" v-if="removeBtn" :title="$t('material.list_buttons.remove')" @click.stop="handleClick('remove')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
|
||||
use(xlink:href='#icon-delete')
|
||||
|
||||
</template>
|
||||
|
||||
@@ -88,10 +88,12 @@ export default {
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.btns {
|
||||
line-height: 1;
|
||||
|
||||
button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
border-radius: @form-radius;
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
padding: 4px 7px;
|
||||
@@ -104,7 +106,7 @@ export default {
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 1.2em;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -6,7 +6,7 @@ transition(enter-active-class="animated fadeIn"
|
||||
:leave-active-class="outClass")
|
||||
div(:class="$style.content" v-show="show" @click.stop)
|
||||
header(:class="$style.header")
|
||||
button(type="button" @click="close")
|
||||
button(type="button" @click="close" v-if="closeBtn")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
|
||||
use(xlink:href='#icon-delete')
|
||||
slot
|
||||
@@ -21,6 +21,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
closeBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
bgClose: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -48,6 +52,7 @@ export default {
|
||||
'slideInLeft',
|
||||
'slideInRight',
|
||||
'slideInUp',
|
||||
'jackInTheBox',
|
||||
],
|
||||
animateOut: [
|
||||
'flipOutX',
|
||||
@@ -80,25 +85,31 @@ export default {
|
||||
...mapGetters(['setting']),
|
||||
},
|
||||
watch: {
|
||||
'setting.randomAnimate': {
|
||||
handler(n) {
|
||||
if (n) {
|
||||
this.unwatchFn = this.$watch('show', function(n) {
|
||||
if (n) {
|
||||
this.inClass = 'animated ' + this.animateIn[getRandom(0, this.animateIn.length)]
|
||||
this.outClass = 'animated ' + this.animateOut[getRandom(0, this.animateOut.length)]
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.unwatchFn && this.unwatchFn()
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
'setting.randomAnimate'(n) {
|
||||
n ? this.createWatch() : this.removeWatch()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.setting.randomAnimate) this.createWatch()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.removeWatch()
|
||||
},
|
||||
methods: {
|
||||
createWatch() {
|
||||
this.removeWatch()
|
||||
this.unwatchFn = this.$watch('show', function(n) {
|
||||
this.inClass = 'animated ' + this.animateIn[getRandom(0, this.animateIn.length)]
|
||||
this.outClass = 'animated ' + this.animateOut[getRandom(0, this.animateOut.length)]
|
||||
})
|
||||
this.inClass = 'animated ' + this.animateIn[getRandom(0, this.animateIn.length)]
|
||||
this.outClass = 'animated ' + this.animateOut[getRandom(0, this.animateOut.length)]
|
||||
},
|
||||
removeWatch() {
|
||||
if (!this.unwatchFn) return
|
||||
this.unwatchFn()
|
||||
this.unwatchFn = null
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
},
|
||||
@@ -127,7 +138,7 @@ export default {
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, .3);
|
||||
overflow: hidden;
|
||||
max-height: 70%;
|
||||
max-height: 80%;
|
||||
max-width: 70%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -142,7 +153,9 @@ export default {
|
||||
flex: none;
|
||||
background-color: @color-theme;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: 18px;
|
||||
|
||||
button {
|
||||
border: none;
|
||||
|
||||
177
src/renderer/components/material/PactModal.vue
Normal file
177
src/renderer/components/material/PactModal.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="!setting.isAgreePact || globalObj.isShowPact" @close="handleClose(false)" :bgClose="setting.isAgreePact" :close-btn="setting.isAgreePact")
|
||||
main(:class="$style.main")
|
||||
h2 许可协议
|
||||
div.select.scroll(:class="$style.content")
|
||||
p
|
||||
| 本项目(软件)基于
|
||||
strong.hover.underline(@click="openUrl('http://www.apache.org/licenses/LICENSE-2.0')") Apache License 2.0
|
||||
| 许可证发行,在使用本软件前,你(使用者)需签署本协议才可继续使用,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。
|
||||
br
|
||||
p 词语约定:本协议中的“本软件”指洛雪音乐桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本软件内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。
|
||||
br
|
||||
p
|
||||
strong 1、
|
||||
| 本软件的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本软件不对数据的准确性负责。
|
||||
p
|
||||
strong 2、
|
||||
| 使用本软件的过程中可能会产生版权数据,对于这些版权数据,本软件不拥有它们的所有权,为了避免造成侵权,使用者务必在
|
||||
strong 24小时内
|
||||
| 清除使用本软件的过程中所产生的版权数据。
|
||||
p
|
||||
strong 3、
|
||||
| 本软件内的官方音乐平台别名为本软件内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本软件更改或移除。
|
||||
p
|
||||
strong 4、
|
||||
| 本软件内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本软件移除。
|
||||
p
|
||||
strong 5、
|
||||
| 由于使用本软件产生的包括由于本协议或由于使用或无法使用本软件而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。
|
||||
p
|
||||
strong 6、
|
||||
| 本项目完全免费,且开源发布于
|
||||
span.hover.underline(@click="openUrl('https://github.com/lyswhut/lx-music-desktop#readme')") GitHub
|
||||
| 面向全世界人用作对技术的学习交流,本软件不对项目内的技术可能存在违反当地法律法规的行为作保证,
|
||||
strong 禁止在违反当地法律法规的情况下使用本软件
|
||||
|,对于使用者在明知或不知当地法律法规不允许的情况下使用本软件所造成的任何违法违规行为由使用者承担,本软件不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。
|
||||
br
|
||||
p
|
||||
strong *
|
||||
| 若协议更新,恕不另行通知,可到开源地址查看。
|
||||
p
|
||||
strong *
|
||||
| 本软件的初衷是帮助官方音乐平台简化数据后代为展示,帮助使用者根据歌曲名、艺术家等关键字快速地定位所需内容所在的音乐平台。
|
||||
p
|
||||
strong *
|
||||
| 音乐平台不易,建议到对应音乐平台支持正版资源。
|
||||
|
||||
br
|
||||
p(v-if="!setting.isAgreePact")
|
||||
strong 若你(使用者)接受以上协议,请点击下面的“接受”按钮签署本协议,若不接受,请点击“不接受”后退出软件并清除本软件的所有数据。
|
||||
|
||||
|
||||
div(:class="$style.btns" v-if="!setting.isAgreePact")
|
||||
material-btn(:class="$style.btn" @click="handleClose(true)") 不接受
|
||||
material-btn(:class="$style.btn" :disabled="!btnEnable" @click="handleClick()") 接受 {{timeStr}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { rendererSend } from '../../../common/ipc'
|
||||
import { openUrl } from '../../utils'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
time: 20,
|
||||
globalObj: {
|
||||
isShowPact: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
btnEnable() {
|
||||
return this.time == 0
|
||||
},
|
||||
timeStr() {
|
||||
return this.btnEnable ? '' : `(${this.time})`
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'setting.isAgreePact'(n) {
|
||||
if (n) return
|
||||
this.time = 10
|
||||
this.startTimeout()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.globalObj = window.globalObj
|
||||
if (!this.setting.isAgreePact) {
|
||||
this.startTimeout()
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setAgreePact']),
|
||||
handleClick() {
|
||||
this.setAgreePact()
|
||||
},
|
||||
handleClose(isExit) {
|
||||
if (isExit) return rendererSend('close', true)
|
||||
this.globalObj.isShowPact = false
|
||||
},
|
||||
openUrl(url) {
|
||||
openUrl(url)
|
||||
},
|
||||
startTimeout() {
|
||||
setTimeout(() => {
|
||||
if (--this.time > 0) this.startTimeout()
|
||||
}, 1000)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
padding: 15px;
|
||||
max-width: 550px;
|
||||
min-width: 200px;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
color: @color-theme_2-font;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: auto;
|
||||
margin: 15px 0;
|
||||
padding-right: 5px;
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
line-height: 2;
|
||||
}
|
||||
p {
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.btn {
|
||||
display: block;
|
||||
width: 48%;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.main {
|
||||
h2 {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
}
|
||||
.name {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -6,20 +6,20 @@ div(:class="$style.pagination" v-if="allPage > 1")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
|
||||
use(xlink:href='#icon-left')
|
||||
li(v-else)
|
||||
button(type="button" @click="handleClick(page - 1)" title="上一页")
|
||||
button(type="button" @click="handleClick(page - 1)" :title="$t('material.pagination.prev')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
|
||||
use(xlink:href='#icon-left')
|
||||
li(v-if="allPage > btnLength && page > pageEvg+1" :class="$style.first")
|
||||
button(type="button" @click="handleClick(1)" title="第 1 页")
|
||||
button(type="button" @click="handleClick(1)" :title="$t('material.pagination.page', { num: 1 })")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
|
||||
use(xlink:href='#icon-first')
|
||||
|
||||
li(v-for="(p, index) in pages" :key="index" :class="{[$style.active] : p == page}")
|
||||
span(v-if="p === page" v-text="page")
|
||||
button(v-else type="button" @click="handleClick(p)" v-text="p" :title="`第 ${p} 页`")
|
||||
button(v-else type="button" @click="handleClick(p)" v-text="p" :title="$t('material.pagination.page', { num: p })")
|
||||
|
||||
li(v-if="allPage > btnLength && allPage - page > pageEvg" :class="$style.last")
|
||||
button(type="button" @click="handleClick(allPage)" :title="`第 ${allPage} 页`")
|
||||
button(type="button" @click="handleClick(allPage)" :title="$t('material.pagination.page', { num: allPage })")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
|
||||
use(xlink:href='#icon-last')
|
||||
|
||||
@@ -29,7 +29,7 @@ div(:class="$style.pagination" v-if="allPage > 1")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
|
||||
use(xlink:href='#icon-right')
|
||||
li(v-else)
|
||||
button(type="button" @click="handleClick(page + 1)" title="下一页")
|
||||
button(type="button" @click="handleClick(page + 1)" :title="$t('material.pagination.next')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
|
||||
use(xlink:href='#icon-right')
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<template lang="pug">
|
||||
div(:class="[$style.search, focus ? $style.active : '', big ? $style.big : '', small ? $style.small : '']")
|
||||
div(:class="$style.form")
|
||||
input(:placeholder="placeholder" v-model.trim="text"
|
||||
input(:placeholder="placeholder" v-model.trim="text" ref="dom_input"
|
||||
@focus="handleFocus" @blur="handleBlur" @input="$emit('input', text)"
|
||||
@change="sendEvent('change')"
|
||||
@keyup.enter="handleSearch")
|
||||
@keyup.enter="handleSearch"
|
||||
@keyup.40.prevent="handleKeyDown"
|
||||
@keyup.38.prevent="handleKeyUp"
|
||||
@contextmenu="handleContextMenu")
|
||||
button(type="button" @click="handleSearch")
|
||||
slot
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 30.239 30.239' space='preserve')
|
||||
@@ -14,11 +17,12 @@ div(:class="[$style.search, focus ? $style.active : '', big ? $style.big : '', s
|
||||
//- leave-active-class="animated flipOutX")
|
||||
div(v-if="list" :class="$style.list" :style="listStyle")
|
||||
ul(ref="dom_list")
|
||||
li(v-for="(item, index) in list" :key="item" @click="handleTemplistClick(index)")
|
||||
li(v-for="(item, index) in list" :key="item" :class="selectIndex === index ? $style.select : null" @mouseenter="selectIndex = index" @click="handleTemplistClick(index)")
|
||||
span {{item}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { clipboardReadText } from '../../utils'
|
||||
export default {
|
||||
props: {
|
||||
placeholder: {
|
||||
@@ -49,7 +53,7 @@ export default {
|
||||
return {
|
||||
isShow: false,
|
||||
text: '',
|
||||
index: null,
|
||||
selectIndex: -1,
|
||||
focus: false,
|
||||
listStyle: {
|
||||
height: 0,
|
||||
@@ -59,6 +63,7 @@ export default {
|
||||
watch: {
|
||||
list(n) {
|
||||
if (!this.visibleList) return
|
||||
if (this.selectIndex > -1) this.selectIndex = -1
|
||||
this.$nextTick(() => {
|
||||
this.listStyle.height = this.$refs.dom_list.scrollHeight + 'px'
|
||||
})
|
||||
@@ -70,6 +75,9 @@ export default {
|
||||
n ? this.showList() : this.hideList()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.$store.getters.setting.search.isFocusSearchBox) this.$refs.dom_input.focus()
|
||||
},
|
||||
methods: {
|
||||
handleTemplistClick(index) {
|
||||
this.sendEvent('listClick', index)
|
||||
@@ -84,7 +92,8 @@ export default {
|
||||
},
|
||||
handleSearch() {
|
||||
this.hideList()
|
||||
this.sendEvent('submit')
|
||||
if (this.selectIndex < 0) return this.sendEvent('submit')
|
||||
this.sendEvent('listClick', this.selectIndex)
|
||||
},
|
||||
showList() {
|
||||
this.isShow = true
|
||||
@@ -93,6 +102,9 @@ export default {
|
||||
hideList() {
|
||||
this.isShow = false
|
||||
this.listStyle.height = 0
|
||||
this.$nextTick(() => {
|
||||
this.selectIndex = -1
|
||||
})
|
||||
},
|
||||
sendEvent(action, data) {
|
||||
this.$emit('event', {
|
||||
@@ -100,6 +112,21 @@ export default {
|
||||
data,
|
||||
})
|
||||
},
|
||||
handleKeyDown() {
|
||||
this.selectIndex = this.selectIndex + 1 < this.list.length ? this.selectIndex + 1 : 0
|
||||
},
|
||||
handleKeyUp() {
|
||||
this.selectIndex = this.selectIndex - 1 < -1 ? this.list.length - 1 : this.selectIndex - 1
|
||||
},
|
||||
handleContextMenu() {
|
||||
let str = clipboardReadText()
|
||||
str = str.trim()
|
||||
str = str.replace(/\t|\r\n|\n|\r/g, ' ')
|
||||
str = str.replace(/\s+/g, ' ')
|
||||
let dom_input = this.$refs.dom_input
|
||||
this.text = `${this.text.substring(0, dom_input.selectionStart)}${str}${this.text.substring(dom_input.selectionEnd, this.text.length)}`
|
||||
this.$emit('input', this.text)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -109,7 +136,7 @@ export default {
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.search {
|
||||
border-radius: 3px;
|
||||
border-radius: @form-radius;
|
||||
transition: box-shadow .4s ease, background-color @transition-theme;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
@@ -187,7 +214,7 @@ export default {
|
||||
.mixin-ellipsis-2;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&.select {
|
||||
background-color: @color-search-list-hover;
|
||||
}
|
||||
&:last-child {
|
||||
@@ -239,7 +266,7 @@ each(@themes, {
|
||||
}
|
||||
.list {
|
||||
li {
|
||||
&:hover {
|
||||
&.select {
|
||||
background-color: ~'@{color-@{value}-search-list-hover}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { isChildren } from '../../utils'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
@@ -83,6 +83,7 @@ export default {
|
||||
border-top-left-radius: 4px;
|
||||
color: @color-btn;
|
||||
cursor: pointer;
|
||||
.mixin-ellipsis-1;
|
||||
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
@@ -94,6 +95,7 @@ export default {
|
||||
|
||||
.list {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
border-bottom: 2px solid @color-tab-border-bottom;
|
||||
@@ -116,6 +118,7 @@ export default {
|
||||
transition: background-color @transition-theme;
|
||||
background-color: @color-btn-background;
|
||||
box-sizing: border-box;
|
||||
.mixin-ellipsis-1;
|
||||
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
|
||||
223
src/renderer/components/material/Selection.vue
Normal file
223
src/renderer/components/material/Selection.vue
Normal file
@@ -0,0 +1,223 @@
|
||||
<template lang="pug">
|
||||
div(:class="[$style.select, show ? $style.active : '']")
|
||||
div(:class="$style.label" ref="dom_btn" @click="handleShow")
|
||||
span {{label}}
|
||||
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')
|
||||
ul.scroll(:class="$style.list" :style="listStyles" ref="dom_list")
|
||||
li(v-for="item in list" :class="(itemKey ? item[itemKey] : item) == value ? $style.active : null" @click="handleClick(item)" :title="itemName ? item[itemName] : item") {{itemName ? item[itemName] : item}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
},
|
||||
itemName: {
|
||||
type: String,
|
||||
},
|
||||
itemKey: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
listStyles: {
|
||||
transform: 'scaleY(0) translateY(0)',
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener('click', this.handleHide)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('click', this.handleHide)
|
||||
},
|
||||
computed: {
|
||||
label() {
|
||||
if (!this.value) return ''
|
||||
if (!this.itemName) return this.value
|
||||
const item = this.list.find(l => l[this.itemKey] == this.value)
|
||||
if (!item) return ''
|
||||
return item[this.itemName]
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleHide(e) {
|
||||
// if (e && e.target.parentNode != this.$refs.dom_list && this.show) return this.show = false
|
||||
if (e && (e.target == this.$refs.dom_btn || this.$refs.dom_btn.contains(e.target))) return
|
||||
this.listStyles.transform = 'scaleY(0) translateY(0)'
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
}, 50)
|
||||
},
|
||||
handleClick(item) {
|
||||
// console.log(this.value)
|
||||
if (item === this.value) return
|
||||
this.$emit('input', this.itemKey ? item[this.itemKey] : item)
|
||||
this.$emit('change', item)
|
||||
},
|
||||
handleShow() {
|
||||
this.show = true
|
||||
this.listStyles.transform = `scaleY(1) translateY(${this.handleGetOffset()}px)`
|
||||
},
|
||||
handleGetOffset() {
|
||||
const listHeight = this.$refs.dom_list.clientHeight
|
||||
const dom_select = this.$refs.dom_list.offsetParent
|
||||
const dom_container = dom_select.offsetParent
|
||||
const containerHeight = dom_container.clientHeight
|
||||
if (containerHeight < listHeight) return 0
|
||||
const offsetHeight = (dom_container.scrollTop + containerHeight) - (dom_select.offsetTop + listHeight)
|
||||
if (offsetHeight > 0) return 0
|
||||
return offsetHeight - 5
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
@selection-height: 28px;
|
||||
|
||||
.select {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
width: 300px;
|
||||
|
||||
&.active {
|
||||
.label {
|
||||
background-color: @color-btn-background;
|
||||
}
|
||||
.list {
|
||||
opacity: 1;
|
||||
}
|
||||
.icon {
|
||||
svg{
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
background-color: @color-btn-background;
|
||||
padding: 0 10px;
|
||||
transition: background-color @transition-theme;
|
||||
height: @selection-height;
|
||||
line-height: 27px;
|
||||
box-sizing: border-box;
|
||||
color: @color-btn;
|
||||
border-radius: @form-radius;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
span {
|
||||
flex: auto;
|
||||
.mixin-ellipsis-1;
|
||||
}
|
||||
.icon {
|
||||
flex: none;
|
||||
margin-left: 7px;
|
||||
line-height: 0;
|
||||
svg {
|
||||
width: 1em;
|
||||
transition: transform .2s ease;
|
||||
transform: rotate(0);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&:active {
|
||||
background-color: @color-theme_2-active;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: @color-theme_2-background_2;
|
||||
opacity: 0;
|
||||
transform: scaleY(0) translateY(0);
|
||||
transform-origin: 0 @selection-height / 2 0;
|
||||
transition: .25s ease;
|
||||
transition-property: transform, opacity;
|
||||
z-index: 10;
|
||||
border-radius: @form-radius;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, .15);
|
||||
overflow: auto;
|
||||
max-height: 200px;
|
||||
|
||||
li {
|
||||
cursor: pointer;
|
||||
padding: 0 10px;
|
||||
line-height: @selection-height;
|
||||
// color: @color-btn;
|
||||
outline: none;
|
||||
transition: background-color @transition-theme;
|
||||
background-color: @color-btn-background;
|
||||
box-sizing: border-box;
|
||||
.mixin-ellipsis-1;
|
||||
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&:active {
|
||||
background-color: @color-theme_2-active;
|
||||
}
|
||||
&.active {
|
||||
color: @color-btn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.label {
|
||||
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}';
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
background-color: ~'@{color-@{value}-theme_2-background_2}';
|
||||
li {
|
||||
// color: ~'@{color-@{value}-btn}';
|
||||
background-color: ~'@{color-@{value}-btn-background}';
|
||||
&:hover {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
}
|
||||
&:active {
|
||||
background-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
&.active {
|
||||
color: ~'@{color-@{value}-btn}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -1,51 +1,52 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.songList")
|
||||
transition(enter-active-class="animated fadeIn" leave-active-class="animated fadeOut")
|
||||
div(v-if="list.length" :class="$style.list")
|
||||
transition(enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut")
|
||||
div(v-show="list.length" :class="$style.list")
|
||||
div(:class="$style.thead")
|
||||
table
|
||||
thead
|
||||
tr
|
||||
th.nobreak.center(style="width: 37px;")
|
||||
material-checkbox(id="search_select_all" v-model="isSelectAll" @change="handleSelectAllData"
|
||||
:indeterminate="isIndeterminate" :title="isSelectAll && !isIndeterminate ? '全不选' : '全选'")
|
||||
th.nobreak(style="width: 25%;") 歌曲名
|
||||
th.nobreak(style="width: 20%;") 歌手
|
||||
th.nobreak(style="width: 20%;") 专辑
|
||||
th.nobreak(style="width: 20%;") 操作
|
||||
th.nobreak(style="width: 10%;") 时长
|
||||
th.nobreak.center(style="width: 10px;") #
|
||||
th.nobreak(style="width: 25%;") {{$t('material.song_list.name')}}
|
||||
th.nobreak(style="width: 20%;") {{$t('material.song_list.singer')}}
|
||||
th.nobreak(style="width: 20%;") {{$t('material.song_list.album')}}
|
||||
th.nobreak(style="width: 20%;") {{$t('material.song_list.action')}}
|
||||
th.nobreak(style="width: 10%;") {{$t('material.song_list.time')}}
|
||||
div.scroll(:class="$style.tbody" ref="dom_scrollContent")
|
||||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid' @click="handleDoubleClick(index)")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdList" @change="handleChangeSelect" :value="item")
|
||||
tbody(@contextmenu="handleContextMenu" ref="dom_tbody")
|
||||
tr(v-for='(item, index) in list' :key='item.songmid' @click="handleDoubleClick($event, index)")
|
||||
td.nobreak.center(style="width: 37px;" :class="$style.noSelect" @click.stop) {{index + 1}}
|
||||
td.break(style="width: 25%;")
|
||||
| {{item.name}}
|
||||
span.badge.badge-info(v-if="item._types['320k']") 高品质
|
||||
span.badge.badge-success(v-if="item._types.ape || item._types.flac") 无损
|
||||
td.break(style="width: 20%;") {{item.singer}}
|
||||
td.break(style="width: 20%;") {{item.albumName}}
|
||||
span.select {{item.name}}
|
||||
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-if="item._types.ape || item._types.flac || item._types.wav") {{$t('material.song_list.lossless')}}
|
||||
span.badge.badge-theme-info(:class="[$style.labelQuality, $style.noSelect]" v-else-if="item._types['320k']") {{$t('material.song_list.high_quality')}}
|
||||
td.break(style="width: 20%;")
|
||||
span.select {{item.singer}}
|
||||
td.break(style="width: 20%;")
|
||||
span.select {{item.albumName}}
|
||||
td(style="width: 20%; padding-left: 0; padding-right: 0;")
|
||||
material-list-buttons(:index="index" :search-btn="true"
|
||||
:remove-btn="false" @btn-click="handleListBtnClick"
|
||||
:listAdd-btn="item.source == 'kw' || (!isAPITemp)"
|
||||
:play-btn="item.source == 'kw' || (!isAPITemp)"
|
||||
:download-btn="item.source == 'kw' || (!isAPITemp)")
|
||||
:listAdd-btn="assertApiSupport(item.source)"
|
||||
:play-btn="assertApiSupport(item.source)"
|
||||
:download-btn="assertApiSupport(item.source)")
|
||||
//- button.btn-info(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k'] || item._types.flac" @click.stop='openDownloadModal(index)') 下载
|
||||
//- button.btn-secondary(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k']" @click.stop='testPlay(index)') 试听
|
||||
//- button.btn-success(type='button' v-if="(item._types['128k'] || item._types['192k'] || item._types['320k']) && userInfo" @click.stop='showListModal(index)') +
|
||||
td(style="width: 10%;") {{item.interval || '--/--'}}
|
||||
td(style="width: 10%;")
|
||||
span(:class="[$style.time, $style.noSelect]") {{item.interval || '--/--'}}
|
||||
div(:class="$style.pagination")
|
||||
material-pagination(:count="total" :limit="limit" :page="page" @btn-click="handleTogglePage")
|
||||
div(v-else :class="$style.noitem")
|
||||
transition(enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut")
|
||||
div(v-show="!list.length" :class="$style.noitem")
|
||||
p(v-html="noItem")
|
||||
material-flow-btn(:show="isShowEditBtn && (source == 'kw' || !isAPITemp)" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||
material-flow-btn(:show="isShowEditBtn && assertApiSupport(source)" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { scrollTo } from '../../utils'
|
||||
import { scrollTo, clipboardWriteText, assertApiSupport } from '../../utils'
|
||||
export default {
|
||||
name: 'MaterialSongList',
|
||||
model: {
|
||||
@@ -85,37 +86,28 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
isAPITemp() {
|
||||
return this.setting.apiSource == 'temp'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectdList(n) {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isShowEditBtn = true
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
}
|
||||
},
|
||||
selectdData(n) {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isShowEditBtn = true
|
||||
this.selectdList = [...n]
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
this.resetSelect()
|
||||
this.removeAllSelect()
|
||||
}
|
||||
},
|
||||
list(n) {
|
||||
this.resetSelect()
|
||||
this.removeAllSelect()
|
||||
if (!this.list.length) return
|
||||
this.$nextTick(() => scrollTo(this.$refs.dom_scrollContent, 0))
|
||||
},
|
||||
@@ -124,14 +116,77 @@ export default {
|
||||
return {
|
||||
clickTime: 0,
|
||||
clickIndex: -1,
|
||||
isSelectAll: false,
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
selectdList: [],
|
||||
keyEvent: {
|
||||
isShiftDown: false,
|
||||
isModDown: false,
|
||||
isADown: false,
|
||||
aDownTimeout: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.listenEvent()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.unlistenEvent()
|
||||
},
|
||||
methods: {
|
||||
handleDoubleClick(index) {
|
||||
listenEvent() {
|
||||
window.eventHub.$on('key_shift_down', this.handle_key_shift_down)
|
||||
window.eventHub.$on('key_shift_up', this.handle_key_shift_up)
|
||||
window.eventHub.$on('key_mod_down', this.handle_key_mod_down)
|
||||
window.eventHub.$on('key_mod_up', this.handle_key_mod_up)
|
||||
window.eventHub.$on('key_mod+a_down', this.handle_key_mod_a_down)
|
||||
window.eventHub.$on('key_mod+a_up', this.handle_key_mod_a_up)
|
||||
},
|
||||
unlistenEvent() {
|
||||
window.eventHub.$off('key_shift_down', this.handle_key_shift_down)
|
||||
window.eventHub.$off('key_shift_up', this.handle_key_shift_up)
|
||||
window.eventHub.$off('key_mod_down', this.handle_key_mod_down)
|
||||
window.eventHub.$off('key_mod_up', this.handle_key_mod_up)
|
||||
window.eventHub.$off('key_mod+a_down', this.handle_key_mod_a_down)
|
||||
window.eventHub.$off('key_mod+a_up', this.handle_key_mod_a_up)
|
||||
},
|
||||
handle_key_shift_down() {
|
||||
if (!this.keyEvent.isShiftDown) this.keyEvent.isShiftDown = true
|
||||
},
|
||||
handle_key_shift_up() {
|
||||
if (this.keyEvent.isShiftDown) this.keyEvent.isShiftDown = false
|
||||
},
|
||||
handle_key_mod_down() {
|
||||
if (!this.keyEvent.isModDown) this.keyEvent.isModDown = true
|
||||
},
|
||||
handle_key_mod_up() {
|
||||
if (this.keyEvent.isModDown) this.keyEvent.isModDown = false
|
||||
},
|
||||
handle_key_mod_a_down() {
|
||||
if (!this.keyEvent.isADown) {
|
||||
this.keyEvent.isModDown = false
|
||||
this.keyEvent.isADown = true
|
||||
this.handleSelectAllData()
|
||||
if (this.keyEvent.aDownTimeout) clearTimeout(this.keyEvent.aDownTimeout)
|
||||
this.keyEvent.aDownTimeout = setTimeout(() => {
|
||||
this.keyEvent.aDownTimeout = null
|
||||
this.keyEvent.isADown = false
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
handle_key_mod_a_up() {
|
||||
if (this.keyEvent.isADown) {
|
||||
if (this.keyEvent.aDownTimeout) {
|
||||
clearTimeout(this.keyEvent.aDownTimeout)
|
||||
this.keyEvent.aDownTimeout = null
|
||||
}
|
||||
this.keyEvent.isADown = false
|
||||
}
|
||||
},
|
||||
handleDoubleClick(event, index) {
|
||||
if (event.target.classList.contains('select')) return
|
||||
|
||||
this.handleSelectData(event, index)
|
||||
|
||||
if (
|
||||
window.performance.now() - this.clickTime > 400 ||
|
||||
this.clickIndex !== index
|
||||
@@ -140,21 +195,71 @@ export default {
|
||||
this.clickIndex = index
|
||||
return
|
||||
}
|
||||
this.emitEvent((this.source == 'kw' || !this.isAPITemp) ? 'testPlay' : 'search', index)
|
||||
this.emitEvent(this.assertApiSupport(this.source) ? 'testPlay' : 'search', index)
|
||||
this.clickTime = 0
|
||||
this.clickIndex = -1
|
||||
},
|
||||
handleSelectData(event, clickIndex) {
|
||||
if (this.keyEvent.isShiftDown) {
|
||||
if (this.selectdList.length) {
|
||||
let lastSelectIndex = this.list.indexOf(this.selectdList[this.selectdList.length - 1])
|
||||
this.removeAllSelect()
|
||||
if (lastSelectIndex != clickIndex) {
|
||||
let isNeedReverse = false
|
||||
if (clickIndex < lastSelectIndex) {
|
||||
let temp = lastSelectIndex
|
||||
lastSelectIndex = clickIndex
|
||||
clickIndex = temp
|
||||
isNeedReverse = true
|
||||
}
|
||||
this.selectdList = this.list.slice(lastSelectIndex, clickIndex + 1)
|
||||
if (isNeedReverse) this.selectdList.reverse()
|
||||
let nodes = this.$refs.dom_tbody.childNodes
|
||||
do {
|
||||
nodes[lastSelectIndex].classList.add('active')
|
||||
lastSelectIndex++
|
||||
} while (lastSelectIndex <= clickIndex)
|
||||
}
|
||||
} else {
|
||||
event.currentTarget.classList.add('active')
|
||||
this.selectdList.push(this.list[clickIndex])
|
||||
}
|
||||
} else if (this.keyEvent.isModDown) {
|
||||
let item = this.list[clickIndex]
|
||||
let index = this.selectdList.indexOf(item)
|
||||
if (index < 0) {
|
||||
this.selectdList.push(item)
|
||||
event.currentTarget.classList.add('active')
|
||||
} else {
|
||||
this.selectdList.splice(index, 1)
|
||||
event.currentTarget.classList.remove('active')
|
||||
}
|
||||
} else if (this.selectdList.length) {
|
||||
this.removeAllSelect()
|
||||
} else return
|
||||
this.$emit('input', [...this.selectdList])
|
||||
},
|
||||
removeAllSelect() {
|
||||
this.selectdList = []
|
||||
let dom_tbody = this.$refs.dom_tbody
|
||||
if (!dom_tbody) return
|
||||
let nodes = dom_tbody.querySelectorAll('.active')
|
||||
for (const node of nodes) {
|
||||
if (node.parentNode == dom_tbody) node.classList.remove('active')
|
||||
}
|
||||
},
|
||||
handleListBtnClick(info) {
|
||||
this.emitEvent('listBtnClick', info)
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdList = isSelect ? [...this.list] : []
|
||||
handleSelectAllData() {
|
||||
this.removeAllSelect()
|
||||
this.selectdList = [...this.list]
|
||||
let nodes = this.$refs.dom_tbody.childNodes
|
||||
for (const node of nodes) {
|
||||
node.classList.add('active')
|
||||
}
|
||||
this.$emit('input', [...this.selectdList])
|
||||
},
|
||||
resetSelect() {
|
||||
this.selectdList = false
|
||||
this.selectdList = []
|
||||
},
|
||||
handleTogglePage(page) {
|
||||
this.emitEvent('togglePage', page)
|
||||
},
|
||||
@@ -167,6 +272,21 @@ export default {
|
||||
handleChangeSelect() {
|
||||
this.$emit('input', [...this.selectdList])
|
||||
},
|
||||
handleContextMenu(event) {
|
||||
if (!event.target.classList.contains('select')) return
|
||||
let classList = this.$refs.dom_scrollContent.classList
|
||||
classList.add(this.$style.copying)
|
||||
window.requestAnimationFrame(() => {
|
||||
let str = window.getSelection().toString()
|
||||
classList.remove(this.$style.copying)
|
||||
str = str.trim()
|
||||
if (!str.length) return
|
||||
clipboardWriteText(str)
|
||||
})
|
||||
},
|
||||
assertApiSupport(source) {
|
||||
return assertApiSupport(source)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -179,6 +299,7 @@ export default {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.list {
|
||||
@@ -190,6 +311,10 @@ export default {
|
||||
}
|
||||
.thead {
|
||||
flex: none;
|
||||
tr > th:first-child {
|
||||
color: @color-theme_2-font-label;
|
||||
// padding-left: 10px;
|
||||
}
|
||||
}
|
||||
.tbody {
|
||||
flex: auto;
|
||||
@@ -197,13 +322,21 @@ export default {
|
||||
td {
|
||||
font-size: 12px;
|
||||
:global(.badge) {
|
||||
margin-right: 3px;
|
||||
&:first-child {
|
||||
margin-left: 3px;
|
||||
}
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
margin-left: 3px;
|
||||
}
|
||||
&:first-child {
|
||||
// padding-left: 10px;
|
||||
font-size: 11px;
|
||||
color: @color-theme_2-font-label;
|
||||
}
|
||||
}
|
||||
:global(.badge) {
|
||||
opacity: .85;
|
||||
}
|
||||
|
||||
&.copying {
|
||||
.no-select {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,8 +347,11 @@ export default {
|
||||
// transform: translateX(-50%);
|
||||
}
|
||||
.noitem {
|
||||
position: relative;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
@@ -229,6 +365,13 @@ export default {
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.tbody {
|
||||
td {
|
||||
&:first-child {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
}
|
||||
}
|
||||
.noitem {
|
||||
p {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
|
||||
@@ -110,13 +110,14 @@ export default {
|
||||
display: inline-block;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 5px 10px 7px;
|
||||
padding: 0 10px;
|
||||
font-size: 12px;
|
||||
min-width: 56px;
|
||||
// color: @color-btn;
|
||||
outline: none;
|
||||
transition: background-color @transition-theme;
|
||||
background-color: @color-tab-btn-background;
|
||||
|
||||
line-height: 28px;
|
||||
}
|
||||
&:hover {
|
||||
// border-left-color: @color-theme_2-hover;
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
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(:class="$style.tag" @click="handleClick(null)") 默认
|
||||
div.scroll(:class="$style.list" :style="{ width: listWidth + 'PX' }" @click.stop ref="dom_list")
|
||||
div(:class="$style.tag" @click="handleClick(null)") {{$t('material.tag_list.default')}}
|
||||
dl(v-for="type in list")
|
||||
dt(:class="$style.type") {{type.name}}
|
||||
dd(:class="$style.tag" v-for="tag in type.list" @click="handleClick(tag)") {{tag.name}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isChildren } from '../../utils'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
@@ -22,10 +22,17 @@ export default {
|
||||
return []
|
||||
},
|
||||
},
|
||||
listWidth: {
|
||||
type: Number,
|
||||
default: 645,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
@@ -40,7 +47,7 @@ export default {
|
||||
methods: {
|
||||
handleHide(e) {
|
||||
// if (e && e.target.parentNode != this.$refs.dom_list && this.show) return this.show = false
|
||||
if (e && (e.target == this.$refs.dom_btn || isChildren(this.$refs.dom_btn, e.target))) return
|
||||
if (e && (e.target == this.$refs.dom_btn || this.$refs.dom_btn.contains(e.target))) return
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
}, 50)
|
||||
@@ -48,7 +55,7 @@ export default {
|
||||
handleClick(item) {
|
||||
if (!item) {
|
||||
item = {
|
||||
name: '默认',
|
||||
name: this.$t('material.tag_list.default'),
|
||||
id: null,
|
||||
}
|
||||
}
|
||||
@@ -109,7 +116,7 @@ export default {
|
||||
margin-left: 7px;
|
||||
line-height: 0;
|
||||
svg {
|
||||
width: 1em;
|
||||
width: .9em;
|
||||
transition: transform .2s ease;
|
||||
transform: rotate(0);
|
||||
}
|
||||
@@ -126,7 +133,7 @@ export default {
|
||||
.list {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
width: 646px;
|
||||
width: 645px;
|
||||
left: 0;
|
||||
border-bottom: 2px solid @color-tab-border-bottom;
|
||||
border-right: 2px solid @color-tab-border-bottom;
|
||||
@@ -165,7 +172,7 @@ export default {
|
||||
.type {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 3px;
|
||||
color: #999;
|
||||
color: @color-theme_2-font-label;
|
||||
}
|
||||
|
||||
.tag {
|
||||
@@ -225,6 +232,10 @@ each(@themes, {
|
||||
background-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
}
|
||||
|
||||
.type {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -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,102 @@ 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 网盘
|
||||
| 下载。
|
||||
material-btn(:class="$style.btn" @click.onec="handleIgnoreClick") {{ isIgnored ? '恢复当前版本的更新失败提醒' : '忽略当前版本的更新失败提醒'}}
|
||||
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 设置-软件更新
|
||||
| 重新打开本弹窗。
|
||||
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,22 +143,22 @@ 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`
|
||||
: '初始化中...'
|
||||
},
|
||||
isIgnored() {
|
||||
return this.setting.ignoreVersion == this.version.newVersion.version
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setVersionModalVisible', 'setSetting']),
|
||||
...mapMutations(['setVersionModalVisible', 'setIgnoreVersion']),
|
||||
handleClose() {
|
||||
this.setVersionModalVisible({
|
||||
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)
|
||||
},
|
||||
@@ -88,6 +170,10 @@ export default {
|
||||
handleCopy(text) {
|
||||
clipboardWriteText(text)
|
||||
},
|
||||
handleIgnoreClick() {
|
||||
this.setIgnoreVersion(this.isIgnored ? null : this.version.newVersion.version)
|
||||
this.handleClose()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -148,6 +234,10 @@ export default {
|
||||
list-style: initial;
|
||||
padding-inline-start: 30px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.history {
|
||||
@@ -175,22 +265,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;
|
||||
line-height: 1.25;
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
color: @color-theme;
|
||||
line-height: 1.25;
|
||||
}
|
||||
}
|
||||
}
|
||||
.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}) {
|
||||
@@ -202,6 +293,9 @@ each(@themes, {
|
||||
.footer {
|
||||
.desc {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
p {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
||||
main(:class="$style.main")
|
||||
h2
|
||||
| 添加
|
||||
| {{$t('material.list_add_modal.title_first')}}
|
||||
span(:class="$style.name") {{this.musicInfo && `${musicInfo.name}`}}
|
||||
| 到...
|
||||
material-btn(:class="$style.btn" :title="`把该歌曲添加到 ${item.name}`" :key="item.id" @click="handleClick(index)" v-for="(item, index) in lists") {{item.name}}
|
||||
| {{$t('material.list_add_modal.title_last')}}
|
||||
material-btn(:class="$style.btn" :title="$t('material.list_add_modal.btn_title', { name: item.name })" :key="item.id" @click="handleClick(index)" v-for="(item, index) in lists") {{item.name}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
||||
main(:class="$style.main")
|
||||
h2 添加已选的 {{musicList.length}} 首歌曲到...
|
||||
material-btn(:class="$style.btn" :title="`把该歌曲添加到 ${item.name}`" :key="item.id" @click="handleClick(index)" v-for="(item, index) in lists") {{item.name}}
|
||||
h2 {{$t('material.list_add_multiple_modal.title', { num: musicList.length })}}
|
||||
material-btn(:class="$style.btn" :title="$t('material.list_add_multiple_modal.btn_title', { name: item.name })" :key="item.id" @click="handleClick(index)" v-for="(item, index) in lists") {{item.name}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
50
src/renderer/components/material/xmVerifyModal.vue
Normal file
50
src/renderer/components/material/xmVerifyModal.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
||||
main.ignore-to-rem(:class="$style.main")
|
||||
h2 {{$t('material.xm_verify_modal.title')}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
bgClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClose() {
|
||||
this.$emit('close')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
background: #fff !important;
|
||||
&:global(.ignore-to-rem) {
|
||||
padding: 15px;
|
||||
width: 360px;
|
||||
height: 330px;
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 13px;
|
||||
color: @color-theme_2-font;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
46
src/renderer/config/bindkey.js
Normal file
46
src/renderer/config/bindkey.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import mousetrap from 'mousetrap'
|
||||
let eventHub
|
||||
|
||||
const bindKey = () => {
|
||||
mousetrap.reset()
|
||||
mousetrap.bind('shift', (event, combo) => {
|
||||
eventHub.$emit('key_shift_down', { event, combo })
|
||||
return false
|
||||
}, 'keydown')
|
||||
mousetrap.bind('shift', (event, combo) => {
|
||||
eventHub.$emit('key_shift_up', { event, combo })
|
||||
return false
|
||||
}, 'keyup')
|
||||
mousetrap.bind('mod', (event, combo) => {
|
||||
eventHub.$emit('key_mod_down', { event, combo })
|
||||
return false
|
||||
}, 'keydown')
|
||||
mousetrap.bind('mod', (event, combo) => {
|
||||
eventHub.$emit('key_mod_up', { event, combo })
|
||||
return false
|
||||
}, 'keyup')
|
||||
mousetrap.bind('mod+a', (event, combo) => {
|
||||
eventHub.$emit('key_mod+a_down', { event, combo })
|
||||
return false
|
||||
}, 'keydown')
|
||||
mousetrap.bind('mod+a', (event, combo) => {
|
||||
eventHub.$emit('key_mod+a_up', { event, combo })
|
||||
return false
|
||||
}, 'keyup')
|
||||
}
|
||||
|
||||
const unbindKey = () => {
|
||||
mousetrap.unbind('shift', 'keydown')
|
||||
mousetrap.unbind('shift', 'keyup')
|
||||
mousetrap.unbind('mod', 'keydown')
|
||||
mousetrap.unbind('mod', 'keyup')
|
||||
mousetrap.unbind('mod+a', 'keydown')
|
||||
mousetrap.unbind('mod+a', 'keyup')
|
||||
}
|
||||
|
||||
export default () => {
|
||||
eventHub = window.eventHub
|
||||
|
||||
eventHub.$on('bindKey', bindKey)
|
||||
eventHub.$on('unbindKey', unbindKey)
|
||||
}
|
||||
12
src/renderer/lang/cns/core/aside.json
Normal file
12
src/renderer/lang/cns/core/aside.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"online_music": "在线音乐",
|
||||
"search": "搜索",
|
||||
"song_list": "歌单",
|
||||
"leaderboard": "排行榜",
|
||||
"my_music": "我的音乐",
|
||||
"default_list": "试听列表",
|
||||
"love_list": "收藏列表",
|
||||
"other": "其他",
|
||||
"download": "下载管理",
|
||||
"setting": "设置"
|
||||
}
|
||||
21
src/renderer/lang/cns/core/player.json
Normal file
21
src/renderer/lang/cns/core/player.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"copy_title": "(点击复制)",
|
||||
"volume": "当前音量:",
|
||||
"pause": "暂停",
|
||||
"play": "播放",
|
||||
"prev": "上一首",
|
||||
"next": "下一首",
|
||||
"playing": "播放中...",
|
||||
"stop": "暂停播放",
|
||||
"end": "播放完毕",
|
||||
"refresh_url": "URL过期,正在刷新URL...",
|
||||
"error": "音频加载出错,5 秒后切换下一首",
|
||||
"loading": "音乐加载中...",
|
||||
"buffering": "缓冲中...",
|
||||
"geting_url": "歌曲链接获取中...",
|
||||
"lyric_error": "歌词获取失败",
|
||||
"hide_detail": "隐藏详情页",
|
||||
"name": "歌曲名:",
|
||||
"singer": "艺术家:",
|
||||
"album": "专辑名:"
|
||||
}
|
||||
4
src/renderer/lang/cns/core/toolbar.json
Normal file
4
src/renderer/lang/cns/core/toolbar.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"min": "最小化",
|
||||
"close": "关闭"
|
||||
}
|
||||
6
src/renderer/lang/cns/material/download_modal.json
Normal file
6
src/renderer/lang/cns/material/download_modal.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"btn_tip": "该音质不可用",
|
||||
"lossless": "无损音质",
|
||||
"high_quality": "高品音质",
|
||||
"normal": "普通音质"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"tip": "已选择 {len} 首歌曲",
|
||||
"tip2": "请选择要优先下载的音质",
|
||||
"normal": "普通音质",
|
||||
"high_quality": "高品音质",
|
||||
"lossless": "无损音质"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user