commit
f2f2008d5d
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -6,6 +6,32 @@ 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/).
|
||||
|
||||
## [1.21.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.20.0...v1.21.0) - 2022-05-22
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增设置-播放设置-显示歌词罗马音,默认关闭,注:目前只有网易源能获取到罗马音歌词(得益于 Binaryify/NeteaseCloudMusicApi/pull/1523),如果你知道其他源的歌词罗马音获取方式,欢迎PR或开issue交流!
|
||||
|
||||
### 优化
|
||||
|
||||
- 同时删除一首歌以上时将需要二次确认删除
|
||||
- 禁用透明窗口时右侧不再偏移5px距离(在win7、Ubuntu等系统上测试发现不偏移也不影响滚动条的拖动了)
|
||||
- 删除未下载完成的任务时,只同时尝试删除已有下载进度的本地文件
|
||||
- 在全屏状态下使用`Esc`键可以退出全屏(#827)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复某些情况下歌曲播放出错时不会自动切歌的问题
|
||||
- 修复关闭“显示切换动画”设置后,在应用启动时该设置没有被应用的问题
|
||||
- 修复原始歌词存在偏移时,歌词偏移设置的重置未按预期工作的问题
|
||||
- 修复长度大于一行的歌词在使用歌词调整播放进度时的时间不准问题
|
||||
- 修复潜在歌单更新失败的问题
|
||||
|
||||
### 文档
|
||||
|
||||
- 将歌曲添加“稍后播放”后,它们会被放在一个优先级最高的特殊队列中,点击“下一曲”时会消耗该队列中的歌曲,并且无法通过“上一曲”功能播放该队列的上一首歌曲
|
||||
- 在切歌时若不是通过“上一曲”、“下一曲”功能切歌(例如直接点击“排行榜列表”、“我的列表”中的歌曲切歌),“稍后播放”队列将会被清空
|
||||
|
||||
## [1.20.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.19.0...v1.20.0) - 2022-04-17
|
||||
|
||||
特别说明:Scheme URL其实是支持Linux系统的,但好像需要deb之类的安装包创建出`.desktop`文件才行。
|
||||
|
|
4
FAQ.md
4
FAQ.md
|
@ -14,6 +14,8 @@
|
|||
4. 对于歌单详情列表,除了可以使用第2条的方式播放外,你可以点击详情页上面的播放按钮临时播放当前歌单,或点击收藏将当前歌单收藏到“我的列表”后再去播放
|
||||
5. 对于排行榜详情列表,除了可以使用第2条的方式播放外,你可以在右击排行榜名字后弹出的菜单中,播放或收藏整个排行榜,这与第四条的歌单中的播放、与收藏按钮功能一致
|
||||
6. v1.18.0及之后新增了“双击列表里的歌曲时自动切换到当前列表播放”设置,默认关闭,此功能仅对歌单、排行榜有效
|
||||
7. 将歌曲添加“稍后播放”后,它们会被放在一个优先级最高的特殊队列中,点击“下一曲”时会消耗该队列中的歌曲,并且无法通过“上一曲”功能播放该队列的上一首歌曲
|
||||
8. 在切歌时若不是通过“上一曲”、“下一曲”功能切歌(例如直接点击“排行榜列表”、“我的列表”中的歌曲切歌),“稍后播放”队列将会被清空
|
||||
|
||||
## 可用的鼠标、键盘快捷操作
|
||||
|
||||
|
@ -165,7 +167,7 @@
|
|||
|
||||
### Windows 7 下界面异常
|
||||
|
||||
由于软件默认使用了透明窗口,根据Electron官方文档的[说明](https://electronjs.org/docs/api/frameless-window#%E5%B1%80%E9%99%90%E6%80%A7):
|
||||
由于软件默认使用了透明窗口,根据Electron官方文档的[说明](https://www.electronjs.org/docs/latest/tutorial/window-customization#limitations):
|
||||
> 在 windows 操作系统上, 当 DWM 被禁用时, 透明窗口将无法工作。
|
||||
|
||||
因此,当 win7 没有使用**Aero**主题时界面将会显示异常,开启AERO的方法请自行百度:`win7开启Aero效果`(开启后可看到任务栏变透明)。<br>
|
||||
|
|
|
@ -6,7 +6,7 @@ module.exports = {
|
|||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../../dist/electron'),
|
||||
path: path.join(__dirname, '../../dist'),
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
@ -25,9 +25,6 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 300000,
|
||||
},
|
||||
plugins: [
|
||||
new ESLintPlugin(),
|
||||
],
|
||||
|
|
|
@ -19,4 +19,8 @@ module.exports = merge(baseConfig, {
|
|||
__userApi: `"${path.join(__dirname, '../../src/main/modules/userApi').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
],
|
||||
performance: {
|
||||
maxEntrypointSize: 1024 * 1024 * 50,
|
||||
maxAssetSize: 1024 * 1024 * 30,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -26,11 +26,11 @@ module.exports = merge(baseConfig, {
|
|||
patterns: [
|
||||
{
|
||||
from: path.join(__dirname, '../../src/main/modules/userApi/renderer'),
|
||||
to: path.join(__dirname, '../../dist/electron/userApi/renderer'),
|
||||
to: path.join(__dirname, '../../dist/userApi/renderer'),
|
||||
},
|
||||
{
|
||||
from: path.join(__dirname, '../../src/main/modules/userApi/rendererEvent/name.js'),
|
||||
to: path.join(__dirname, '../../dist/electron/userApi/rendererEvent/name.js'),
|
||||
to: path.join(__dirname, '../../dist/userApi/rendererEvent/name.js'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
@ -40,6 +40,10 @@ module.exports = merge(baseConfig, {
|
|||
},
|
||||
}),
|
||||
],
|
||||
performance: {
|
||||
maxEntrypointSize: 1024 * 1024 * 10,
|
||||
maxAssetSize: 1024 * 1024 * 20,
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
},
|
||||
|
|
|
@ -14,7 +14,7 @@ const okayLog = chalk.bgGreen.white(' OKAY ') + ' '
|
|||
|
||||
|
||||
function build() {
|
||||
del.sync(['dist/electron/**', 'build/**'])
|
||||
del.sync(['dist/**', 'build/**'])
|
||||
|
||||
const spinners = new Spinnies({ color: 'blue' })
|
||||
spinners.add('main', { text: 'main building' })
|
||||
|
|
|
@ -17,7 +17,7 @@ module.exports = {
|
|||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../../dist/electron'),
|
||||
path: path.join(__dirname, '../../dist'),
|
||||
publicPath: 'auto',
|
||||
},
|
||||
resolve: {
|
||||
|
@ -127,9 +127,6 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 300000,
|
||||
},
|
||||
plugins: [
|
||||
new HTMLPlugin({
|
||||
filename: 'lyric.html',
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
const path = require('path')
|
||||
// const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
@ -20,14 +19,6 @@ module.exports = merge(baseConfig, {
|
|||
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d)),
|
||||
],
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: path.join(__dirname, '../../src/static'),
|
||||
to: path.join(__dirname, '../../dist/electron/static'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"production"',
|
||||
|
@ -44,6 +35,8 @@ module.exports = merge(baseConfig, {
|
|||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 1024 * 1024 * 10,
|
||||
maxAssetSize: 1024 * 1024 * 20,
|
||||
hints: 'warning',
|
||||
},
|
||||
node: {
|
||||
|
|
|
@ -17,7 +17,7 @@ module.exports = {
|
|||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../../dist/electron'),
|
||||
path: path.join(__dirname, '../../dist'),
|
||||
publicPath: 'auto',
|
||||
},
|
||||
resolve: {
|
||||
|
@ -127,9 +127,6 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 300000,
|
||||
},
|
||||
plugins: [
|
||||
new HTMLPlugin({
|
||||
filename: 'index.html',
|
||||
|
|
|
@ -23,7 +23,7 @@ module.exports = merge(baseConfig, {
|
|||
patterns: [
|
||||
{
|
||||
from: path.join(__dirname, '../../src/static'),
|
||||
to: path.join(__dirname, '../../dist/electron/static'),
|
||||
to: path.join(__dirname, '../../dist/static'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
@ -43,6 +43,8 @@ module.exports = merge(baseConfig, {
|
|||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 1024 * 1024 * 10,
|
||||
maxAssetSize: 1024 * 1024 * 20,
|
||||
hints: 'warning',
|
||||
},
|
||||
node: {
|
||||
|
|
|
@ -151,7 +151,7 @@ function startElectron() {
|
|||
let args = [
|
||||
'--inspect=5858',
|
||||
// 'NODE_ENV=development',
|
||||
path.join(__dirname, '../dist/electron/main.js'),
|
||||
path.join(__dirname, '../dist/main.js'),
|
||||
]
|
||||
|
||||
// detect yarn or npm and process commandline args accordingly
|
||||
|
|
File diff suppressed because it is too large
Load Diff
63
package.json
63
package.json
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "1.20.0",
|
||||
"version": "1.21.0",
|
||||
"description": "一个免费的音乐查找助手",
|
||||
"main": "./dist/electron/main.js",
|
||||
"main": "./dist/main.js",
|
||||
"productName": "lx-music-desktop",
|
||||
"scripts": {
|
||||
"pack": "node build-config/pack.js && npm run pack:win:setup:x64",
|
||||
|
@ -57,7 +57,7 @@
|
|||
"publish:linux:rpm": "cross-env ARCH=x64 electron-builder -l=rpm --x64 -p onTagOrDraft",
|
||||
"publish:linux:pacman": "cross-env ARCH=x64 electron-builder -l=pacman --x64 -p onTagOrDraft",
|
||||
"dev": "node build-config/runner-dev.js",
|
||||
"clean:electron": "rimraf dist/electron",
|
||||
"clean:electron": "rimraf dist",
|
||||
"clean": "rimraf dist && rimraf build",
|
||||
"build:src": "node build-config/pack.js",
|
||||
"build:main": "cross-env NODE_ENV=production webpack --config build-config/main/webpack.config.prod.js --progress",
|
||||
|
@ -74,7 +74,7 @@
|
|||
],
|
||||
"engines": {
|
||||
"node": ">= 16",
|
||||
"npm": ">=8.3.0"
|
||||
"npm": ">=8.5.2"
|
||||
},
|
||||
"build": {
|
||||
"appId": "cn.toside.music.desktop",
|
||||
|
@ -89,7 +89,7 @@
|
|||
"output": "./build"
|
||||
},
|
||||
"files": [
|
||||
"dist/electron/**/*"
|
||||
"dist/**/*"
|
||||
],
|
||||
"asar": {
|
||||
"smartUnpack": false
|
||||
|
@ -178,33 +178,33 @@
|
|||
},
|
||||
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.9",
|
||||
"@babel/core": "^7.18.0",
|
||||
"@babel/eslint-parser": "^7.17.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.17.12",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-modules-umd": "^7.16.7",
|
||||
"@babel/plugin-transform-runtime": "^7.17.0",
|
||||
"@babel/plugin-transform-modules-umd": "^7.18.0",
|
||||
"@babel/plugin-transform-runtime": "^7.18.0",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"babel-loader": "^8.2.4",
|
||||
"babel-preset-minify": "^0.5.1",
|
||||
"browserslist": "^4.20.2",
|
||||
"@babel/preset-env": "^7.18.0",
|
||||
"babel-loader": "^8.2.5",
|
||||
"babel-preset-minify": "^0.5.2",
|
||||
"browserslist": "^4.20.3",
|
||||
"chalk": "^4.1.2",
|
||||
"changelog-parser": "^2.8.1",
|
||||
"copy-webpack-plugin": "^10.2.4",
|
||||
"core-js": "^3.22.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"core-js": "^3.22.5",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.1",
|
||||
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||
"del": "^6.0.0",
|
||||
"css-minimizer-webpack-plugin": "^4.0.0",
|
||||
"del": "^6.1.0",
|
||||
"electron": "^13.6.9",
|
||||
"electron-builder": "^23.0.6",
|
||||
"electron-builder": "^23.0.9",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-to-chromium": "^1.4.111",
|
||||
"electron-updater": "^5.0.2",
|
||||
"eslint": "^8.13.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"electron-to-chromium": "^1.4.137",
|
||||
"electron-updater": "^5.0.4",
|
||||
"eslint": "^8.16.0",
|
||||
"eslint-config-standard": "^17.0.0",
|
||||
"eslint-formatter-friendly": "git+https://github.com/lyswhut/eslint-friendly-formatter.git#2170d1320e2fad13615a9dcf229669f0bb473a53",
|
||||
"eslint-plugin-html": "^6.2.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
|
@ -215,12 +215,11 @@
|
|||
"file-loader": "^6.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"less": "^4.1.2",
|
||||
"less-loader": "^10.2.0",
|
||||
"markdown-it": "^12.3.2",
|
||||
"less-loader": "^11.0.0",
|
||||
"mini-css-extract-plugin": "^2.6.0",
|
||||
"node-loader": "^2.0.0",
|
||||
"postcss": "^8.4.12",
|
||||
"postcss-loader": "^6.2.1",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-loader": "^7.0.0",
|
||||
"postcss-pxtorem": "^6.0.0",
|
||||
"pug": "^3.0.2",
|
||||
"pug-loader": "^2.4.0",
|
||||
|
@ -235,16 +234,16 @@
|
|||
"url-loader": "^4.1.1",
|
||||
"vue-loader": "^17.0.0",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"webpack": "^5.72.0",
|
||||
"webpack": "^5.72.1",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.8.1",
|
||||
"webpack-dev-server": "^4.9.0",
|
||||
"webpack-hot-middleware": "git+https://github.com/lyswhut/webpack-hot-middleware.git#329c4375134b89d39da23a56a94db651247c74a1",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bufferutil": "^4.0.6",
|
||||
"crypto-js": "^4.1.1",
|
||||
"electron-log": "^4.4.6",
|
||||
"electron-log": "^4.4.7",
|
||||
"electron-store": "^8.0.1",
|
||||
"font-list": "git+https://github.com/lyswhut/node-font-list.git#4edbb1933b49a9bac1eedd63a31da16b487fe57d",
|
||||
"http-terminator": "^3.2.0",
|
||||
|
@ -256,13 +255,13 @@
|
|||
"needle": "^3.1.0",
|
||||
"node-id3": "^0.2.3",
|
||||
"request": "^2.88.2",
|
||||
"socket.io": "^4.4.1",
|
||||
"socket.io": "^4.5.1",
|
||||
"sortablejs": "^1.15.0",
|
||||
"tunnel": "^0.0.6",
|
||||
"utf-8-validate": "^5.0.9",
|
||||
"vue": "^3.2.33",
|
||||
"vue": "^3.2.35",
|
||||
"vue-i18n": "^9.2.0-beta.35",
|
||||
"vue-router": "^4.0.14",
|
||||
"vue-router": "^4.1.0-aabe509",
|
||||
"vuex": "^4.0.2"
|
||||
},
|
||||
"overrides": {
|
||||
|
|
|
@ -1,36 +1,23 @@
|
|||
特别说明:Scheme URL其实是支持Linux系统的,但好像需要deb之类的安装包创建出`.desktop`文件才行。
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增播放详情页歌词右键菜单,原来设置-播放详情页设置的字体重置已迁移到此菜单内
|
||||
- 新增歌词偏移设置,可以在播放详情页歌词右键菜单中使用
|
||||
- 新增设置-播放设置-播放错误时自动切换歌曲设置,默认开启(原来的行为),若你不想在遇到音频加载失败、url获取失败等错误时自动切歌可以关闭此设置
|
||||
- 新增设置-桌面歌词设置-自动刷新歌词置顶(当歌词置顶后仍被某些程序遮挡时可尝试启用此设置)
|
||||
- 新增列表更新管理,可以在鼠标移入“我的列表”标题时出现的按钮中进入,这可以用来设置启动软件时需要自动从原平台更新的列表
|
||||
- 新增设置-播放设置-显示歌词罗马音,默认关闭,注:目前只有网易源能获取到罗马音歌词(得益于 Binaryify/NeteaseCloudMusicApi/pull/1523),如果你知道其他源的歌词罗马音获取方式,欢迎PR或开issue交流!
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化播放详情页背景显示,现在有背景图片的主题可以在播放详情页显示它的图片了
|
||||
- 播放详情页在全屏状态下仍会显示退出播放详情页按钮,同时在其旁边添加退出全屏按钮
|
||||
- 播放详情页在全屏状态下鼠标在空白处静止不动3秒后自动将其隐藏
|
||||
- 同时删除一首歌以上时将需要二次确认删除
|
||||
- 禁用透明窗口时右侧不再偏移5px距离(在win7、Ubuntu等系统上测试发现不偏移也不影响滚动条的拖动了)
|
||||
- 删除未下载完成的任务时,只同时尝试删除已有下载进度的本地文件
|
||||
- 在全屏状态下使用`Esc`键可以退出全屏(#827)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复Linux无法全屏的问题
|
||||
- 修复播放下载列表的歌曲时,使用Windows任务栏缩略图工具栏控制按钮的收藏按钮收藏歌曲时的异常问题
|
||||
- 修复启用搜索历史但不启用热门搜索时,搜索历史不显示的问题
|
||||
- 修复窗口尺寸设置对应的字体大小在启动后不生效的问题
|
||||
- 修复wy源搜索某些歌曲时第一页之后的歌曲无法加载的问题
|
||||
- 修复使用Scheme URL搜索歌曲时,不会自动关闭播放详情页(若处于打开状态)的问题
|
||||
- 修复换源失败时的处理问题
|
||||
- 修复启用代理时,https请求可能被挂起或被转为http的问题
|
||||
- 修复正在下载的歌曲暂停任务后,再开始会导致程序卡死的问题
|
||||
- 修复某些情况下歌曲播放出错时不会自动切歌的问题
|
||||
- 修复关闭“显示切换动画”设置后,在应用启动时该设置没有被应用的问题
|
||||
- 修复原始歌词存在偏移时,歌词偏移设置的重置未按预期工作的问题
|
||||
- 修复长度大于一行的歌词在使用歌词调整播放进度时的时间不准问题
|
||||
- 修复潜在歌单更新失败的问题
|
||||
|
||||
### 变更
|
||||
### 文档
|
||||
|
||||
- 播放详情页的任意地方右键双击隐藏详情页的行为,“任意区域”改为在“非歌词区域”
|
||||
|
||||
### 移除
|
||||
|
||||
- 移除设置-播放详情页设置-歌词字体重置,此设置项已迁移到播放详情页的歌词菜单中
|
||||
- 移除播放详情页使用+-快捷键调整字体大小的功能,改用歌词右键菜单的字体大小调整功能
|
||||
- 将歌曲添加“稍后播放”后,它们会被放在一个优先级最高的特殊队列中,点击“下一曲”时会消耗该队列中的歌曲,并且无法通过“上一曲”功能播放该队列的上一首歌曲
|
||||
- 在切歌时若不是通过“上一曲”、“下一曲”功能切歌(例如直接点击“排行榜列表”、“我的列表”中的歌曲切歌),“稍后播放”队列将会被清空
|
||||
|
|
|
@ -9,12 +9,12 @@ const version_bak = JSON.stringify(version, null, 2)
|
|||
const parseChangelog = require('changelog-parser')
|
||||
const changelogPath = jp('../../CHANGELOG.md')
|
||||
|
||||
const md_renderer = markdownStr => new (require('markdown-it'))({
|
||||
html: true,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
breaks: true,
|
||||
}).render(markdownStr)
|
||||
// const md_renderer = markdownStr => new (require('markdown-it'))({
|
||||
// html: true,
|
||||
// linkify: true,
|
||||
// typographer: true,
|
||||
// breaks: true,
|
||||
// }).render(markdownStr)
|
||||
|
||||
const getPrevVer = () => parseChangelog(changelogPath).then(res => {
|
||||
if (!res.versions.length) throw new Error('CHANGELOG 无法解析到版本号')
|
||||
|
@ -28,7 +28,7 @@ const updateChangeLog = async(newVerNum, newChangeLog) => {
|
|||
fs.writeFileSync(changelogPath, changeLog.replace(new RegExp('(## [?0.1.1]?)'), log + '\n$1'), 'utf-8')
|
||||
}
|
||||
|
||||
const renderChangeLog = md => md_renderer(md)
|
||||
// const renderChangeLog = md => md_renderer(md)
|
||||
|
||||
|
||||
module.exports = async newVerNum => {
|
||||
|
@ -38,7 +38,7 @@ module.exports = async newVerNum => {
|
|||
newVerNum = verArr.join('.')
|
||||
}
|
||||
const newMDChangeLog = fs.readFileSync(jp('../changeLog.md'), 'utf-8')
|
||||
const newChangeLog = renderChangeLog(newMDChangeLog)
|
||||
// const newChangeLog = renderChangeLog(newMDChangeLog)
|
||||
version.history.unshift({
|
||||
version: version.version,
|
||||
desc: version.desc,
|
||||
|
@ -58,7 +58,7 @@ module.exports = async newVerNum => {
|
|||
return {
|
||||
pkg_bak,
|
||||
version_bak,
|
||||
changeLog: newChangeLog,
|
||||
// changeLog: newChangeLog,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2,7 +2,7 @@ const path = require('path')
|
|||
const os = require('os')
|
||||
|
||||
const defaultSetting = {
|
||||
version: '1.0.56',
|
||||
version: '1.0.57',
|
||||
player: {
|
||||
togglePlayMethod: 'listLoop',
|
||||
highQuality: false,
|
||||
|
@ -12,6 +12,7 @@ const defaultSetting = {
|
|||
mediaDeviceId: 'default',
|
||||
isMediaDeviceRemovedStopPlay: false,
|
||||
isShowLyricTranslation: false,
|
||||
isShowLyricRoma: false,
|
||||
isS2t: false, // 是否将歌词从简体转换为繁体
|
||||
isPlayLxlrc: true,
|
||||
isSavePlayTime: false,
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
"lists__new_list_btn": "Create list",
|
||||
"lists__new_list_input": "New list...",
|
||||
"lists__remove": "Remove",
|
||||
"lists__remove music_tip": "Do you really want to remove the selected {len} songs?",
|
||||
"lists__remove_tip": "Do you really want to remove {name}?",
|
||||
"lists__remove_tip_button": "Yes, that's right",
|
||||
"lists__rename": "Rename",
|
||||
|
@ -355,7 +356,8 @@
|
|||
"setting__play_detail_font_size_reset": "Reset",
|
||||
"setting__play_detail_font_zoom": "Zoom the currently playing lyrics",
|
||||
"setting__play_detail_lyric_progress": "Allows to adjust playback progress by lyrics",
|
||||
"setting__play_lyric_lxlrc": "Use Karaoke-style lyrics playback (if supported)",
|
||||
"setting__play_lyric_lxlrc": "Play with karaoke-style lyrics (if available)",
|
||||
"setting__play_lyric_roma": "Show lyrics roman",
|
||||
"setting__play_lyric_s2t": "Convert the playing and downloading lyrics to Traditional Chinese",
|
||||
"setting__play_lyric_transition": "Show lyrics translation",
|
||||
"setting__play_mediaDevice": "Audio output",
|
||||
|
@ -363,7 +365,7 @@
|
|||
"setting__play_mediaDevice_title": "Select a media device for audio output",
|
||||
"setting__play_media_device_error_tip": "This function conflicts with the audio visualization function. You have enabled audio visualization when you started the software this time. This setting is temporarily unavailable. Please restart the software and then modify this setting.",
|
||||
"setting__play_media_device_tip": "This feature conflicts with Audio Visualization, both cannot be enabled at the same time, would you like to turn Audio Visualization off and apply the selected audio output settings?",
|
||||
"setting__play_quality": "Play 320K quality songs first (if supported)",
|
||||
"setting__play_quality": "Priority playback of 320K quality songs (if available)",
|
||||
"setting__play_save_play_time": "Remember playback progress",
|
||||
"setting__play_task_bar": "Show playing progress on the taskbar",
|
||||
"setting__play_timeout": "Timed pause",
|
||||
|
@ -432,6 +434,7 @@
|
|||
"sync__title": "Choose how to synchronize the list with {name}",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
"tag__lossless_24bit": "24bit",
|
||||
"theme_auto": "Auto",
|
||||
"theme_auto_tip": "Right-click to open the light and dark theme settings window",
|
||||
"theme_black": "Black",
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
"lists__new_list_btn": "新建列表",
|
||||
"lists__new_list_input": "新列表...",
|
||||
"lists__remove": "删除",
|
||||
"lists__remove music_tip": "你真的要移除所选的 {len} 首歌曲吗?",
|
||||
"lists__remove_tip": "你真的想要移除 {name} 吗?",
|
||||
"lists__remove_tip_button": "是的 没错",
|
||||
"lists__rename": "重命名",
|
||||
|
@ -355,15 +356,16 @@
|
|||
"setting__play_detail_font_size_reset": "重置",
|
||||
"setting__play_detail_font_zoom": "缩放当前正在播放的歌词",
|
||||
"setting__play_detail_lyric_progress": "允许通过歌词调整播放进度",
|
||||
"setting__play_lyric_lxlrc": "使用卡拉OK式歌词播放(如果支持)",
|
||||
"setting__play_lyric_lxlrc": "使用卡拉OK式歌词播放(如果可用)",
|
||||
"setting__play_lyric_roma": "显示歌词罗马音(如果可用)",
|
||||
"setting__play_lyric_s2t": "将播放与下载的歌词转换为繁体中文",
|
||||
"setting__play_lyric_transition": "显示歌词翻译",
|
||||
"setting__play_lyric_transition": "显示歌词翻译(如果可用)",
|
||||
"setting__play_mediaDevice": "音频输出",
|
||||
"setting__play_mediaDevice_remove_stop_play": "当前的声音输出设备被改变时暂停播放歌曲",
|
||||
"setting__play_mediaDevice_title": "选择声音输出的媒体设备",
|
||||
"setting__play_media_device_error_tip": "此功能与音频可视化功能冲突,你本次启动软件时已启用过音频可视化,此设置暂不可用,请 重启 软件后,再来修改此设置。",
|
||||
"setting__play_media_device_tip": "此功能与音频可视化功能冲突,两者无法同时启用,是否将音频可视化关闭 并 应用所选音频输出设置?",
|
||||
"setting__play_quality": "优先播放320K品质的歌曲(如果支持)",
|
||||
"setting__play_quality": "优先播放320K品质的歌曲(如果可用)",
|
||||
"setting__play_save_play_time": "记住播放进度",
|
||||
"setting__play_task_bar": "在任务栏上显示当前歌曲播放进度",
|
||||
"setting__play_timeout": "定时暂停",
|
||||
|
@ -432,6 +434,7 @@
|
|||
"sync__title": "选择与 {name} 的列表同步方式",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
"tag__lossless_24bit": "24bit",
|
||||
"theme_auto": "道法自然",
|
||||
"theme_auto_tip": "鼠标 右击 可打开亮、暗主题设置窗口",
|
||||
"theme_black": "黑灯瞎火",
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
"lists__new_list_btn": "新建列表",
|
||||
"lists__new_list_input": "新列表...",
|
||||
"lists__remove": "刪除",
|
||||
"lists__remove music_tip": "你真的要移除所選的 {len} 首歌曲嗎?",
|
||||
"lists__remove_tip": "你真的想要移除 {name} 嗎?",
|
||||
"lists__remove_tip_button": "是的 沒錯",
|
||||
"lists__rename": "重命名",
|
||||
|
@ -355,15 +356,16 @@
|
|||
"setting__play_detail_font_size_reset": "重置",
|
||||
"setting__play_detail_font_zoom": "縮放當前正在播放的歌詞",
|
||||
"setting__play_detail_lyric_progress": "允許通過歌詞調整播放進度",
|
||||
"setting__play_lyric_lxlrc": "使用卡拉OK式歌詞播放(如果支持)",
|
||||
"setting__play_lyric_lxlrc": "使用卡拉OK式歌詞播放(如果可用)",
|
||||
"setting__play_lyric_roma": "顯示歌詞羅馬音(如果可用)",
|
||||
"setting__play_lyric_s2t": "將播放與下載的歌詞轉換為繁體中文",
|
||||
"setting__play_lyric_transition": "顯示歌詞翻譯",
|
||||
"setting__play_lyric_transition": "顯示歌詞翻譯(如果可用)",
|
||||
"setting__play_mediaDevice": "音頻輸出",
|
||||
"setting__play_mediaDevice_remove_stop_play": "當前的聲音輸出設備被改變時暫停播放歌曲",
|
||||
"setting__play_mediaDevice_title": "選擇聲音輸出的媒體設備",
|
||||
"setting__play_media_device_error_tip": "此功能與音頻可視化功能衝突,你本次啟動軟件時已啟用過音頻可視化,此設置暫不可用,請 重啟 軟件後,再來修改此設置。",
|
||||
"setting__play_media_device_tip": "此功能與音頻可視化功能衝突,兩者無法同時啟用,是否將音頻可視化關閉 並 應用所選音頻輸出設置?",
|
||||
"setting__play_quality": "優先播放320K品質的歌曲(如果支持)",
|
||||
"setting__play_quality": "優先播放320K品質的歌曲(如果可用)",
|
||||
"setting__play_save_play_time": "記住播放進度",
|
||||
"setting__play_task_bar": "在任務欄上顯示當前歌曲播放進度",
|
||||
"setting__play_timeout": "定時暫停",
|
||||
|
@ -432,6 +434,7 @@
|
|||
"sync__title": "選擇與 {name} 的列表同步方式",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
"tag__lossless_24bit": "24bit",
|
||||
"theme_auto": "道法自然",
|
||||
"theme_auto_tip": "鼠標 右擊 可打開亮、暗主題設置窗口",
|
||||
"theme_black": "黑燈瞎火",
|
||||
|
|
|
@ -67,11 +67,10 @@ exports.createWindow = async userApi => {
|
|||
event.preventDefault()
|
||||
})
|
||||
}
|
||||
global.modules.userApiWindow.webContents.session.setPermissionRequestHandler((webContents, permission, callback) => {
|
||||
if (webContents === global.modules.mainWindow.webContents) return callback(true)
|
||||
global.modules.userApiWindow.webContents.session.setPermissionRequestHandler((webContents, permission, resolve) => {
|
||||
if (webContents === global.modules.mainWindow.webContents) return resolve(true)
|
||||
|
||||
// eslint-disable-next-line node/no-callback-literal
|
||||
callback(false)
|
||||
resolve(false)
|
||||
})
|
||||
global.modules.userApiWindow.webContents.setWindowOpenHandler(() => {
|
||||
return { action: 'deny' }
|
||||
|
|
|
@ -165,7 +165,7 @@ contextBridge.exposeInMainWorld('lx', {
|
|||
headers: resp.headers,
|
||||
bytes: resp.bytes,
|
||||
raw: resp.raw,
|
||||
body: body,
|
||||
body,
|
||||
}, body)
|
||||
}).request
|
||||
|
||||
|
@ -212,7 +212,7 @@ contextBridge.exposeInMainWorld('lx', {
|
|||
},
|
||||
rsaEncrypt(buffer, key) {
|
||||
buffer = Buffer.concat([Buffer.alloc(128 - buffer.length), buffer])
|
||||
return publicEncrypt({ key: key, padding: constants.RSA_NO_PADDING }, buffer)
|
||||
return publicEncrypt({ key, padding: constants.RSA_NO_PADDING }, buffer)
|
||||
},
|
||||
randomBytes(size) {
|
||||
return randomBytes(size)
|
||||
|
|
|
@ -41,6 +41,7 @@ const setLrcConfig = () => {
|
|||
config: desktopLyric,
|
||||
languageId: global.appSetting.langId,
|
||||
isShowLyricTranslation: global.appSetting.player.isShowLyricTranslation,
|
||||
isShowLyricRoma: global.appSetting.player.isShowLyricRoma,
|
||||
isPlayLxlrc: global.appSetting.player.isPlayLxlrc,
|
||||
})
|
||||
if (isLock != desktopLyric.isLock) {
|
||||
|
|
|
@ -28,6 +28,7 @@ mainHandle(ipcWinLyricNames.get_lyric_config, async() => {
|
|||
config: global.appSetting.desktopLyric,
|
||||
languageId: global.appSetting.langId,
|
||||
isShowLyricTranslation: global.appSetting.player.isShowLyricTranslation,
|
||||
isShowLyricRoma: global.appSetting.player.isShowLyricRoma,
|
||||
isPlayLxlrc: global.appSetting.player.isPlayLxlrc,
|
||||
}
|
||||
})
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
transition(enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut")
|
||||
.control-bar(v-show="!lrcConfig.isLock")
|
||||
core-control-bar(:lrcConfig="lrcConfig" :themes="themeList")
|
||||
core-lyric(:lrcConfig="lrcConfig" :isPlayLxlrc="isPlayLxlrc" :isShowLyricTranslation="isShowLyricTranslation")
|
||||
core-lyric(:lrcConfig="lrcConfig" :isPlayLxlrc="isPlayLxlrc" :isShowLyricTranslation="isShowLyricTranslation" :isShowLyricRoma="isShowLyricRoma")
|
||||
div.resize-left(@mousedown.self="handleMouseDown('left', $event)" @touchstart.self="handleTouchDown('left', $event)")
|
||||
div.resize-top(@mousedown.self="handleMouseDown('top', $event)" @touchstart.self="handleTouchDown('top', $event)")
|
||||
div.resize-right(@mousedown.self="handleMouseDown('right', $event)" @touchstart.self="handleTouchDown('right', $event)")
|
||||
|
@ -46,7 +46,8 @@ export default {
|
|||
isZoomActiveLrc: true,
|
||||
},
|
||||
},
|
||||
isShowLyricTranslation: true,
|
||||
isShowLyricTranslation: false,
|
||||
isShowLyricRoma: false,
|
||||
isPlayLxlrc: true,
|
||||
themeList: [
|
||||
{
|
||||
|
@ -111,9 +112,10 @@ export default {
|
|||
document.removeEventListener('mouseup', this.handleMouseUp)
|
||||
},
|
||||
methods: {
|
||||
handleUpdateConfig({ config, languageId, isShowLyricTranslation, isPlayLxlrc }) {
|
||||
handleUpdateConfig({ config, languageId, isShowLyricTranslation, isShowLyricRoma, isPlayLxlrc }) {
|
||||
this.lrcConfig = config
|
||||
this.isShowLyricTranslation = isShowLyricTranslation
|
||||
this.isShowLyricRoma = isShowLyricRoma
|
||||
this.isPlayLxlrc = isPlayLxlrc
|
||||
if (this.$i18n.locale !== languageId && languageId != null) this.$i18n.locale = languageId
|
||||
},
|
||||
|
|
|
@ -40,6 +40,10 @@ export default {
|
|||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isShowLyricRoma: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -74,6 +78,7 @@ export default {
|
|||
lyrics: {
|
||||
lyric: '',
|
||||
tlyric: '',
|
||||
rlyric: '',
|
||||
lxlyric: '',
|
||||
},
|
||||
}
|
||||
|
@ -143,6 +148,10 @@ export default {
|
|||
this.setLyric()
|
||||
rendererSend(NAMES.winLyric.get_lyric_info, 'status')
|
||||
},
|
||||
isShowLyricRoma() {
|
||||
this.setLyric()
|
||||
rendererSend(NAMES.winLyric.get_lyric_info, 'status')
|
||||
},
|
||||
isPlayLxlrc() {
|
||||
this.setLyric()
|
||||
rendererSend(NAMES.winLyric.get_lyric_info, 'status')
|
||||
|
@ -195,6 +204,7 @@ export default {
|
|||
case 'lyric':
|
||||
this.lyrics.lyric = data.lrc
|
||||
this.lyrics.tlyric = data.tlrc
|
||||
this.lyrics.rlyric = data.rlrc
|
||||
this.lyrics.lxlyric = data.lxlrc
|
||||
this.setLyric()
|
||||
break
|
||||
|
@ -211,12 +221,14 @@ export default {
|
|||
this.lyrics.lyric = ''
|
||||
this.lyrics.tlyric = ''
|
||||
this.lyrics.lxlyric = ''
|
||||
this.lyrics.rlyric = ''
|
||||
this.setLyric()
|
||||
break
|
||||
case 'info':
|
||||
// console.log('info', data)
|
||||
this.lyrics.lyric = data.lrc
|
||||
this.lyrics.tlyric = data.tlrc
|
||||
this.lyrics.rlyric = data.rlrc
|
||||
this.lyrics.lxlyric = data.lxlrc
|
||||
this.setLyric()
|
||||
this.$nextTick(() => {
|
||||
|
@ -343,10 +355,12 @@ export default {
|
|||
rendererSend(NAMES.winLyric.close)
|
||||
},
|
||||
setLyric() {
|
||||
const extendedLyrics = []
|
||||
if (this.isShowLyricTranslation && this.lyrics.tlyric) extendedLyrics.push(this.lyrics.tlyric)
|
||||
if (this.isShowLyricRoma && this.lyrics.rlyric) extendedLyrics.push(this.lyrics.rlyric)
|
||||
window.lrc.setLyric(
|
||||
this.isPlayLxlrc && this.lyrics.lxlyric ? this.lyrics.lxlyric : this.lyrics.lyric,
|
||||
this.isShowLyricTranslation && this.lyrics.tlyric ? this.lyrics.tlyric : '',
|
||||
// (this.isShowLyricTranslation && this.lyrics.tlyric ? (this.lyrics.tlyric + '\n') : '') + (this.lyrics.lyric || ''),
|
||||
extendedLyrics,
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -375,11 +389,11 @@ export default {
|
|||
display: inline-block;
|
||||
}
|
||||
|
||||
.font, .translation {
|
||||
.font, .extended {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.translation {
|
||||
.extended {
|
||||
transition: @transition-theme !important;
|
||||
transition-property: font-size, color;
|
||||
font-size: 0.8em;
|
||||
|
@ -396,7 +410,7 @@ export default {
|
|||
.line {
|
||||
color: @color-theme;
|
||||
}
|
||||
.translation {
|
||||
.extended {
|
||||
color: @color-theme;
|
||||
}
|
||||
// span {
|
||||
|
@ -465,7 +479,7 @@ export default {
|
|||
.draging {
|
||||
:global {
|
||||
.lrc-content {
|
||||
.font, .translation {
|
||||
.font, .extended {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
@ -475,7 +489,7 @@ export default {
|
|||
:global {
|
||||
.lrc-content {
|
||||
&.active {
|
||||
.translation {
|
||||
.extended {
|
||||
font-size: .94em;
|
||||
}
|
||||
span {
|
||||
|
@ -508,7 +522,7 @@ each(@themes, {
|
|||
:global {
|
||||
.lrc-content {
|
||||
&.active {
|
||||
.translation {
|
||||
.extended {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
.line {
|
||||
|
|
|
@ -14,41 +14,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { useRefGetter, watch, onMounted } from '@renderer/utils/vueTools'
|
||||
import { onMounted } from '@renderer/utils/vueTools'
|
||||
import useApp from '@renderer/core/useApp'
|
||||
import { isFullscreen } from '@renderer/core/share'
|
||||
import { getFontSizeWithScreen } from '@renderer/utils'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const theme = useRefGetter('theme')
|
||||
const font = useRefGetter('font')
|
||||
const windowSizeActive = useRefGetter('windowSizeActive')
|
||||
|
||||
const dom_root = document.getElementById('root')
|
||||
|
||||
watch(theme, (val) => {
|
||||
dom_root.className = val
|
||||
})
|
||||
watch(font, (val) => {
|
||||
document.documentElement.style.fontFamily = val
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
watch(isFullscreen, val => {
|
||||
if (val) {
|
||||
document.body.classList.remove(window.dt ? 'disableTransparent' : 'transparent')
|
||||
document.body.classList.add('fullscreen')
|
||||
document.documentElement.style.fontSize = getFontSizeWithScreen(window.screen.width) + 'px'
|
||||
} else {
|
||||
document.body.classList.remove('fullscreen')
|
||||
document.body.classList.add(window.dt ? 'disableTransparent' : 'transparent')
|
||||
document.documentElement.style.fontSize = windowSizeActive.value.fontSize
|
||||
}
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
useApp()
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -124,9 +96,9 @@ body {
|
|||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
#view { // 偏移5px距离解决非透明模式下右侧滚动条无法拖动的问题
|
||||
margin-right: 5Px;
|
||||
}
|
||||
// #view { // 偏移5px距离解决非透明模式下右侧滚动条无法拖动的问题
|
||||
// margin-right: 5Px;
|
||||
// }
|
||||
}
|
||||
.fullscreen {
|
||||
background-color: #fff;
|
||||
|
|
|
@ -55,6 +55,7 @@ export default {
|
|||
},
|
||||
getTypeName(type) {
|
||||
switch (type) {
|
||||
case 'flac32bit':
|
||||
case 'flac':
|
||||
case 'ape':
|
||||
case 'wav':
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<base-btn :class="$style.btn" @click="handleClick('128k')">{{$t('download__normal')}} - 128K</base-btn>
|
||||
<base-btn :class="$style.btn" @click="handleClick('320k')">{{$t('download__high_quality')}} - 320K</base-btn>
|
||||
<base-btn :class="$style.btn" @click="handleClick('flac')">{{$t('download__lossless')}} - FLAC</base-btn>
|
||||
<base-btn :class="$style.btn" @click="handleClick('flac32bit')">{{$t('download__lossless')}} - FLAC 24bit</base-btn>
|
||||
</main>
|
||||
</material-modal>
|
||||
</template>
|
||||
|
|
|
@ -68,7 +68,7 @@ export default {
|
|||
}
|
||||
|
||||
return {
|
||||
setting: setting,
|
||||
setting,
|
||||
isShowAddMusicTo,
|
||||
nextTogglePlayName,
|
||||
toggleNextPlayMode,
|
||||
|
|
|
@ -27,8 +27,10 @@
|
|||
<div :class="[$style.lyricSelectContent, 'select', 'scroll', 'lyricSelectContent']" v-if="isShowLrcSelectContent" @contextmenu="handleCopySelectText">
|
||||
<div v-for="(info, index) in lyric.lines" :key="index" :class="[$style.lyricSelectline, { [$style.lrcActive]: lyric.line == index }]">
|
||||
<span>{{info.text}}</span>
|
||||
<br v-if="info.translation"/>
|
||||
<span :class="$style.lyricSelectlineTransition">{{info.translation}}</span>
|
||||
<template v-for="(lrc, index) in info.extendedLyrics" :key="index">
|
||||
<br />
|
||||
<span :class="$style.lyricSelectlineExtended">{{lrc}}</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
@ -77,13 +79,17 @@ export default {
|
|||
const lyricInfo = reactive({
|
||||
lyric: '',
|
||||
tlyric: '',
|
||||
rlyric: '',
|
||||
lxlyric: '',
|
||||
rawlyric: '',
|
||||
musicInfo: null,
|
||||
})
|
||||
const updateMusicInfo = () => {
|
||||
lyricInfo.lyric = playerMusicInfo.lrc
|
||||
lyricInfo.tlyric = playerMusicInfo.tlrc
|
||||
lyricInfo.rlyric = playerMusicInfo.rlrc
|
||||
lyricInfo.lxlyric = playerMusicInfo.lxlrc
|
||||
lyricInfo.rawlyric = playerMusicInfo.rawlrc
|
||||
lyricInfo.musicInfo = musicInfoItem.value
|
||||
}
|
||||
const handleShowLyricMenu = event => {
|
||||
|
@ -92,13 +98,14 @@ export default {
|
|||
lyricMenuXY.y = event.pageY
|
||||
lyricMenuVisible.value = true
|
||||
}
|
||||
const handleUpdateLyric = ({ lyric, tlyric, lxlyric, offset }) => {
|
||||
const handleUpdateLyric = ({ lyric, tlyric, rlyric, lxlyric, offset }) => {
|
||||
setMusicInfo({
|
||||
lrc: lyric,
|
||||
tlrc: tlyric,
|
||||
rlrc: rlyric,
|
||||
lxlrc: lxlyric,
|
||||
})
|
||||
console.log(offset)
|
||||
// console.log(offset)
|
||||
window.eventHub.emit(eventPlayerNames.updateLyricOffset, offset)
|
||||
}
|
||||
|
||||
|
@ -181,13 +188,13 @@ export default {
|
|||
:global {
|
||||
.lrc-content {
|
||||
line-height: 1.2;
|
||||
padding: calc(var(--playDetail-lrc-font-size, 16px) / 2) 0;
|
||||
padding: calc(var(--playDetail-lrc-font-size, 16px) / 2) 1px;
|
||||
overflow-wrap: break-word;
|
||||
color: @color-player-detail-lyric;
|
||||
transition: @transition-theme;
|
||||
transition-property: padding;
|
||||
|
||||
.translation {
|
||||
.extended {
|
||||
transition: @transition-theme !important;
|
||||
transition-property: font-size, color;
|
||||
font-size: .9em;
|
||||
|
@ -203,7 +210,7 @@ export default {
|
|||
.line {
|
||||
color: @color-theme;
|
||||
}
|
||||
.translation {
|
||||
.extended {
|
||||
color: @color-theme;
|
||||
}
|
||||
// span {
|
||||
|
@ -241,7 +248,7 @@ export default {
|
|||
:global {
|
||||
.lrc-content {
|
||||
&.active {
|
||||
.translation {
|
||||
.extended {
|
||||
font-size: .94em;
|
||||
}
|
||||
span {
|
||||
|
@ -314,7 +321,7 @@ export default {
|
|||
transition-property: color, font-size;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.lyricSelectlineTransition {
|
||||
.lyricSelectlineExtended {
|
||||
font-size: 14px;
|
||||
}
|
||||
.lrc-active {
|
||||
|
@ -334,7 +341,7 @@ each(@themes, {
|
|||
color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
|
||||
&.active {
|
||||
.translation {
|
||||
.extended {
|
||||
color: ~'@{color-@{value}-player-detail-lyric-active}';
|
||||
}
|
||||
.line {
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<div :class="$style.group">
|
||||
<div :class="$style.subGroup">
|
||||
<div :class="$style.title">{{$t('lyric_menu__offset', { offset })}}</div>
|
||||
<button :class="[$style.btn, $style.titleBtn]" :disabled="offsetDisabled || !offset" @click="offsetReset">{{$t('lyric_menu__offset_reset')}}</button>
|
||||
<button :class="[$style.btn, $style.titleBtn]" :disabled="offsetDisabled || offset == originOffset" @click="offsetReset">{{$t('lyric_menu__offset_reset')}}</button>
|
||||
</div>
|
||||
<div :class="$style.subGroup">
|
||||
<button :class="$style.btn" :disabled="offsetDisabled" @click="setOffset(10)" ignore-tip :aria-label="$t('lyric_menu__offset_add_10')">+ 10ms</button>
|
||||
|
@ -59,6 +59,15 @@ const removeLyric = debounce(musicInfo => {
|
|||
removeLyricEdited(musicInfo)
|
||||
})
|
||||
|
||||
const getOffset = lrc => {
|
||||
let offset = offsetTagRxp.exec(lrc)
|
||||
if (offset) {
|
||||
offset = parseInt(offset[1])
|
||||
if (Number.isNaN(offset)) offset = 0
|
||||
} else offset = 0
|
||||
return offset
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'LyricMenu',
|
||||
props: {
|
||||
|
@ -75,6 +84,7 @@ export default {
|
|||
|
||||
const offset = ref(0)
|
||||
const offsetDisabled = ref(true)
|
||||
const originOffset = ref(0)
|
||||
|
||||
const visible = computed(() => props.modelValue)
|
||||
const musicInfo = computed(() => props.lyricInfo.musicInfo)
|
||||
|
@ -104,28 +114,35 @@ export default {
|
|||
const updateLyric = offset => {
|
||||
let lyric = props.lyricInfo.lyric
|
||||
let tlyric = props.lyricInfo.tlyric
|
||||
let rlyric = props.lyricInfo.rlyric
|
||||
let lxlyric = props.lyricInfo.lxlyric
|
||||
if (offsetTagRxp.test(lyric)) {
|
||||
lyric = lyric.replace(offsetTagAllRxp, `[offset:${offset}]`)
|
||||
if (tlyric) tlyric = tlyric.replace(offsetTagAllRxp, `[offset:${offset}]`)
|
||||
if (lxlyric) lxlyric = lxlyric.replace(offsetTagAllRxp, `[offset:${offset}]`)
|
||||
if (rlyric) rlyric = rlyric.replace(offsetTagAllRxp, `[offset:${offset}]`)
|
||||
} else {
|
||||
lyric = `[offset:${offset}]\n` + lyric
|
||||
if (tlyric) tlyric = `[offset:${offset}]\n` + tlyric
|
||||
if (lxlyric) lxlyric = `[offset:${offset}]\n` + lxlyric
|
||||
if (rlyric) rlyric = `[offset:${offset}]\n` + rlyric
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
if (offset == originOffset.value) {
|
||||
removeLyric(props.lyricInfo.musicInfo)
|
||||
} else {
|
||||
saveLyric(props.lyricInfo.musicInfo, {
|
||||
lyric,
|
||||
tlyric,
|
||||
rlyric,
|
||||
lxlyric,
|
||||
})
|
||||
} else removeLyric(props.lyricInfo.musicInfo)
|
||||
}
|
||||
|
||||
emit('updateLyric', {
|
||||
lyric,
|
||||
tlyric,
|
||||
rlyric,
|
||||
lxlyric,
|
||||
offset,
|
||||
})
|
||||
|
@ -135,25 +152,15 @@ export default {
|
|||
updateLyric(offset.value)
|
||||
}
|
||||
const offsetReset = () => {
|
||||
if (!offset.value) return
|
||||
offset.value = 0
|
||||
updateLyric(0)
|
||||
if (offset.value == originOffset.value) return
|
||||
offset.value = originOffset.value
|
||||
updateLyric(originOffset.value)
|
||||
}
|
||||
|
||||
const parseLrcOffset = () => {
|
||||
let lrcOffset
|
||||
if (props.lyricInfo.lyric) {
|
||||
lrcOffset = offsetTagRxp.exec(props.lyricInfo.lyric)
|
||||
if (lrcOffset) {
|
||||
lrcOffset = parseInt(lrcOffset[1])
|
||||
if (Number.isNaN(lrcOffset)) lrcOffset = 0
|
||||
} else lrcOffset = 0
|
||||
offsetDisabled.value = false
|
||||
} else {
|
||||
offsetDisabled.value = true
|
||||
lrcOffset = 0
|
||||
}
|
||||
offset.value = lrcOffset
|
||||
offset.value = getOffset(props.lyricInfo.lyric)
|
||||
originOffset.value = getOffset(props.lyricInfo.rawlyric)
|
||||
offsetDisabled.value = !props.lyricInfo.lyric
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,6 +184,7 @@ export default {
|
|||
menuStyles,
|
||||
playDetailSetting,
|
||||
offset,
|
||||
originOffset,
|
||||
fontSizeUp,
|
||||
fontSizeDown,
|
||||
fontSizeReset,
|
||||
|
|
|
@ -119,6 +119,7 @@ export default {
|
|||
p {
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,10 @@ div(:class="$style.songList")
|
|||
div.list-item(@click="handleListItemClick($event, index)" @contextmenu="handleListItemRightClick($event, index)"
|
||||
:class="[{ selected: rightClickSelectedIndex == index }, { active: selectedList.includes(item) }]")
|
||||
div.list-item-cell.nobreak.center(:style="{ width: rowWidth.r1 }" style="padding-left: 3px; padding-right: 3px;" :class="$style.noSelect" @click.stop) {{index + 1}}
|
||||
div.list-item-cell.auto(:style="{ width: rowWidth.r2 }" :aria-label="item.name + ((item._types.ape || item._types.flac || item._types.wav) ? ` - ${$t('tag__lossless')}` : item._types['320k'] ? ` - ${$t('tag__high_quality')}` : '')")
|
||||
div.list-item-cell.auto(:style="{ width: rowWidth.r2 }" :aria-label="item.name + (item._types.flac32bit ? ` - ${$t('tag__lossless_24bit')}` : (item._types.ape || item._types.flac || item._types.wav) ? ` - ${$t('tag__lossless')}` : item._types['320k'] ? ` - ${$t('tag__high_quality')}` : '')")
|
||||
span.select {{item.name}}
|
||||
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-if="item._types.ape || item._types.flac || item._types.wav") {{$t('tag__lossless')}}
|
||||
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-if="item._types.flac32bit") {{$t('tag__lossless_24bit')}}
|
||||
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-else-if="item._types.ape || item._types.flac || item._types.wav") {{$t('tag__lossless')}}
|
||||
span.badge.badge-theme-info(:class="[$style.labelQuality, $style.noSelect]" v-else-if="item._types['320k']") {{$t('tag__high_quality')}}
|
||||
div.list-item-cell(:style="{ width: rowWidth.r3 }" :aria-label="item.singer")
|
||||
span.select {{item.singer}}
|
||||
|
|
|
@ -6,7 +6,9 @@ export const musicInfo = window.musicInfo = reactive({
|
|||
img: null,
|
||||
lrc: null,
|
||||
tlrc: null,
|
||||
rlrc: null,
|
||||
lxlrc: null,
|
||||
rawlrc: null,
|
||||
url: null,
|
||||
name: '',
|
||||
singer: '',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { openUrl } from '@renderer/utils'
|
||||
import { openUrl, getFontSizeWithScreen } from '@renderer/utils'
|
||||
import { base as eventBaseName } from '@renderer/event/names'
|
||||
import { onSetConfig, onSystemThemeChange } from '@renderer/utils/tools'
|
||||
import { isFullscreen, themeShouldUseDarkColors } from '@renderer/core/share'
|
||||
|
@ -14,9 +14,18 @@ import {
|
|||
|
||||
const handle_key_esc_down = ({ event }) => {
|
||||
if (event.repeat) return
|
||||
if (event.target.tagName != 'INPUT' || event.target.classList.contains('ignore-esc')) return
|
||||
if (event.target.tagName != 'INPUT' || event.target.classList.contains('ignore-esc')) {
|
||||
if (isFullscreen.value) {
|
||||
event.lx_handled = true
|
||||
rendererInvoke(NAMES.mainWindow.fullscreen, false).then(fullscreen => {
|
||||
isFullscreen.value = fullscreen
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
event.target.value = ''
|
||||
event.target.blur()
|
||||
event.lx_handled = true
|
||||
}
|
||||
const handleBodyClick = event => {
|
||||
if (event.target.tagName != 'A') return
|
||||
|
@ -44,10 +53,37 @@ export default ({
|
|||
isProd,
|
||||
isLinux,
|
||||
}) => {
|
||||
const setSetting = useCommit('setSetting')
|
||||
const theme = useRefGetter('theme')
|
||||
const font = useRefGetter('font')
|
||||
const windowSizeActive = useRefGetter('windowSizeActive')
|
||||
const setSetting = useCommit('setSetting')
|
||||
const isShowAnimation = useRefGetter('isShowAnimation')
|
||||
|
||||
const dom_root = document.getElementById('root')
|
||||
|
||||
|
||||
watch(theme, (val) => {
|
||||
dom_root.className = val
|
||||
})
|
||||
watch(font, (val) => {
|
||||
document.documentElement.style.fontFamily = val
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
watch(isFullscreen, val => {
|
||||
if (val) {
|
||||
document.body.classList.remove(window.dt ? 'disableTransparent' : 'transparent')
|
||||
document.body.classList.add('fullscreen')
|
||||
document.documentElement.style.fontSize = getFontSizeWithScreen(window.screen.width) + 'px'
|
||||
} else {
|
||||
document.body.classList.remove('fullscreen')
|
||||
document.body.classList.add(window.dt ? 'disableTransparent' : 'transparent')
|
||||
document.documentElement.style.fontSize = windowSizeActive.value.fontSize
|
||||
}
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
watch(windowSizeActive, ({ fontSize }) => {
|
||||
document.documentElement.style.fontSize = fontSize
|
||||
})
|
||||
|
@ -61,6 +97,8 @@ export default ({
|
|||
document.body.classList.add('disableAnimation')
|
||||
}
|
||||
}
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
const rSetConfig = onSetConfig((event, config) => {
|
||||
|
|
|
@ -39,7 +39,7 @@ export default ({ setting }) => {
|
|||
promise: userApiRequest({
|
||||
requestKey,
|
||||
data: {
|
||||
source: source,
|
||||
source,
|
||||
action: 'musicUrl',
|
||||
info: {
|
||||
type,
|
||||
|
|
|
@ -43,11 +43,14 @@ export default ({ setting }) => {
|
|||
|
||||
const setLyric = () => {
|
||||
if (!musicInfo.songmid) return
|
||||
const extendedLyrics = []
|
||||
if (setting.value.player.isShowLyricTranslation && musicInfo.tlrc) extendedLyrics.push(musicInfo.tlrc)
|
||||
if (setting.value.player.isShowLyricRoma && musicInfo.rlrc) extendedLyrics.push(musicInfo.rlrc)
|
||||
lrc.setLyric(
|
||||
setting.value.player.isPlayLxlrc && musicInfo.lxlrc ? musicInfo.lxlrc : musicInfo.lrc,
|
||||
setting.value.player.isShowLyricTranslation && musicInfo.tlrc ? musicInfo.tlrc : '',
|
||||
extendedLyrics,
|
||||
)
|
||||
setDesktopLyricInfo('lyric', { lrc: musicInfo.lrc, tlrc: musicInfo.tlrc, lxlrc: musicInfo.lxlrc })
|
||||
setDesktopLyricInfo('lyric', { lrc: musicInfo.lrc, tlrc: musicInfo.tlrc, rlrc: musicInfo.rlrc, lxlrc: musicInfo.lxlrc })
|
||||
|
||||
if (isPlay.value && (musicInfo.url || playMusicInfo.listId == 'download')) {
|
||||
setTimeout(() => {
|
||||
|
@ -99,6 +102,7 @@ export default ({ setting }) => {
|
|||
album: musicInfo.album,
|
||||
lrc: musicInfo.lrc,
|
||||
tlrc: musicInfo.tlrc,
|
||||
rlrc: musicInfo.rlrc,
|
||||
lxlrc: musicInfo.lxlrc,
|
||||
isPlay: isPlay.value,
|
||||
line: lyric.line,
|
||||
|
|
|
@ -91,8 +91,12 @@ export default ({
|
|||
}
|
||||
|
||||
if (setting.value.player.autoSkipOnError) {
|
||||
setAllStatus(t('player__error'))
|
||||
addDelayNextTimeout()
|
||||
if (document.hidden) {
|
||||
playNext()
|
||||
} else {
|
||||
setAllStatus(t('player__error'))
|
||||
setTimeout(addDelayNextTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,21 +135,24 @@ export default ({ setting }) => {
|
|||
}
|
||||
}
|
||||
const setLrc = (targetSong) => {
|
||||
getLrc(targetSong).then(({ lyric, tlyric, lxlyric }) => {
|
||||
getLrc(targetSong).then(({ lyric, tlyric, rlyric, lxlyric, rawInfo }) => {
|
||||
if (targetSong.songmid !== musicInfo.songmid) return
|
||||
return (
|
||||
setting.value.player.isS2t
|
||||
? Promise.all([
|
||||
lyric ? langS2T(lyric) : Promise.resolve(''),
|
||||
tlyric ? langS2T(tlyric) : Promise.resolve(''),
|
||||
rlyric ? langS2T(rlyric) : Promise.resolve(''),
|
||||
lxlyric ? langS2T(lxlyric) : Promise.resolve(''),
|
||||
])
|
||||
: Promise.resolve([lyric, tlyric, lxlyric])
|
||||
).then(([lyric, tlyric, lxlyric]) => {
|
||||
: Promise.resolve([lyric, tlyric, rlyric, lxlyric])
|
||||
).then(([lyric, tlyric, rlyric, lxlyric]) => {
|
||||
setMusicInfo({
|
||||
lrc: lyric,
|
||||
tlrc: tlyric,
|
||||
rlrc: rlyric,
|
||||
lxlrc: lxlyric,
|
||||
rawlrc: rawInfo.lyric,
|
||||
})
|
||||
})
|
||||
}).catch((err) => {
|
||||
|
@ -212,7 +215,9 @@ export default ({ setting }) => {
|
|||
img: null,
|
||||
lrc: null,
|
||||
tlrc: null,
|
||||
rlrc: null,
|
||||
lxlrc: null,
|
||||
rawlrc: null,
|
||||
url: null,
|
||||
name: '',
|
||||
singer: '',
|
||||
|
@ -223,6 +228,7 @@ export default ({ setting }) => {
|
|||
// 播放音乐
|
||||
const playMusic = async() => {
|
||||
// console.log('playMusic')
|
||||
isGettingUrl = false
|
||||
setStopStatus()
|
||||
if (window.restorePlayInfo) {
|
||||
handleRestorePlay(window.restorePlayInfo)
|
||||
|
|
|
@ -32,8 +32,9 @@ export default () => {
|
|||
})
|
||||
const rOnError = onError(() => {
|
||||
// console.log('onError')
|
||||
window.eventHub.emit(player.player_error, getErrorCode())
|
||||
window.eventHub.emit(player.error)
|
||||
const errorCode = getErrorCode()
|
||||
window.eventHub.emit(player.player_error, errorCode)
|
||||
window.eventHub.emit(player.error, errorCode)
|
||||
})
|
||||
const rOnLoadeddata = onLoadeddata(() => {
|
||||
// console.log('onLoadeddata')
|
||||
|
|
|
@ -10,7 +10,7 @@ function route(path, view, name, meta, props) {
|
|||
path,
|
||||
meta,
|
||||
props,
|
||||
component: (resovle) => import(`../views/${view}.vue`).then(resovle),
|
||||
component: require(`../views/${view}.vue`).default,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ const getExt = type => {
|
|||
case 'ape':
|
||||
return 'ape'
|
||||
case 'flac':
|
||||
case 'flac32bit':
|
||||
return 'flac'
|
||||
case 'wav':
|
||||
return 'wav'
|
||||
|
@ -185,14 +186,14 @@ const getLyric = function(musicInfo, isUseOtherSource, isS2t) {
|
|||
return getLyricFromStorage(musicInfo).then(lrcInfo => {
|
||||
return (
|
||||
existTimeExp.test(lrcInfo.lyric)
|
||||
? Promise.resolve({ lyric: lrcInfo.lyric, tlyric: lrcInfo.tlyric || '' })
|
||||
? Promise.resolve({ lyric: lrcInfo.lyric, tlyric: lrcInfo.tlyric || '', rlyric: lrcInfo.rlyric || '', lxlyric: lrcInfo.lxlyric || '' })
|
||||
: (
|
||||
isUseOtherSource
|
||||
? handleGetLyric.call(this, musicInfo)
|
||||
: music[musicInfo.source].getLyric(musicInfo).promise
|
||||
).then(({ lyric, tlyric, lxlyric }) => {
|
||||
setLyric(musicInfo, { lyric, tlyric, lxlyric })
|
||||
return { lyric, tlyric, lxlyric }
|
||||
).then(({ lyric, tlyric, rlyric, lxlyric }) => {
|
||||
setLyric(musicInfo, { lyric, tlyric, rlyric, lxlyric })
|
||||
return { lyric, tlyric, rlyric, lxlyric }
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
return null
|
||||
|
@ -519,7 +520,8 @@ const actions = {
|
|||
delete dls[item.key]
|
||||
}
|
||||
commit('removeTask', item)
|
||||
if (item.status != downloadStatus.COMPLETED) {
|
||||
// 没有未完成、已下载大于1k
|
||||
if (item.status != downloadStatus.COMPLETED && item.progress.total && item.progress.downloaded > 1024) {
|
||||
try {
|
||||
await deleteFile(item.metadata.filePath)
|
||||
} catch (_) {}
|
||||
|
@ -541,7 +543,8 @@ const actions = {
|
|||
delete dls[item.key]
|
||||
}
|
||||
}
|
||||
if (item.status != downloadStatus.COMPLETED) {
|
||||
// 没有未完成、已下载大于1k
|
||||
if (item.status != downloadStatus.COMPLETED && item.progress.total && item.progress.downloaded > 1024) {
|
||||
deleteFile(item.metadata.filePath).catch(_ => _)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
getRandom,
|
||||
checkPath,
|
||||
getLyric as getStoreLyric,
|
||||
getLyricRaw as getStoreLyricRaw,
|
||||
setLyric,
|
||||
setMusicUrl,
|
||||
getMusicUrl as getStoreMusicUrl,
|
||||
|
@ -177,6 +178,14 @@ const getLyric = function(musicInfo, retryedSource = [], originMusic) {
|
|||
})
|
||||
}
|
||||
|
||||
const buildLyricInfo = async(lyricInfo, musicInfo) => {
|
||||
const lyricRawInfo = await getStoreLyricRaw(musicInfo)
|
||||
return {
|
||||
...lyricInfo,
|
||||
rawInfo: lyricRawInfo,
|
||||
}
|
||||
}
|
||||
|
||||
// getters
|
||||
const getters = {
|
||||
|
||||
|
@ -214,7 +223,7 @@ const actions = {
|
|||
},
|
||||
async getLrc({ commit, state }, musicInfo) {
|
||||
const lrcInfo = await getStoreLyric(musicInfo)
|
||||
// lrcInfo = {}
|
||||
// let lrcInfo = {}
|
||||
// if (lrcRequest && lrcRequest.cancelHttp) lrcRequest.cancelHttp()
|
||||
if (existTimeExp.test(lrcInfo.lyric) && lrcInfo.tlyric != null) {
|
||||
// if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) {
|
||||
|
@ -231,16 +240,18 @@ const actions = {
|
|||
case 'kw':
|
||||
break
|
||||
default:
|
||||
return lrcInfo
|
||||
return buildLyricInfo(lrcInfo, musicInfo)
|
||||
}
|
||||
} else return lrcInfo
|
||||
} else if (lrcInfo.rlyric == null) {
|
||||
if (musicInfo.source != 'wy') return buildLyricInfo(lrcInfo, musicInfo)
|
||||
} else return buildLyricInfo(lrcInfo, musicInfo)
|
||||
}
|
||||
|
||||
// lrcRequest = music[musicInfo.source].getLyric(musicInfo)
|
||||
return getLyric.call(this, musicInfo).then(({ lyric, tlyric, lxlyric }) => {
|
||||
return getLyric.call(this, musicInfo).then(({ lyric, tlyric, rlyric, lxlyric }) => {
|
||||
// lrcRequest = null
|
||||
commit('setLrc', { musicInfo, lyric, tlyric, lxlyric })
|
||||
return { lyric, tlyric, lxlyric }
|
||||
commit('setLrc', { musicInfo, lyric, tlyric, rlyric, lxlyric })
|
||||
return buildLyricInfo({ lyric, tlyric, rlyric, lxlyric }, musicInfo)
|
||||
}).catch(err => {
|
||||
// lrcRequest = null
|
||||
return Promise.reject(err)
|
||||
|
@ -434,6 +445,7 @@ const mutations = {
|
|||
setLyric(datas.musicInfo, {
|
||||
lyric: datas.lyric,
|
||||
tlyric: datas.tlyric,
|
||||
rlyric: datas.rlyric,
|
||||
lxlyric: datas.lxlyric,
|
||||
})
|
||||
},
|
||||
|
|
|
@ -151,6 +151,7 @@ const mutations = {
|
|||
state.text = text
|
||||
},
|
||||
setList(state, datas) {
|
||||
if (!state.text) return
|
||||
let source = state.sourceList[datas.source]
|
||||
datas.list = deduplicationList(datas.list)
|
||||
source.list = markRawList(datas.list)
|
||||
|
@ -160,6 +161,7 @@ const mutations = {
|
|||
source.limit = datas.limit
|
||||
},
|
||||
setLists(state, { results, page }) {
|
||||
if (!state.text) return
|
||||
let pages = []
|
||||
let total = 0
|
||||
let limit = 0
|
||||
|
|
|
@ -65,6 +65,8 @@ const getters = {
|
|||
},
|
||||
}
|
||||
|
||||
let loadId = null
|
||||
|
||||
// actions
|
||||
const actions = {
|
||||
getTags({ state, rootState, commit }) {
|
||||
|
@ -76,11 +78,14 @@ const actions = {
|
|||
let tabId = rootState.setting.songList.tagInfo.id
|
||||
let sortId = rootState.setting.songList.sortId
|
||||
// console.log(sortId)
|
||||
let key = `slist__${source}__${sortId}__${tabId}__${page}`
|
||||
let key = loadId = `slist__${source}__${sortId}__${tabId}__${page}`
|
||||
if (state.list.list.length && state.list.key == key) return
|
||||
if (cache.has(key)) return Promise.resolve(cache.get(key)).then(result => commit('setList', { result, key, page }))
|
||||
commit('clearList')
|
||||
return music[source]?.songList.getList(sortId, tabId, page).then(result => commit('setList', { result, key, page }))
|
||||
return music[source]?.songList.getList(sortId, tabId, page).then(result => {
|
||||
if (loadId != key) return
|
||||
commit('setList', { result, key, page })
|
||||
})
|
||||
},
|
||||
getListDetail({ state, commit }, { id, source, page, isRefresh = false }) {
|
||||
let key = `sdetail__${source}__${id}__${page}`
|
||||
|
|
|
@ -513,13 +513,14 @@ export const parseUrlParams = str => {
|
|||
}
|
||||
|
||||
export const getLyric = musicInfo => rendererInvoke(NAMES.mainWindow.get_lyric, `${musicInfo.source}_${musicInfo.songmid}`)
|
||||
export const setLyric = (musicInfo, { lyric, tlyric, lxlyric }) => rendererSend(NAMES.mainWindow.save_lyric_raw, {
|
||||
export const getLyricRaw = musicInfo => rendererInvoke(NAMES.mainWindow.get_lyric_raw, `${musicInfo.source}_${musicInfo.songmid}`)
|
||||
export const setLyric = (musicInfo, { lyric, tlyric, rlyric, lxlyric }) => rendererSend(NAMES.mainWindow.save_lyric_raw, {
|
||||
id: `${musicInfo.source}_${musicInfo.songmid}`,
|
||||
lyrics: { lyric, tlyric, lxlyric },
|
||||
lyrics: { lyric, tlyric, rlyric, lxlyric },
|
||||
})
|
||||
export const setLyricEdited = (musicInfo, { lyric, tlyric, lxlyric }) => rendererSend(NAMES.mainWindow.save_lyric_edited, {
|
||||
export const setLyricEdited = (musicInfo, { lyric, tlyric, rlyric, lxlyric }) => rendererSend(NAMES.mainWindow.save_lyric_edited, {
|
||||
id: `${musicInfo.source}_${musicInfo.songmid}`,
|
||||
lyrics: { lyric, tlyric, lxlyric },
|
||||
lyrics: { lyric, tlyric, rlyric, lxlyric },
|
||||
})
|
||||
export const removeLyricEdited = musicInfo => rendererSend(NAMES.mainWindow.remove_lyric_edited, `${musicInfo.source}_${musicInfo.songmid}`)
|
||||
|
||||
|
|
|
@ -20,14 +20,14 @@ const createAnimation = (dom, duration) => new window.Animation(new window.Keyfr
|
|||
// https://jsfiddle.net/ceqpnbky/1/
|
||||
|
||||
module.exports = class FontPlayer {
|
||||
constructor({ time = 0, lyric = '', translationLyric = '', lineClassName = '', fontClassName = '', translationClassName = '', lineModeClassName = '', shadowContent = false, shadowClassName = '' }) {
|
||||
constructor({ time = 0, lyric = '', extendedLyrics = '', lineClassName = '', fontClassName = '', extendedLrcClassName = '', lineModeClassName = '', shadowContent = false, shadowClassName = '' }) {
|
||||
this.time = time
|
||||
this.lyric = lyric
|
||||
this.translationLyric = translationLyric
|
||||
this.extendedLyrics = extendedLyrics
|
||||
|
||||
this.lineClassName = lineClassName
|
||||
this.fontClassName = fontClassName
|
||||
this.translationClassName = translationClassName
|
||||
this.extendedLrcClassName = extendedLrcClassName
|
||||
this.lineModeClassName = lineModeClassName
|
||||
this.shadowContent = shadowContent
|
||||
this.shadowClassName = shadowClassName
|
||||
|
@ -40,8 +40,8 @@ module.exports = class FontPlayer {
|
|||
|
||||
this.fontContent = null
|
||||
|
||||
this.timeoutTools = new TimeoutTools()
|
||||
this.waitPlayTimeout = new TimeoutTools()
|
||||
this.timeoutTools = new TimeoutTools(80)
|
||||
this.waitPlayTimeout = new TimeoutTools(80)
|
||||
|
||||
this._init()
|
||||
}
|
||||
|
@ -64,20 +64,20 @@ module.exports = class FontPlayer {
|
|||
this.fontContent.appendChild(this.fontShadowContent)
|
||||
}
|
||||
this.lineContent.appendChild(this.fontContent)
|
||||
if (this.translationLyric) {
|
||||
this.translationContent = document.createElement('div')
|
||||
this.translationContent.style = 'position:relative;display:inline-block;'
|
||||
this.translationContent.className = this.translationClassName
|
||||
this.translationContent.textContent = this.translationLyric
|
||||
for (const lrc of this.extendedLyrics) {
|
||||
const extendedLrcContent = document.createElement('div')
|
||||
extendedLrcContent.style = 'position:relative;display:inline-block;'
|
||||
extendedLrcContent.className = this.extendedLrcClassName
|
||||
extendedLrcContent.textContent = lrc
|
||||
this.lineContent.appendChild(document.createElement('br'))
|
||||
this.lineContent.appendChild(this.translationContent)
|
||||
this.lineContent.appendChild(extendedLrcContent)
|
||||
|
||||
if (this.shadowContent) {
|
||||
this.translationShadowContent = document.createElement('div')
|
||||
this.translationShadowContent.style = 'position:absolute;top:0;left:0;width:100%;z-index:-1;'
|
||||
this.translationShadowContent.className = this.shadowClassName
|
||||
this.translationShadowContent.textContent = this.translationLyric
|
||||
this.translationContent.appendChild(this.translationShadowContent)
|
||||
const extendedLrcShadowContent = document.createElement('div')
|
||||
extendedLrcShadowContent.style = 'position:absolute;top:0;left:0;width:100%;z-index:-1;'
|
||||
extendedLrcShadowContent.className = this.shadowClassName
|
||||
extendedLrcShadowContent.textContent = lrc
|
||||
extendedLrcContent.appendChild(extendedLrcShadowContent)
|
||||
}
|
||||
}
|
||||
this._parseLyric()
|
||||
|
|
|
@ -6,11 +6,11 @@ const fontTimeExp = /<(\d+),(\d+)>/g
|
|||
module.exports = class Lyric {
|
||||
constructor({
|
||||
lyric = '',
|
||||
translationLyric = '',
|
||||
extendedLyrics = [],
|
||||
offset = 0,
|
||||
lineClassName = '',
|
||||
fontClassName = 'font',
|
||||
translationClassName = 'translation',
|
||||
extendedLrcClassName = 'extended',
|
||||
activeLineClassName = 'active',
|
||||
lineModeClassName = 'line',
|
||||
shadowClassName = '',
|
||||
|
@ -19,14 +19,14 @@ module.exports = class Lyric {
|
|||
onSetLyric = function() { },
|
||||
}) {
|
||||
this.lyric = lyric
|
||||
this.translationLyric = translationLyric
|
||||
this.extendedLyrics = extendedLyrics
|
||||
this.offset = offset
|
||||
this.onPlay = onPlay
|
||||
this.onSetLyric = onSetLyric
|
||||
|
||||
this.lineClassName = lineClassName
|
||||
this.fontClassName = fontClassName
|
||||
this.translationClassName = translationClassName
|
||||
this.extendedLrcClassName = extendedLrcClassName
|
||||
this.activeLineClassName = activeLineClassName
|
||||
this.lineModeClassName = lineModeClassName
|
||||
this.shadowClassName = shadowClassName
|
||||
|
@ -46,7 +46,7 @@ module.exports = class Lyric {
|
|||
this.playingLineNum = -1
|
||||
this.isLineMode = false
|
||||
|
||||
this.linePlayer.setLyric(this.lyric, this.translationLyric)
|
||||
this.linePlayer.setLyric(this.lyric, this.extendedLyrics)
|
||||
}
|
||||
|
||||
_handleLinePlayerOnPlay = (num, text, curTime) => {
|
||||
|
@ -104,10 +104,10 @@ module.exports = class Lyric {
|
|||
const fontPlayer = new FontPlayer({
|
||||
time: line.time,
|
||||
lyric: line.text,
|
||||
translationLyric: line.translation,
|
||||
extendedLyrics: line.extendedLyrics,
|
||||
lineClassName: this.lineClassName,
|
||||
fontClassName: this.fontClassName,
|
||||
translationClassName: this.translationClassName,
|
||||
extendedLrcClassName: this.extendedLrcClassName,
|
||||
lineModeClassName: this.lineModeClassName,
|
||||
shadowClassName: this.shadowClassName,
|
||||
shadowContent: this.shadowContent,
|
||||
|
@ -117,7 +117,7 @@ module.exports = class Lyric {
|
|||
return {
|
||||
text: line.text,
|
||||
time: line.time,
|
||||
translation: line.translation,
|
||||
extendedLyrics: line.extendedLyrics,
|
||||
dom_line: fontPlayer.lineContent,
|
||||
}
|
||||
})
|
||||
|
@ -126,10 +126,10 @@ module.exports = class Lyric {
|
|||
const fontPlayer = new FontPlayer({
|
||||
time: line.time,
|
||||
lyric: line.text,
|
||||
translationLyric: line.translation,
|
||||
extendedLyrics: line.extendedLyrics,
|
||||
lineClassName: this.lineClassName,
|
||||
fontClassName: this.fontClassName,
|
||||
translationClassName: this.translationClassName,
|
||||
extendedLrcClassName: this.extendedLrcClassName,
|
||||
shadowClassName: this.shadowClassName,
|
||||
shadowContent: this.shadowContent,
|
||||
})
|
||||
|
@ -138,7 +138,7 @@ module.exports = class Lyric {
|
|||
return {
|
||||
text: line.text.replace(fontTimeExp, ''),
|
||||
time: line.time,
|
||||
translation: line.translation,
|
||||
extendedLyrics: line.extendedLyrics,
|
||||
dom_line: fontPlayer.lineContent,
|
||||
}
|
||||
})
|
||||
|
@ -162,9 +162,9 @@ module.exports = class Lyric {
|
|||
if (this.playingLineNum > -1) this._lineFonts[this.playingLineNum].pause()
|
||||
}
|
||||
|
||||
setLyric(lyric, translationLyric) {
|
||||
setLyric(lyric, extendedLyrics) {
|
||||
this.lyric = lyric
|
||||
this.translationLyric = translationLyric
|
||||
this.extendedLyrics = extendedLyrics
|
||||
this._init()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,26 @@ const tagRegMap = {
|
|||
|
||||
const timeoutTools = new TimeoutTools()
|
||||
|
||||
const parseExtendedLyric = (lrcLinesMap, extendedLyric) => {
|
||||
const extendedLines = extendedLyric.split(/\r\n|\n|\r/)
|
||||
for (let i = 0; i < extendedLines.length; i++) {
|
||||
const line = extendedLines[i].trim()
|
||||
let result = timeExp.exec(line)
|
||||
if (result) {
|
||||
const text = line.replace(timeExp, '').trim()
|
||||
if (text) {
|
||||
const timeStr = RegExp.$1.replace(/(\.\d\d)0$/, '$1')
|
||||
const targetLine = lrcLinesMap[timeStr]
|
||||
if (targetLine) targetLine.extendedLyrics.push(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = class LinePlayer {
|
||||
constructor({ offset = 0, onPlay = function() { }, onSetLyric = function() { } } = {}) {
|
||||
this.tags = {}
|
||||
this.lines = null
|
||||
this.translationLines = null
|
||||
this.onPlay = onPlay
|
||||
this.onSetLyric = onSetLyric
|
||||
this.isPlay = false
|
||||
|
@ -28,7 +43,7 @@ module.exports = class LinePlayer {
|
|||
|
||||
_init() {
|
||||
if (this.lyric == null) this.lyric = ''
|
||||
if (this.translationLyric == null) this.translationLyric = ''
|
||||
if (this.extendedLyrics == null) this.extendedLyrics = []
|
||||
this._initTag()
|
||||
this._initLines()
|
||||
this.onSetLyric(this.lines, this.tags.offset + this.offset)
|
||||
|
@ -50,17 +65,15 @@ module.exports = class LinePlayer {
|
|||
|
||||
_initLines() {
|
||||
this.lines = []
|
||||
this.translationLines = []
|
||||
const lines = this.lyric.split(/\r\n|\r|\n/)
|
||||
const linesMap = {}
|
||||
// const translationLines = this.translationLyric.split('\n')
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim()
|
||||
let result = timeExp.exec(line)
|
||||
if (result) {
|
||||
const text = line.replace(timeExp, '').trim()
|
||||
if (text) {
|
||||
const timeStr = RegExp.$1
|
||||
const timeStr = RegExp.$1.replace(/(\.\d\d)0$/, '$1')
|
||||
const timeArr = timeStr.split(':')
|
||||
if (timeArr.length < 3) timeArr.unshift(0)
|
||||
if (timeArr[2].indexOf('.') > -1) {
|
||||
|
@ -70,24 +83,13 @@ module.exports = class LinePlayer {
|
|||
linesMap[timeStr] = {
|
||||
time: parseInt(timeArr[0]) * 60 * 60 * 1000 + parseInt(timeArr[1]) * 60 * 1000 + parseInt(timeArr[2]) * 1000 + parseInt(timeArr[3] || 0),
|
||||
text,
|
||||
extendedLyrics: [],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const translationLines = this.translationLyric.split('\n')
|
||||
for (let i = 0; i < translationLines.length; i++) {
|
||||
const line = translationLines[i].trim()
|
||||
let result = timeExp.exec(line)
|
||||
if (result) {
|
||||
const text = line.replace(timeExp, '').trim()
|
||||
if (text) {
|
||||
const timeStr = RegExp.$1
|
||||
const targetLine = linesMap[timeStr]
|
||||
if (targetLine) targetLine.translation = text
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const lrc of this.extendedLyrics) parseExtendedLyric(linesMap, lrc)
|
||||
this.lines = Object.values(linesMap)
|
||||
this.lines.sort((a, b) => {
|
||||
return a.time - b.time
|
||||
|
@ -172,11 +174,11 @@ module.exports = class LinePlayer {
|
|||
}
|
||||
}
|
||||
|
||||
setLyric(lyric, translationLyric) {
|
||||
// console.log(translationLyric)
|
||||
setLyric(lyric, extendedLyrics) {
|
||||
// console.log(extendedLyrics)
|
||||
if (this.isPlay) this.pause()
|
||||
this.lyric = lyric
|
||||
this.translationLyric = translationLyric
|
||||
this.extendedLyrics = extendedLyrics
|
||||
this._init()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
const getNow = exports.getNow = typeof performance == 'object' && window.performance.now ? window.performance.now.bind(window.performance) : Date.now.bind(Date)
|
||||
|
||||
exports.TimeoutTools = class TimeoutTools {
|
||||
constructor() {
|
||||
constructor(thresholdTime = 200) {
|
||||
this.invokeTime = 0
|
||||
this.animationFrameId = null
|
||||
this.timeoutId = null
|
||||
this.callback = null
|
||||
this.thresholdTime = 200
|
||||
this.thresholdTime = thresholdTime
|
||||
}
|
||||
|
||||
run() {
|
||||
|
|
|
@ -79,11 +79,9 @@ export default {
|
|||
item: /data-song="({.+?})"/g,
|
||||
info: /{total[\s:]+"(\d+)", size[\s:]+"(\d+)", page[\s:]+"(\d+)"}/,
|
||||
},
|
||||
requestObj: null,
|
||||
getData(url) {
|
||||
if (this.requestObj) this.requestObj.cancelHttp()
|
||||
this.requestObj = httpFetch(url)
|
||||
return this.requestObj.promise
|
||||
const requestObj = httpFetch(url)
|
||||
return requestObj.promise
|
||||
},
|
||||
filterData(rawList) {
|
||||
// console.log(rawList)
|
||||
|
|
|
@ -5,15 +5,13 @@ import { formatPlayTime } from '../../index'
|
|||
// import { debug } from '../../utils/env'
|
||||
// import { formatSinger } from './util'
|
||||
|
||||
let searchRequest
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
|
||||
searchRequest = httpFetch(`http://tingapi.ting.baidu.com/v1/restserver/ting?from=android&version=5.6.5.6&method=baidu.ting.search.merge&format=json&query=${encodeURIComponent(str)}&page_no=${page}&page_size=${limit}&type=0&data_source=0&use_cluster=1`)
|
||||
const searchRequest = httpFetch(`http://tingapi.ting.baidu.com/v1/restserver/ting?from=android&version=5.6.5.6&method=baidu.ting.search.merge&format=json&query=${encodeURIComponent(str)}&page_no=${page}&page_size=${limit}&type=0&data_source=0&use_cluster=1`)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
handleResult(rawData) {
|
||||
|
@ -81,7 +79,7 @@ export default {
|
|||
return Promise.resolve({
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit: limit,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'bd',
|
||||
})
|
||||
|
|
|
@ -6,7 +6,6 @@ export default {
|
|||
_requestObj_tags: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listRecommend: null,
|
||||
_requestObj_listDetail: null,
|
||||
limit_list: 30,
|
||||
limit_song: 10000,
|
||||
successCode: 22000,
|
||||
|
@ -66,7 +65,7 @@ export default {
|
|||
},
|
||||
}
|
||||
let encrypted = CryptoJS.AES.encrypt(strData, key, {
|
||||
iv: iv,
|
||||
iv,
|
||||
blockSize: 16,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
format: JsonFormatter,
|
||||
|
@ -74,9 +73,9 @@ export default {
|
|||
let ciphertext = encrypted.toString().ct
|
||||
let sign = toMD5('baidu_taihe_music' + ciphertext + timestamp)
|
||||
let jsonRet = {
|
||||
timestamp: timestamp,
|
||||
timestamp,
|
||||
param: ciphertext,
|
||||
sign: sign,
|
||||
sign,
|
||||
}
|
||||
return jsonRet
|
||||
},
|
||||
|
@ -188,13 +187,12 @@ export default {
|
|||
|
||||
// 获取歌曲列表内的音乐
|
||||
getListDetail(id, page, tryNum = 0) {
|
||||
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
|
||||
this._requestObj_listDetail = httpFetch(this.getListDetailUrl(id, page))
|
||||
return this._requestObj_listDetail.promise.then(({ body }) => {
|
||||
const requestObj_listDetail = httpFetch(this.getListDetailUrl(id, page))
|
||||
return requestObj_listDetail.promise.then(({ body }) => {
|
||||
if (body.error_code !== this.successCode) return this.getListDetail(id, page, ++tryNum)
|
||||
let listData = this.filterData(body.result.songlist)
|
||||
return {
|
||||
|
|
|
@ -71,16 +71,14 @@ export default {
|
|||
listData: /global\.features = (\[.+\]);/,
|
||||
},
|
||||
_requestBoardsObj: null,
|
||||
_requestDataObj: null,
|
||||
getBoardsData() {
|
||||
if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this._requestBoardsObj = httpFetch('http://mobilecdnbj.kugou.com/api/v3/rank/list?version=9108&plat=0&showtype=2&parentid=0&apiver=6&area_code=1&withsong=1')
|
||||
return this._requestBoardsObj.promise
|
||||
},
|
||||
getData(url) {
|
||||
if (this._requestDataObj) this._requestDataObj.cancelHttp()
|
||||
this._requestDataObj = httpFetch(url)
|
||||
return this._requestDataObj.promise
|
||||
const requestDataObj = httpFetch(url)
|
||||
return requestDataObj.promise
|
||||
},
|
||||
filterData(rawList) {
|
||||
// console.log(rawList)
|
||||
|
|
|
@ -5,15 +5,13 @@ import { decodeName, formatPlayTime, sizeFormate } from '../../index'
|
|||
// import { debug } from '../../utils/env'
|
||||
// import { formatSinger } from './util'
|
||||
|
||||
let searchRequest
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
|
||||
searchRequest = httpFetch(`http://ioscdn.kugou.com/api/v3/search/song?keyword=${encodeURIComponent(str)}&page=${page}&pagesize=${limit}&showtype=10&plat=2&version=7910&tag=1&correct=1&privilege=1&sver=5`)
|
||||
const searchRequest = httpFetch(`http://ioscdn.kugou.com/api/v3/search/song?keyword=${encodeURIComponent(str)}&page=${page}&pagesize=${limit}&showtype=10&plat=2&version=7910&tag=1&correct=1&privilege=1&sver=5`)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
filterData(rawData) {
|
||||
|
|
|
@ -18,7 +18,6 @@ export default {
|
|||
_requestObj_listInfo: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listRecommend: null,
|
||||
_requestObj_listDetail: null,
|
||||
listDetailLimit: 10000,
|
||||
currentTagInfo: {
|
||||
id: undefined,
|
||||
|
@ -477,15 +476,14 @@ export default {
|
|||
}
|
||||
} else if (!link.includes('song.html')) return this.getUserListDetail3(link.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'), page)
|
||||
}
|
||||
if (this._requestObj_listDetailLink) this._requestObj_listDetailLink.cancelHttp()
|
||||
|
||||
this._requestObj_listDetailLink = httpFetch(link, {
|
||||
const requestObj_listDetailLink = httpFetch(link, {
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
|
||||
Referer: link,
|
||||
},
|
||||
})
|
||||
const { headers: { location }, statusCode, body } = await this._requestObj_listDetailLink.promise
|
||||
const { headers: { location }, statusCode, body } = await requestObj_listDetailLink.promise
|
||||
// console.log(body, location)
|
||||
if (statusCode > 400) return this.getUserListDetail(link, page, ++retryNum)
|
||||
if (location) {
|
||||
|
@ -512,7 +510,6 @@ export default {
|
|||
},
|
||||
|
||||
getListDetail(id, page, tryNum = 0) { // 获取歌曲列表内的音乐
|
||||
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
id = id.toString()
|
||||
|
@ -528,8 +525,8 @@ export default {
|
|||
|
||||
// if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
|
||||
this._requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id))
|
||||
return this._requestObj_listDetail.promise.then(({ body }) => {
|
||||
const requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id))
|
||||
return requestObj_listDetail.promise.then(({ body }) => {
|
||||
let listData = body.match(this.regExps.listData)
|
||||
let listInfo = body.match(this.regExps.listInfo)
|
||||
if (!listData) return this.getListDetail(id, page, ++tryNum)
|
||||
|
|
|
@ -3,7 +3,6 @@ import { decodeName } from '../../index'
|
|||
import { formatSinger, objStr2JSON } from './util'
|
||||
|
||||
// let requestObj_list
|
||||
let requestObj_listDetail
|
||||
export default {
|
||||
limit_list: 36,
|
||||
limit_song: 1000,
|
||||
|
@ -72,11 +71,8 @@ export default {
|
|||
return num
|
||||
},
|
||||
getAlbumListDetail(id, page, retryNum = 0) {
|
||||
if (requestObj_listDetail) {
|
||||
requestObj_listDetail.cancelHttp()
|
||||
}
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
requestObj_listDetail = httpFetch(`http://search.kuwo.cn/r.s?pn=${page - 1}&rn=${this.limit_song}&stype=albuminfo&albumid=${id}&show_copyright_off=0&encoding=utf&vipver=MUSIC_9.1.0`)
|
||||
const requestObj_listDetail = httpFetch(`http://search.kuwo.cn/r.s?pn=${page - 1}&rn=${this.limit_song}&stype=albuminfo&albumid=${id}&show_copyright_off=0&encoding=utf&vipver=MUSIC_9.1.0`)
|
||||
return requestObj_listDetail.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode !== 200) return this.getAlbumListDetail(id, page, ++retryNum)
|
||||
body = objStr2JSON(body)
|
||||
|
|
|
@ -69,16 +69,14 @@ export default {
|
|||
limit: 100,
|
||||
_requestBoardsObj: null,
|
||||
|
||||
_requestDataObj: null,
|
||||
getBoardsData() {
|
||||
if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this._requestBoardsObj = httpFetch('http://qukudata.kuwo.cn/q.k?op=query&cont=tree&node=2&pn=0&rn=1000&fmt=json&level=2')
|
||||
return this._requestBoardsObj.promise
|
||||
},
|
||||
getData(url) {
|
||||
if (this._requestDataObj) this._requestDataObj.cancelHttp()
|
||||
this._requestDataObj = httpFetch(url)
|
||||
return this._requestDataObj.promise
|
||||
const requestDataObj = httpFetch(url)
|
||||
return requestDataObj.promise
|
||||
},
|
||||
filterData(rawList) {
|
||||
// console.log(rawList)
|
||||
|
|
|
@ -93,6 +93,58 @@ const buildParams = (id, isGetLyricx) => {
|
|||
const timeExp = /^\[([\d:.]*)\]{1}/g
|
||||
const existTimeExp = /\[\d{1,2}:.*\d{1,4}\]/
|
||||
export default {
|
||||
/* sortLrcArr(arr) {
|
||||
const lrcSet = new Set()
|
||||
let lrc = []
|
||||
let lrcT = []
|
||||
let markIndex = []
|
||||
for (const item of arr) {
|
||||
if (lrcSet.has(item.time)) {
|
||||
if (lrc.length < 2) continue
|
||||
const index = lrc.findIndex(l => l.time == item.time)
|
||||
markIndex.push(index)
|
||||
if (index == lrc.length - 1) {
|
||||
lrcT.push({ ...lrc[index], time: item.time })
|
||||
lrc.push(item)
|
||||
} else {
|
||||
lrcT.push({ ...lrc[index], time: lrc[index + 1].time })
|
||||
if (item.text) {
|
||||
// const lastIndex = lrc.length - 1
|
||||
// markIndex.push(lastIndex)
|
||||
// lrcT.push({ ...lrc[lastIndex], time: lrc[lastIndex - 1].time })
|
||||
lrc.push(item)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lrc.push(item)
|
||||
lrcSet.add(item.time)
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(markIndex)
|
||||
markIndex = Array.from(new Set(markIndex))
|
||||
for (let index = markIndex.length - 1; index >= 0; index--) {
|
||||
lrc.splice(markIndex[index], 1)
|
||||
}
|
||||
|
||||
// if (lrcT.length) {
|
||||
// if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译
|
||||
// const tItem = lrc.pop()
|
||||
// tItem.time = lrc[lrc.length - 1].time
|
||||
// lrcT.push(tItem)
|
||||
// } else {
|
||||
// lrc = arr
|
||||
// lrcT = []
|
||||
// }
|
||||
// }
|
||||
|
||||
console.log(lrc, lrcT)
|
||||
|
||||
return {
|
||||
lrc,
|
||||
lrcT,
|
||||
}
|
||||
}, */
|
||||
sortLrcArr(arr) {
|
||||
const lrcSet = new Set()
|
||||
let lrc = []
|
||||
|
@ -111,15 +163,16 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
if (lrcT.length) {
|
||||
if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译
|
||||
const tItem = lrc.pop()
|
||||
tItem.time = lrc[lrc.length - 1].time
|
||||
lrcT.push(tItem)
|
||||
} else {
|
||||
lrc = arr
|
||||
lrcT = []
|
||||
}
|
||||
if (lrcT.length > lrc.length * 0.3) {
|
||||
throw new Error('failed')
|
||||
// if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译
|
||||
// const tItem = lrc.pop()
|
||||
// tItem.time = lrc[lrc.length - 1].time
|
||||
// lrcT.push(tItem)
|
||||
// } else {
|
||||
// lrc = arr
|
||||
// lrcT = []
|
||||
// }
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -9,16 +9,14 @@ export default {
|
|||
regExps: {
|
||||
mInfo: /bitrate:(\d+),format:(\w+),size:([\w.]+)/,
|
||||
},
|
||||
_musicSearchRequestObj: null,
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
// cancelFn: null,
|
||||
musicSearch(str, page, limit) {
|
||||
if (this._musicSearchRequestObj) this._musicSearchRequestObj.cancelHttp()
|
||||
this._musicSearchRequestObj = httpFetch(`http://search.kuwo.cn/r.s?client=kt&all=${encodeURIComponent(str)}&pn=${page - 1}&rn=${limit}&uid=794762570&ver=kwplayer_ar_9.2.2.1&vipver=1&show_copyright_off=1&newver=1&ft=music&cluster=0&strategy=2012&encoding=utf8&rformat=json&vermerge=1&mobi=1&issubtitle=1`)
|
||||
return this._musicSearchRequestObj.promise
|
||||
const musicSearchRequestObj = httpFetch(`http://search.kuwo.cn/r.s?client=kt&all=${encodeURIComponent(str)}&pn=${page - 1}&rn=${limit}&uid=794762570&ver=kwplayer_ar_9.2.2.1&vipver=1&show_copyright_off=1&newver=1&ft=music&cluster=0&strategy=2012&encoding=utf8&rformat=json&vermerge=1&mobi=1&issubtitle=1`)
|
||||
return musicSearchRequestObj.promise
|
||||
},
|
||||
// getImg(songId) {
|
||||
// return httpGet(`http://player.kuwo.cn/webmusic/sj/dtflagdate?flag=6&rid=MUSIC_${songId}`)
|
||||
|
|
|
@ -7,7 +7,6 @@ export default {
|
|||
_requestObj_tags: null,
|
||||
_requestObj_hotTags: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listDetail: null,
|
||||
limit_list: 36,
|
||||
limit_song: 10000,
|
||||
successCode: 200,
|
||||
|
@ -165,13 +164,10 @@ export default {
|
|||
},
|
||||
|
||||
getListDetailDigest8(id, page, tryNum = 0) {
|
||||
if (this._requestObj_listDetail) {
|
||||
this._requestObj_listDetail.cancelHttp()
|
||||
}
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
this._requestObj_listDetail = httpFetch(this.getListDetailUrl(id, page))
|
||||
return this._requestObj_listDetail.promise.then(({ body }) => {
|
||||
const requestObj = httpFetch(this.getListDetailUrl(id, page))
|
||||
return requestObj.promise.then(({ body }) => {
|
||||
if (body.result !== 'ok') return this.getListDetail(id, page, ++tryNum)
|
||||
return {
|
||||
list: this.filterListDetail(body.musiclist),
|
||||
|
@ -190,24 +186,18 @@ export default {
|
|||
})
|
||||
},
|
||||
getListDetailDigest5Info(id, tryNum = 0) {
|
||||
if (this._requestObj_listDetail) {
|
||||
this._requestObj_listDetail.cancelHttp()
|
||||
}
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_listDetail = httpFetch(`http://qukudata.kuwo.cn/q.k?op=query&cont=ninfo&node=${id}&pn=0&rn=1&fmt=json&src=mbox&level=2`)
|
||||
return this._requestObj_listDetail.promise.then(({ statusCode, body }) => {
|
||||
const requestObj = httpFetch(`http://qukudata.kuwo.cn/q.k?op=query&cont=ninfo&node=${id}&pn=0&rn=1&fmt=json&src=mbox&level=2`)
|
||||
return requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode != 200 || !body.child) return this.getListDetail(id, ++tryNum)
|
||||
// console.log(body)
|
||||
return body.child.length ? body.child[0].sourceid : null
|
||||
})
|
||||
},
|
||||
getListDetailDigest5Music(id, page, tryNum = 0) {
|
||||
if (this._requestObj_listDetail) {
|
||||
this._requestObj_listDetail.cancelHttp()
|
||||
}
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_listDetail = httpFetch(`http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}}&rn=${this.limit_song}&encode=utf-8&keyset=pl2012&identity=kuwo&pcmp4=1`)
|
||||
return this._requestObj_listDetail.promise.then(({ body }) => {
|
||||
const requestObj = httpFetch(`http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}}&rn=${this.limit_song}&encode=utf-8&keyset=pl2012&identity=kuwo&pcmp4=1`)
|
||||
return requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (body.result !== 'ok') return this.getListDetail(id, page, ++tryNum)
|
||||
return {
|
||||
|
|
|
@ -65,7 +65,6 @@ export default {
|
|||
},
|
||||
successCode: '000000',
|
||||
requestBoardsObj: null,
|
||||
requestObj: null,
|
||||
getBoardsData() {
|
||||
if (this.requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this.requestBoardsObj = httpFetch('https://app.c.nf.migu.cn/MIGUM3.0/v1.0/template/rank-list/release', {
|
||||
|
@ -79,9 +78,8 @@ export default {
|
|||
return this.requestBoardsObj.promise
|
||||
},
|
||||
getData(url) {
|
||||
if (this.requestObj) this.requestObj.cancelHttp()
|
||||
this.requestObj = httpFetch(url)
|
||||
return this.requestObj.promise
|
||||
const requestObj = httpFetch(url)
|
||||
return requestObj.promise
|
||||
},
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
|
@ -105,28 +103,28 @@ export default {
|
|||
let size
|
||||
switch (type.formatType) {
|
||||
case 'PQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'HQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'SQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'ZQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: 'flac32bit', size })
|
||||
_types.flac32bit = {
|
||||
size,
|
||||
|
|
|
@ -57,14 +57,12 @@ export default {
|
|||
},
|
||||
successCode: '000000',
|
||||
requestBoardsObj: null,
|
||||
requestObj: null,
|
||||
regExps: {
|
||||
listData: /var listData = (\{.+\})<\/script>/,
|
||||
},
|
||||
getData(url) {
|
||||
if (this.requestObj) this.requestObj.cancelHttp()
|
||||
this.requestObj = httpFetch(url)
|
||||
return this.requestObj.promise
|
||||
const requestObj = httpFetch(url)
|
||||
return requestObj.promise
|
||||
},
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
|
|
|
@ -5,15 +5,13 @@ import { sizeFormate } from '../../index'
|
|||
// import { debug } from '../../utils/env'
|
||||
// import { formatSinger } from './util'
|
||||
|
||||
let searchRequest
|
||||
export default {
|
||||
limit: 20,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
|
||||
searchRequest = httpFetch(`http://pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do?ua=Android_migu&version=5.0.1&text=${encodeURIComponent(str)}&pageNo=${page}&pageSize=${limit}&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22songlist%22%3A0%2C%22bestShow%22%3A1%7D`, {
|
||||
const searchRequest = httpFetch(`http://pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do?ua=Android_migu&version=5.0.1&text=${encodeURIComponent(str)}&pageNo=${page}&pageSize=${limit}&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22songlist%22%3A0%2C%22bestShow%22%3A1%7D`, {
|
||||
// searchRequest = httpFetch(`http://jadeite.migu.cn:7090/music_search/v2/search/searchAll?sid=4f87090d01c84984a11976b828e2b02c18946be88a6b4c47bcdc92fbd40762db&isCorrect=1&isCopyright=1&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A1%2C%22mvSong%22%3A0%2C%22bestShow%22%3A1%2C%22songlist%22%3A0%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(str)}&pageNo=${page}&sort=0`, {
|
||||
headers: {
|
||||
// sign: 'c3b7ae985e2206e97f1b2de8f88691e2',
|
||||
|
@ -49,28 +47,28 @@ export default {
|
|||
let size
|
||||
switch (type.formatType) {
|
||||
case 'PQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'HQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'SQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'ZQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: 'flac32bit', size })
|
||||
_types.flac32bit = {
|
||||
size,
|
||||
|
|
|
@ -6,9 +6,6 @@ import { sizeFormate } from '../../index'
|
|||
export default {
|
||||
_requestObj_tags: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listDetail: null,
|
||||
_requestObj_listDetailLink: null,
|
||||
_requestObj_listDetailInfo: null,
|
||||
limit_list: 10,
|
||||
limit_song: 50,
|
||||
successCode: '000000',
|
||||
|
@ -74,7 +71,6 @@ export default {
|
|||
},
|
||||
|
||||
getListDetailList(id, page, tryNum = 0) {
|
||||
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
// https://h5.nf.migu.cn/app/v4/p/share/playlist/index.html?id=184187437&channel=0146921
|
||||
|
||||
|
@ -82,8 +78,8 @@ export default {
|
|||
id = id.replace(/.*(?:\?|&)id=(\d+)(?:&.*|$)/, '$1')
|
||||
} else if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
|
||||
this._requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id, page), { headers: this.defaultHeaders })
|
||||
return this._requestObj_listDetail.promise.then(({ body }) => {
|
||||
const requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id, page), { headers: this.defaultHeaders })
|
||||
return requestObj_listDetail.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getListDetail(id, page, ++tryNum)
|
||||
// console.log(JSON.stringify(body))
|
||||
// console.log(body)
|
||||
|
@ -98,14 +94,13 @@ export default {
|
|||
},
|
||||
|
||||
getListDetailInfo(id, tryNum = 0) {
|
||||
if (this._requestObj_listDetailInfo) this._requestObj_listDetailInfo.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
if (this.cachedDetailInfo[id]) return Promise.resolve(this.cachedDetailInfo[id])
|
||||
this._requestObj_listDetailInfo = httpFetch(`https://c.musicapp.migu.cn/MIGUM3.0/resource/playlist/v2.0?playlistId=${id}`, {
|
||||
const requestObj_listDetailInfo = httpFetch(`https://c.musicapp.migu.cn/MIGUM3.0/resource/playlist/v2.0?playlistId=${id}`, {
|
||||
headers: this.defaultHeaders,
|
||||
})
|
||||
return this._requestObj_listDetailInfo.promise.then(({ body }) => {
|
||||
return requestObj_listDetailInfo.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getListDetail(id, ++tryNum)
|
||||
// console.log(JSON.stringify(body))
|
||||
// console.log(body)
|
||||
|
@ -123,15 +118,13 @@ export default {
|
|||
async getDetailUrl(link, page, retryNum = 0) {
|
||||
if (retryNum > 3) return Promise.reject(new Error('link try max num'))
|
||||
|
||||
if (this._requestObj_listDetailLink) this._requestObj_listDetailLink.cancelHttp()
|
||||
|
||||
this._requestObj_listDetailLink = httpFetch(link, {
|
||||
const requestObj_listDetailLink = httpFetch(link, {
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
|
||||
Referer: link,
|
||||
},
|
||||
})
|
||||
const { headers: { location }, statusCode } = await this._requestObj_listDetailLink.promise
|
||||
const { headers: { location }, statusCode } = await requestObj_listDetailLink.promise
|
||||
// console.log(body, location)
|
||||
if (statusCode > 400) return this.getDetailUrl(link, page, ++retryNum)
|
||||
if (location) {
|
||||
|
@ -174,28 +167,28 @@ export default {
|
|||
let size
|
||||
switch (type.formatType) {
|
||||
case 'PQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'HQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'SQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'ZQ':
|
||||
size = sizeFormate(type.size)
|
||||
size = sizeFormate(type.size ?? type.androidSize)
|
||||
types.push({ type: 'flac32bit', size })
|
||||
_types.flac32bit = {
|
||||
size,
|
||||
|
|
|
@ -86,16 +86,14 @@ export default {
|
|||
periods: {},
|
||||
periodUrl: 'https://c.y.qq.com/node/pc/wk_v15/top.html',
|
||||
_requestBoardsObj: null,
|
||||
_requestDataObj: null,
|
||||
getBoardsData() {
|
||||
if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this._requestBoardsObj = httpFetch('https://c.y.qq.com/v8/fcg-bin/fcg_myqq_toplist.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=json&uin=0&needNewCode=1&platform=h5')
|
||||
return this._requestBoardsObj.promise
|
||||
},
|
||||
getData(url) {
|
||||
if (this._requestDataObj) this._requestDataObj.cancelHttp()
|
||||
this._requestDataObj = httpFetch(url)
|
||||
return this._requestDataObj.promise
|
||||
const requestDataObj = httpFetch(url)
|
||||
return requestDataObj.promise
|
||||
},
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
|
|
|
@ -5,7 +5,6 @@ import { formatPlayTime, sizeFormate } from '../../index'
|
|||
// import { debug } from '../../utils/env'
|
||||
// import { formatSinger } from './util'
|
||||
|
||||
let searchRequest
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
|
@ -13,10 +12,9 @@ export default {
|
|||
allPage: 1,
|
||||
successCode: 0,
|
||||
musicSearch(str, page, limit, retryNum = 0) {
|
||||
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
|
||||
if (retryNum > 5) return Promise.reject(new Error('搜索失败'))
|
||||
// searchRequest = httpFetch(`https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=sizer.yqq.song_next&searchid=49252838123499591&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=${page}&n=${limit}&w=${encodeURIComponent(str)}&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0`)
|
||||
searchRequest = httpFetch(`https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&remoteplace=txt.yqq.top&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=${page}&n=${limit}&w=${encodeURIComponent(str)}&cv=4747474&ct=24&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&uin=0&hostUin=0&loginUin=0`)
|
||||
const searchRequest = httpFetch(`https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&remoteplace=txt.yqq.top&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=${page}&n=${limit}&w=${encodeURIComponent(str)}&cv=4747474&ct=24&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&uin=0&hostUin=0&loginUin=0`)
|
||||
// searchRequest = httpFetch(`http://ioscdn.kugou.com/api/v3/search/song?keyword=${encodeURIComponent(str)}&page=${page}&pagesize=${this.limit}&showtype=10&plat=2&version=7910&tag=1&correct=1&privilege=1&sver=5`)
|
||||
return searchRequest.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.musicSearch(str, page, limit, ++retryNum)
|
||||
|
|
|
@ -5,8 +5,6 @@ export default {
|
|||
_requestObj_tags: null,
|
||||
_requestObj_hotTags: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listDetail: null,
|
||||
_requestObj_listDetailLink: null,
|
||||
limit_list: 36,
|
||||
limit_song: 100000,
|
||||
successCode: 0,
|
||||
|
@ -175,11 +173,10 @@ export default {
|
|||
},
|
||||
|
||||
async handleParseId(link, retryNum = 0) {
|
||||
if (this._requestObj_listDetailLink) this._requestObj_listDetailLink.cancelHttp()
|
||||
if (retryNum > 2) return Promise.reject(new Error('link try max num'))
|
||||
|
||||
this._requestObj_listDetailLink = httpFetch(link)
|
||||
const { headers: { location }, statusCode } = await this._requestObj_listDetailLink.promise
|
||||
const requestObj_listDetailLink = httpFetch(link)
|
||||
const { headers: { location }, statusCode } = await requestObj_listDetailLink.promise
|
||||
// console.log(headers)
|
||||
if (statusCode > 400) return this.handleParseId(link, ++retryNum)
|
||||
return location == null ? link : location
|
||||
|
@ -200,18 +197,17 @@ export default {
|
|||
},
|
||||
// 获取歌曲列表内的音乐
|
||||
async getListDetail(id, tryNum = 0) {
|
||||
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
id = await this.getListId(id)
|
||||
|
||||
this._requestObj_listDetail = httpFetch(this.getListDetailUrl(id), {
|
||||
const requestObj_listDetail = httpFetch(this.getListDetailUrl(id), {
|
||||
headers: {
|
||||
Origin: 'https://y.qq.com',
|
||||
Referer: `https://y.qq.com/n/yqq/playsquare/${id}.html`,
|
||||
},
|
||||
})
|
||||
const { body } = await this._requestObj_listDetail.promise
|
||||
const { body } = await requestObj_listDetail.promise
|
||||
|
||||
if (body.code !== this.successCode) return this.getListDetail(id, ++tryNum)
|
||||
const cdlist = body.cdlist[0]
|
||||
|
|
|
@ -104,7 +104,6 @@ export default {
|
|||
list: /<textarea id="song-list-pre-data" style="display:none;">(.+?)<\/textarea>/,
|
||||
},
|
||||
_requestBoardsObj: null,
|
||||
_requestBoardsDetailObj: null,
|
||||
getBoardsData() {
|
||||
if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp()
|
||||
this._requestBoardsObj = httpFetch('https://music.163.com/weapi/toplist', {
|
||||
|
@ -114,8 +113,7 @@ export default {
|
|||
return this._requestBoardsObj.promise
|
||||
},
|
||||
getData(id) {
|
||||
if (this._requestBoardsDetailObj) this._requestBoardsDetailObj.cancelHttp()
|
||||
this._requestBoardsDetailObj = httpFetch('https://music.163.com/weapi/v3/playlist/detail', {
|
||||
const requestBoardsDetailObj = httpFetch('https://music.163.com/weapi/v3/playlist/detail', {
|
||||
method: 'post',
|
||||
form: weapi({
|
||||
id,
|
||||
|
@ -123,7 +121,7 @@ export default {
|
|||
p: 1,
|
||||
}),
|
||||
})
|
||||
return this._requestBoardsDetailObj.promise
|
||||
return requestBoardsDetailObj.promise
|
||||
},
|
||||
|
||||
filterBoardsData(rawList) {
|
||||
|
|
|
@ -34,26 +34,30 @@ import { linuxapi } from './utils/crypto'
|
|||
// return lxlyric.trim()
|
||||
// }
|
||||
|
||||
// https://github.com/Binaryify/NeteaseCloudMusicApi/pull/1523/files
|
||||
export default songmid => {
|
||||
const requestObj = httpFetch('https://music.163.com/api/linux/forward', {
|
||||
method: 'post',
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
form: linuxapi({
|
||||
method: 'POST',
|
||||
url: 'https://music.163.com/api/song/lyric',
|
||||
url: 'https://music.163.com/api/song/lyric?_nmclfl=1',
|
||||
params: {
|
||||
id: songmid,
|
||||
lv: -1,
|
||||
kv: -1,
|
||||
tv: -1,
|
||||
lv: -1,
|
||||
rv: -1,
|
||||
kv: -1,
|
||||
},
|
||||
}),
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
if (body.code !== 200 || !body?.lrc?.lyric) return Promise.reject(new Error('Get lyric failed'))
|
||||
// console.log(body)
|
||||
return {
|
||||
lyric: body.lrc.lyric,
|
||||
tlyric: body.tlyric?.lyric ?? '',
|
||||
rlyric: body.romalrc?.lyric ?? '',
|
||||
// lxlyric: parseLyric(body.klyric.lyric),
|
||||
}
|
||||
})
|
||||
|
|
|
@ -4,7 +4,6 @@ import { formatPlayTime, sizeFormate } from '../..'
|
|||
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/song_detail.js
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
singers.forEach(singer => {
|
||||
|
@ -70,10 +69,9 @@ export default {
|
|||
return list
|
||||
},
|
||||
async getList(ids = [], retryNum = 0) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
const _requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', {
|
||||
const requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
|
@ -84,7 +82,7 @@ export default {
|
|||
ids: '[' + ids.join(',') + ']',
|
||||
}),
|
||||
})
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
const { body, statusCode } = await requestObj.promise
|
||||
if (statusCode != 200 || body.code !== 200) throw new Error('获取歌曲详情失败')
|
||||
// console.log(body)
|
||||
return { source: 'wy', list: this.filterList(body) }
|
||||
|
|
|
@ -4,15 +4,13 @@ import { sizeFormate, formatPlayTime } from '../../index'
|
|||
// import musicDetailApi from './musicDetail'
|
||||
import { eapiRequest } from './utils'
|
||||
|
||||
let searchRequest
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
|
||||
searchRequest = eapiRequest('/api/cloudsearch/pc', {
|
||||
const searchRequest = eapiRequest('/api/cloudsearch/pc', {
|
||||
s: str,
|
||||
type: 1, // 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频
|
||||
limit,
|
||||
|
|
|
@ -12,8 +12,6 @@ export default {
|
|||
_requestObj_tags: null,
|
||||
_requestObj_hotTags: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listDetail: null,
|
||||
_requestObj_listDetailLink: null,
|
||||
limit_list: 30,
|
||||
limit_song: 100000,
|
||||
successCode: 200,
|
||||
|
@ -50,11 +48,10 @@ export default {
|
|||
},
|
||||
|
||||
async handleParseId(link, retryNum = 0) {
|
||||
if (this._requestObj_listDetailLink) this._requestObj_listDetailLink.cancelHttp()
|
||||
if (retryNum > 2) throw new Error('link try max num')
|
||||
|
||||
this._requestObj_listDetailLink = httpFetch(link)
|
||||
const { headers: { location }, statusCode } = await this._requestObj_listDetailLink.promise
|
||||
const requestObj_listDetailLink = httpFetch(link)
|
||||
const { headers: { location }, statusCode } = await requestObj_listDetailLink.promise
|
||||
// console.log(headers)
|
||||
if (statusCode > 400) return this.handleParseId(link, ++retryNum)
|
||||
const url = location == null ? link : location
|
||||
|
@ -83,13 +80,12 @@ export default {
|
|||
return { id, cookie }
|
||||
},
|
||||
async getListDetail(rawId, page, tryNum = 0) { // 获取歌曲列表内的音乐
|
||||
if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
const { id, cookie } = await this.getListId(rawId)
|
||||
if (cookie) this.cookie = cookie
|
||||
|
||||
this._requestObj_listDetail = httpFetch('https://music.163.com/api/linux/forward', {
|
||||
const requestObj_listDetail = httpFetch('https://music.163.com/api/linux/forward', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
|
@ -105,7 +101,7 @@ export default {
|
|||
},
|
||||
}),
|
||||
})
|
||||
const { statusCode, body } = await this._requestObj_listDetail.promise
|
||||
const { statusCode, body } = await requestObj_listDetail.promise
|
||||
if (statusCode !== 200 || body.code !== this.successCode) return this.getListDetail(id, page, ++tryNum)
|
||||
let limit = 1000
|
||||
let rangeStart = (page - 1) * limit
|
||||
|
|
|
@ -19,7 +19,7 @@ const aesDecrypt = function(cipherBuffer, mode, key, iv) {
|
|||
|
||||
const rsaEncrypt = (buffer, key) => {
|
||||
buffer = Buffer.concat([Buffer.alloc(128 - buffer.length), buffer])
|
||||
return publicEncrypt({ key: key, padding: constants.RSA_NO_PADDING }, buffer)
|
||||
return publicEncrypt({ key, padding: constants.RSA_NO_PADDING }, buffer)
|
||||
}
|
||||
|
||||
export const weapi = object => {
|
||||
|
|
|
@ -27,7 +27,7 @@ export const setAllowShowUserApiUpdateAlert = (id, enable) => {
|
|||
export const saveMyList = data => {
|
||||
rendererSend(NAMES.mainWindow.save_playlist, {
|
||||
type: 'myList',
|
||||
data: data,
|
||||
data,
|
||||
})
|
||||
}
|
||||
export const saveDownloadList = list => {
|
||||
|
|
|
@ -22,7 +22,8 @@ div(:class="$style.search")
|
|||
td.nobreak.center(style="width: 5%; padding-left: 3px; padding-right: 3px;" :class="$style.noSelect" @click.stop) {{index + 1}}
|
||||
td.break
|
||||
span.select {{item.name}}
|
||||
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-if="item._types.ape || item._types.flac || item._types.wav") {{$t('tag__lossless')}}
|
||||
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-if="item._types.flac32bit") {{$t('tag__lossless_24bit')}}
|
||||
span.badge.badge-theme-success(:class="[$style.labelQuality, $style.noSelect]" v-else-if="item._types.ape || item._types.flac || item._types.wav") {{$t('tag__lossless')}}
|
||||
span.badge.badge-theme-info(:class="[$style.labelQuality, $style.noSelect]" v-else-if="item._types['320k']") {{$t('tag__high_quality')}}
|
||||
span(:class="[$style.labelSource, $style.noSelect]" v-if="searchSourceId == 'all'") {{item.source}}
|
||||
td.break(style="width: 22%;")
|
||||
|
@ -107,6 +108,7 @@ export default {
|
|||
},
|
||||
},
|
||||
isLoading: false,
|
||||
searchId: null,
|
||||
}
|
||||
},
|
||||
beforeRouteUpdate(to, from) {
|
||||
|
@ -259,14 +261,20 @@ export default {
|
|||
this.handleSelectAllData()
|
||||
},
|
||||
handleSearch(text, page) {
|
||||
if (text === '') return this.clearList()
|
||||
const searchId = this.searchId = `${this.searchSourceId}__${page}__${text}`
|
||||
if (text === '') {
|
||||
this.isLoading = false
|
||||
return this.clearList()
|
||||
}
|
||||
this.isLoading = true
|
||||
this.search({ text, page, limit: this.listInfo.limit }).then(data => {
|
||||
if (this.searchId != searchId) return
|
||||
this.page = page
|
||||
this.$nextTick(() => {
|
||||
this.$refs.dom_scrollContent.scrollTo(0, 0)
|
||||
})
|
||||
}).finally(() => {
|
||||
if (this.searchId != searchId) return
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { useCommit, useRouter } from '@renderer/utils/vueTools'
|
||||
import { useCommit, useRouter, useI18n } from '@renderer/utils/vueTools'
|
||||
import musicSdk from '@renderer/utils/music'
|
||||
import { openUrl, clipboardWriteText } from '@renderer/utils'
|
||||
import { dialog } from '@renderer/plugins/Dialog'
|
||||
|
||||
|
||||
export default ({ props, list, setting, selectedList, removeAllSelect }) => {
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
|
||||
const listRemove = useCommit('list', 'listRemove')
|
||||
const listRemoveMultiple = useCommit('list', 'listRemoveMultiple')
|
||||
|
@ -31,8 +33,16 @@ export default ({ props, list, setting, selectedList, removeAllSelect }) => {
|
|||
clipboardWriteText(setting.value.download.fileName.replace('歌名', minfo.name).replace('歌手', minfo.singer))
|
||||
}
|
||||
|
||||
const handleRemoveMusic = (index, single) => {
|
||||
const handleRemoveMusic = async(index, single) => {
|
||||
if (selectedList.value.length && !single) {
|
||||
const confirm = await (selectedList.value.length > 1
|
||||
? dialog.confirm({
|
||||
message: t('lists__remove music_tip', { len: selectedList.value.length }),
|
||||
confirmButtonText: t('lists__remove_tip_button'),
|
||||
})
|
||||
: Promise.resolve(true)
|
||||
)
|
||||
if (!confirm) return
|
||||
listRemoveMultiple({ listId: props.listId, ids: selectedList.value.map(m => m.songmid) })
|
||||
removeAllSelect()
|
||||
} else {
|
||||
|
|
|
@ -5,6 +5,8 @@ dd
|
|||
base-checkbox(id="setting_player_save_play_time" v-model="currentStting.player.isSavePlayTime" :label="$t('setting__play_save_play_time')")
|
||||
.gap-top
|
||||
base-checkbox(id="setting_player_lyric_transition" v-model="currentStting.player.isShowLyricTranslation" :label="$t('setting__play_lyric_transition')")
|
||||
.gap-top
|
||||
base-checkbox(id="setting_player_lyric_roma" v-model="currentStting.player.isShowLyricRoma" :label="$t('setting__play_lyric_roma')")
|
||||
.gap-top
|
||||
base-checkbox(id="setting_player_auto_skip_on_error" v-model="currentStting.player.autoSkipOnError" :label="$t('setting__play_auto_skip_on_error')")
|
||||
.gap-top
|
||||
|
|
|
@ -10,6 +10,7 @@ export const currentStting = ref({
|
|||
mediaDeviceId: 'default',
|
||||
isMediaDeviceRemovedStopPlay: false,
|
||||
isShowLyricTranslation: false,
|
||||
isShowLyricRoma: false,
|
||||
isS2t: false, // 是否将歌词从简体转换为繁体
|
||||
isPlayLxlrc: true,
|
||||
isSavePlayTime: false,
|
||||
|
|
Loading…
Reference in New Issue