Compare commits

...
100 Commits
Author SHA1 Message Date
lyswhut a546b75986 修复音量条在调整音量时实际音量与显示的数值不一致的问题(#2606)
Build / Windows (push) Waiting to run
Build / Windows_7 (push) Waiting to run
Build / Mac (push) Waiting to run
Build / Linux (push) Waiting to run
2025-12-07 14:07:12 +08:00
lyswhut 8686ecfa54 更新二进制库 2025-11-29 16:31:23 +08:00
lyswhut 270c48a1dd 发布 v2.12.0 2025-11-29 16:27:28 +08:00
lyswhut fdbec2cbac 更新说明 2025-11-29 16:26:14 +08:00
lyswhut 46049fd15c 更新版本号(2.12.0-beta.15) 2025-11-28 12:06:21 +08:00
lyswhut a81fe6ff7f 修复MG最新评论翻页 2025-11-28 12:06:17 +08:00
lyswhut fd4e8ecb01 更新版本号(2.12.0-beta.14) 2025-11-26 13:41:57 +08:00
lyswhut 8142e5e79e 修复MG源评论加载失败 2025-11-26 13:41:22 +08:00
lyswhut 0c71772953 修复MG源歌单加载失败 2025-11-26 13:41:22 +08:00
lyswhut d54bc21441 更新版本号(2.12.0-beta.13) 2025-11-23 10:21:40 +08:00
lyswhut be4bca2c15 更新字体设置,支持最多设置两种字体,并调整选择组件宽度 2025-11-23 10:20:27 +08:00
lyswhut 2bd54673de 更新依赖&版本号(2.12.0-beta.12) 2025-11-21 09:09:01 +08:00
lyswhut 4a3359f773 更新依赖 2025-11-14 18:52:51 +08:00
lyswhut c35095f90e 修复获取歌曲图片的函数,改为直接返回图片链接 2025-11-14 18:52:51 +08:00
lyswhut 32abccd8c2 更新版本号(2.12.0-beta.11) 2025-11-02 21:21:15 +08:00
Folltosheandlyswhut 5d68ca3e18 修复TX源搜索失败 (#2575)
* 修复TX源搜索失败

* 清理音乐搜索模块中的多余空行

---------

Co-authored-by: lyswhut <lyswhut@qq.com>
2025-11-02 21:19:26 +08:00
lyswhut 8efa5335b0 更新版本号(2.12.0-beta.10) 2025-10-01 13:30:12 +08:00
lyswhut 4710bb16d8 下载列表菜单新增歌曲添加弹窗(#2537) 2025-10-01 13:29:35 +08:00
lyswhut db4f3e4e1b 更新版本号(2.12.0-beta.9) 2025-09-29 12:48:33 +08:00
lyswhut e18272a6d7 更新依赖 2025-09-29 12:43:24 +08:00
lyswhut 85aed9ce9d 修复隐藏状态下的透明度问题,增加鼠标悬停时恢复不透明度的效果 2025-09-29 12:43:12 +08:00
lyswhut d03f93166f 新增完整歌词相关字段和API支持 2025-09-29 12:37:22 +08:00
lyswhut a3b1a433c6 更新版本号(2.12.0-beta.8) 2025-09-19 23:54:44 +08:00
lyswhut 608f63bc9c 临时修复桌面歌词交互时背景异常的问题 2025-09-19 23:53:45 +08:00
lyswhut a4c118648a mac下默认不使用透明窗口 2025-09-19 23:51:00 +08:00
lyswhut 42866b8e4f 修复构建 2025-09-07 12:14:31 +08:00
lyswhut 0b7455b74f 更新依赖&版本号(2.12.0-beta.7) 2025-09-07 11:53:50 +08:00
lyswhut eab7bc3f5f 优化歌词解析 2025-08-11 13:49:26 +08:00
lyswhut af2623d16c 更新版本号(2.12.0-beta.6) 2025-08-10 13:46:52 +08:00
lyswhut e683034e77 新增 Any Listen 歌词标签数据嵌入、下载、读取播放(#2485) 2025-08-10 13:42:54 +08:00
lyswhut ffa979ddc8 更新依赖版本,优化组件逻辑 2025-08-09 18:07:16 +08:00
3gf8jv4dv 8a8c8a5699 Revise text for lyric position switching feature (#2463)
- Fix incorrect i18n key
- Revise English translation
- Revise changelog descriptions to be more accurate
2025-08-06 12:24:03 +08:00
lyswhut 2aea956fd0 更新依赖&版本号(2.12.0-beta.5) 2025-08-06 12:22:20 +08:00
lyswhut 1803517943 优化 hidden 启动参数的行为 2025-08-06 12:21:47 +08:00
lyswhut 49c8081f68 尝试修复进度为0时仍然显示下载完成的问题(#2471) 2025-08-05 12:16:24 +08:00
lyswhut 3d64ca37e7 更新版本号(2.12.0-beta.4) 2025-07-19 14:29:32 +08:00
lyswhut ccc88745a6 降级 electron 版本至 35.3.0 2025-07-19 14:28:47 +08:00
lyswhut 0bf6dbd402 更新依赖&版本号(2.12.0-beta.3) 2025-07-19 02:16:52 +08:00
lyswhut b9abb4ce47 新增启动参数 -hidden,在启动时将软件最小化到系统托盘(#2459) 2025-07-18 22:24:15 +08:00
lyswhut ad0c0f37c9 新增调换翻译歌词与罗马音歌词位置设置,优化歌词显示逻辑(#2451) 2025-07-09 08:58:34 +08:00
Folltosheandlyswhut 4c6257c145 更新代理配置规则,现在不启用代理时,图片、音频加载将不再走系统代理 (#2382)
* 完善代理设置

* 更新

* update

---------

Co-authored-by: lyswhut <lyswhut@qq.com>
2025-05-10 10:43:58 +08:00
lyswhut 6c5231dbff 恢复更新日志 2025-05-10 10:07:45 +08:00
lyswhut 0454bb9b3c 更新依赖&版本号(2.12.0-beta.2) 2025-05-10 01:30:48 +08:00
lyswhut 021f89da29 新增播放器声音大小、静音、播放进度控制(#2386) 2025-05-10 00:58:19 +08:00
lyswhut 2ccca633ed 优化滚动事件监听,启用 passive 选项以提升性能 2025-05-09 10:02:37 +08:00
lyswhut fe15e025aa 更新数据库备份逻辑 2025-05-09 10:02:37 +08:00
3gf8jv4dv 9e0c416db5 Revise chinese terminology for window and font size (#2384)
addresses https://github.com/lyswhut/lx-music-mobile/issues/769
2025-05-07 21:53:24 +08:00
3gf8jv4dv fa9b84a9c9 Revise wording of main window style options - 2 (#2379)
- Not all operating systems use rounded corners. Like Windows 10.
- Further optimize wording.
- Forgot to add line breaks to CHANGELOG :(
2025-05-06 09:15:31 +08:00
lyswhut b3b1bd7bc8 更新版本号(2.12.0-beta.1) 2025-05-03 11:23:53 +08:00
lyswhut 91e806a619 为数据库启用 WAL 模式 2025-05-03 11:22:35 +08:00
3gf8jv4dv 6df6eefd3d Revise wording of main window style options (#2372)
- Correct typos
- Edit i18n key name
- Avoid displaying long descriptions directly
2025-05-03 11:06:28 +08:00
lyswhut ae35d05649 修正透明窗口设置逻辑 2025-05-02 13:02:01 +08:00
lyswhut 72939db2df 更新版本号(2.12.0-beta.0) 2025-05-02 12:36:08 +08:00
lyswhut b6f5770dc2 新增「设置 → 其他设置 → 主窗口使用软件内置的圆角及阴影」设置 2025-05-02 12:28:16 +08:00
lyswhut c1e7faa7bf 发布 2.11.0 2025-05-01 16:55:22 +08:00
lyswhut 37a18eae9c 更新依赖 2025-05-01 16:55:14 +08:00
lyswhut 010bc5e328 修复 kg 歌单打开失败的问题 2025-04-23 09:13:45 +08:00
lyswhut a166051781 更新版本号(2.11.0-beta.6) 2025-04-19 19:55:36 +08:00
3gf8jv4dvandlyswhut c2341d6697 Disable rounded corners for lyric window (#2356)
* Disable rounded corners for lyric window

Ensure that the lyric window looks the same
on Windows 11 as it does on other systems.

Ref: https://github.com/electron/electron/issues/46468

* update

---------

Co-authored-by: lyswhut <lyswhut@qq.com>
2025-04-19 19:54:43 +08:00
lyswhut 03bba4259e 更新版本号(2.11.0-beta.5) 2025-04-19 15:35:56 +08:00
lyswhut 80844580df 更新 Electron 到 35(#2354) 2025-04-19 15:34:29 +08:00
lyswhut a8790b9835 更新依赖 2025-04-09 09:39:34 +08:00
lyswhut 36262ff166 更新 歌曲换源 机制 2025-04-09 09:24:45 +08:00
lyswhut 98d67be9d9 歌词选择模式下的歌词调整为跟随歌词字体大小显示 2025-03-29 13:11:07 +08:00
lyswhut 131f077c3f 更新空音频输出设备提示信息 2025-03-21 09:31:47 +08:00
lyswhut 2c428ef099 减少桌面歌词窗口自动置顶刷新间隔,修复窗口被遮挡时歌词会被暂停的问题(#2320) 2025-03-21 09:15:39 +08:00
lyswhut 08887cd6ed 更新 Node.js 版本至 22 2025-03-20 13:49:37 +08:00
lyswhut f786a29b70 更新依赖&版本号(2.11.0-beta.3) 2025-03-20 13:08:01 +08:00
lyswhut d3f1d7f378 更新依赖&版本号(2.11.0-beta.2) 2025-03-20 12:54:54 +08:00
lyswhut c48a31fd63 修复 kw 歌单详情打开失败和 kg 热门评论获取问题 2025-03-20 09:22:21 +08:00
lyswhut 1217f06324 修复潜在播放暂停的问题 2025-03-07 12:20:41 +08:00
lyswhut 4cc3197be8 修复构建 2025-03-04 12:04:20 +08:00
lyswhut eb940d5968 更新依赖&版本号(2.11.0-beta.1) 2025-03-04 11:59:44 +08:00
lyswhut 6381389cac 减少歌词延迟隐藏时间 2025-03-04 11:57:08 +08:00
3gf8jv4dv ab939e859a Improve description of seek backward/forward shortcuts (english only) (#2297)
Match the style of other shortcuts' descriptions
2025-03-04 11:56:51 +08:00
3gf8jv4dv 9bdc71c487 Fix description of transparent lyric window in desktop lyrics settings (#2296)
- Fix incorrect i18n key
- Fix the wrong description
2025-03-04 11:55:40 +08:00
lyswhut 56a4abfaff 更新版本号(2.11.0-beta.1) 2025-03-03 22:32:57 +08:00
lyswhut 769bc7f109 新增「设置 → 桌面歌词设置 → 暂停时降低歌词透明度」设置,默认启用(#2294) 2025-03-03 22:14:21 +08:00
lyswhut a587847e41 更新版本号(2.11.0-beta.0) 2025-03-01 20:04:08 +08:00
lyswhut bda4650de8 新增 快进/快退5秒 自定义快捷键设置(#2289) 2025-03-01 20:03:25 +08:00
lyswhut 4f0af93b72 允许拖动桌面歌词控制栏空白处移动歌词窗口(#2280) 2025-02-28 18:40:47 +08:00
lyswhut 4a656268b8 update electron to 34.3.0 2025-02-28 13:01:10 +08:00
lyswhut 2ad9d5990f 更新依赖&版本号(2.10.1-beta.4) 2025-02-22 15:37:03 +08:00
3gf8jv4dvandlyswhut 32585bc453 Revise License (#2273)
* Revise License

* update rtf file

---------

Co-authored-by: lyswhut <lyswhut@qq.com>
2025-02-22 15:35:48 +08:00
3gf8jv4dv 66307d4545 Refine English translation (#2259) 2025-02-22 15:33:16 +08:00
3gf8jv4dv 8b9ae2734f Update publish/changeLog.md [skip ci] (#2270) 2025-02-20 00:29:22 +08:00
3gf8jv4dv 96f9e12d93 Optimize statusbar lyrics option description (#2269)
Clarify the meaning of enabling the system tray.

ref: https://support.apple.com/guide/mac-help/mchlp1446

related: comments on https://github.com/lyswhut/lx-music-desktop/pull/1940
2025-02-17 22:58:34 +08:00
lyswhut 43c4e13c11 修复本地 FLAC 文件内嵌歌词无法读取的问题 2025-02-12 22:00:03 +08:00
3gf8jv4dv 27f6168a29 Revise description about Kugou on "Open Playlist" dialog (#2266)
Related: https://github.com/lyswhut/lx-music-desktop/issues/2246
2025-02-12 20:27:24 +08:00
lyswhut 70dbbc93f4 更新依赖&版本号(2.10.1-beta.3) 2025-02-10 18:17:45 +08:00
lyswhut 92c9808bfb 修复 Windows 下桌面歌词最小高度与宽度设置问题,允许更小的桌面歌词窗口宽度(#2244) 2025-02-10 18:17:45 +08:00
3gf8jv4dv 1f8df84b87 Fix music api management dialog layout (#2247) 2025-02-08 09:57:46 +08:00
3gf8jv4dv 271c1bcd51 Change window title to LX Music (#2248) 2025-02-08 09:57:22 +08:00
lyswhut f830b1199a 更新依赖&版本号(2.10.1-beta.2) 2025-02-07 12:55:24 +08:00
lyswhut b80d48aa91 修复windows下界面缩放后移动桌面歌词会改变歌词窗口大小的问题(#2244) 2025-02-07 12:54:41 +08:00
lyswhut 691d835d16 更新依赖&版本号(2.10.1-beta.1) 2025-02-04 23:26:00 +08:00
lyswhut 3ac6d0ff5f 修复 tx 歌单搜索名字、描述出现乱码的问题(#2250) 2025-02-04 23:20:51 +08:00
lyswhut 68b32a20a4 更新版本号(2.10.1-beta.0) 2025-01-28 19:50:56 +08:00
lyswhut 88e4df4388 修复 Windows 下桌面歌词最小高度设置问题(#2244) 2025-01-28 19:49:33 +08:00
lyswhut 3e13980870 发布 v2.10.0 2025-01-27 00:59:37 +08:00
157 changed files with 4995 additions and 4088 deletions
+1 -1
View File
@@ -21,6 +21,6 @@
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-transform-modules-umd",
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-class-properties"
"@babel/plugin-transform-class-properties"
]
}
+1 -1
View File
@@ -7,7 +7,7 @@ runs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: '22'
# - name: Get npm cache directory
# run: node -p -e '`NPM_CACHE_DIR=${require("child_process").execSync("npm config get cache").toString()}`' >> $GITHUB_ENV
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 22
- name: Install Dependencies
run: npm ci
+12 -1
View File
@@ -6,12 +6,17 @@ module.exports = {
'del',
'comlink',
'vue',
'vue-router',
'image-size',
'message2call',
'@types/ws',
'eslint',
'@types/node',
'electron-debug',
'eslint-webpack-plugin',
'eslint-plugin-vue',
'vue-eslint-parser',
// 'eslint-config-standard-with-typescript',
],
@@ -23,14 +28,20 @@ module.exports = {
// target: 'patch',
// filter: [
// 'electron',
// 'vue',
// 'vue-router',
// ],
// target: 'minor',
// filter: [
// 'electron',
// // 'electron',
// 'eslint',
// 'eslint-webpack-plugin',
// 'electron-debug',
// '@types/node',
// 'eslint-plugin-vue',
// 'vue-eslint-parser',
// ],
}
+137
View File
@@ -6,6 +6,143 @@ 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/).
## [2.12.0](https://github.com/lyswhut/lx-music-desktop/compare/v2.11.0...v2.12.0) - 2025-11-29
我们很高兴地宣布新项目 Any Listen 的桌面版已发布,目前已支持列表跟随本地文件自动更新、加载并播放WebDAV上的歌曲等功能,更多功能仍在积极开发中,桌面版与Web版将同步更新。
对于有播放本地音乐或播放服务器上音乐需求的人可以试试,若遇到任何问题可以发 issue 反馈。
### 新增
- 新增「设置 → 其他设置 → 主窗口使用软件内置的圆角及阴影」选项 (#2360)
*默认启用,关闭后将使用系统原生的窗口样式,该选项重启软件后生效*
- 开放 API 新增播放器声音大小、静音、播放进度控制、完整歌词获取,详情看接入文档 (#2386)
- 新增「设置 → 播放设置 → 调换歌词翻译与歌词罗马音位置」选项,默认关闭 (#2451)
- 新增启动参数 `-hidden`,在启动时将软件最小化到系统托盘 (#2459)
- 新增 Any Listen 歌词(用于支持已下载歌曲的歌词逐字播放)标签数据读取与播放 (#2485)
- 新增 Any Listen 歌词(包含逐字歌词、翻译、罗马音歌词,如果有)嵌入与下载,默认启用
- 下载列表菜单新增歌曲添加弹窗,允许将所选歌曲的在线版本添加到收藏列表 (#2537)
### 修复
- 尝试修复进度为0时仍然显示下载完成的问题 (#2471)
- 修复TX源搜索失败 (#2575 @Folltoshe)
- 修复MG源歌单加载失败
- 修复MG源评论加载失败
### 变更
- 调换「歌词翻译」与「歌词罗马音」的位置,现在歌词罗马音在歌词翻译的上方展示
*若你想要恢复以前的行为,可以开启「调换歌词翻译与歌词罗马音位置」选项*
- 更新代理配置规则,现在不启用代理时,图片、音频加载将不再走系统代理 (#2382 @Folltoshe)
- 字体设置可以最多设置两种字体([any-listen#82](https://github.com/any-listen/any-listen/issues/82))
### 其他
- 更新 Electron 到 37.6.0
## [2.11.0](https://github.com/lyswhut/lx-music-desktop/compare/v2.10.0...v2.11.0) - 2025-05-01
### 新增
- 新增「快进/快退5秒」自定义快捷键设置(#2289)
- 新增「设置 → 桌面歌词设置 → 暂停时提高歌词透明度」设置,默认启用(#2294)
### 修复
- 修复 Windows 下桌面歌词最小高度与宽度设置问题(#2244)
- 修复 Windows 下界面缩放后移动桌面歌词会改变歌词窗口大小的问题(#2244)
- 修复 tx 歌单搜索名字、描述出现乱码的问题(#2250)
- 修复本地 FLAC 文件内嵌歌词无法读取的问题
- 修复潜在播放暂停的问题
- 修复 kw 歌单详情出现打开失败的问题(#2317)
- 修复 kg 热门评论无法获取的问题
- 修复桌面歌词被遮挡时会被暂停的问题(#2320)
- 修复 kg 歌单打开失败的问题(thanks @Folltoshe)
### 优化
- 允许更小的桌面歌词窗口宽度
- 允许拖动桌面歌词控制栏空白处移动歌词窗口(#2280)
- 优化「自定义源管理」对话框在小窗口下的布局(#2247, @3gf8jv4dv)
- 优化软件文案编排(#2259, #2266, #2269, #2296, @3gf8jv4dv)
### 变更
- 我的列表-歌曲菜单中的 歌曲换源 功能从之前的类似软连接的形式改成替换歌曲的形式,也就是说,现在该功能相当于快速在线搜索歌曲,确认换源后将自动将原来的歌曲删除再将选择的歌曲插入被删除歌曲的位置。
### 其他
- 更新项目文档(@3gf8jv4dv)
- 更新 Electron 到 35.2.2
## [2.10.0](https://github.com/lyswhut/lx-music-desktop/compare/v2.9.0...v2.10.0) - 2025-01-27
落雪祝大家新年快乐!
### 关于之前提到的新项目
新项目我取名叫 Any Listen,希望它能像它的名字一样让我们能到处任意听歌。
经过一年多的开发,因各种原因,实际进度比预期的慢,但还是赶在年前发布了第一个web服务预览版,第一个版本仅支持播放服务器上的歌曲,扩展功能暂时未能开放,但已趋于完成,一两个月内可以搞定。
目前的版本仅是“能用”的状态,因时间关系,部分UI未能重新设计,但后面会继续完善。
该项目目前的目标用户是拥有自己服务器且上面存储有歌曲的人使用。
项目刚发布,文档未能完善,遇到使用问题或有任何建议欢迎提 issue 交流,
项目地址: https://github.com/any-listen/any-listen
---
*感谢 @3gf8jv4dv 对 LX 系列项目翻译、文档等文案的大幅修订优化。*
### 不兼容性变更
Linux 系统至少需要 `GLIBC_2.29` 版本才能运行。
由于将 Electron 升级到 v32.x,原生库的编译被限制到不低于 C++ 20,试了几次无法在 docker 镜像 `node:16` 安装 gcc-10,最终将构建使用镜像更新到 `node:18`。
### 新增
- 新增下载的歌曲按列表名分组的功能,默认关闭,可以通过「设置 → 下载设置 → 将文件保存到以对应列表命名的子目录中」启用(#2145)
- 新增托盘图标样式「跟随系统亮暗模式」设置,可以在「设置 → 其他」里启用 (#2016)
- 支持本地同名 `.krc` 格式歌词文件的读取(#2053)
- 开放 API 新增播放器播放/暂停、切歌、收藏当前播放歌曲等接口调用,详情看文档「开放 API 服务」部分(#2077, @14Kay)
### 优化
- 优化正常播放结束时的下一首歌曲播放衔接度,在歌曲即将结束播放时将预获取下一首歌曲的播放链接,减少自动切歌时的等待时间(#2126)
- 优化歌曲换源机制,提升换源正确率
- 优化 Windows 平台上桌面歌词窗口大小调整机制,改用原生的窗口调整方式(#2137)
- 修正搜索歌曲提示框文案(#2050)
- 优化播放详情页 UI,修复「歌曲名」「艺术家」等文字过长时被截断的问题(#2049)
- Scheme URL 的播放歌曲允许更长的专辑名称
- 播放本地歌曲时,将优先尝试读取本地同名 `.jpg` 或 `.png` 图片作为播放封面显示,若文件不存在则从音频文件内读取,最后再尝试使用在线图片(#2096)
- 客户端模式的同步服务连接允许重定向 5 次(#2109)
- 更新软件默认使用的字体,修复 macOS Sequoia (15) 上界面出现乱码的问题(#2076)
- 优化简体、繁体中文文案编排,大幅修订英语文案编排(#2159, #2166, #2174 等, @3gf8jv4dv)
- 优化排序歌曲、主题名称、添加/编辑主题、列表更新管理等对话框布局及长文本显示效果(#2176, #2188, #2189, #2198 等, @3gf8jv4dv)
### 修复
- 修复歌单详情页内歌单名字过长时的 UI 显示问题(#2028)
- 修复获取自定义环境音效预设列表逻辑问题
- 修复 `.m4a` 文件内嵌歌词无法读取的问题(#2090)
- 修复 Windows 任务管理器中的进程名显示为软件描述的问题(#2147)
- 修复本地歌曲同名歌词文件调整偏移时间后,下次再播放时调整的设置未被应用的问题(#2139)
- 修复首次打开软件后直接创建并删除列表时的报错问题(#2175, @14Kay)
### 变更
- 不再长期缓存换源歌曲信息
- 更新软件默认使用的字体,现在软件尽量使用系统自带的默认字体
- Linux 系统至少需要 `GLIBC_2.29` 版本才能运行
### 其他
- 更新 Readme 文档,优化文案编排(#2146, Thanks @3gf8jv4dv)
- 更新 Issue 模板(#2153, @3gf8jv4dv)
- 更新项目文档(@3gf8jv4dv)
- 修订项目协议文件(#2146, #2152, @3gf8jv4dv)
- 更新 Electron 到 v32.3.0
## [2.9.0](https://github.com/lyswhut/lx-music-desktop/compare/v2.8.0...v2.9.0) - 2024-08-24
### 新增
+4 -2
View File
@@ -47,6 +47,8 @@
*移动版项目地址:https://github.com/lyswhut/lx-music-mobile*
*LX Music 项目发展调整与新项目计划:https://github.com/lyswhut/lx-music-desktop/issues/1912*
软件变化请查看[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)。
软件下载请查看 [GitHub Releases](https://github.com/lyswhut/lx-music-desktop/releases)。
@@ -117,9 +119,9 @@
1.1 本项目的各官方平台在线数据来源原理是从其公开服务器中拉取数据(与未登录状态在官方平台 APP 获取的数据相同),经过对数据简单地筛选与合并后进行展示,因此本项目不对数据的合法性、准确性负责。
1.2 本项目本身没有获取某个音频数据的能力,本项目使用的在线音频数据来源来自软件设置内“音乐来源”设置所选择的“源”返回的在线链接。例如播放某首歌,本项目所做的只是将希望播放的歌曲名字、歌手名字等信息传递给“源”,若“源”返回了一个链接,则本项目将认为这就是该歌曲的音频数据而进行使用,至于这是不是正确的音频数据本项目无法校验其准确性,所以使用本项目的过程中可能会出现希望播放的音频与实际播放的音频不对应或者无法播放的问题。
1.2 本项目本身没有获取某个音频数据的能力,本项目使用的在线音频数据来源来自软件设置内“自定义源”设置所选择的“源”返回的在线链接。例如播放某首歌,本项目所做的只是将希望播放的歌曲名、艺术家等信息传递给“源”,若“源”返回了一个链接,则本项目将认为这就是该歌曲的音频数据而进行使用,至于这是不是正确的音频数据本项目无法校验其准确性,所以使用本项目的过程中可能会出现希望播放的音频与实际播放的音频不对应或者无法播放的问题。
1.3 本项目的非官方平台数据(例如我的收藏列表)来自使用者本地系统或者使用者连接的同步服务,本项目不对这些数据的合法性、准确性负责。
1.3 本项目的非官方平台数据(例如“我的列表”内列表)来自使用者本地系统或者使用者连接的同步服务,本项目不对这些数据的合法性、准确性负责。
### 二、版权数据
+105 -106
View File
@@ -1,7 +1,7 @@
{\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;}
{\f36\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df{\*\falt DengXian};}{\f44\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}@\'cb\'ce\'cc\'e5;}
{\f45\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}@\'b5\'c8\'cf\'df;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
{\f36\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df{\*\falt DengXian};}{\f44\fbidi \fnil\fcharset134\fprq2{\*\panose 00000000000000000000}@\'cb\'ce\'cc\'e5;}
{\f45\fbidi \fnil\fcharset134\fprq2{\*\panose 00000000000000000000}@\'b5\'c8\'cf\'df;}{\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};}
@@ -41,12 +41,12 @@
\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;}{\*\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\rsid3758332\rsid3950508\rsid4133944\rsid4355753\rsid9533173\rsid10447395\rsid11081282\rsid12910709\rsid13643782\rsid14384001\rsid14511311\rsid15225067\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\yr2024\mo12\dy7\hr14\min56}{\version11}{\edmins5}{\nofpages2}{\nofwords195}
{\nofchars1116}{\nofcharsws1309}{\vern77}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw11906\paperh16838\margl2253\margr2253\margt1440\margb1440\gutter0\ltrsect
{\*\rsidtbl \rsid927107\rsid1398824\rsid2109456\rsid2766548\rsid3758332\rsid3950508\rsid4133944\rsid4355753\rsid9533173\rsid10447395\rsid11081282\rsid12910709\rsid13643782\rsid14384001\rsid14511311\rsid15225067\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\yr2025\mo2\dy22\hr15\min34}{\version12}{\edmins5}{\nofpages2}
{\nofwords195}{\nofchars1117}{\nofcharsws1310}{\vern77}}{\*\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\viewscale160\splytwnine\ftnlytwnine\htmautsp\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct\asianbrkrule\rsidroot3950508\newtblstyruls
\viewkind1\viewscale100\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
@@ -56,130 +56,129 @@ $([\'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\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid15225067 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0
\fs21\lang1033\langfe2052\kerning2\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf
\'bb\'f9\'d3\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \hich\af13\dbch\af13\loch\f13 Apache License 2.0 }{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d0\'ed\'bf\'c9\'d6\'a4\'b7\'a2\'d0\'d0\'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\insrsid15225067\charrsid15225067 \hich\af13\dbch\af13\loch\f13 Apache License 2.0 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \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\insrsid15225067\charrsid15225067
\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}\pard\plain \ltrpar\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid2766548 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0
\fs21\lang1033\langfe2052\kerning2\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf
\'bb\'f9\'d3\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \hich\af13\dbch\af13\loch\f13 Apache License 2.0 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\loch\af13\hich\af13\dbch\f13 \'d0\'ed\'bf\'c9\'d6\'a4\'b7\'a2\'d0\'d0\'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\insrsid2766548\charrsid2766548
\hich\af13\dbch\af13\loch\f13 Apache License 2.0 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \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\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \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\'cf\'ee\'c4\'bf\'a1\'b1\'d6\'b8}
{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \hich\af13\dbch\af13\loch\f13 LX Music }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\loch\af13\hich\af13\dbch\f13 \'d7\'c0\'c3\'e6\'b0\'e6\'cf\'ee\'c4\'bf\'a3\'bb}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'ca\'b9\'d3\'c3\'d5\'df}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8221\'a1\'b1}{\rtlch\fcs1 \af13
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d6\'b8\'c7\'a9\'ca\'f0\'b1\'be\'d0\'ad\'d2\'e9\'b5\'c4\'ca\'b9\'d3\'c3\'d5\'df\'a3\'bb}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d6\'b8\'b6\'d4
\'b1\'be\'cf\'ee\'c4\'bf\'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}{\rtlch\fcs1 \af13
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'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\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \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\'cf\'ee\'c4\'bf\'a1\'b1\'d6\'b8}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \hich\af13\dbch\af13\loch\f13 LX Music }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\loch\af13\hich\af13\dbch\f13 \'d7\'c0\'c3\'e6\'b0\'e6\'cf\'ee\'c4\'bf\'a3\'bb}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'ca\'b9\'d3\'c3\'d5\'df}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8221\'a1\'b1}{\rtlch\fcs1 \af13
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d6\'b8\'c7\'a9\'ca\'f0\'b1\'be\'d0\'ad\'d2\'e9\'b5\'c4\'ca\'b9\'d3\'c3\'d5\'df\'a3\'bb}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d6\'b8\'b6\'d4\'b1\'be
\'cf\'ee\'c4\'bf\'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}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd}{\rtlch\fcs1 \af13
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'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\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d2\'bb\'a1\'a2\'ca\'fd\'be\'dd\'c0\'b4\'d4\'b4}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d2\'bb\'a1\'a2\'ca\'fd\'be\'dd\'c0\'b4\'d4\'b4}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 1.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'b5\'c4\'b8\'f7\'b9\'d9\'b7\'bd\'c6\'bd\'cc\'a8\'d4\'da\'cf\'df
\'ca\'fd\'be\'dd\'c0\'b4\'d4\'b4\'d4\'ad\'c0\'ed\'ca\'c7\'b4\'d3\'c6\'e4\'b9\'ab\'bf\'aa\'b7\'fe\'ce\'f1\'c6\'f7\'d6\'d0\'c0\'ad\'c8\'a1\'ca\'fd\'be\'dd\'a3\'a8\'d3\'eb\'ce\'b4\'b5\'c7\'c2\'bc\'d7\'b4\'cc\'ac\'d4\'da\'b9\'d9\'b7\'bd\'c6\'bd\'cc\'a8}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \hich\af13\dbch\af13\loch\f13 APP }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13
\'bb\'f1\'c8\'a1\'b5\'c4\'ca\'fd\'be\'dd\'cf\'e0\'cd\'ac\'a3\'a9\'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
\'cf\'ee\'c4\'bf\'b2\'bb\'b6\'d4\'ca\'fd\'be\'dd\'b5\'c4\'ba\'cf\'b7\'a8\'d0\'d4\'a1\'a2\'d7\'bc\'c8\'b7\'d0\'d4\'b8\'ba\'d4\'f0\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 1.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'b5\'c4\'b8\'f7\'b9\'d9\'b7\'bd\'c6\'bd\'cc\'a8\'d4\'da\'cf\'df\'ca\'fd
\'be\'dd\'c0\'b4\'d4\'b4\'d4\'ad\'c0\'ed\'ca\'c7\'b4\'d3\'c6\'e4\'b9\'ab\'bf\'aa\'b7\'fe\'ce\'f1\'c6\'f7\'d6\'d0\'c0\'ad\'c8\'a1\'ca\'fd\'be\'dd\'a3\'a8\'d3\'eb\'ce\'b4\'b5\'c7\'c2\'bc\'d7\'b4\'cc\'ac\'d4\'da\'b9\'d9\'b7\'bd\'c6\'bd\'cc\'a8}{\rtlch\fcs1
\af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \hich\af13\dbch\af13\loch\f13 APP }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'bb\'f1\'c8\'a1
\'b5\'c4\'ca\'fd\'be\'dd\'cf\'e0\'cd\'ac\'a3\'a9\'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\'cf\'ee\'c4\'bf
\'b2\'bb\'b6\'d4\'ca\'fd\'be\'dd\'b5\'c4\'ba\'cf\'b7\'a8\'d0\'d4\'a1\'a2\'d7\'bc\'c8\'b7\'d0\'d4\'b8\'ba\'d4\'f0\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 1.2 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'b1\'be\'c9\'ed\'c3\'bb\'d3\'d0\'bb\'f1\'c8\'a1\'c4\'b3\'b8\'f6
\'d2\'f4\'c6\'b5\'ca\'fd\'be\'dd\'b5\'c4\'c4\'dc\'c1\'a6\'a3\'ac\'b1\'be\'cf\'ee\'c4\'bf\'ca\'b9\'d3\'c3\'b5\'c4\'d4\'da\'cf\'df\'d2\'f4\'c6\'b5\'ca\'fd\'be\'dd\'c0\'b4\'d4\'b4\'c0\'b4\'d7\'d4\'c8\'ed\'bc\'fe\'c9\'e8\'d6\'c3\'c4\'da}{\rtlch\fcs1 \af13
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d2\'f4\'c0\'d6\'c0\'b4\'d4\'b4}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'c9\'e8\'d6\'c3
\'cb\'f9\'d1\'a1\'d4\'f1\'b5\'c4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\loch\af13\hich\af13\dbch\f13 \'d4\'b4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 1.2 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'b1\'be\'c9\'ed\'c3\'bb\'d3\'d0\'bb\'f1\'c8\'a1\'c4\'b3\'b8\'f6\'d2\'f4
\'c6\'b5\'ca\'fd\'be\'dd\'b5\'c4\'c4\'dc\'c1\'a6\'a3\'ac\'b1\'be\'cf\'ee\'c4\'bf\'ca\'b9\'d3\'c3\'b5\'c4\'d4\'da\'cf\'df\'d2\'f4\'c6\'b5\'ca\'fd\'be\'dd\'c0\'b4\'d4\'b4\'c0\'b4\'d7\'d4\'c8\'ed\'bc\'fe\'c9\'e8\'d6\'c3\'c4\'da}{\rtlch\fcs1 \af13
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d7\'d4\'b6\'a8\'d2\'e5\'d4\'b4}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'c9\'e8\'d6\'c3\'cb\'f9
\'d1\'a1\'d4\'f1\'b5\'c4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\loch\af13\hich\af13\dbch\f13 \'d4\'b4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\loch\af13\hich\af13\dbch\f13 \'b7\'b5\'bb\'d8\'b5\'c4\'d4\'da\'cf\'df\'c1\'b4\'bd\'d3\'a1\'a3\'c0\'fd\'c8\'e7\'b2\'a5\'b7\'c5\'c4\'b3\'ca\'d7\'b8\'e8\'a3\'ac\'b1\'be\'cf\'ee\'c4\'bf\'cb\'f9\'d7\'f6\'b5\'c4\'d6\'bb\'ca\'c7\'bd\'ab\'cf\'a3\'cd\'fb\'b2\'a5
\'b7\'c5\'b5\'c4\'b8\'e8\'c7\'fa\'c3\'fb\'d7\'d6\'a1\'a2\'b8\'e8\'ca\'d6\'c3\'fb\'d7\'d6\'b5\'c8\'d0\'c5\'cf\'a2\'b4\'ab\'b5\'dd\'b8\'f8}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8220\'a1\'b0}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d4\'b4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8221\'a1\'b1}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'a3\'ac\'c8\'f4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8220\'a1\'b0}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d4\'b4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \u8221\'a1\'b1}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b7\'b5\'bb\'d8\'c1\'cb\'d2\'bb\'b8\'f6\'c1\'b4\'bd\'d3\'a3\'ac\'d4\'f2\'b1\'be\'cf\'ee\'c4\'bf\'bd\'ab\'c8\'cf\'ce\'aa\'d5\'e2
\'be\'cd\'ca\'c7\'b8\'c3\'b8\'e8\'c7\'fa\'b5\'c4\'d2\'f4\'c6\'b5\'ca\'fd\'be\'dd\'b6\'f8\'bd\'f8\'d0\'d0\'ca\'b9\'d3\'c3\'a3\'ac\'d6\'c1\'d3\'da\'d5\'e2\'ca\'c7\'b2\'bb\'ca\'c7\'d5\'fd\'c8\'b7\'b5\'c4\'d2\'f4\'c6\'b5\'ca\'fd\'be\'dd\'b1\'be\'cf\'ee
\'c4\'bf\'ce\'de\'b7\'a8\'d0\'a3\'d1\'e9\'c6\'e4\'d7\'bc\'c8\'b7\'d0\'d4\'a3\'ac\'cb\'f9\'d2\'d4\'ca\'b9\'d3\'c3\'b1\'be\'cf\'ee\'c4\'bf\'b5\'c4\'b9\'fd\'b3\'cc\'d6\'d0\'bf\'c9\'c4\'dc\'bb\'e1\'b3\'f6\'cf\'d6\'cf\'a3\'cd\'fb\'b2\'a5\'b7\'c5\'b5\'c4
\'d2\'f4\'c6\'b5\'d3\'eb\'ca\'b5\'bc\'ca\'b2\'a5\'b7\'c5\'b5\'c4\'d2\'f4\'c6\'b5\'b2\'bb\loch\af13\hich\af13\dbch\f13 \'b6\'d4\'d3\'a6\'bb\'f2\'d5\'df\'ce\'de\'b7\'a8\'b2\'a5\'b7\'c5\'b5\'c4\'ce\'ca\'cc\'e2\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\'b7\'c5\'b5\'c4\'b8\'e8\'c7\'fa\'c3\'fb\'a1\'a2\'d2\'d5\'ca\'f5\'bc\'d2\'b5\'c8\'d0\'c5\'cf\'a2\'b4\'ab\'b5\'dd\'b8\'f8}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8220\'a1\'b0}{\rtlch\fcs1 \af13
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d4\'b4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'a3\'ac\'c8\'f4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d4\'b4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b7\'b5\'bb\'d8\'c1\'cb\'d2\'bb\'b8\'f6\'c1\'b4\'bd\'d3\'a3\'ac\'d4\'f2\'b1\'be\'cf\'ee\'c4\'bf\'bd\'ab\'c8\'cf\'ce\'aa\'d5\'e2\'be\'cd\'ca\'c7\'b8\'c3\'b8\'e8
\'c7\'fa\'b5\'c4\'d2\'f4\'c6\'b5\'ca\'fd\'be\'dd\'b6\'f8\'bd\'f8\'d0\'d0\'ca\'b9\'d3\'c3\'a3\'ac\'d6\'c1\'d3\'da\'d5\'e2\'ca\'c7\'b2\'bb\'ca\'c7\'d5\'fd\'c8\'b7\'b5\'c4\'d2\'f4\'c6\'b5\'ca\'fd\'be\'dd\'b1\'be\'cf\'ee\'c4\'bf\'ce\'de\'b7\'a8\'d0\'a3
\'d1\'e9\'c6\'e4\'d7\'bc\'c8\'b7\'d0\'d4\'a3\'ac\'cb\'f9\'d2\'d4\'ca\'b9\'d3\'c3\'b1\'be\'cf\'ee\'c4\'bf\'b5\'c4\'b9\'fd\'b3\'cc\'d6\'d0\'bf\'c9\'c4\'dc\'bb\'e1\'b3\'f6\'cf\'d6\'cf\'a3\'cd\'fb\'b2\'a5\'b7\'c5\'b5\'c4\'d2\'f4\'c6\'b5\'d3\'eb\'ca\'b5
\'bc\'ca\'b2\'a5\'b7\'c5\'b5\'c4\'d2\'f4\'c6\'b5\'b2\'bb\'b6\'d4\'d3\'a6\'bb\'f2\'d5\'df\'ce\'de\'b7\'a8\'b2\'a5\'b7\'c5\'b5\'c4\'ce\'ca\'cc\'e2\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 1.3 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'b5\'c4\'b7\'c7\'b9\'d9\'b7\'bd\'c6\'bd\'cc\'a8\'ca\'fd\'be\'dd
\'a3\'a8\'c0\'fd\'c8\'e7\'ce\'d2\'b5\'c4\'ca\'d5\'b2\'d8\'c1\'d0\'b1\'ed\'a3\'a9\'c0\'b4\'d7\'d4\'ca\'b9\'d3\'c3\'d5\'df\'b1\'be\'b5\'d8\'cf\'b5\'cd\'b3\'bb\'f2\'d5\'df\'ca\'b9\'d3\'c3\'d5\'df\'c1\'ac\'bd\'d3\'b5\'c4\'cd\'ac\'b2\'bd\'b7\'fe\'ce\'f1
\'a3\'ac\'b1\'be\'cf\'ee\'c4\'bf\'b2\'bb\'b6\'d4\'d5\'e2\'d0\'a9\'ca\'fd\'be\'dd\'b5\'c4\'ba\'cf\'b7\'a8\'d0\'d4\'a1\'a2\'d7\'bc\'c8\'b7\'d0\'d4\'b8\'ba\'d4\'f0\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 1.3 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'b5\'c4\'b7\'c7\'b9\'d9\'b7\'bd\'c6\'bd\'cc\'a8\'ca\'fd\'be\'dd\'a3\'a8
\'c0\'fd\'c8\'e7}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8220\'a1\'b0}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13
\'ce\'d2\'b5\'c4\'c1\'d0\'b1\'ed}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \u8221\'a1\'b1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\loch\af13\hich\af13\dbch\f13 \'c4\'da\'c1\'d0\'b1\'ed\'a3\'a9\'c0\'b4\'d7\'d4\'ca\'b9\'d3\'c3\'d5\'df\'b1\'be\'b5\'d8\'cf\'b5\'cd\'b3\'bb\'f2\'d5\'df\'ca\'b9\'d3\'c3\'d5\'df\'c1\'ac\'bd\'d3\'b5\'c4\'cd\'ac\'b2\'bd\'b7\'fe\'ce\'f1\'a3\'ac\'b1\'be\'cf\'ee
\'c4\'bf\'b2\'bb\'b6\'d4\'d5\'e2\'d0\'a9\'ca\'fd\'be\'dd\'b5\'c4\'ba\'cf\'b7\'a8\'d0\'d4\'a1\'a2\'d7\'bc\'c8\'b7\'d0\'d4\'b8\'ba\'d4\'f0\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b6\'fe\'a1\'a2\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b6\'fe\'a1\'a2\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 2.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'ca\'b9\'d3\'c3\'b1\'be\'cf\'ee\'c4\'bf\'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\'a1\'a3\'b6\'d4\'d3\'da\'d5\'e2\'d0\'a9\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a3\'ac\'b1\'be\'cf\'ee\'c4\'bf\'b2\'bb\'d3\'b5\'d3\'d0\'cb\'fc\'c3\'c7\'b5\'c4\'cb\'f9\'d3\'d0\'c8\'a8\'a1\'a3\'ce\'aa
\'c1\'cb\'b1\'dc\'c3\'e2\'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\insrsid15225067\charrsid15225067 \hich\af13\dbch\af13\loch\f13 **24 }{\rtlch\fcs1 \af13
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d0\'a1\'ca\'b1\'c4\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\hich\af13\dbch\af13\loch\f13 ** }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'c7\'e5\'b3\'fd\'ca\'b9\'d3\'c3\'b1\'be\'cf\'ee\'c4\'bf\'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\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 2\hich\af13\dbch\af13\loch\f13 .1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'ca\'b9\'d3\'c3\'b1\'be\'cf\'ee\'c4\'bf\'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\'a1\'a3\'b6\'d4\'d3\'da\'d5\'e2\'d0\'a9\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a3\'ac\'b1\'be\'cf\'ee\'c4\'bf\'b2\'bb\'d3\'b5\'d3\'d0\'cb\'fc\'c3\'c7\'b5\'c4\'cb\'f9\'d3\'d0
\'c8\'a8\'a1\'a3\'ce\'aa\'c1\'cb\'b1\'dc\'c3\'e2\'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\insrsid2766548\charrsid2766548 \hich\af13\dbch\af13\loch\f13 **24 }{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d0\'a1\'ca\'b1\'c4\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\hich\af13\dbch\af13\loch\f13 ** }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'c7\'e5\'b3\'fd\'ca\'b9\'d3\'c3\'b1\'be\'cf\'ee\'c4\'bf\'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\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'c8\'fd\'a1\'a2\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b1\'f0\'c3\'fb}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'c8\'fd\'a1\'a2\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b1\'f0\'c3\'fb}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 3.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'c4\'da\'b5\'c4\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8
\'b1\'f0\'c3\'fb\'ce\'aa\'b1\'be\'cf\'ee\'c4\'bf\'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\'a1\'a3\'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\'cf\'ee\'c4\'bf\'b8\'fc\'b8\'c4\'bb\'f2\'d2\'c6\'b3\'fd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 3.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'c4\'da\'b5\'c4\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b1\'f0
\'c3\'fb\'ce\'aa\'b1\'be\'cf\'ee\'c4\'bf\'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\'a1\'a3\'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\'cf\'ee\'c4\'bf\'b8\'fc\'b8\'c4\'bb\'f2\'d2\'c6\'b3\'fd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'cb\'c4\'a1\'a2\'d7\'ca\'d4\'b4\'ca\'b9\'d3\'c3}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'cb\'c4\'a1\'a2\'d7\'ca\'d4\'b4\'ca\'b9\'d3\'c3}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 4.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'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\'a1\'a3\'c8\'e7\'b9\'fb\'b3\'f6\'cf\'d6\'c7\'d6\'c8\'a8\'bf\'c9\'c1\'aa\'cf\'b5\'b1\'be\'cf\'ee\'c4\'bf
\'d2\'c6\'b3\'fd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 4.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'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\'a1\'a3\'c8\'e7\'b9\'fb\'b3\'f6\'cf\'d6\'c7\'d6\'c8\'a8\'bf\'c9\'c1\'aa\'cf\'b5\'b1\'be\'cf\'ee\'c4\'bf\'d2\'c6
\'b3\'fd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'ce\'e5\'a1\'a2\'c3\'e2\'d4\'f0\'c9\'f9\'c3\'f7}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'ce\'e5\'a1\'a2\'c3\'e2\'d4\'f0\'c9\'f9\'c3\'f7}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 5.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d3\'c9\'d3\'da\'ca\'b9\'d3\'c3\'b1\'be\'cf\'ee\'c4\'bf\'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\'cf\'ee\'c4\'bf\'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\'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\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 5.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d3\'c9\'d3\'da\'ca\'b9\'d3\'c3\'b1\'be\'cf\'ee\'c4\'bf\'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\'cf\'ee\'c4\'bf\'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\'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\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'c1\'f9\'a1\'a2\'ca\'b9\'d3\'c3\'cf\'de\'d6\'c6}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'c1\'f9\'a1\'a2\'ca\'b9\'d3\'c3\'cf\'de\'d6\'c6}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 6.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'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\insrsid15225067\charrsid15225067 \hich\af13\dbch\af13\loch\f13 GitHub }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 6.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'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\insrsid2766548\charrsid2766548 \hich\af13\dbch\af13\loch\f13 GitHub }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\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\'a1\'a3\'b1\'be\'cf\'ee\'c4\'bf\'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\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\'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\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 6.2 **}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'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\'cf\'ee\'c4\'bf\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \hich\af13\dbch\af13\loch\f13 ** }{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'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\'cf\'ee\'c4\'bf\'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\loch\af13\hich\af13\dbch\f13 \'d3\'c3\'d5\'df\'b3\'d0\'b5\'a3\'a3\'ac
\'b1\'be\'cf\'ee\'c4\'bf\'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\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 6.2 **}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'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\'cf\'ee\'c4\'bf\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \hich\af13\dbch\af13\loch\f13 ** }{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'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\'cf\'ee\'c4\'bf\'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\'cf\'ee\'c4\'bf
\'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\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'c6\'df\'a1\'a2\'b0\'e6\'c8\'a8\'b1\'a3\'bb\'a4}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'c6\'df\'a1\'a2\'b0\'e6\'c8\'a8\'b1\'a3\'bb\'a4}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 7.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b2\'bb\'d2\'d7\'a3\'ac\'c7\'eb\'d7\'f0\'d6\'d8\'b0\'e6
\'c8\'a8\'a3\'ac\'d6\'a7\'b3\'d6\'d5\'fd\'b0\'e6\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 7.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b2\'bb\'d2\'d7\'a3\'ac\'c7\'eb\'d7\'f0\'d6\'d8\'b0\'e6\'c8\'a8
\'a3\'ac\'d6\'a7\'b3\'d6\'d5\'fd\'b0\'e6\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b0\'cb\'a1\'a2\'b7\'c7\'c9\'cc\'d2\'b5\'d0\'d4\'d6\'ca}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b0\'cb\'a1\'a2\'b7\'c7\'c9\'cc\'d2\'b5\'d0\'d4\'d6\'ca}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 8.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'bd\'f6\'d3\'c3\'d3\'da\'b6\'d4\'bc\'bc\'ca\'f5\'bf\'c9\'d0\'d0
\'d0\'d4\'b5\'c4\'cc\'bd\'cb\'f7\'bc\'b0\'d1\'d0\'be\'bf\'a3\'ac\'b2\'bb\'bd\'d3\'ca\'dc\'c8\'ce\'ba\'ce\'c9\'cc\'d2\'b5\'a3\'a8\'b0\'fc\'c0\'a8\'b5\'ab\'b2\'bb\'cf\'de\'d3\'da\'b9\'e3\'b8\'e6\'b5\'c8\'a3\'a9\'ba\'cf\'d7\'f7\'bc\'b0\'be\'e8\'d4\'f9
\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 8.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'bd\'f6\'d3\'c3\'d3\'da\'b6\'d4\'bc\'bc\'ca\'f5\'bf\'c9\'d0\'d0\'d0\'d4
\'b5\'c4\'cc\'bd\'cb\'f7\'bc\'b0\'d1\'d0\'be\'bf\'a3\'ac\'b2\'bb\'bd\'d3\'ca\'dc\'c8\'ce\'ba\'ce\'c9\'cc\'d2\'b5\'a3\'a8\'b0\'fc\'c0\'a8\'b5\'ab\'b2\'bb\'cf\'de\'d3\'da\'b9\'e3\'b8\'e6\'b5\'c8\'a3\'a9\'ba\'cf\'d7\'f7\'bc\'b0\'be\'e8\'d4\'f9\'a1\'a3}{
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'be\'c5\'a1\'a2\'bd\'d3\'ca\'dc\'d0\'ad\'d2\'e9}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'be\'c5\'a1\'a2\'bd\'d3\'ca\'dc\'d0\'ad\'d2\'e9}{\rtlch\fcs1 \af13 \ltrch\fcs0
\loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 9.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'c8\'f4\'c4\'e3\'ca\'b9\'d3\'c3\'c1\'cb\'b1\'be\'cf\'ee\'c4\'bf\'a3\'ac\'bc\'b4\'b4\'fa
\'b1\'ed\'c4\'e3\'bd\'d3\'ca\'dc\'b1\'be\'d0\'ad\'d2\'e9\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 9.1 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'c8\'f4\'c4\'e3\'ca\'b9\'d3\'c3\'c1\'cb\'b1\'be\'cf\'ee\'c4\'bf\'a3\'ac\'bc\'b4\'b4\'fa\'b1\'ed
\'c4\'e3\'bd\'d3\'ca\'dc\'b1\'be\'d0\'ad\'d2\'e9\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 * }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \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\insrsid15225067\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 * }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \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\insrsid2766548\charrsid2766548
\par
\par \hich\af13\dbch\af13\loch\f13 By: }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15225067\charrsid15225067 \loch\af13\hich\af13\dbch\f13 \'c2\'e4\'d1\'a9\'ce\'de\'ba\'db}{\rtlch\fcs1 \af0 \ltrch\fcs0
\insrsid12910709\charrsid15225067
\par \hich\af13\dbch\af13\loch\f13 By: }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid2766548\charrsid2766548 \loch\af13\hich\af13\dbch\f13 \'c2\'e4\'d1\'a9\'ce\'de\'ba\'db}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid12910709\charrsid2766548
\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a
9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad
5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6
@@ -321,8 +320,8 @@ fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000f065
8a1b7548db01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000d096
bf3efc84db01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000105000000000000}}
+3 -3
View File
@@ -6,11 +6,11 @@ DEFINITIONS:
1. Data Source
1.1 The principle of the online data sources of the various official streaming services of this project is to draw data from its open servers (the same as the data obtained in the unlogged-in state in the official streaming service app). After simply screening and merging the data, this project is responsible for the legitimacy and accuracy of the data.
1.1 The principle of the online data sources of the various official music streaming services of this project is to draw data from its open servers (the same as the data obtained in the unlogged-in state in the official music streaming service app). After simply screening and merging the data, this project is responsible for the legitimacy and accuracy of the data.
1.2 The ability of this project itself does not obtain certain audio data. The online audio data source used in this project comes from the online link of the "source" selected in the software settings. For example, when playing a song, this project only transmits information such as the song name, singer name, and other information to be played to "source". If the "source" returns a link, this project will think that this is the audio data of the song for use, as for whether this is the correct audio data, this project cannot verify its accuracy, so, in the process of using this project, there may be a problem that the audio you want to play does not correspond to the audio you actually play, or you cannot play it.
1.2 The ability of this project itself does not obtain certain audio data. The online audio data source used in this project comes from the online link provided by the "API" selected in the software settings. For example, when playing a song, this project only transmits information such as the song title, artist, and other information to the "API". If the "API" returns a link, this project will think that this is the audio data of the song for use, but as for whether this is the correct audio data, this project cannot verify its accuracy. So, in the process of using this project, there may be a problem that the audio you want to play does not correspond to the audio you actually play, or you cannot play it.
1.3 The unofficial streaming service data (such as my collection list) of this project comes from synchronous services connected by the user's local system or user connection. This project is not responsible for the legality and accuracy of this data.
1.3 Data in this project other than official music streaming service (such as lists in "Your Library") comes from the user's local system or a synchronization service that the user connected to. This project is not responsible for the legality and accuracy of this data.
2. Copyrighted Data
+2 -2
View File
@@ -6,9 +6,9 @@
1.1 本项目的各官方平台在线数据来源原理是从其公开服务器中拉取数据(与未登录状态在官方平台 APP 获取的数据相同),经过对数据简单地筛选与合并后进行展示,因此本项目不对数据的合法性、准确性负责。
1.2 本项目本身没有获取某个音频数据的能力,本项目使用的在线音频数据来源来自软件设置内“音乐来源”设置所选择的“源”返回的在线链接。例如播放某首歌,本项目所做的只是将希望播放的歌曲名字、歌手名字等信息传递给“源”,若“源”返回了一个链接,则本项目将认为这就是该歌曲的音频数据而进行使用,至于这是不是正确的音频数据本项目无法校验其准确性,所以使用本项目的过程中可能会出现希望播放的音频与实际播放的音频不对应或者无法播放的问题。
1.2 本项目本身没有获取某个音频数据的能力,本项目使用的在线音频数据来源来自软件设置内“自定义源”设置所选择的“源”返回的在线链接。例如播放某首歌,本项目所做的只是将希望播放的歌曲名、艺术家等信息传递给“源”,若“源”返回了一个链接,则本项目将认为这就是该歌曲的音频数据而进行使用,至于这是不是正确的音频数据本项目无法校验其准确性,所以使用本项目的过程中可能会出现希望播放的音频与实际播放的音频不对应或者无法播放的问题。
1.3 本项目的非官方平台数据(例如我的收藏列表)来自使用者本地系统或者使用者连接的同步服务,本项目不对这些数据的合法性、准确性负责。
1.3 本项目的非官方平台数据(例如“我的列表”内列表)来自使用者本地系统或者使用者连接的同步服务,本项目不对这些数据的合法性、准确性负责。
二、版权数据
+3228 -3340
View File
File diff suppressed because it is too large Load Diff
+48 -49
View File
@@ -1,6 +1,6 @@
{
"name": "lx-music-desktop",
"version": "2.10.0-beta.12",
"version": "2.12.0",
"description": "一个免费的音乐查找助手",
"main": "./dist/main.js",
"scripts": {
@@ -71,7 +71,7 @@
"Electron 22.3.0"
],
"engines": {
"node": ">= 18",
"node": ">= 22",
"npm": ">=8.5.2"
},
"macLanguagesInfoPlistStrings": {
@@ -107,97 +107,96 @@
},
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
"devDependencies": {
"@babel/core": "^7.26.7",
"@babel/eslint-parser": "^7.26.5",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/core": "^7.28.5",
"@babel/eslint-parser": "^7.28.5",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-modules-umd": "^7.25.9",
"@babel/plugin-transform-runtime": "^7.25.9",
"@babel/preset-env": "^7.26.7",
"@babel/preset-typescript": "^7.26.0",
"@tsconfig/recommended": "^1.0.8",
"@types/better-sqlite3": "^7.6.12",
"@babel/plugin-transform-class-properties": "^7.27.1",
"@babel/plugin-transform-modules-umd": "^7.27.1",
"@babel/plugin-transform-runtime": "^7.28.5",
"@babel/preset-env": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@babel/runtime": "^7.28.4",
"@tsconfig/recommended": "^1.0.13",
"@types/better-sqlite3": "^7.6.13",
"@types/needle": "^3.3.0",
"@types/node": "^20.17.16",
"@types/node": "^20.19.25",
"@types/tunnel": "^0.0.7",
"@types/ws": "8.5.4",
"@volar/vue-language-plugin-pug": "^1.6.5",
"@vue/language-plugin-pug": "^2.2.0",
"babel-loader": "^9.2.1",
"browserslist": "^4.24.4",
"@vue/language-plugin-pug": "^3.1.5",
"babel-loader": "^10.0.0",
"browserslist": "^4.28.0",
"chalk": "^4.1.2",
"changelog-parser": "^3.0.1",
"copy-webpack-plugin": "^12.0.2",
"core-js": "^3.40.0",
"cross-env": "^7.0.3",
"copy-webpack-plugin": "^13.0.1",
"core-js": "^3.47.0",
"cross-env": "^10.1.0",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.0",
"css-minimizer-webpack-plugin": "^7.0.2",
"del": "^6.1.1",
"electron": "^32.3.0",
"electron-builder": "^26.0.0-alpha.11",
"electron": "37.6.1",
"electron-builder": "^26.3.2",
"electron-debug": "^3.2.0",
"electron-devtools-installer": "github:lyswhut/electron-devtools-installer#64596d615c1fc891eefd8aef1dfcb2c87aaadf03",
"electron-to-chromium": "^1.5.88",
"electron-updater": "^6.4.0-alpha.4",
"electron-to-chromium": "^1.5.262",
"electron-updater": "6.7.2",
"eslint": "^8.57.1",
"eslint-config-standard": "^17.1.0",
"eslint-config-standard-with-typescript": "^43.0.1",
"eslint-formatter-friendly": "github:lyswhut/eslint-friendly-formatter#2170d1320e2fad13615a9dcf229669f0bb473a53",
"eslint-plugin-html": "^8.1.2",
"eslint-plugin-vue": "^9.32.0",
"eslint-plugin-html": "^8.1.3",
"eslint-plugin-vue": "^9.33.0",
"eslint-plugin-vue-pug": "^0.6.2",
"eslint-webpack-plugin": "^4.2.0",
"html-webpack-plugin": "^5.6.3",
"less": "^4.2.2",
"less-loader": "^12.2.0",
"mini-css-extract-plugin": "^2.9.2",
"html-webpack-plugin": "^5.6.5",
"less": "^4.4.2",
"less-loader": "^12.3.0",
"mini-css-extract-plugin": "^2.9.4",
"node-loader": "^2.1.0",
"postcss": "^8.5.1",
"postcss-loader": "^8.1.1",
"postcss": "^8.5.6",
"postcss-loader": "^8.2.0",
"postcss-pxtorem": "^6.1.0",
"pug": "^3.0.3",
"pug-plain-loader": "^1.1.0",
"rimraf": "^6.0.1",
"rimraf": "^6.1.2",
"spinnies": "github:lyswhut/spinnies#233305c58694aa3b053e3ab9af9049993f918b9d",
"svg-sprite-loader": "^6.0.11",
"svg-transform-loader": "^2.0.13",
"svgo-loader": "^4.0.0",
"terser": "^5.37.0",
"terser-webpack-plugin": "^5.3.11",
"terser": "^5.44.1",
"terser-webpack-plugin": "^5.3.14",
"tree-kill": "^1.2.2",
"ts-loader": "^9.5.2",
"typescript": "5.7.3",
"ts-loader": "^9.5.4",
"typescript": "5.9.3",
"vue-eslint-parser": "^9.4.3",
"vue-loader": "^17.4.2",
"vue-template-compiler": "^2.7.16",
"webpack": "^5.97.1",
"webpack": "^5.103.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "5.2.0",
"webpack-dev-server": "5.2.2",
"webpack-hot-middleware": "github:lyswhut/webpack-hot-middleware#329c4375134b89d39da23a56a94db651247c74a1",
"webpack-merge": "^6.0.1"
},
"dependencies": {
"@simonwep/pickr": "^1.9.1",
"better-sqlite3": "^11.8.1",
"better-sqlite3": "^12.5.0",
"bufferutil": "^4.0.9",
"comlink": "~4.3.1",
"crypto-js": "^4.2.0",
"electron-log": "^5.2.4",
"font-list": "^1.5.1",
"iconv-lite": "^0.6.3",
"electron-log": "^5.4.3",
"font-list": "^2.0.1",
"iconv-lite": "^0.7.0",
"image-size": "^1.1.0",
"jschardet": "^3.1.4",
"long": "^5.2.4",
"long": "^5.3.2",
"message2call": "^0.1.3",
"music-metadata": "^10.7.1",
"music-metadata": "^11.10.3",
"needle": "github:lyswhut/needle#93299ac841b7e9a9f82ca7279b88aaaeda404060",
"node-id3": "^0.2.6",
"node-id3": "^0.2.9",
"sortablejs": "^1.15.6",
"tunnel": "^0.0.6",
"utf-8-validate": "^6.0.5",
"vue": "~3.3.13",
"vue-router": "^4.5.0",
"ws": "^8.18.0"
"vue-router": "^4.5.1",
"ws": "^8.18.3"
},
"overrides": {
"got": "^11",
+3 -46
View File
@@ -1,49 +1,6 @@
### 不兼容性变更
Linux 系统至少需要 `GLIBC_2.29` 版本才能运行。
由于将 Electron 升级到 v32.x,原生库的编译被限制到不低于 C++ 20,试了几次无法在 docker 镜像 `node:16` 安装 gcc-10,最终将构建使用镜像更新到 `node:18`。
### 新增
- 新增下载的歌曲按列表名分组的功能,默认关闭,可以通过「设置 → 下载设置 → 将文件保存到以对应列表命名的子目录中」启用(#2145)
- 新增托盘图标样式「跟随系统亮暗模式」设置,可以在「设置 → 其他」里启用 (#2016)
- 支持本地同名 `.krc` 格式歌词文件的读取(#2053)
- 开放 API 新增播放器播放/暂停、切歌、收藏当前播放歌曲等接口调用,详情看文档「开放 API 服务」部分(#2077, @14Kay)
### 优化
- 优化正常播放结束时的下一首歌曲播放衔接度,在歌曲即将结束播放时将预获取下一首歌曲的播放链接,减少自动切歌时的等待时间(#2126)
- 优化歌曲换源机制,提升换源正确率
- 优化 Windows 平台上桌面歌词窗口大小调整机制,改用原生的窗口调整方式(#2137)
- 修正搜索歌曲提示框文案(#2050)
- 优化播放详情页 UI,修复「歌曲名」「艺术家」等文字过长时被截断的问题(#2049)
- Scheme URL 的播放歌曲允许更长的专辑名称
- 播放本地歌曲时,将优先尝试读取本地同名 `.jpg` 或 `.png` 图片作为播放封面显示,若文件不存在则从音频文件内读取,最后再尝试使用在线图片(#2096)
- 客户端模式的同步服务连接允许重定向 5 次(#2109)
- 更新软件默认使用的字体,修复 macOS Sequoia (15) 上界面出现乱码的问题(#2076)
- 优化简体、繁体中文文案编排,大幅修订英语文案编排(#2159, #2166, #2174 等, @3gf8jv4dv)
- 优化排序歌曲、主题名称、添加/编辑主题、列表更新管理等对话框布局及长文本显示效果(#2176, #2188, #2189, #2198 等, @3gf8jv4dv)
我们很高兴地宣布新项目 Any Listen 的桌面版已发布,目前已支持列表跟随本地文件自动更新、加载并播放WebDAV上的歌曲等功能,更多功能仍在积极开发中,桌面版与Web版将同步更新。
对于有播放本地音乐或播放服务器上音乐需求的人可以试试,若遇到任何问题可以发 issue 反馈。
### 修复
- 修复歌单详情页内歌单名字过长时的 UI 显示问题(#2028)
- 修复获取自定义环境音效预设列表逻辑问题
- 修复 `.m4a` 文件内嵌歌词无法读取的问题(#2090)
- 修复 Windows 任务管理器中的进程名显示为软件描述的问题(#2147)
- 修复本地歌曲同名歌词文件调整偏移时间后,下次再播放时调整的设置未被应用的问题(#2139)
- 修复首次打开软件后直接创建并删除列表时的报错问题(#2175, @14Kay)
### 变更
- 不再长期缓存换源歌曲信息
- 更新软件默认使用的字体,现在软件尽量使用系统自带的默认字体
- Linux 系统至少需要 `GLIBC_2.29` 版本才能运行
### 其他
- 更新 Readme 文档,优化文案编排(#2146, Thanks @3gf8jv4dv)
- 更新 Issue 模板(#2153, @3gf8jv4dv)
- 更新项目文档(@3gf8jv4dv)
- 修订项目协议文件(#2146, #2152, @3gf8jv4dv)
- 更新 Electron 到 v32.3.0
- 修复音量条在调整音量时实际音量与显示的数值不一致的问题(#2606)
+40
View File
@@ -0,0 +1,40 @@
/**
*
* @param {string} text
* @returns
*/
export const parseChangelog = async(text) => {
const versions = []
const lines = text.split(/\r\n|\r|\n/)
let currentVersion = null
let currentDate = null
let currentDesc = ''
for (const line of lines) {
const versionMatch = line.match(/^\s*##\s+\[?(\d+\.\d+\.\d+)\]?.*?-\s+(\d{4}-\d{2}-\d{2})$/)
if (versionMatch) {
if (currentVersion) {
versions.push({
version: currentVersion,
date: currentDate,
desc: currentDesc.trim(),
})
}
currentVersion = versionMatch[1]
currentDate = versionMatch[3]
currentDesc = ''
} else {
currentDesc += `${line}\n`
}
}
if (currentVersion) {
versions.push({
version: currentVersion,
date: currentDate,
desc: currentDesc.trim(),
})
}
return versions
}
+6 -10
View File
@@ -6,8 +6,8 @@ const version = require('../version.json')
const chalk = require('chalk')
const pkg_bak = JSON.stringify(pkg, null, 2)
const version_bak = JSON.stringify(version, null, 2)
const parseChangelog = require('changelog-parser')
const changelogPath = jp('../../CHANGELOG.md')
const { parseChangelog } = require('./parseChangelog')
// const md_renderer = markdownStr => new (require('markdown-it'))({
// html: true,
@@ -16,27 +16,23 @@ const changelogPath = jp('../../CHANGELOG.md')
// breaks: true,
// }).render(markdownStr)
const getPrevVer = () => parseChangelog(changelogPath).then(res => {
if (!res.versions.length) throw new Error('CHANGELOG 无法解析到版本号')
return res.versions[0].version
const getPrevVer = () => parseChangelog(fs.readFileSync(changelogPath, 'utf-8').toString()).then(versions => {
if (!versions.length) throw new Error('CHANGELOG 无法解析到版本号')
return versions[0].version
})
const updateChangeLog = async(newVerNum, newChangeLog) => {
let changeLog = fs.readFileSync(changelogPath, 'utf-8')
const prevVer = await getPrevVer()
const log = `## [${newVerNum}](${pkg.repository.url.replace(/^git\+(http.+)\.git$/, '$1')}/compare/v${prevVer}...v${newVerNum}) - ${formatTime()}\n\n${newChangeLog}`
fs.writeFileSync(changelogPath, changeLog.replace(new RegExp('(## [?0.1.1]?)'), log + '\n$1'), 'utf-8')
fs.writeFileSync(changelogPath, changeLog.replace(/(## \[(?:\d+\.))/, log + '\n$1'), 'utf-8')
}
// const renderChangeLog = md => md_renderer(md)
module.exports = async newVerNum => {
if (!newVerNum) {
let verArr = pkg.version.split('.')
verArr[verArr.length - 1] = parseInt(verArr[verArr.length - 1]) + 1
newVerNum = verArr.join('.')
}
if (!newVerNum) newVerNum = pkg.version
const newMDChangeLog = fs.readFileSync(jp('../changeLog.md'), 'utf-8')
// const newChangeLog = renderChangeLog(newMDChangeLog)
version.history.unshift({
+1 -1
View File
File diff suppressed because one or more lines are too long
+5
View File
@@ -19,6 +19,7 @@ const defaultSetting: LX.AppSetting = {
'common.isAgreePact': false,
'common.controlBtnPosition': isMac ? 'left' : 'right',
'common.playBarProgressStyle': 'mini',
'common.transparentWindow': !isMac,
'common.tryAutoUpdate': true,
'common.showChangeLog': true,
@@ -37,6 +38,7 @@ const defaultSetting: LX.AppSetting = {
'player.isMediaDeviceRemovedStopPlay': false,
'player.isShowLyricTranslation': false,
'player.isShowLyricRoma': false,
'player.isSwapLyricTranslationAndRoma': false,
'player.isS2t': false,
'player.isPlayLxlrc': !isMac,
'player.isSavePlayTime': false,
@@ -76,6 +78,7 @@ const defaultSetting: LX.AppSetting = {
'desktopLyric.isShowTaskbar': false,
'desktopLyric.audioVisualization': false,
'desktopLyric.fullscreenHide': true,
'desktopLyric.pauseHide': true,
'desktopLyric.width': 450,
'desktopLyric.height': 300,
'desktopLyric.x': null,
@@ -113,11 +116,13 @@ const defaultSetting: LX.AppSetting = {
'download.maxDownloadNum': 3,
'download.skipExistFile': true,
'download.isDownloadLrc': false,
'download.isDownloadLxLrc': true,
'download.isDownloadTLrc': false,
'download.isDownloadRLrc': false,
'download.lrcFormat': 'utf8',
'download.isEmbedPic': true,
'download.isEmbedLyric': false,
'download.isEmbedLyricLx': true,
'download.isEmbedLyricT': false,
'download.isEmbedLyricR': false,
'download.isUseOtherSource': false,
+10
View File
@@ -51,6 +51,16 @@ const hotKey = {
action: 'prev',
type: '',
},
seekbackward: {
name: 'seekbackward',
action: 'seekbackward',
type: '',
},
seekforward: {
name: 'seekforward',
action: 'seekforward',
type: '',
},
volume_up: {
name: 'volume_up',
action: 'volume_up',
+1
View File
@@ -162,6 +162,7 @@ const modules = {
on_config_change: 'on_config_change',
main_window_inited: 'main_window_inited',
set_win_bounds: 'set_win_bounds',
set_win_resizeable: 'set_win_resizeable',
key_down: 'key_down',
request_main_window_channel: 'request_main_window_channel',
provide_main_window_channel: 'provide_main_window_channel',
+25
View File
@@ -68,6 +68,11 @@ declare global {
*/
'common.playBarProgressStyle': 'mini' | 'full' | 'middle'
/**
* 启用透明窗口
*/
'common.transparentWindow': boolean
/**
* 尝试自动更新
*/
@@ -154,6 +159,11 @@ declare global {
*/
'player.isShowLyricRoma': boolean
/**
* 是否调换翻译歌词与罗马音歌词位置
*/
'player.isSwapLyricTranslationAndRoma': boolean
/**
* 是否将歌词从简体转换为繁体
*/
@@ -340,6 +350,11 @@ declare global {
*/
'desktopLyric.fullscreenHide': boolean
/**
* 是否在暂停时隐藏歌词
*/
'desktopLyric.pauseHide': boolean
/**
* 桌面歌词窗口宽度
*/
@@ -515,6 +530,11 @@ declare global {
*/
'download.isDownloadLrc': boolean
/**
* 是否在下载 lx 歌词
*/
'download.isDownloadLxLrc': boolean
/**
* 是否下载翻译歌词文件
*/
@@ -535,6 +555,11 @@ declare global {
*/
'download.isEmbedPic': boolean
/**
* 是否在音频文件中嵌入 lx 歌词
*/
'download.isEmbedLyricLx': boolean
/**
* 是否在音频文件中嵌入歌词
*/
+5
View File
@@ -37,6 +37,11 @@ declare namespace LX {
*/
play?: string
/**
* 启动后最小化到系统托盘
*/
hidden?: boolean
[key: string]: boolean | number | string
}
+2
View File
@@ -6,6 +6,7 @@ declare namespace LX {
'desktopLyric.isAlwaysOnTop': LX.AppSetting['desktopLyric.isAlwaysOnTop']
'desktopLyric.isAlwaysOnTopLoop': LX.AppSetting['desktopLyric.isAlwaysOnTopLoop']
'desktopLyric.isShowTaskbar': LX.AppSetting['desktopLyric.isShowTaskbar']
'desktopLyric.pauseHide': LX.AppSetting['desktopLyric.pauseHide']
'desktopLyric.audioVisualization': LX.AppSetting['desktopLyric.audioVisualization']
'desktopLyric.width': LX.AppSetting['desktopLyric.width']
'desktopLyric.height': LX.AppSetting['desktopLyric.height']
@@ -33,6 +34,7 @@ declare namespace LX {
'common.langId': LX.AppSetting['common.langId']
'player.isShowLyricTranslation': LX.AppSetting['player.isShowLyricTranslation']
'player.isShowLyricRoma': LX.AppSetting['player.isShowLyricRoma']
'player.isSwapLyricTranslationAndRoma': LX.AppSetting['player.isSwapLyricTranslationAndRoma']
'player.isPlayLxlrc': LX.AppSetting['player.isPlayLxlrc']
'player.playbackRate': LX.AppSetting['player.playbackRate']
}
+8
View File
@@ -11,6 +11,9 @@ declare namespace LX {
| 'pause'
| 'play'
| 'next'
| 'seek'
| 'volume'
| 'mute'
interface LyricInfo extends LX.Music.LyricInfo {
rawlrcInfo: LX.Music.LyricInfo
@@ -28,7 +31,12 @@ declare namespace LX {
lyricLineText: string
lyricLineAllText: string
lyric: string
tlyric: string
rlyric: string
lxlyric: string
collect: boolean
volume: number
mute: boolean
}
}
}
-13
View File
@@ -71,19 +71,6 @@ export const formatPlayTime2 = (time: number) => {
}
const encodeNames = {
'&nbsp;': ' ',
'&amp;': '&',
'&lt;': '<',
'&gt;': '>',
'&quot;': '"',
'&apos;': "'",
'&#039;': "'",
} as const
export const decodeName = (str: string | null = '') => {
return str?.replace(/(?:&amp;|&lt;|&gt;|&quot;|&apos;|&#039;|&nbsp;)/gm, (s: string) => encodeNames[s as keyof typeof encodeNames]) ?? ''
}
export const isUrl = (path: string) => /https?:\/\//.test(path)
// 解析URL参数为对象
+5
View File
@@ -230,6 +230,11 @@ class Task extends EventEmitter {
__handleComplete() {
if (this.status == STATUS.error) return
this.__clearTimeout()
if (this.progress.progress <= 0) {
this.status = STATUS.error
this.emit('error', new Error('Progress is 0, download failed.'))
return
}
void this.__closeWriteStream().then(() => {
if (this.progress.downloaded == this.progress.total) {
this.status = STATUS.completed
+1 -1
View File
@@ -342,7 +342,7 @@ export const scrollXRTo = (element: ScrollElement<HTMLElement>, to: number, dura
*/
let dom_title = document.getElementsByTagName('title')[0]
export const setTitle = (title: string | null) => {
title ||= '洛雪音乐助手'
title ||= 'LX Music'
dom_title.innerText = title
}
+36 -25
View File
@@ -122,10 +122,10 @@
"list_add__title_first_move": "Move",
"list_add__title_last": "to ...",
"list_duplicate_tip": "A list with the same name already exists. Do you want to continue creating it?",
"list_import_tip__alldata": "Failed to import. This is an \"All Data\" backup file. You need to go here to import: \n\n\"Settings → Backup & Restore → All Data → Import\"",
"list_import_tip__playlist": "Failed to import. This is a \"List\" backup file. You need to go here to import: \n\n\"Settings → Backup & Restore → Partial Data → Import lists\"",
"list_import_tip__playlist_part": "Failed to import. This is a \"List-only\" backup file. You need to go here to import: \n\n\"Your Library → Right-click on any list name → Select 'Import' in the menu\"",
"list_import_tip__setting": "Failed to import. This is a \"Settings\" backup file. You need to go here to import: \n\n\"Settings → Backup & Restore → Partial Data → Import settings\"",
"list_import_tip__alldata": "Failed to import. This is an \"All Data\" backup file. You need to go here to import: \n\nSettings → Backup & Restore → All Data → Import",
"list_import_tip__playlist": "Failed to import. This is a \"List\" backup file. You need to go here to import: \n\nSettings → Backup & Restore → Partial Data → Import lists",
"list_import_tip__playlist_part": "Failed to import. This is a \"List-only\" backup file. You need to go here to import: \n\nYour Library → Right-click on any list name → Select 'Import' in the menu",
"list_import_tip__setting": "Failed to import. This is a \"Settings\" backup file. You need to go here to import: \n\nSettings → Backup & Restore → Partial Data → Import settings",
"list_import_tip__unknown": "Failed to import. Unknown file type. Please try to upgrade the app to the latest version and try again.",
"list_sort_modal_by_album": "Album",
"list_sort_modal_by_down": "Descending",
@@ -184,7 +184,7 @@
"lyric_menu__size_add": "Increase font size\n(Right-click to fine-tune)",
"lyric_menu__size_dec": "Decrease font size\n(Right-click to fine-tune)",
"lyric_menu__size_reset": "Reset",
"media_device__empty_device_tip": "The audio output device is empty. If it cannot be played, please check whether the sound card driver has been installed or reinstall it!",
"media_device__empty_device_tip": "The audio output device is empty. If there is no playback, please check whether the sound card driver is installed. \nOr uninstall and reinstall the software, select \"install for me only\" during installation, and keep the default installation path.",
"min": "Minimize",
"music_album": "Album",
"music_duplicate": "Duplicate song",
@@ -195,6 +195,8 @@
"music_sort__title_multiple": "Adjust the position of the selected {num} songs to: ",
"music_time": "Length",
"music_toggle_clean": "Cancel Change",
"music_toggle_confirm": "Confirm",
"music_toggle_duplicate_tip": "The same song already exists in the list, should I remove it and continue?",
"my_list": "Your Library",
"no_item": "Nothing's here...",
"not_agree": "Decline",
@@ -227,7 +229,7 @@
"player__music_singer": "Artist: ",
"player__next": "Next",
"player__pause": "Pause",
"player__pic_tip": "Play detail page\n(Right-click to locate the currently playing song in \"Your Library\")",
"player__pic_tip": "Playback detail page\n(Right-click to locate the currently playing song in \"Your Library\")",
"player__play": "Play",
"player__play_toggle_mode_list": "In Order",
"player__play_toggle_mode_list_loop": "Repeat Playlist",
@@ -301,7 +303,7 @@
"setting__backup_other_export_list_csv": "Export lists in CSV format",
"setting__backup_other_export_list_text": "Export lists in TXT format",
"setting__backup_other_export_list_text_confirm": "Do you want to merge all the lists into one file?",
"setting__backup_part": "Partial Data (\"List\" data includes \"Default\", \"Loved\", and user-created lists. \"Setting\" data does not include shortcut key settings)",
"setting__backup_part": "Partial Data (\"List\" data includes \"Default\", \"Loved\", and user-created lists. \"Setting\" data does not include \"Shortcuts\" settings)",
"setting__backup_part_export_list": "Export lists",
"setting__backup_part_export_list_desc": "Save the lists to ...",
"setting__backup_part_export_setting": "Export settings",
@@ -310,7 +312,7 @@
"setting__backup_part_import_list_confirm": "If the list in the backup file has the same ID as the existing list, the songs in the existing list will be overwritten. Do you want to continue?",
"setting__backup_part_import_list_desc": "Choose a list backup file",
"setting__backup_part_import_setting": "Import settings",
"setting__backup_part_import_setting_desc": "Choose a settings backup file",
"setting__backup_part_import_setting_desc": "Choose a setting backup file",
"setting__basic": "General",
"setting__basic_animation": "Randomize pop-up animation",
"setting__basic_control_btn_position": "Control Button Position",
@@ -364,7 +366,7 @@
"setting__desktop_lyric_align_right": "Right",
"setting__desktop_lyric_always_on_top": "Stay always-on-top",
"setting__desktop_lyric_always_on_top_loop": "Refresh lyric window repeatedly when \"Stay always-on-top\" is enabled",
"setting__desktop_lyric_always_on_top_loop_tip": "Try to enable this option when the window are still blocked by some programs.",
"setting__desktop_lyric_always_on_top_loop_tip": "Try to enable this option when the window are still covered by some programs.",
"setting__desktop_lyric_audio_visualization": "Enable audio visualization (EXPERIMENTAL)",
"setting__desktop_lyric_color": "Lyric Font Color",
"setting__desktop_lyric_color_reset": "Reset color",
@@ -381,13 +383,14 @@
"setting__desktop_lyric_font_weight_font": "Verbatim lyrics",
"setting__desktop_lyric_font_weight_line": "Progressive lyrics",
"setting__desktop_lyric_fullscreen_hide": "Hide lyric window when in fullscreen",
"setting__desktop_lyric_hover_hide": "Decrease lyric window transparency when the mouse moves into the lyric window",
"setting__desktop_lyric_hover_hide": "Increase lyric window transparency when the mouse moves into the lyric window",
"setting__desktop_lyric_hover_hide_tip": "This feature has platform compatibility issues.",
"setting__desktop_lyric_line_gap": "Lyric Spacing ({num})",
"setting__desktop_lyric_line_gap_add": "Increase spacing",
"setting__desktop_lyric_line_gap_dec": "Decrease spacing",
"setting__desktop_lyric_lock": "Lock lyric window",
"setting__desktop_lyric_lock_screen": "Do not allow lyric window to be dragged out of main screen",
"setting__desktop_lyric_pause_hide": "Increase lyric window transparency when pausing music",
"setting__desktop_lyric_played_color": "Played",
"setting__desktop_lyric_reset": "Reset",
"setting__desktop_lyric_reset_window": "Reset Desktop Lyric Options",
@@ -404,11 +407,13 @@
"setting__dislike_list_title": "Disliked Song Rule List",
"setting__download": "Download",
"setting__download_data_embed": "Embed the Following into Audio File",
"setting__download_embed_lxlyric": "Embed LX Music lyrics at the same time (if any, verbatim lyrics can be supported when playing with LX Music)",
"setting__download_embed_lyric": "Embed lyrics",
"setting__download_embed_pic": "Embed cover",
"setting__download_embed_rlyric": "Also embed romanized lyrics if available",
"setting__download_embed_tlyric": "Also embed translated lyrics if available",
"setting__download_enable": "Enable Download",
"setting__download_lxlyric": "Also write LX Music lyrics into the lyrics file (if any, verbatim lyrics can be supported when playing with LX Music)",
"setting__download_lyric": "Lyric Download",
"setting__download_lyric_format": "Encoding Format of Downloaded Lyric Files",
"setting__download_lyric_format_gbk": "GBK",
@@ -416,13 +421,13 @@
"setting__download_lyric_format_utf8": "UTF-8",
"setting__download_lyric_title": "Select whether to download the lyrics file",
"setting__download_max_num": "Number of Simultaneous Downloads",
"setting__download_max_num_tip": "An excessively large number of simultaneous downloads may cause your IP to be blocked by the music API. Do you confirm the modification?",
"setting__download_max_num_tooltip": "Set too high may result in IP being blocked, depending on the music API.",
"setting__download_max_num_tip": "An excessively large number of simultaneous downloads may cause your IP to be blocked by the Music API. Do you confirm the modification?",
"setting__download_max_num_tooltip": "Set too high may result in IP being blocked, depending on the Music API.",
"setting__download_name": "Music File Naming",
"setting__download_name1": "\"Title - Artist\"",
"setting__download_name2": "\"Artist - Title\"",
"setting__download_name3": "Title only",
"setting__download_name_title": "Select the music naming method for downloading",
"setting__download_name_title": "Select the music naming style for downloading",
"setting__download_path": "Download Path",
"setting__download_path_change_btn": "Change",
"setting__download_path_label": "Current: ",
@@ -450,6 +455,8 @@
"setting__hot_key_player_music_unlove": "Unlove Song",
"setting__hot_key_player_next": "Next Song",
"setting__hot_key_player_prev": "Previous Song",
"setting__hot_key_player_seekbackward": "Seek Backward 5s",
"setting__hot_key_player_seekforward": "Seek Forward 5s",
"setting__hot_key_player_toggle_play": "Play/Pause Control",
"setting__hot_key_player_volume_down": "Decrease Volume",
"setting__hot_key_player_volume_mute": "Toggle Mute",
@@ -478,9 +485,9 @@
"setting__open_api": "Open API",
"setting__open_api_address": "Service Address: ",
"setting__open_api_bind_lan": "Allow access from LAN",
"setting__open_api_enable": "Enable open API service",
"setting__open_api_enable": "Enable Open API service",
"setting__open_api_port": "Service Port",
"setting__open_api_port_tip": "Please enter the open API service port",
"setting__open_api_port_tip": "Please enter the Open API service port",
"setting__open_api_tip": "This feature is used to provide third-party programs with the ability to call LX Music. You can see the currently available features: ",
"setting__open_api_tip_link": "Visit Documents",
"setting__other": "Extras",
@@ -507,17 +514,19 @@
"setting__other_resource_cache_label": "The app has used cache size: ",
"setting__other_resource_cache_tip": "Includes pictures, audios, and other caches. After cleaning, these resources will need to be downloaded again. It is not recommended to clean up. The app will dynamically manage the cache size according to the disk space.",
"setting__other_resource_cache_tip_confirm": "Involving the cache of pictures, audios, etc., these resources will need to be downloaded again after cleaning. It is not recommended to clean up. The app will dynamically manage the cache size according to the disk space. Do you still need to clean up?",
"setting__other_transparent_window": "Use built-in rounded corners and shadows for the main window",
"setting__other_transparent_window_tip": "Turning off this option will use the system's native window style. Requires a restart of the software for the change to take effect.",
"setting__other_tray_theme": "Tray Icon Style",
"setting__other_tray_theme_auto": "Follow System",
"setting__other_tray_theme_black": "Black",
"setting__other_tray_theme_native": "White",
"setting__other_tray_theme_origin": "Default",
"setting__play": "Play",
"setting__play": "Playback",
"setting__play_advanced_audio_features_tip": "A custom audio output device conflicts with this feature. After enabling this feature, the audio output device will be reset to the default output device. This problem cannot be solved at the moment. Do you still want to enable it?",
"setting__play_auto_clean_played_list": "Empty played list when playing the same list as the current playlist",
"setting__play_auto_clean_played_list_tip": "All songs in the list in shuffle mode will participate in the random again.",
"setting__play_auto_skip_on_error": "Automatically switch songs when playback error occurs",
"setting__play_detail": "Play Detail Page",
"setting__play_detail": "Playback Detail Page",
"setting__play_detail_align": "Lyric Alignment",
"setting__play_detail_align_center": "Center",
"setting__play_detail_align_left": "Left",
@@ -535,7 +544,7 @@
"setting__play_lyric_transition": "Show translated lyrics if available",
"setting__play_max_output_channel_count": "Output audio using the maximum number of channels the device can handle",
"setting__play_mediaDevice": "Audio Output",
"setting__play_mediaDevice_remove_stop_play": "Pause song when current sound output device is changed",
"setting__play_mediaDevice_remove_stop_play": "Pause playback when current audio output device is changed",
"setting__play_mediaDevice_title": "Select a media device for audio output",
"setting__play_media_device_error_tip": "This feature conflicts with advanced audio features (audio visualization, sound effect options, audio output using the maximum number of channels that the device can handle). You have enabled these features when you started the app this time. This option is temporarily unavailable. Please turn off these features and change this option again after restarting the app.",
"setting__play_media_device_tip": "This feature conflicts with the audio visualization feature and cannot be enabled at the same time. Do you want to turn audio visualization off and apply the selected audio output options?",
@@ -543,10 +552,12 @@
"setting__play_power_save_blocker": "Prevent device from hibernating while playing songs",
"setting__play_save_play_time": "Remember playback progress",
"setting__play_startup_auto_play": "Automatically play music on startup",
"setting__play_statusbar_lyric": "Show lyrics in status bar (Needs tray enabled)",
"setting__play_task_bar": "Show playing progress on the taskbar",
"setting__play_statusbar_lyric": "Show lyrics on status menus",
"setting__play_statusbar_lyric_tip": "Requires \"Minimize the app window to the system tray when closing it\" to be enabled in Settings → General",
"setting__play_task_bar": "Show playback progress on the taskbar",
"setting__play_timeout": "Timed Pause",
"setting__player_audio_visualization_tip": "The custom audio output device feature conflicts with the audio visualization feature. After the audio visualization is enabled, the audio output device will be reset to the default. At present, this problem cannot be resolved. Do you still want to enable it?",
"setting__player_swap_lyric_trans_roma": "Swap the position of the translated and romanized lyrics",
"setting__search": "Search",
"setting__search_focus_search_box": "Automatically focus search box on startup",
"setting__search_history": "Enable Search History",
@@ -601,7 +612,7 @@
"songlist__import_input_tip": "Enter a playlist link/ID",
"songlist__import_input_tip_1": "Cross-service playlists are not supported. Please confirm whether the playlist to be opened corresponds to the current chosen service",
"songlist__import_input_tip_2": "If you encounter a playlist link that cannot be opened. Please send us your feedback",
"songlist__import_input_tip_3": "Unable to open Kugou playlist with playlist ID, but support to open it with Kugou code",
"songlist__import_input_tip_3": "Unable to open Kugou playlist with playlist ID or link from lite edition, but support to open it with Kugou code or link from main edition",
"songlist__import_input_tip_4": "NetEase Cloud Music's \"I Like\" playlist requires a token to open. For details, see ",
"songlist__import_input_title": "Open shared playlist",
"songlist__open_list": "Open \"{name}\" playlist",
@@ -720,8 +731,8 @@
"user_api__btn_import": "Import from Local File",
"user_api__btn_import_online": "Import from Network",
"user_api__btn_remove": "Remove",
"user_api__import_file": "Choose music API script file",
"user_api__init_failed_alert": "Failed to initialize music API \"{name}\": ",
"user_api__import_file": "Choose Music API script file",
"user_api__init_failed_alert": "Failed to initialize Music API \"{name}\": ",
"user_api__max_tip": "There can only be a maximum of 20 APIs at the same time🤪.\n\nIf you want to continue importing, please remove some unnecessary APIs to make room.",
"user_api__noitem": "There is nothing here...😲",
"user_api__note": "TIP: Although we have isolated the API script's running environment as much as possible, importing API scripts containing malicious behaviors may still affect your system. Please import them with caution.",
@@ -729,9 +740,9 @@
"user_api__title": "Music API Management",
"user_api__update_alert": "Music API \"{name}\" found new version: ",
"user_api__update_alert_open_url": "Open update address",
"user_api_import__failed": "Failed to import music API:\n\n{message}",
"user_api_import__failed": "Failed to import Music API:\n\n{message}",
"user_api_import_online__input_confirm": "Import",
"user_api_import_online__input_loading": "Importing...",
"user_api_import_online__input_tip": "Please enter an HTTP link",
"user_api_import_online__title": "Import music API from network."
"user_api_import_online__title": "Import Music API from network."
}
+23 -12
View File
@@ -184,7 +184,7 @@
"lyric_menu__size_add": "加大字体(右击可微调)",
"lyric_menu__size_dec": "减小字体(右击可微调)",
"lyric_menu__size_reset": "重置",
"media_device__empty_device_tip": "音频输出设备为空,若出现无法播放的情况,请检查声卡驱动是否已安装或重装声卡驱动!",
"media_device__empty_device_tip": "音频输出设备为空,若出现无法播放的情况,请检查声卡驱动是否已安装。或卸载并重新安装软件,安装时选「仅为我安装」,并保持默认安装路径。",
"min": "最小化",
"music_album": "专辑名",
"music_duplicate": "重复歌曲",
@@ -195,6 +195,8 @@
"music_sort__title_multiple": "将已选的 {num} 首歌曲的位置调整到:",
"music_time": "时长",
"music_toggle_clean": "取消换源",
"music_toggle_confirm": "确认",
"music_toggle_duplicate_tip": "列表中已存在相同的歌曲,是否将其移除并继续?",
"my_list": "我的列表",
"no_item": "列表竟然是空的...",
"not_agree": "不接受",
@@ -318,11 +320,11 @@
"setting__basic_control_btn_position_right": "右边",
"setting__basic_font": "字体",
"setting__basic_font_size": "字体大小",
"setting__basic_font_size_14px": "较小",
"setting__basic_font_size_14px": "更小",
"setting__basic_font_size_15px": "小",
"setting__basic_font_size_16px": "标准",
"setting__basic_font_size_17px": "大",
"setting__basic_font_size_18px": "较大",
"setting__basic_font_size_18px": "更大",
"setting__basic_font_size_19px": "非常大",
"setting__basic_lang": "语言",
"setting__basic_lang_title": "软件显示的语言",
@@ -349,11 +351,11 @@
"setting__basic_window_size": "窗口尺寸",
"setting__basic_window_size_big": "大",
"setting__basic_window_size_huge": "巨大",
"setting__basic_window_size_larger": "较大",
"setting__basic_window_size_larger": "更大",
"setting__basic_window_size_medium": "中",
"setting__basic_window_size_oversized": "超大",
"setting__basic_window_size_small": "小",
"setting__basic_window_size_smaller": "较小",
"setting__basic_window_size_smaller": "更小",
"setting__basic_window_size_title": "设置软件窗口尺寸",
"setting__click_copy": "点击复制",
"setting__click_open": "点击打开",
@@ -377,14 +379,18 @@
"setting__desktop_lyric_font": "歌词字体",
"setting__desktop_lyric_font_default": "默认",
"setting__desktop_lyric_font_weight": "加粗字体",
"setting__desktop_lyric_font_weight_extended": "翻译、罗马音歌词",
"setting__desktop_lyric_font_weight_font": "逐字歌词",
"setting__desktop_lyric_font_weight_line": "逐行歌词",
"setting__desktop_lyric_fullscreen_hide": "全屏时自动关闭歌词",
"setting__desktop_lyric_hover_hide": "鼠标移入歌词区域时降低歌词透明度",
"setting__desktop_lyric_hover_hide": "鼠标移入歌词区域时提高歌词透明度",
"setting__desktop_lyric_hover_hide_tip": "此功能存在平台兼容性问题,在某些平台上可能会出现预料外的问题",
"setting__desktop_lyric_line_gap": "歌词间距({num})",
"setting__desktop_lyric_line_gap_add": "加大间距",
"setting__desktop_lyric_line_gap_dec": "减小间距",
"setting__desktop_lyric_lock": "锁定歌词",
"setting__desktop_lyric_lock_screen": "不允许歌词窗口拖出主屏幕之外",
"setting__desktop_lyric_pause_hide": "暂停时提高歌词透明度",
"setting__desktop_lyric_played_color": "已播放颜色",
"setting__desktop_lyric_reset": "重置",
"setting__desktop_lyric_reset_window": "重置窗口设置",
@@ -401,15 +407,17 @@
"setting__dislike_list_title": "「不喜欢的歌曲」规则列表",
"setting__download": "下载设置",
"setting__download_data_embed": "嵌入到音频文件中的内容",
"setting__download_embed_lxlyric": "同时嵌入 LX Music 歌词(如果有,使用 LX Music 播放时可支持逐字歌词)",
"setting__download_embed_lyric": "嵌入歌词",
"setting__download_embed_pic": "嵌入封面",
"setting__download_embed_rlyric": "同时嵌入罗马音歌词(如果有)",
"setting__download_embed_tlyric": "同时嵌入翻译歌词(如果有)",
"setting__download_enable": "启用下载功能",
"setting__download_lxlyric": "同时将 LX Music 歌词写入歌词文件中(如果有,使用 LX Music 播放时可支持逐字歌词)",
"setting__download_lyric": "歌词下载",
"setting__download_lyric_format": "下载的歌词文件编码格式",
"setting__download_lyric_format_tip": "在某些设备上出现中文乱码时可尝试选择 GBK 格式",
"setting__download_lyric_format_gbk": "GBK",
"setting__download_lyric_format_tip": "在某些设备上出现中文乱码时可尝试选择 GBK 格式",
"setting__download_lyric_format_utf8": "UTF-8",
"setting__download_lyric_title": "同时下载歌词文件",
"setting__download_max_num": "同时下载任务数",
@@ -447,6 +455,8 @@
"setting__hot_key_player_music_unlove": "取消收藏",
"setting__hot_key_player_next": "下一首歌曲",
"setting__hot_key_player_prev": "上一首歌曲",
"setting__hot_key_player_seekbackward": "快退 5s",
"setting__hot_key_player_seekforward": "快进 5s",
"setting__hot_key_player_toggle_play": "播放/暂停控制",
"setting__hot_key_player_volume_down": "减少音量",
"setting__hot_key_player_volume_mute": "静音切换",
@@ -504,6 +514,8 @@
"setting__other_resource_cache_label": "软件已使用缓存大小:",
"setting__other_resource_cache_tip": "包括图片、音频等缓存,清理后这些资源将需要重新下载,不建议清理,软件会根据磁盘空间动态管理缓存大小",
"setting__other_resource_cache_tip_confirm": "涉及图片、音频等缓存,清理后这些资源将需要重新下载,不建议清理,软件会根据磁盘空间动态管理缓存大小,是否仍要清理?",
"setting__other_transparent_window": "主窗口使用软件内置的圆角及阴影",
"setting__other_transparent_window_tip": "关闭后将使用系统原生窗口样式。更改后重启软件生效。",
"setting__other_tray_theme": "托盘图标样式",
"setting__other_tray_theme_auto": "跟随系统亮暗模式",
"setting__other_tray_theme_black": "黑色",
@@ -540,17 +552,16 @@
"setting__play_power_save_blocker": "播放歌曲时阻止电脑休眠",
"setting__play_save_play_time": "记住播放进度",
"setting__play_startup_auto_play": "启动软件后自动播放音乐",
"setting__play_statusbar_lyric": "在状态栏显示歌词(需要启用托盘)",
"setting__play_statusbar_lyric": "在菜单栏的状态菜单显示歌词",
"setting__play_statusbar_lyric_tip": "需要在「设置 → 基本设置」启用「关闭窗口时不退出软件将其最小化到系统托盘」。",
"setting__play_task_bar": "在任务栏上显示当前歌曲播放进度",
"setting__play_timeout": "定时暂停",
"setting__player_audio_visualization_tip": "自定义音频输出设备与音频可视化功能冲突,启用「音频可视化」后音频输出设备将会被重置为默认,目前此问题暂无法解决。是否仍要开启?",
"setting__player_swap_lyric_trans_roma": "调换歌词翻译与歌词罗马音位置",
"setting__search": "搜索设置",
"setting__search_focus_search_box": "启动时自动聚焦搜索框",
"setting__search_history": "显示历史搜索记录",
"setting__search_hot": "显示热门搜索",
"setting__desktop_lyric_font_weight_extended": "翻译、罗马音歌词",
"setting__desktop_lyric_font_weight_font": "逐字歌词",
"setting__desktop_lyric_font_weight_line": "逐行歌词",
"setting__sync": "数据同步",
"setting__sync_client_address": "当前设备地址:{address}",
"setting__sync_client_host": "同步服务地址",
@@ -601,7 +612,7 @@
"songlist__import_input_tip": "输入歌单链接或歌单 ID",
"songlist__import_input_tip_1": "不支持跨源打开歌单,请确认要打开的歌单与当前选择的歌单来源是否对应",
"songlist__import_input_tip_2": "若遇到无法打开的歌单链接,欢迎反馈",
"songlist__import_input_tip_3": "不支持用歌单 ID 打开酷狗源歌单,但支持用酷狗码打开",
"songlist__import_input_tip_3": "酷狗源歌单不支持用歌单 ID 或概念版链接打开,但支持用普通版链接或酷狗码打开",
"songlist__import_input_tip_4": "网易源的「我喜欢」歌单需要 Token 才能打开,详情看 ",
"songlist__import_input_title": "打开分享的歌单",
"songlist__open_list": "打开「{name}」歌单",
+23 -12
View File
@@ -184,7 +184,7 @@
"lyric_menu__size_add": "加大字體(右擊可微調)",
"lyric_menu__size_dec": "減小字體(右擊可微調)",
"lyric_menu__size_reset": "重設",
"media_device__empty_device_tip": "音訊輸出裝置為空,若出現無法播放的狀況,請檢查音效卡驅動是否已安裝或重裝音效卡驅動!",
"media_device__empty_device_tip": "音頻輸出設備為空,若出現無法播放的情況,請檢查聲卡驅動是否已安裝。\n或卸載並重新安裝軟件,安裝時選「僅為我安裝」,並保持默認安裝路徑。",
"min": "最小化",
"music_album": "專輯",
"music_duplicate": "重複歌曲",
@@ -195,6 +195,8 @@
"music_sort__title_multiple": "將已選取的 {num} 首歌曲的位置調整到:",
"music_time": "長度",
"music_toggle_clean": "取消變更",
"music_toggle_confirm": "確認",
"music_toggle_duplicate_tip": "列表中已存在相同的歌曲,是否將其移除並繼續?",
"my_list": "我的清單",
"no_item": "清單竟然是空的...",
"not_agree": "不接受",
@@ -318,11 +320,11 @@
"setting__basic_control_btn_position_right": "右邊",
"setting__basic_font": "字體",
"setting__basic_font_size": "字體大小",
"setting__basic_font_size_14px": "較小",
"setting__basic_font_size_14px": "更小",
"setting__basic_font_size_15px": "小",
"setting__basic_font_size_16px": "標準",
"setting__basic_font_size_17px": "大",
"setting__basic_font_size_18px": "較大",
"setting__basic_font_size_18px": "更大",
"setting__basic_font_size_19px": "非常大",
"setting__basic_lang": "語言",
"setting__basic_lang_title": "軟體顯示的語言",
@@ -349,11 +351,11 @@
"setting__basic_window_size": "視窗尺寸",
"setting__basic_window_size_big": "大",
"setting__basic_window_size_huge": "巨大",
"setting__basic_window_size_larger": "較大",
"setting__basic_window_size_larger": "更大",
"setting__basic_window_size_medium": "中",
"setting__basic_window_size_oversized": "超大",
"setting__basic_window_size_small": "小",
"setting__basic_window_size_smaller": "較小",
"setting__basic_window_size_smaller": "更大",
"setting__basic_window_size_title": "設定軟體視窗尺寸",
"setting__click_copy": "點擊複製",
"setting__click_open": "點擊開啟",
@@ -377,14 +379,18 @@
"setting__desktop_lyric_font": "歌詞字體",
"setting__desktop_lyric_font_default": "預設",
"setting__desktop_lyric_font_weight": "加粗字體",
"setting__desktop_lyric_font_weight_extended": "翻譯、羅馬音歌詞",
"setting__desktop_lyric_font_weight_font": "逐字歌詞",
"setting__desktop_lyric_font_weight_line": "逐行歌詞",
"setting__desktop_lyric_fullscreen_hide": "全螢幕時自動關閉歌詞視窗",
"setting__desktop_lyric_hover_hide": "滑鼠移入歌詞視窗時降低歌詞透明度",
"setting__desktop_lyric_hover_hide": "滑鼠移入歌詞視窗時增加歌詞透明度",
"setting__desktop_lyric_hover_hide_tip": "此功能存在平台相容性問題,在某些平台上可能會出現預料外的問題",
"setting__desktop_lyric_line_gap": "歌詞間距({num})",
"setting__desktop_lyric_line_gap_add": "加大間距",
"setting__desktop_lyric_line_gap_dec": "減小間距",
"setting__desktop_lyric_lock": "鎖定歌詞視窗",
"setting__desktop_lyric_lock_screen": "不允許歌詞視窗拖出主螢幕之外",
"setting__desktop_lyric_pause_hide": "暫停時增加歌詞視窗透明度",
"setting__desktop_lyric_played_color": "已播放顏色",
"setting__desktop_lyric_reset": "重設",
"setting__desktop_lyric_reset_window": "重設視窗設定",
@@ -401,15 +407,17 @@
"setting__dislike_list_title": "「不喜歡的歌曲」規則清單",
"setting__download": "下載設定",
"setting__download_data_embed": "嵌入到音訊檔案中的內容",
"setting__download_embed_lxlyric": "同時嵌入 LX Music 歌詞(如果有,使用 LX Music 播放時可支持逐字歌詞)",
"setting__download_embed_lyric": "嵌入歌詞",
"setting__download_embed_pic": "嵌入封面",
"setting__download_embed_rlyric": "同時嵌入羅馬音歌詞(如果有)",
"setting__download_embed_tlyric": "同時嵌入翻譯歌詞(如果有)",
"setting__download_enable": "啟用下載功能",
"setting__download_lxlyric": "同時將 LX Music 歌詞寫入歌詞文件中(如果有,使用 LX Music 播放時可支持逐字歌詞)",
"setting__download_lyric": "歌詞下載",
"setting__download_lyric_format": "下載的歌詞檔案編碼格式",
"setting__download_lyric_format_tip": "在某些裝置上出現中文亂碼時可嘗試選取 GBK 格式",
"setting__download_lyric_format_gbk": "GBK",
"setting__download_lyric_format_tip": "在某些裝置上出現中文亂碼時可嘗試選取 GBK 格式",
"setting__download_lyric_format_utf8": "UTF-8",
"setting__download_lyric_title": "同時下載歌詞檔案",
"setting__download_max_num": "同時下載任務數",
@@ -447,6 +455,8 @@
"setting__hot_key_player_music_unlove": "取消收藏",
"setting__hot_key_player_next": "下一首歌曲",
"setting__hot_key_player_prev": "上一首歌曲",
"setting__hot_key_player_seekbackward": "快退 5s",
"setting__hot_key_player_seekforward": "快進 5s",
"setting__hot_key_player_toggle_play": "播放/暫停控制",
"setting__hot_key_player_volume_down": "減少音量",
"setting__hot_key_player_volume_mute": "靜音切換",
@@ -504,6 +514,8 @@
"setting__other_resource_cache_label": "軟體已使用快取大小:",
"setting__other_resource_cache_tip": "包括圖片、音訊等快取,清理後這些資源將需要重新下載,不建議清理,軟體會根據磁碟空間動態管理快取大小",
"setting__other_resource_cache_tip_confirm": "涉及圖片、音訊等快取,清理後這些資源將需要重新下載,不建議清理,軟體會根據磁碟空間動態管理快取大小,是否仍要清理?",
"setting__other_transparent_window": "主視窗使用軟體內建的圓角及陰影",
"setting__other_transparent_window_tip": "關閉後將使用系統原生視窗樣式。更改後重啟軟體生效。",
"setting__other_tray_theme": "系統匣圖示樣式",
"setting__other_tray_theme_auto": "跟隨系統亮暗模式",
"setting__other_tray_theme_black": "黑色",
@@ -540,17 +552,16 @@
"setting__play_power_save_blocker": "播放歌曲時阻止電腦休眠",
"setting__play_save_play_time": "記住播放進度",
"setting__play_startup_auto_play": "啟動軟體後自動播放音樂",
"setting__play_statusbar_lyric": "在狀態欄顯示歌詞(需要啟用系統匣)",
"setting__play_statusbar_lyric": "在選單列的「狀態」選單顯示歌詞",
"setting__play_statusbar_lyric_tip": "需要在「設定 → 基本設定」啟用「關閉視窗時不退出軟體將其最小化到系統匣」。",
"setting__play_task_bar": "在工具列上顯示目前歌曲播放進度",
"setting__play_timeout": "定時暫停",
"setting__player_audio_visualization_tip": "自訂音訊輸出裝置與音訊可視化功能衝突,啟用「音訊可視化」後音訊輸出裝置將會被重設為預設,目前此問題暫無法解決。是否仍要開啟?",
"setting__player_swap_lyric_trans_roma": "調換歌詞翻譯與歌詞羅馬音位置",
"setting__search": "搜尋設定",
"setting__search_focus_search_box": "啟動時自動聚焦搜尋框",
"setting__search_history": "顯示歷史搜尋記錄",
"setting__search_hot": "顯示熱門搜尋",
"setting__desktop_lyric_font_weight_extended": "翻譯、羅馬音歌詞",
"setting__desktop_lyric_font_weight_font": "逐字歌詞",
"setting__desktop_lyric_font_weight_line": "逐行歌詞",
"setting__sync": "資料同步",
"setting__sync_client_address": "目前裝置位址:{address}",
"setting__sync_client_host": "同步服務位址",
@@ -601,7 +612,7 @@
"songlist__import_input_tip": "輸入歌單連結或歌單 ID",
"songlist__import_input_tip_1": "不支援跨平台開啟歌單,請確認要開啟的歌單與目前歌單的來源平台是否對應",
"songlist__import_input_tip_2": "若遇到無法開啟的歌單連結,歡迎回報",
"songlist__import_input_tip_3": "不支援用歌單 ID 開啟酷狗音樂歌單,但支援用酷狗碼開啟",
"songlist__import_input_tip_3": "酷狗音樂歌單不支援用歌單 ID 與概念版連結開啟,但支援用普通版連結與酷狗碼開啟",
"songlist__import_input_tip_4": "網易雲音樂的「我喜歡」歌單需要 Token 才能開啟,詳情看 ",
"songlist__import_input_title": "開啟分享的歌單",
"songlist__open_list": "開啟「{name}」歌單",
+43 -13
View File
@@ -14,6 +14,8 @@ import { openDirInExplorer } from '@common/utils/electron'
export const initGlobalData = () => {
const envParams = parseEnvParams()
// envParams.cmdParams.dt = !!envParams.cmdParams.dt
global.envParams = {
cmdParams: envParams.cmdParams,
deeplink: envParams.deeplink,
@@ -62,7 +64,12 @@ export const initGlobalData = () => {
lyricLineText: '',
lyricLineAllText: '',
lyric: '',
tlyric: '',
rlyric: '',
lxlyric: '',
collect: false,
volume: 0,
mute: false,
},
}
@@ -80,16 +87,16 @@ export const initSingleInstanceHandle = () => {
}
app.on('second-instance', (event, argv, cwd) => {
for (const param of argv) {
if (URL_SCHEME_RXP.test(param)) {
global.envParams.deeplink = param
break
}
}
if (isExistMainWindow()) {
if (global.envParams.deeplink) global.lx.event_app.deeplink(global.envParams.deeplink)
else showMainWindow()
const envParams = parseEnvParams(argv)
if (envParams.deeplink) {
global.envParams.deeplink = envParams.deeplink
global.lx.event_app.deeplink(global.envParams.deeplink)
return
}
if (envParams.cmdParams.hidden !== true) {
showMainWindow()
}
} else {
app.quit()
}
@@ -228,6 +235,15 @@ export const listenerAppEvent = (startApp: () => void) => {
global.lx.theme.shouldUseDarkColors = shouldUseDarkColors
global.lx?.event_app.system_theme_change(shouldUseDarkColors)
})
global.lx.event_app.on('updated_config', (config, setting) => {
if (config.includes('player.volume')) {
global.lx.event_app.player_status({ volume: Math.trunc(setting['player.volume']! * 100) })
}
if (config.includes('player.isMute')) {
global.lx.event_app.player_status({ mute: setting['player.isMute'] })
}
})
}
const initTheme = () => {
@@ -254,6 +270,20 @@ const initTheme = () => {
})
}
const backupDB = (backupPath: string) => {
const dbPath = path.join(global.lxDataPath, 'lx.data.db')
try {
renameSync(dbPath, backupPath)
} catch {}
try {
renameSync(`${dbPath}-wal`, `${backupPath}-wal`)
} catch {}
try {
renameSync(`${dbPath}-shm`, `${backupPath}-shm`)
} catch {}
openDirInExplorer(backupPath)
}
let isInitialized = false
export const initAppSetting = async() => {
if (!global.lx.inited) {
@@ -266,19 +296,19 @@ export const initAppSetting = async() => {
if (!isInitialized) {
let dbFileExists = await global.lx.worker.dbService.init(global.lxDataPath)
if (dbFileExists === null) {
const backPath = path.join(global.lxDataPath, `lx.data.db.${Date.now()}.bak`)
const backupPath = path.join(global.lxDataPath, `lx.data.db.${Date.now()}.bak`)
dialog.showMessageBoxSync({
type: 'warning',
message: 'Database verify failed',
detail: `数据库表结构校验失败,我们将把有问题的数据库备份到:${backPath}\n若此问题导致你的数据丢失,你可以尝试从备份文件找回它们。\n\nThe database table structure verification failed, we will back up the problematic database to: ${backPath}\nIf this problem causes your data to be lost, you can try to retrieve them from the backup file.`,
detail: `数据库表结构校验失败,我们将把有问题的数据库备份到:${backupPath}\n若此问题导致你的数据丢失,你可以尝试从备份文件找回它们。\n\nThe database table structure verification failed, we will back up the problematic database to: ${backupPath}\nIf this problem causes your data to be lost, you can try to retrieve them from the backup file.`,
})
renameSync(path.join(global.lxDataPath, 'lx.data.db'), backPath)
openDirInExplorer(backPath)
backupDB(backupPath)
dbFileExists = await global.lx.worker.dbService.init(global.lxDataPath)
}
global.lx.appSetting = (await initSetting()).setting
if (!dbFileExists) await migrateDBData().catch(err => { log.error(err) })
initTheme()
if (envParams.cmdParams.dt == null) envParams.cmdParams.dt = !global.lx.appSetting['common.transparentWindow']
}
// global.lx.theme = getTheme()
+44
View File
@@ -52,6 +52,15 @@ const handleSendStatus = (res: http.ServerResponse<http.IncomingMessage>, query?
for (const k of keys) resp[k] = global.lx.player_status[k]
sendResponse(res, 200, resp, 'application/json; charset=utf-8')
}
const handleSendAllLyric = (res: http.ServerResponse<http.IncomingMessage>) => {
const resp: Partial<Record<SubscribeKeys, any>> = {
lyric: global.lx.player_status.lyric,
tlyric: global.lx.player_status.tlyric,
rlyric: global.lx.player_status.rlyric,
lxlyric: global.lx.player_status.lxlyric,
}
sendResponse(res, 200, resp, 'application/json; charset=utf-8')
}
const handleSubscribePlayerStatus = (req: http.IncomingMessage, res: http.ServerResponse<http.IncomingMessage>, query?: string) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
@@ -130,6 +139,9 @@ const handleStartServer = async(port: number, ip: string) => new Promise<void>((
case '/lyric':
msg = global.lx.player_status.lyric
break
case '/lyric-all':
handleSendAllLyric(res)
return
case '/play':
sendTaskbarButtonClick('play')
break
@@ -142,12 +154,44 @@ const handleStartServer = async(port: number, ip: string) => new Promise<void>((
case '/skip-prev':
sendTaskbarButtonClick('prev')
break
case '/seek': {
const offset = parseFloat(querystring.parse(query ?? '').offset as string)
if (Number.isNaN(offset) || offset < 0 || offset > global.lx.player_status.duration) {
code = 400
msg = 'Invalid offset'
} else {
sendTaskbarButtonClick('seek', parseFloat(offset.toFixed(3)))
}
break
}
case '/collect':
sendTaskbarButtonClick('collect')
break
case '/uncollect':
sendTaskbarButtonClick('unCollect')
break
case '/volume': {
const volume = parseInt(querystring.parse(query ?? '').volume as string)
if (Number.isNaN(volume) || volume < 0 || volume > 100) {
code = 400
msg = 'Invalid volume'
} else {
sendTaskbarButtonClick('volume', volume / 100)
}
break
}
case '/mute': {
const mute = querystring.parse(query ?? '').mute
if (mute == 'true') {
sendTaskbarButtonClick('mute', true)
} else if (mute == 'false') {
sendTaskbarButtonClick('mute', false)
} else {
code = 400
msg = 'Invalid mute value'
}
break
}
case '/subscribe-player-status':
try {
handleSubscribePlayerStatus(req, res, query)
+1
View File
@@ -77,6 +77,7 @@ export const createWindow = async(userApi: LX.UserApi.UserApiInfo) => {
minimizable: false,
maximizable: false,
fullscreenable: false,
roundedCorners: false,
hasShadow: false,
show: false,
webPreferences: {
+11 -4
View File
@@ -1,7 +1,7 @@
import path from 'node:path'
import { BrowserWindow } from 'electron'
import { debounce, getPlatform, isLinux, isWin } from '@common/utils'
import { initWindowSize } from './utils'
import { initWindowSize, minHeight, minWidth } from './utils'
import { mainSend } from '@common/mainIpc'
import { encodePath } from '@common/utils/electron'
@@ -115,8 +115,8 @@ export const createWindow = () => {
width: winSize.width,
x: winSize.x,
y: winSize.y,
minWidth: 380,
minHeight: 80,
minWidth,
minHeight,
useContentSize: true,
frame: false,
transparent: true,
@@ -127,6 +127,7 @@ export const createWindow = () => {
minimizable: false,
maximizable: false,
fullscreenable: false,
roundedCorners: false,
show: false,
alwaysOnTop: isAlwaysOnTop,
skipTaskbar: !isShowTaskbar,
@@ -138,6 +139,7 @@ export const createWindow = () => {
enableWebSQL: false,
webgl: false,
spellcheck: false, // 禁用拼写检查器
backgroundThrottling: false,
},
})
@@ -160,6 +162,11 @@ export const showWindow = () => {
browserWindow.show()
}
export const setResizeable = (isResizeable: boolean) => {
if (!browserWindow) return
browserWindow.setResizable(isResizeable)
}
export const sendEvent = <T = any>(name: string, params?: T) => {
if (!browserWindow) return
mainSend(browserWindow, name, params)
@@ -219,7 +226,7 @@ export const alwaysOnTopTools: AlwaysOnTopTools = {
return
}
setAlwaysOnTop(true, 'screen-saver')
}, 1000)
}, 500)
},
clearLoop() {
if (!this.timeout) return
+6 -2
View File
@@ -3,7 +3,7 @@ import { mainOn, mainHandle } from '@common/mainIpc'
import { WIN_LYRIC_RENDERER_EVENT_NAME } from '@common/ipcNames'
import { buildLyricConfig, getLyricWindowBounds } from './utils'
import { sendNewDesktopLyricClient } from '@main/modules/winMain'
import { getBounds, getMainFrame, sendEvent, setBounds } from './main'
import { getBounds, getMainFrame, sendEvent, setBounds, setResizeable } from './main'
import { MessageChannelMain } from 'electron'
@@ -29,6 +29,10 @@ export default () => {
setBounds(getLyricWindowBounds(getBounds(), options))
})
mainOn<boolean>(WIN_LYRIC_RENDERER_EVENT_NAME.set_win_resizeable, ({ params: resizable }) => {
setResizeable(resizable)
})
mainOn(WIN_LYRIC_RENDERER_EVENT_NAME.request_main_window_channel, ({ event }) => {
if (event.senderFrame !== getMainFrame()) return
// Create a new channel ...
@@ -36,7 +40,7 @@ export default () => {
// ... send one end to the worker ...
sendNewDesktopLyricClient(port1)
// ... and the other end to the main window.
event.senderFrame.postMessage(WIN_LYRIC_RENDERER_EVENT_NAME.provide_main_window_channel, null, [port2])
event.senderFrame?.postMessage(WIN_LYRIC_RENDERER_EVENT_NAME.provide_main_window_channel, null, [port2])
// Now the main window and the worker can communicate with each other
// without going through the main process!
console.log('request_main_window_channel')
+6 -4
View File
@@ -1,6 +1,6 @@
// 设置窗口位置、大小
export let minWidth = 80
export let minHeight = 50
export let minWidth = 38
export let minHeight = 38
// const updateBounds = (bounds: Bounds) => {
@@ -14,7 +14,7 @@ export let minHeight = 50
* @param param 新设置(相对于当前设置)
* @returns
*/
export const getLyricWindowBounds = (bounds: Electron.Rectangle, { x = 0, y = 0, w = 0, h = 0 }: LX.DesktopLyric.NewBounds): Electron.Rectangle => {
export const getLyricWindowBounds = (bounds: Electron.Rectangle, { x, y, w, h }: LX.DesktopLyric.NewBounds): Electron.Rectangle => {
if (w < minWidth) w = minWidth
if (h < minHeight) h = minHeight
@@ -53,6 +53,7 @@ export const watchConfigKeys = [
'desktopLyric.isAlwaysOnTop',
'desktopLyric.isAlwaysOnTopLoop',
'desktopLyric.isShowTaskbar',
'desktopLyric.pauseHide',
'desktopLyric.audioVisualization',
'desktopLyric.width',
'desktopLyric.height',
@@ -80,9 +81,10 @@ export const watchConfigKeys = [
'common.langId',
'player.isShowLyricTranslation',
'player.isShowLyricRoma',
'player.isSwapLyricTranslationAndRoma',
'player.isPlayLxlrc',
'player.playbackRate',
] as const
] satisfies Array<keyof LX.AppSetting>
export const buildLyricConfig = (appSetting: Partial<LX.AppSetting>): Partial<LX.DesktopLyric.Config> => {
const setting: Partial<LX.DesktopLyric.Config> = {}
+20 -18
View File
@@ -42,8 +42,10 @@ const winEvent = () => {
})
browserWindow.once('ready-to-show', () => {
showWindow()
setThumbarButtons()
if (!global.envParams.cmdParams.hidden) {
showWindow()
setThumbarButtons()
}
global.lx.event_app.main_window_ready_to_show()
})
@@ -66,11 +68,7 @@ export const createWindow = () => {
const { shouldUseDarkColors, theme } = global.lx.theme
const ses = session.fromPartition('persist:win-main')
const proxy = getProxy()
if (proxy) {
void ses.setProxy({
proxyRules: `http://${proxy.host}:${proxy.port}`,
})
}
setSesProxy(ses, proxy?.host, proxy?.port)
/**
* Initial window options
@@ -87,7 +85,7 @@ export const createWindow = () => {
resizable: false,
maximizable: false,
fullscreenable: true,
roundedCorners: false,
roundedCorners: global.envParams.cmdParams.dt,
show: false,
webPreferences: {
session: ses,
@@ -109,7 +107,7 @@ export const createWindow = () => {
browserWindow = new BrowserWindow(options)
const winURL = process.env.NODE_ENV !== 'production' ? 'http://localhost:9080' : `file://${path.join(encodePath(__dirname), 'index.html')}`
void browserWindow.loadURL(winURL + `?os=${getPlatform()}&dt=${!!global.envParams.cmdParams.dt}&dark=${shouldUseDarkColors}&theme=${encodeURIComponent(JSON.stringify(theme))}`)
void browserWindow.loadURL(winURL + `?os=${getPlatform()}&dt=${global.envParams.cmdParams.dt}&dark=${shouldUseDarkColors}&theme=${encodeURIComponent(JSON.stringify(theme))}`)
winEvent()
@@ -131,18 +129,22 @@ export const closeWindow = () => {
browserWindow.close()
}
const setSesProxy = (ses: Electron.Session, host?: string, port?: string | number) => {
if (host) {
void ses.setProxy({
mode: 'fixed_servers',
proxyRules: `http://${host}:${port}`,
})
} else {
void ses.setProxy({
mode: 'direct',
})
}
}
export const setProxy = () => {
if (!browserWindow) return
const proxy = getProxy()
if (proxy) {
void browserWindow.webContents.session.setProxy({
proxyRules: `http://${proxy.host}:${proxy.port}`,
})
} else {
void browserWindow.webContents.session.setProxy({
proxyRules: '',
})
}
setSesProxy(browserWindow.webContents.session, proxy?.host, proxy?.port)
}
@@ -137,8 +137,8 @@ export const sendFocus = () => {
sendEvent(WIN_MAIN_RENDERER_EVENT_NAME.focus)
}
export const sendTaskbarButtonClick = (action: LX.Player.StatusButtonActions) => {
sendEvent(WIN_MAIN_RENDERER_EVENT_NAME.player_action_on_button_click, action)
export const sendTaskbarButtonClick = (action: LX.Player.StatusButtonActions, data?: unknown) => {
sendEvent(WIN_MAIN_RENDERER_EVENT_NAME.player_action_on_button_click, { action, data })
}
export const sendConfigChange = (setting: Partial<LX.AppSetting>) => {
sendEvent(WIN_MAIN_RENDERER_EVENT_NAME.on_config_change, setting)
+8 -2
View File
@@ -9,11 +9,11 @@ import { nativeTheme, powerSaveBlocker } from 'electron'
import { joinPath } from '@common/utils/nodejs'
import themes from '@common/theme/index.json'
export const parseEnvParams = (): { cmdParams: LX.CmdParams, deeplink: string | null } => {
export const parseEnvParams = (argv = process.argv): { cmdParams: LX.CmdParams, deeplink: string | null } => {
const cmdParams: LX.CmdParams = {}
let deeplink = null
const rx = /^-\w+/
for (let param of process.argv) {
for (let param of argv) {
if (URL_SCHEME_RXP.test(param)) {
deeplink = param
}
@@ -107,6 +107,11 @@ export const mergeSetting = (originSetting: LX.AppSetting, targetSetting?: Parti
}
}
const applyInitSetting = (setting: LX.AppSetting) => {
if (global.envParams.cmdParams.hidden && !setting['tray.enable']) {
setting['tray.enable'] = true
}
}
export const updateSetting = (setting?: Partial<LX.AppSetting>, isInit: boolean = false) => {
const electronStore_config = getStore(STORE_NAMES.APP_SETTINGS)
@@ -114,6 +119,7 @@ export const updateSetting = (setting?: Partial<LX.AppSetting>, isInit: boolean
let originSetting: LX.AppSetting
if (isInit) {
setting &&= migrateSetting(setting)
applyInitSetting(setting as LX.AppSetting)
originSetting = { ...defaultSetting }
} else originSetting = global.lx.appSetting
+1
View File
@@ -36,6 +36,7 @@ export const init = (lxDataPath: string): boolean | null => {
initTables(db)
dbFileExists = false
}
db.pragma('journal_mode = WAL')
if (dbFileExists) migrateData(db)
+6 -1
View File
@@ -1,5 +1,5 @@
<template>
<div id="container" :class="[{ lock: setting['desktopLyric.isLock'] }, { hide: isHoverHide && isMouseEnter }]">
<div id="container" :class="[{ lock: setting['desktopLyric.isLock'] }, { hide: isHide || (isHoverHide && isMouseEnter) }]">
<div id="main" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" @mousemove="handleMouseMoveMain">
<transition enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut">
<div v-show="!setting['desktopLyric.isLock']" class="control-bar">
@@ -36,6 +36,7 @@ import useCommon from '@lyric/useApp/useCommon'
import useLyric from '@lyric/useApp/useLyric'
import useTheme from '@lyric/useApp/useTheme'
import { init as initLyricPlayer } from '@lyric/core/lyric'
import usePauseHide from '@lyric/useApp/usePauseHide'
const isShowResize = window.os != 'windows'
useCommon()
@@ -43,6 +44,7 @@ const { handleMouseDown, handleTouchDown } = useWindowSize()
const { handleMouseMoveMain, isHoverHide, isMouseEnter } = useHoverHide()
useLyric()
useTheme()
const isHide = usePauseHide()
onMounted(() => {
@@ -85,6 +87,9 @@ body {
}
&.hide {
opacity: .05;
&:hover {
opacity: 1;
}
}
}
+1 -1
View File
@@ -20,7 +20,7 @@ html {
}
.auto-hidden {
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
.center {
@@ -1,7 +1,7 @@
<template>
<div :class="$style.container">
<transition enter-active-class="animated-fast fadeIn" leave-active-class="animated fadeOut">
<div v-show="!isShowThemeList" :class="$style.btns">
<div v-show="!isShowThemeList" :class="$style.btns" @mousedown="handleLyricMouseDown" @touchstart="handleLyricTouchStart">
<button :class="$style.btn" :title="$t('desktop_lyric__close')" @click="handleClose">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="20px" viewBox="0 0 24 24" space="preserve">
<use xlink:href="#icon-close" />
@@ -60,10 +60,12 @@
import { ref } from '@common/utils/vueTools'
import { setting } from '@lyric/store/state'
import { updateSetting } from '@lyric/store/action'
import useDrag from './useDrag'
export default {
setup() {
const isShowThemeList = ref(false)
const { handleLyricMouseDown, handleLyricTouchStart } = useDrag()
const handleClose = () => {
updateSetting({ 'desktopLyric.enable': false })
@@ -113,6 +115,8 @@ export default {
handleZoomLrc,
handleFontChange,
handleOpactiyChange,
handleLyricMouseDown,
handleLyricTouchStart,
}
},
}
@@ -2,7 +2,8 @@ import { ref, onMounted, onBeforeUnmount, watch, nextTick } from '@common/utils/
import { scrollTo } from '@common/utils/renderer'
import { lyric } from '@lyric/store/lyric'
import { isPlay, setting } from '@lyric/store/state'
import { setWindowBounds } from '@lyric/utils/ipc'
import { setWindowBounds, setWindowResizeable } from '@lyric/utils/ipc'
import { isWin } from '@common/utils'
const getOffsetTop = (contentHeight, lineHeight) => {
switch (setting['desktopLyric.scrollAlign']) {
@@ -21,6 +22,8 @@ export default (isComputeHeight) => {
isMsDown: false,
msDownX: 0,
msDownY: 0,
windowW: 0,
windowH: 0,
}
let msDownY = 0
@@ -82,6 +85,10 @@ export default (isComputeHeight) => {
winEvent.isMsDown = true
winEvent.msDownX = x
winEvent.msDownY = y
winEvent.windowW = window.innerWidth
winEvent.windowH = window.innerHeight
// https://github.com/lyswhut/lx-music-desktop/issues/2244
if (isWin) setWindowResizeable(false)
}
}
const handleLyricMouseDown = event => {
@@ -96,6 +103,7 @@ export default (isComputeHeight) => {
const handleMouseMsUp = () => {
isMsDown.value = false
winEvent.isMsDown = false
if (isWin) setWindowResizeable(true)
}
const handleMove = (x, y) => {
@@ -108,12 +116,22 @@ export default (isComputeHeight) => {
dom_lyric.value.scrollTop = msDownScrollY + msDownY - y
startLyricScrollTimeout()
} else if (winEvent.isMsDown) {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: window.innerWidth,
h: window.innerHeight,
})
// https://github.com/lyswhut/lx-music-desktop/issues/2244
if (isWin) {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: winEvent.windowW,
h: winEvent.windowH,
})
} else {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: window.innerWidth,
h: window.innerHeight,
})
}
}
}
const handleMouseMsMove = event => {
@@ -2,7 +2,8 @@ import { ref, onMounted, onBeforeUnmount, watch, nextTick } from '@common/utils/
import { scrollXRTo } from '@common/utils/renderer'
import { lyric } from '@lyric/store/lyric'
import { isPlay, setting } from '@lyric/store/state'
import { setWindowBounds } from '@lyric/utils/ipc'
import { setWindowBounds, setWindowResizeable } from '@lyric/utils/ipc'
import { isWin } from '@common/utils'
const getOffsetTop = (contentWidth, lineWidth) => {
switch (setting['desktopLyric.scrollAlign']) {
@@ -21,6 +22,8 @@ export default (isComputeWidth) => {
isMsDown: false,
msDownX: 0,
msDownY: 0,
windowW: 0,
windowH: 0,
}
let msDownX = 0
@@ -82,6 +85,10 @@ export default (isComputeWidth) => {
winEvent.isMsDown = true
winEvent.msDownX = x
winEvent.msDownY = y
winEvent.windowW = window.innerWidth
winEvent.windowH = window.innerHeight
// https://github.com/lyswhut/lx-music-desktop/issues/2244
if (isWin) setWindowResizeable(false)
}
}
const handleLyricMouseDown = event => {
@@ -96,6 +103,7 @@ export default (isComputeWidth) => {
const handleMouseMsUp = () => {
isMsDown.value = false
winEvent.isMsDown = false
if (isWin) setWindowResizeable(true)
}
const handleMove = (x, y) => {
@@ -108,12 +116,22 @@ export default (isComputeWidth) => {
dom_lyric.value.scrollLeft = msDownScrollX + msDownX - x
startLyricScrollTimeout()
} else if (winEvent.isMsDown) {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: window.innerWidth,
h: window.innerHeight,
})
// https://github.com/lyswhut/lx-music-desktop/issues/2244
if (isWin) {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: winEvent.windowW,
h: winEvent.windowH,
})
} else {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: window.innerWidth,
h: window.innerHeight,
})
}
}
}
const handleMouseMsMove = event => {
@@ -0,0 +1,87 @@
import { onMounted, onBeforeUnmount } from '@common/utils/vueTools'
import { setWindowBounds, setWindowResizeable } from '@lyric/utils/ipc'
import { isWin } from '@common/utils'
export default () => {
const winEvent = {
isMsDown: false,
msDownX: 0,
msDownY: 0,
windowW: 0,
windowH: 0,
}
const handleLyricDown = (target, x, y) => {
winEvent.isMsDown = true
winEvent.msDownX = x
winEvent.msDownY = y
winEvent.windowW = window.innerWidth
winEvent.windowH = window.innerHeight
// https://github.com/lyswhut/lx-music-desktop/issues/2244
if (isWin) setWindowResizeable(false)
}
const handleLyricMouseDown = event => {
console.log(event.target, event.currentTarget)
if (event.target !== event.currentTarget) return
handleLyricDown(event.target, event.clientX, event.clientY)
}
const handleLyricTouchStart = event => {
if (event.changedTouches.length) {
const touch = event.changedTouches[0]
if (touch.target !== touch.currentTarget) return
handleLyricDown(event.target, touch.clientX, touch.clientY)
}
}
const handleMouseMsUp = () => {
winEvent.isMsDown = false
if (isWin) setWindowResizeable(true)
}
const handleMove = (x, y) => {
if (!winEvent.isMsDown) return
// https://github.com/lyswhut/lx-music-desktop/issues/2244
if (isWin) {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: winEvent.windowW,
h: winEvent.windowH,
})
} else {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: window.innerWidth,
h: window.innerHeight,
})
}
}
const handleMouseMsMove = event => {
handleMove(event.clientX, event.clientY)
}
const handleTouchMove = (e) => {
if (e.changedTouches.length) {
const touch = e.changedTouches[0]
handleMove(touch.clientX, touch.clientY)
}
}
onMounted(() => {
document.addEventListener('mousemove', handleMouseMsMove)
document.addEventListener('mouseup', handleMouseMsUp)
document.addEventListener('touchmove', handleTouchMove)
document.addEventListener('touchend', handleMouseMsUp)
})
onBeforeUnmount(() => {
document.removeEventListener('mousemove', handleMouseMsMove)
document.removeEventListener('mouseup', handleMouseMsUp)
document.removeEventListener('touchmove', handleTouchMove)
document.removeEventListener('touchend', handleMouseMsUp)
})
return {
handleLyricMouseDown,
handleLyricTouchStart,
}
}
+2 -1
View File
@@ -41,8 +41,9 @@ export const setPlaybackRate = (rate: number) => {
export const setLyric = () => {
if (!musicInfo.id) return
const extendedLyrics = []
if (setting['player.isShowLyricTranslation'] && lyrics.tlyric) extendedLyrics.push(lyrics.tlyric)
if (setting['player.isShowLyricRoma'] && lyrics.rlyric) extendedLyrics.push(lyrics.rlyric)
if (setting['player.isShowLyricTranslation'] && lyrics.tlyric) extendedLyrics.push(lyrics.tlyric)
if (setting['player.isSwapLyricTranslationAndRoma']) extendedLyrics.reverse()
lrc.setLyric(
setting['player.isPlayLxlrc'] && lyrics.lxlyric ? lyrics.lxlyric : lyrics.lyric,
extendedLyrics,
+1 -1
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>桌面歌词-洛雪音乐助手</title>
<title>Lyric - LX Music</title>
</head>
<body id="body" style="background-color: transparent;">
<div id="root"></div>
+2
View File
@@ -6,6 +6,7 @@ export const setting = shallowReactive<LX.DesktopLyric.Config>({
'desktopLyric.isAlwaysOnTop': false,
'desktopLyric.isAlwaysOnTopLoop': false,
'desktopLyric.isShowTaskbar': true,
'desktopLyric.pauseHide': false,
'desktopLyric.audioVisualization': false,
'desktopLyric.width': 450,
'desktopLyric.height': 300,
@@ -33,6 +34,7 @@ export const setting = shallowReactive<LX.DesktopLyric.Config>({
'common.langId': 'zh-cn',
'player.isShowLyricTranslation': false,
'player.isShowLyricRoma': false,
'player.isSwapLyricTranslationAndRoma': false,
'player.isPlayLxlrc': false,
'player.playbackRate': 1,
})
+1
View File
@@ -6,6 +6,7 @@ import { isPlay, setting } from '@lyric/store/state'
export default () => {
watch(() => setting['player.isShowLyricTranslation'], setLyric)
watch(() => setting['player.isShowLyricRoma'], setLyric)
watch(() => setting['player.isSwapLyricTranslationAndRoma'], setLyric)
watch(() => setting['player.isPlayLxlrc'], setLyric)
watch(() => setting['player.playbackRate'], (rate) => {
setPlaybackRate(rate)
+41
View File
@@ -0,0 +1,41 @@
import { ref, watch } from '@common/utils/vueTools'
import { isPlay, setting } from '@lyric/store/state'
export default () => {
let unWatch: (() => void) | null = null
let isHide = ref(false)
let timeout: NodeJS.Timeout | null = null
const clearIntv = () => {
if (!timeout) return
clearTimeout(timeout)
timeout = null
}
watch(() => setting['desktopLyric.pauseHide'], (enable) => {
if (enable) {
unWatch = watch(isPlay, (isPlay) => {
clearIntv()
if (isPlay) {
isHide.value &&= false
} else {
timeout = setTimeout(() => {
timeout = null
isHide.value = true
}, 200)
}
}, {
immediate: true,
})
} else {
clearIntv()
isHide.value &&= false
if (unWatch) {
unWatch()
unWatch = null
}
}
}, {
immediate: true,
})
return isHide
}
+7
View File
@@ -18,6 +18,13 @@ export const onSettingChanged = (listener: LX.IpcRendererEventListenerParams<Par
export const setWindowBounds = (bounds: LX.DesktopLyric.NewBounds) => {
rendererSend<LX.DesktopLyric.NewBounds>(WIN_LYRIC_RENDERER_EVENT_NAME.set_win_bounds, bounds)
}
let previousResizable: boolean | null = null
export const setWindowResizeable = (resizable: boolean) => {
if (previousResizable === resizable) return
previousResizable = resizable
// https://github.com/electron/electron/issues/48352
// rendererSend<boolean>(WIN_LYRIC_RENDERER_EVENT_NAME.set_win_resizeable, resizable)
}
export const sendConnectMainWindowEvent = () => {
rendererSend(WIN_LYRIC_RENDERER_EVENT_NAME.request_main_window_channel)
+7 -7
View File
@@ -311,7 +311,7 @@ html {
}
.auto-hidden {
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
.center {
@@ -455,8 +455,8 @@ input, textarea {
flex: none;
.num {
.nobreak;
.center;
.nobreak();
.center();
color: var(--color-font-label);
}
// box-shadow: 0 0 2px var(--color-primary-dark-500-alpha-800);
@@ -521,15 +521,15 @@ table {
line-height: 16px;
vertical-align: middle;
box-sizing: border-box;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
&.auto {
flex: auto;
}
&.num, .num {
.nobreak;
.center;
.nobreak();
.center();
padding-left: 3px;
padding-right: 3px;
font-size: 11px;
@@ -545,7 +545,7 @@ table {
align-items: center;
>.name {
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
}
.badge {
+1 -1
View File
@@ -109,7 +109,7 @@ export default {
transition: @transition-normal;
transition-property: background-color, opacity;
box-sizing: border-box;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
// background-color: var(--color-primary-light-600-alpha-800);
&:hover {
+4 -1
View File
@@ -259,7 +259,10 @@ export default {
})
onMounted(() => {
dom_scrollContainer.value.addEventListener('scroll', onScroll, false)
dom_scrollContainer.value.addEventListener('scroll', onScroll, {
capture: false,
passive: true,
})
cachedList = Array(props.list.length)
startIndex = -1
endIndex = -1
+3 -3
View File
@@ -120,7 +120,7 @@ export default {
display: inline-block;
font-size: 12px;
position: relative;
width: 300px;
width: var(--selection-width, 300px);
&.active {
.label {
@@ -153,7 +153,7 @@ export default {
span {
flex: auto;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
.icon {
flex: none;
@@ -200,7 +200,7 @@ export default {
transition: background-color @transition-normal;
background-color: transparent;
box-sizing: border-box;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
&:hover {
background-color: var(--color-button-background-hover);
+34 -12
View File
@@ -29,6 +29,10 @@ export default {
type: Number,
required: true,
},
step: {
type: Number,
default: 1,
},
disabled: {
type: Boolean,
default: false,
@@ -39,33 +43,51 @@ export default {
const sliderEvent = {
isMsDown: false,
msDownX: 0,
msDownValue: 0,
msDownRatio: 0,
}
const dom_sliderBar = ref(null)
const clampValue = val => {
if (val < props.min) return props.min
if (val > props.max) return props.max
return val
}
const getSteppedValue = val => {
const step = props.step > 0 ? props.step : 1
const stepped = Math.round((val - props.min) / step) * step + props.min
return clampValue(Number(stepped.toFixed(10)))
}
const getSliderWidth = () => dom_sliderBar.value?.clientWidth || 0
const getRange = () => props.max - props.min
const emitSteppedValue = rawValue => {
const value = getSteppedValue(rawValue)
emit('change', value)
return value
}
const handleSliderMsDown = event => {
if (props.disabled) return
const width = getSliderWidth()
if (!width) return
sliderEvent.isMsDown = true
sliderEvent.msDownX = event.clientX
sliderEvent.msDownValue = event.offsetX / dom_sliderBar.value.clientWidth
let val = sliderEvent.msDownValue * (props.max - props.min) + props.min
if (val < props.min) val = props.min
if (val > props.max) val = props.max
emit('change', val)
// if (isMute.value) window.app_event.setSliderIsMute(false)
const rawValue = (event.offsetX / width) * getRange() + props.min
const value = emitSteppedValue(rawValue)
sliderEvent.msDownRatio = getRange() === 0 ? 0 : (value - props.min) / getRange()
}
const handleSliderMsUp = () => {
sliderEvent.isMsDown = false
}
const handleSliderMsMove = event => {
if (!sliderEvent.isMsDown || props.disabled) return
let value = (sliderEvent.msDownValue + (event.clientX - sliderEvent.msDownX) / dom_sliderBar.value.clientWidth) * (props.max - props.min) + props.min
if (value > props.max) value = props.max
else if (value < props.min) value = props.min
emit('change', value)
const width = getSliderWidth()
if (!width) return
const ratio = sliderEvent.msDownRatio + (event.clientX - sliderEvent.msDownX) / width
const rawValue = ratio * getRange() + props.min
emitSteppedValue(rawValue)
}
document.addEventListener('mousemove', handleSliderMsMove)
+1 -1
View File
@@ -103,7 +103,7 @@ export default {
position: relative;
padding: 8px 0;
&:after {
.mixin-after;
.mixin-after();
left: 0;
bottom: 0;
width: 100%;
@@ -270,9 +270,15 @@ export default {
cachedList = Array(list.length)
startIndex = -1
endIndex = -1
void nextTick(() => {
updateView()
})
if (cachedList.length) {
void nextTick(() => {
requestAnimationFrame(() => {
updateView()
})
})
} else {
views.value = []
}
}
watch(() => props.itemHeight, () => {
handleReset(props.list)
@@ -282,11 +288,22 @@ export default {
})
onMounted(() => {
dom_scrollContainer.value.addEventListener('scroll', onScroll, false)
dom_scrollContainer.value.addEventListener('scroll', onScroll, {
capture: false,
passive: true,
})
cachedList = Array(props.list.length)
startIndex = -1
endIndex = -1
updateView()
if (props.list.length) {
void nextTick(() => {
requestAnimationFrame(() => {
console.log('updateView')
updateView()
})
})
}
window.addEventListener('resize', handleResize)
})
onBeforeUnmount(() => {
@@ -229,7 +229,7 @@ export default {
padding: 0 10px !important;
width: calc(@item-width - 15px);
min-width: 160px;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
.newList {
@@ -186,7 +186,7 @@ export default {
padding: 0 10px !important;
width: calc(@item-width - 15px);
min-width: 160px;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
.newList {
@@ -64,7 +64,7 @@ const handleUpdateSpeed = (value) => {
flex-flow: column nowrap;
gap: 8px;
&:before {
.mixin-after;
.mixin-after();
position: absolute;
top: 0;
height: 1px;
@@ -107,7 +107,7 @@ onMounted(() => {
position: relative;
&:before {
.mixin-after;
.mixin-after();
position: absolute;
left: 50%;
height: 100%;
@@ -83,7 +83,7 @@ const handleUpdatePlaybackRate = (value) => {
min-height: 0;
flex: none;
&:before {
.mixin-after;
.mixin-after();
position: absolute;
top: 0;
height: 1px;
@@ -114,7 +114,7 @@ watch(visible, (visible) => {
min-height: 0;
&:before {
.mixin-after;
.mixin-after();
position: absolute;
left: 50%;
height: 100%;
+1 -1
View File
@@ -16,7 +16,7 @@
@update:model-value="saveVolumeIsMute($event)"
/>
</div>
<base-slider-bar :class="$style.slider" :value="volume" :min="0" :max="1" @change="handleUpdateVolume" />
<base-slider-bar :class="$style.slider" :value="volume" :min="0" :max="1" :step="0.01" @change="handleUpdateVolume" />
</div>
</template>
</material-popup-btn>
@@ -119,7 +119,7 @@ export default {
// transition: @transition-normal;
// transition-property: color;
// color: @color-theme-font-label;
// .mixin-ellipsis-1;
// .mixin-ellipsis-1();
// }
}
.navItem {
@@ -161,9 +161,9 @@ export default {
justify-content: center;
// border-radius: @radius-border;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
&:before {
.mixin-after;
.mixin-after();
left: 0;
top: 0;
width: 3px;
+2 -2
View File
@@ -8,8 +8,8 @@
<p>词语约定:本协议中的“本项目”指 LX Music(洛雪音乐助手)桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本项目内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。</p><br>
<p><strong>一、数据来源</strong></p><br>
<p>1.1&nbsp;本项目的各官方平台在线数据来源原理是从其公开服务器中拉取数据(与未登录状态在官方平台 APP 获取的数据相同),经过对数据简单地筛选与合并后进行展示,因此本项目不对数据的合法性、准确性负责。</p><br>
<p>1.2&nbsp;本项目本身没有获取某个音频数据的能力,本项目使用的在线音频数据来源来自软件设置内“音乐来源”设置所选择的“源”返回的在线链接。例如播放某首歌,本项目所做的只是将希望播放的歌曲名字、歌手名字等信息传递给“源”,若“源”返回了一个链接,则本项目将认为这就是该歌曲的音频数据而进行使用,至于这是不是正确的音频数据本项目无法校验其准确性,所以使用本项目的过程中可能会出现希望播放的音频与实际播放的音频不对应或者无法播放的问题。</p><br>
<p>1.3&nbsp;本项目的非官方平台数据(例如我的收藏列表)来自使用者本地系统或者使用者连接的同步服务,本项目不对这些数据的合法性、准确性负责。</p><br>
<p>1.2&nbsp;本项目本身没有获取某个音频数据的能力,本项目使用的在线音频数据来源来自软件设置内“自定义源”设置所选择的“源”返回的在线链接。例如播放某首歌,本项目所做的只是将希望播放的歌曲名、艺术家等信息传递给“源”,若“源”返回了一个链接,则本项目将认为这就是该歌曲的音频数据而进行使用,至于这是不是正确的音频数据本项目无法校验其准确性,所以使用本项目的过程中可能会出现希望播放的音频与实际播放的音频不对应或者无法播放的问题。</p><br>
<p>1.3&nbsp;本项目的非官方平台数据(例如“我的列表”内列表)来自使用者本地系统或者使用者连接的同步服务,本项目不对这些数据的合法性、准确性负责。</p><br>
<p><strong>二、版权数据</strong></p><br>
<p>2.1&nbsp;使用本项目的过程中可能会产生版权数据。对于这些版权数据,本项目不拥有它们的所有权。为了避免侵权,使用者务必在&nbsp;<strong>24&nbsp;小时内</strong>&nbsp;清除使用本项目的过程中所产生的版权数据。</p><br>
<p><strong>三、音乐平台别名</strong></p><br>
@@ -164,7 +164,7 @@ export default {
}
&:before {
.mixin-after;
.mixin-after();
left: 0;
top: 0;
width: 100%;
@@ -257,12 +257,12 @@ export default {
max-width: 100%;
font-size: 12px;
color: var(--color-font-label);
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
.status {
padding-top: 3px;
height: 23px;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
max-width: 100%;
}
@@ -164,7 +164,7 @@ export default {
}
&:before {
.mixin-after;
.mixin-after();
left: 0;
top: 0;
width: 100%;
@@ -245,12 +245,12 @@ export default {
max-width: 100%;
font-size: 12px;
color: var(--color-font-label);
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
.status {
padding-top: 3px;
height: 23px;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
max-width: 100%;
}
@@ -166,7 +166,7 @@ export default {
}
&:before {
.mixin-after;
.mixin-after();
left: 0;
top: 0;
width: 100%;
@@ -247,12 +247,12 @@ export default {
max-width: 100%;
font-size: 12px;
color: var(--color-font-label);
.mixin-ellipsis-1;
.mixin-ellipsis-1();
}
.status {
padding-top: 3px;
height: 23px;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
max-width: 100%;
}
@@ -335,12 +335,12 @@ export default {
// text-align: center;
height: 100%;
width: 100%;
font-size: 16px;
font-size: var(--playDetail-lrc-font-size, 16px);
z-index: 10;
color: var(--color-400);
.lyricSelectline {
padding: 8px 0;
padding: calc(var(--playDetail-lrc-font-size, 16px) / 2) 1px;
overflow-wrap: break-word;
transition: @transition-normal !important;
transition-property: color, font-size;
@@ -256,7 +256,7 @@ export default {
transition: @transition-normal;
transition-property: background-color, opacity;
box-sizing: border-box;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
background-color: var(--color-content-background);
border: none;
@@ -112,7 +112,7 @@ export default {
.name {
flex: 0 1 auto;
min-width: 0;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
color: var(--color-650);
}
.label {
@@ -261,7 +261,7 @@ export default {
// border-bottom: 1px solid #eee;
h3 {
font-size: 14px;
.mixin-ellipsis-1;
.mixin-ellipsis-1();
line-height: 1.2;
}
}
@@ -98,7 +98,7 @@ export default {
// line-height: 36px;
// padding: 0 10px !important;
min-width: 70px;
// .mixin-ellipsis-1;
// .mixin-ellipsis-1();
+.btn {
margin-left: 10px;
+1 -1
View File
@@ -256,7 +256,7 @@ export default {
}
// &:before {
// .mixin-after;
// .mixin-after();
// position: absolute;
// left: 0;
// top: 0;
@@ -293,7 +293,7 @@ export default {
transition: background-color .2s ease;
line-height: 1.3;
span {
.mixin-ellipsis-2;
.mixin-ellipsis-2();
}
&.select {
+3 -1
View File
@@ -160,8 +160,10 @@ export const setLyric = () => {
if (!musicInfo.id) return
if (musicInfo.lrc) {
const extendedLyrics = []
if (appSetting['player.isShowLyricTranslation'] && musicInfo.tlrc) extendedLyrics.push(musicInfo.tlrc)
if (appSetting['player.isShowLyricRoma'] && musicInfo.rlrc) extendedLyrics.push(musicInfo.rlrc)
if (appSetting['player.isShowLyricTranslation'] && musicInfo.tlrc) extendedLyrics.push(musicInfo.tlrc)
if (appSetting['player.isSwapLyricTranslationAndRoma']) extendedLyrics.reverse()
lrc.setLyric(
appSetting['player.isPlayLxlrc'] && musicInfo.lxlrc ? musicInfo.lxlrc : musicInfo.lrc,
extendedLyrics,
+18
View File
@@ -232,6 +232,23 @@ const handlePlay = () => {
})
}
/**
* 播放列表内歌曲
* @param listId 列表id
* @param id 歌曲id
*/
export const playListById = (listId: string, id: string) => {
const prevListId = playInfo.playerListId
setPlayListId(listId)
// pause()
const musicInfo = getList(listId).find(m => m.id == id)
if (!musicInfo) return
setPlayMusicInfo(listId, musicInfo)
if (appSetting['player.isAutoCleanPlayedList'] || prevListId != listId) clearPlayedList()
clearTempPlayeList()
handlePlay()
}
/**
* 播放列表内歌曲
* @param listId 列表id
@@ -564,6 +581,7 @@ export const playPrev = async(isAutoToggle = false): Promise<void> => {
* 恢复播放
*/
export const play = () => {
window.lx.isPlayedStop &&= false
if (playMusicInfo.musicInfo == null) return
if (isEmpty()) {
if (createGettingUrlId(playMusicInfo.musicInfo) != gettingUrlId) setMusicUrl(playMusicInfo.musicInfo)
@@ -1,6 +1,6 @@
import { markRaw } from '@common/utils/vueTools'
import { useRouter } from '@common/utils/vueRouter'
import { decodeName } from '@common/utils/common'
import { decodeName } from '@renderer/utils'
// import { allList, defaultList, loveList, userLists } from '@renderer/store/list'
import { playMusicInfo, isShowPlayerDetail } from '@renderer/store/player/state'
import { setShowPlayerDetail, addTempPlayList } from '@renderer/store/player/action'
@@ -25,6 +25,7 @@ export default () => {
watch(() => appSetting['player.isShowLyricTranslation'], setLyric)
watch(() => appSetting['player.isShowLyricRoma'], setLyric)
watch(() => appSetting['player.isSwapLyricTranslationAndRoma'], setLyric)
watch(() => appSetting['player.isPlayLxlrc'], setLyric)
window.app_event.on('play', play)

Some files were not shown because too many files have changed in this diff Show More