Merge branch 'dev'

pull/486/head
lyswhut 2021-05-19 18:21:49 +08:00
commit 5f2cbb30c2
42 changed files with 3538 additions and 4014 deletions

View File

@ -99,7 +99,9 @@ jobs:
run: npm run build:src
- name: Build Package dmg
run: npm run pack:mac:dmg
run: |
npm run publish:mac:dmg
npm run publish:mac:dmg:arm64
env:
ELECTRON_CACHE: $HOME/.cache/electron
ELECTRON_BUILDERCACHE: $HOME/.cache/electron-builder
@ -107,8 +109,15 @@ jobs:
- name: Upload Artifact dmg
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-mac_dmg
path: build/*.dmg
name: lx-music-desktop-mac-dmg
path: |
build/*.dmg
!build/*-arm64.dmg
- name: Upload Artifact dmg
uses: actions/upload-artifact@v2
with:
name: lx-music-desktop-mac-dmg-arm64
path: build/*-arm64.dmg
Linux:
name: Linux

View File

@ -77,7 +77,9 @@ jobs:
run: npm run build:src
- name: Release package
run: npm run publish:mac:dmg:always
run: |
npm run publish:mac:dmg:always
npm run publish:mac:dmg:arm64
env:
ELECTRON_CACHE: $HOME/.cache/electron
ELECTRON_BUILDERCACHE: $HOME/.cache/electron-builder

View File

@ -6,6 +6,30 @@ 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.10.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.9.0...v1.10.0) - 2021-05-19
lx music移动端已经发布了使用习惯仍跟桌面版一样不过功能、界面仍比较简单有兴趣的可以去体检一下项目地址
https://github.com/lyswhut/lx-music-mobile#readme
### 新增
- 排行榜界面添加播放、收藏整个排行榜功能,可以右击排行榜名字后,在弹出的右键菜单中使用。注:收藏、播放存在分页的排行榜时需等待操作完成后才能切换排行榜,不然会导致操作中断。
- 新增Mac arm64位dmg包的构建
### 修复
- 修复全局快捷键对桌面歌词无效的问题
- 修复快捷键设置框内的提示问题
- 修复在当前正常播放的列表中使用稍后播放功能时,播放完后稍后播放的歌曲后不会恢复原来播放位置播放的问题
- 修复kw部分歌单无法打开的问题
- 修复wy源的歌曲音质匹配问题
- 修复mg源歌单标签、排行榜歌曲列表无法加载的问题
- 修复了一个歌曲下载失败时不会跳过任务的问题
### 其他
- 更新 Electron 到 12.0.8
## [1.9.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.8.2...v1.9.0) - 2021-04-24
### 新增

37
FAQ.md
View File

@ -8,7 +8,24 @@
## 歌曲无法试听与下载
该问题解决顺序如下:
### 所有歌曲都提示 `请求异常😮,可以多试几次,若还是不行就换一首吧。。。`
尝试更换网络,如切换到移动网络,若移动网络还是不行则尝试开关下手机的飞行模式后再试,<br>
若使用家庭网络的话可尝试将光猫断电5分钟左右再通电联网后播放。
### 提示`getaddrinfo EAI_AGAIN ...`
尝试在在浏览器打开这个地址`http://ts.tempmusic.tk`浏览器显示404是正常的如果不是404那就证明所在网络无法访问接口服务器。
若网页无法打开或打开来不是404则可能是DNS的问题可以尝试以下办法
1. 将DNS改成自动获取试试改完可能需要清理下系统DNS缓存才生效
2. 手动把DNS改一下不要用360的DNS可以把DNS改成`114.114.114.114`、`8.8.8.8`改完可能需要清理下系统DNS缓存才生效
改完DNS后可能需要重启软件才生效
### 通用解决方法
尝试按以下顺序解决:
1. 尝试更新到最新版本
2. 尝试切换其他歌曲(或直接搜索该歌曲),若全部歌曲都无法试听与下载则进行下一步
@ -55,6 +72,8 @@
因此,当 win7 没有使用**AERO**主题时界面将会显示异常开启AERO的方法请自行百度`win7开启aero效果`(开启后可看到任务栏变透明)。<br>
从`0.14.0`版本起不再强制要求开启透明效果,若你实在不想开启(若非电脑配置太低,墙裂建议开启!),可通过添加运行参数`-dt`来运行程序即可,例如:`.\lx-music-desktop.exe -dt`,添加方法可自行百度“给快捷方式加参数”,该参数的作用是用来控制程序是否使用非透明窗口运行。
注:启用**AERO**主题后,若软件出现黑边框,则重启软件即可恢复正常。
对于一些完全无法正常显示界面、开启了AERO后问题仍未解决的情况请阅读下面的 **软件启动后,界面无法显示** 解决。
### Linux 下界面异常
@ -97,7 +116,7 @@
### Windows 7 系统桌面歌词显示异常
Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看下面的 **Windows 7 下界面异常(界面显示不完整)** 方法解决。
Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看上面的 **Windows 7 下界面异常** 方法解决。
### MAC OS 系统、桌面歌词有残留阴影
@ -113,25 +132,15 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看下面的
其他 Linux 系统未测试,如有异常也是意料之中,目前不打算去处理 Linux 平台的桌面歌词问题,但你可以尝试按照`Linux 下界面异常`的解决方案去解决。
## 歌曲下载失败
### 提示 `ENOENT: no such file or directory, mkdir`
## 歌曲下载失败,提示 `ENOENT: no such file or directory, mkdir`
更换下载歌曲目录即可解决(一般是设置的歌曲下载目录没有读写权限导致的)。
### 提示 `请求异常``Fail`
尝试更换网络,如切换到移动网络。
## 使用软件时导致耳机意外关机
据反馈,漫步者部分型号的耳机与本软件一起使用时将会导致耳机意外关机,
详情看:<https://github.com/lyswhut/lx-music-desktop/issues/457>
若出现该问题可尝试添加`-dhmkh`启动参数解决启动参数添加方法请自行百度“windows给应用程序加启动参数的方法”。
### 其他错误
按照前面的 "歌曲无法试听与下载" 方案解决。
若出现该问题可尝试添加`-dhmkh`启动参数解决启动参数添加方法请自行百度“windows给快捷方式添加启动参数”。
## 软件安装包说明

View File

@ -47,7 +47,7 @@
软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)<br>
软件下载请转到:[发布页面](https://github.com/lyswhut/lx-music-desktop/releases)<br>
或者到网盘下载网盘内有MAC、windows版`https://www.lanzous.com/b0bf2cfa/` 密码:`glqw`(若链接无法打开请百度:蓝奏云链接打不开)<br>
或者到网盘下载网盘内有MAC、windows版`https://www.lanzoui.com/b0bf2cfa/` 密码:`glqw`(若链接无法打开请百度:蓝奏云链接打不开)<br>
使用常见问题请转至:[常见问题](https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md)
### 源码使用方法
@ -83,7 +83,7 @@ npm run pack:linux
- `-search` 启动软件时自动在搜索框搜索指定的内容,例如:`-search="突然的自我 - 伍佰"`
- `-dha` 禁用硬件加速启动Disable Hardware Acceleration窗口显示有问题时可以尝试添加此参数启动v1.6.0起新增)
- `-dt` 以非透明模式启动Disable Transparent对于未开启AERO效果的win7系统可加此参数启动以确保界面正常显示该参数对桌面歌词无效原来的`-nt`参数已重命名为`-dt`v1.6.0起重命名)
- `-dhmkh` 禁用硬件媒体密钥处理Disable Hardware Media Key Handling此选项将禁用Chromium的Hardware Media Key Handling特性v1.8.1起新增)
- `-dhmkh` 禁用硬件媒体密钥处理Disable Hardware Media Key Handling此选项将禁用Chromium的Hardware Media Key Handling特性v1.9.0起新增)
- `-play` 启动时播放指定列表的音乐,参数说明:
- `type`:播放类型,目前固定为`songList`
- `source`:播放源,可用值为`kw/kg/tx/wy/mg/myList`,其中`kw/kg/tx/wy/mg`对应各源的在线列表,`myList`为本地列表

View File

@ -1,6 +1,6 @@
const path = require('path')
const webpack = require('webpack')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { merge } = require('webpack-merge')
@ -36,7 +36,7 @@ module.exports = merge(baseConfig, {
optimization: {
minimizer: [
new TerserPlugin(),
new OptimizeCSSAssetsPlugin({}),
new CssMinimizerPlugin(),
],
},
performance: {

View File

@ -1,6 +1,6 @@
const path = require('path')
const webpack = require('webpack')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { merge } = require('webpack-merge')
@ -36,7 +36,7 @@ module.exports = merge(baseConfig, {
optimization: {
minimizer: [
new TerserPlugin(),
new OptimizeCSSAssetsPlugin({}),
new CssMinimizerPlugin(),
],
},
performance: {

6460
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "lx-music-desktop",
"version": "1.9.0",
"version": "1.10.0",
"description": "一个免费的音乐查找助手",
"main": "./dist/electron/main.js",
"productName": "lx-music-desktop",
@ -27,8 +27,9 @@
"pack:linux:deb:armv7l": "cross-env ARCH=armv7l electron-builder -l=deb --armv7l -p never",
"pack:linux:rpm": "cross-env ARCH=x64 electron-builder -l=rpm --x64 -p never",
"pack:linux:pacman": "cross-env ARCH=x64 electron-builder -l=pacman --x64 -p never",
"pack:mac": "node build-config/pack.js && npm run pack:mac:dmg",
"pack:mac": "node build-config/pack.js && npm run pack:mac:dmg && npm run pack:mac:dmg:arm64",
"pack:mac:dmg": "cross-env electron-builder -m=dmg -p never",
"pack:mac:dmg:arm64": "cross-env electron-builder -m=dmg --arm64 -p never",
"pack:dir": "node build-config/pack.js && electron-builder --dir",
"publish": "node publish",
"publish:win:setup:always": "cross-env TARGET=Setup ARCH=x86_64 electron-builder -w=nsis --x64 --ia32 -p always",
@ -42,6 +43,7 @@
"publish:win:7z:arm64": "cross-env TARGET=green ARCH=win_arm64 electron-builder -w=7z --arm64 -p onTagOrDraft",
"publish:mac:dmg:always": "electron-builder -m=dmg -p always",
"publish:mac:dmg": "electron-builder -m=dmg -p onTagOrDraft",
"publish:mac:dmg:arm64": "electron-builder -m=dmg --arm64 -p onTagOrDraft",
"publish:linux:deb:x64:always": "cross-env ARCH=x64 electron-builder -l=deb --x64 -p always",
"publish:linux:deb:x64": "cross-env ARCH=x64 electron-builder -l=deb --x64 -p onTagOrDraft",
"publish:linux:deb:x86": "cross-env ARCH=x86 electron-builder -l=deb --ia32 -p onTagOrDraft",
@ -60,6 +62,7 @@
"build": "npm run clean:electron && npm run build:main && npm run build:renderer && npm run build:renderer-lyric",
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-formatter-friendly src",
"lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-formatter-friendly --fix src",
"dp": "cross-env ELECTRON_GET_USE_PROXY=true GLOBAL_AGENT_HTTPS_PROXY=http://localhost:1081 npm run pack",
"up": "cross-env ELECTRON_GET_USE_PROXY=true GLOBAL_AGENT_HTTPS_PROXY=http://localhost:1081 npm update"
},
"browserslist": [
@ -156,35 +159,36 @@
},
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
"devDependencies": {
"@babel/core": "^7.13.16",
"@babel/core": "^7.14.3",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-modules-umd": "^7.13.0",
"@babel/plugin-transform-runtime": "^7.13.15",
"@babel/plugin-transform-modules-umd": "^7.14.0",
"@babel/plugin-transform-runtime": "^7.14.3",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.13.15",
"@babel/preset-env": "^7.14.2",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"babel-minify-webpack-plugin": "^0.3.1",
"babel-preset-minify": "^0.5.1",
"cfonts": "^2.9.1",
"cfonts": "^2.9.2",
"chalk": "^4.1.1",
"changelog-parser": "^2.8.0",
"copy-webpack-plugin": "^8.1.1",
"core-js": "^3.11.0",
"core-js": "^3.12.1",
"cross-env": "^7.0.3",
"css-loader": "^5.2.4",
"css-minimizer-webpack-plugin": "^3.0.0",
"del": "^6.0.0",
"electron": "^9.4.4",
"electron-builder": "^22.10.5",
"electron": "^12.0.8",
"electron-builder": "^22.11.4",
"electron-debug": "^3.2.0",
"electron-devtools-installer": "^3.2.0",
"eslint": "^7.25.0",
"eslint": "^7.26.0",
"eslint-config-standard": "^14.1.1",
"eslint-formatter-friendly": "^7.0.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-html": "^6.1.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-import": "^2.23.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^4.1.0",
@ -192,13 +196,12 @@
"friendly-errors-webpack-plugin": "^1.7.0",
"html-webpack-plugin": "^5.3.1",
"less": "^4.1.1",
"less-loader": "^8.1.1",
"less-loader": "^9.0.0",
"less-plugin-clean-css": "^1.5.1",
"markdown-it": "^12.0.6",
"mini-css-extract-plugin": "^1.5.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss": "^8.2.12",
"postcss-loader": "^5.2.0",
"mini-css-extract-plugin": "^1.6.0",
"postcss": "^8.2.15",
"postcss-loader": "^5.3.0",
"postcss-pxtorem": "^6.0.0",
"pug": "^3.0.2",
"pug-loader": "^2.4.0",
@ -207,13 +210,13 @@
"rimraf": "^3.0.2",
"spinnies": "^0.5.1",
"stylus": "^0.54.8",
"stylus-loader": "^5.0.0",
"terser-webpack-plugin": "^5.1.1",
"stylus-loader": "^6.0.0",
"terser-webpack-plugin": "^5.1.2",
"url-loader": "^4.1.1",
"vue-loader": "^15.9.6",
"vue-loader": "^15.9.7",
"vue-template-compiler": "^2.6.12",
"webpack": "^5.35.1",
"webpack-cli": "^4.6.0",
"webpack": "^5.37.0",
"webpack-cli": "^4.7.0",
"webpack-dev-server": "^3.11.2",
"webpack-hot-middleware": "^2.25.0",
"webpack-merge": "^5.7.3"
@ -221,18 +224,18 @@
"dependencies": {
"crypto-js": "^4.0.0",
"dnscache": "^1.0.2",
"electron-log": "^4.3.4",
"electron-store": "^6.0.1",
"electron-updater": "^4.3.8",
"electron-log": "^4.3.5",
"electron-store": "^8.0.0",
"electron-updater": "^4.3.9",
"iconv-lite": "^0.6.2",
"image-size": "^1.0.0",
"js-htmlencode": "^0.3.0",
"lrc-file-parser": "^1.0.7",
"needle": "^2.6.0",
"node-id3": "^0.2.2",
"node-id3": "^0.2.3",
"request": "^2.88.2",
"vue": "^2.6.12",
"vue-i18n": "^8.24.3",
"vue-i18n": "^8.24.4",
"vue-router": "^3.5.1",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0"

View File

@ -1,20 +1,21 @@
lx music移动端已经发布了使用习惯仍跟桌面版一样不过功能、界面仍比较简单有兴趣的可以去体检一下项目地址
https://github.com/lyswhut/lx-music-mobile#readme
### 新增
- 新增启动参数`-dhmkh`此参数将禁用Chromium的Hardware Media Key Handling特性用于解决漫步者部分型号耳机与本程序冲突导致耳机意外关机的问题
- 新增Windows arm64位免安装版的构建
- 新增黑色皮肤“黑灯瞎火”,有关于皮肤配色的建议欢迎反馈
- 新增自动换源下载功能默认关闭当无法从歌曲的原始源下载时将尝试切换到其他源下载此功能不100%保证换源后的歌曲版本与原版一致
### 优化
- 程序启动时对数据文件做读取校验数据出现损坏时自动备份损坏的数据若出现数据读取错误的弹窗并出现我的列表丢失时可到GitHub或加群反馈
- 当设置-代理启用,但主机地址为空的时,将不再使用代理配置进行网络连接,并且在离开设置界面时自动禁用代理
- 优化歌曲自动换源匹配
- 分离歌词与歌曲列表信息的保存,以减小列表列表文件损坏的几率
- 兼容打开咪咕移动端分享的歌单链接,添加打开歌单的信息显示
- 排行榜界面添加播放、收藏整个排行榜功能,可以右击排行榜名字后,在弹出的右键菜单中使用。注:收藏、播放存在分页的排行榜时需等待操作完成后才能切换排行榜,不然会导致操作中断。
- 新增Mac arm64位dmg包的构建
### 修复
- 修复备份与恢复功能在恢复数据时某些设置不立即生效的问题
- 修正设置页“搜索设置”部分内容的缩进显示问题
- 修复正在播放“稍后播放”的歌曲时,对“稍后播放”前播放的列表进行添加、删除操作会导致切歌的问题
- 修复全局快捷键对桌面歌词无效的问题
- 修复快捷键设置框内的提示问题
- 修复在当前正常播放的列表中使用稍后播放功能时,播放完后稍后播放的歌曲后不会恢复原来播放位置播放的问题
- 修复kw部分歌单无法打开的问题
- 修复wy源的歌曲音质匹配问题
- 修复mg源歌单标签、排行榜歌曲列表无法加载的问题
- 修复了一个歌曲下载失败时不会跳过任务的问题
### 其他
- 更新 Electron 到 12.0.8

File diff suppressed because one or more lines are too long

View File

@ -28,8 +28,11 @@ require('./env')
// Is disable hardware acceleration
if (global.envParams.cmdParams.dha) app.disableHardwareAcceleration()
if (global.envParams.cmdParams.dt == null && global.envParams.cmdParams.nt != null) global.envParams.cmdParams.dt = global.envParams.cmdParams.nt
if (global.envParams.cmdParams.dhmkh) app.commandLine.appendSwitch('disable-features', 'HardwareMediaKeyHandling')
// fix linux transparent fail. https://github.com/electron/electron/issues/25153#issuecomment-843688494
if (process.platform == 'linux') app.commandLine.appendSwitch('use-gl', 'desktop')
// https://github.com/electron/electron/issues/22691
app.commandLine.appendSwitch('wm-window-animations-disabled')
@ -112,7 +115,7 @@ function createWindow() {
fullscreenable: false,
show: false,
webPreferences: {
// contextIsolation: true,
contextIsolation: false,
webSecurity: !isDev,
nodeIntegration: true,
},

View File

@ -2,7 +2,6 @@ const { common: COMMON_EVENT_NAME, winLyric: WIN_LYRIC_EVENT_NAME, hotKey: HOT_K
const { mainSend, NAMES: { winLyric: ipcWinLyricNames } } = require('../../../common/ipc')
const { desktop_lyric } = require('../../../common/hotKey')
const { getLyricWindowBounds } = require('./utils')
const { updateSetting } = require('../../utils')
let isLock = null
let isEnable = null
@ -78,5 +77,5 @@ global.lx_event.hotKey.on(HOT_KEY_EVENT_NAME.keyDown, ({ type, key }) => {
}
desktopLyricSetting[settingKey] = !desktopLyricSetting[settingKey]
updateSetting({ desktopLyric: desktopLyricSetting }, null)
global.lx_core.setAppConfig({ desktopLyric: desktopLyricSetting }, null)
})

View File

@ -109,7 +109,7 @@ const createWindow = () => {
alwaysOnTop: isAlwaysOnTop,
skipTaskbar: true,
webPreferences: {
// contextIsolation: true,
contextIsolation: false,
webSecurity: !global.isDev,
nodeIntegration: true,
},

View File

@ -202,7 +202,7 @@ svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/19
path(d='M69.148,97.826l17.7-17.651,333,334-17.7,17.652Z')
g#icon-add-2(fill='currentColor')
//- 0 0 1024 1024
//- 0 0 512 512
path(d='M256,170s-62.469-76.808-141-24C44.762,222.824,84.909,325.08,256,415c21.339-8.361,44-17,44-17,19-6.392,28.155,20.742,16,26-27.589,11.935,5.974-4.141-60,28C-35.524,313.85,43.993,149.031,95,117c86.8-65.89,162,10,162,10s58.158-60.523,140-23c104.032,58.528,64,161.9,45,196-9.152,15.154-39.559-4.159-32-16,20.34-37.888,45.522-107.349-25-150C314.919,103.92,256,170,256,170Z')
path(d='M383,368c-8.1.01-24.77-.155-40,0-15.713.16-15.282,34.964,0,35,15.1,0.035,40,0,40,0s-0.068,42.8,0,48c0.208,15.961,32.261,15.791,32-1-0.072-4.649,0-47,0-47s38.008-.031,43,0c15.732,0.046,14.947-33.98-1-34-4.884.093-42,0-42,0s-0.053-28.341,0-46c0.046-15.189-32.028-15.512-32,0C383.027,337.74,382.782,365.139,383,368Z')

View File

@ -41,7 +41,8 @@ div(:class="$style.player")
div(:class="$style.column2")
div(:class="$style.progress" v-if="!isShowPlayerDetail")
//- div(:class="[$style.progressBar, $style.progressBar1]" :style="{ transform: `scaleX(${progress || 0})` }")
div(:class="[$style.progressBar, $style.progressBar2, isActiveTransition ? $style.barTransition : '']" @transitionend="handleTransitionEnd" :style="{ transform: `scaleX(${progress || 0})`, willChange: isPlay || isActiveTransition ? 'transform' : 'auto' }")
div(:class="[$style.progressBar, $style.progressBar2, isActiveTransition ? $style.barTransition : '']"
@transitionend="handleTransitionEnd" :style="{ transform: `scaleX(${progress || 0})` }")
div(:class="$style.progressMask" @click='handleSetProgress' ref="dom_progress")
div(:class="$style.column3")
span(:class="$style.statusText") {{statusText}}
@ -604,37 +605,28 @@ export default {
if (highQuality && songInfo._types['320k'] && list && list.includes('320k')) type = '320k'
return type
},
setUrl(targetSong, isRefresh, isRetryed = false, retryedSource = [], originMusic = null) {
if (!retryedSource.includes(targetSong.source)) retryedSource.push(targetSong.source)
setUrl(targetSong, isRefresh, isRetryed = false) {
let type = this.getPlayType(this.setting.player.highQuality, targetSong)
// this.musicInfo.url = await getMusicUrl(targetSong, type)
this.status = this.statusText = this.$t('core.player.geting_url')
return this.getUrl({ musicInfo: targetSong, originMusic, type, isRefresh }).then(url => {
if ((targetSong !== this.targetSong && originMusic !== this.targetSong) || this.isPlay) return
return this.getUrl({
musicInfo: targetSong,
type,
isRefresh,
onToggleSource: () => {
this.status = this.statusText = 'Try toggle source...'
},
}).then(url => {
if (targetSong !== this.targetSong || this.isPlay) return
audio.src = this.musicInfo.url = url
}).catch(err => {
// console.log('err', err.message)
if (err.message == requestMsg.cancelRequest) return
if (!isRetryed) return this.setUrl(targetSong, isRefresh, true, retryedSource, originMusic)
if (!originMusic) originMusic = targetSong
this.status = this.statusText = 'Try toggle source...'
return this.getOtherSource(originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source) || !this.assertApiSupport(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return this.setUrl(item, isRefresh, false, retryedSource, originMusic)
}
}
this.status = this.statusText = err.message
this.addDelayNextTimeout()
return Promise.reject(err)
})
if (!isRetryed) return this.setUrl(targetSong, isRefresh, true)
this.status = this.statusText = err.message
this.addDelayNextTimeout()
return Promise.reject(err)
})
},
setImg(targetSong) {
@ -1131,7 +1123,7 @@ export default {
.progress {
width: 100%;
height: 3px;
height: 4px;
// overflow: hidden;
transition: @transition-theme;
transition-property: background-color;
@ -1164,6 +1156,7 @@ export default {
.progress-bar2 {
background-color: @color-player-progress-bar2;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
opacity: 0.8;
}
.bar-transition {

View File

@ -84,6 +84,10 @@ export default {
type: String,
default: '列表加载中...',
},
hideListsMenu: {
type: Function,
default: () => {},
},
rowWidth: {
type: Object,
default() {
@ -349,6 +353,7 @@ export default {
this.listMenu.rightClickItemIndex = index
this.listMenu.menuLocation.x = dom_td.offsetLeft + event.offsetX
this.listMenu.menuLocation.y = dom_td.offsetParent.offsetTop + dom_td.offsetTop + event.offsetY - this.$refs.dom_scrollContent.scrollTop
this.hideListsMenu()
this.$nextTick(() => {
this.listMenu.isShowItemMenu = true
})

View File

@ -46,7 +46,7 @@ material-modal(:show="version.showModal" @close="handleClose" v-if="version.newV
| 你可以去&nbsp;
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
| &nbsp;&nbsp;
strong.hover.underline(@click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')" tips="点击打开") 网盘
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
| (密码
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
| )&nbsp;下载新版本
@ -63,7 +63,7 @@ material-modal(:show="version.showModal" @close="handleClose" v-if="version.newV
| 你可以去
material-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
material-btn(min @click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')" tips="点击打开") 网盘
material-btn(min @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
| (密码
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
| )下载新版本
@ -84,7 +84,7 @@ material-modal(:show="version.showModal" @close="handleClose" v-if="version.newV
| 检查方法打开
material-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
material-btn(min @click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')" tips="点击打开") 网盘
material-btn(min @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
| (密码
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
| )查看它们的
@ -117,7 +117,7 @@ material-modal(:show="version.showModal" @close="handleClose" v-if="version.newV
| 手动更新可以去&nbsp;
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
| &nbsp;&nbsp;
strong.hover.underline(@click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')" tips="点击打开") 网盘
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
| (密码
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
| )&nbsp;下载

View File

@ -0,0 +1,4 @@
{
"play": "播放",
"collect": "收藏"
}

View File

@ -165,12 +165,12 @@ const handleGetMusicUrl = function(musicInfo, type, retryedSource = [], originMu
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source) || !assertApiSupport(musicInfo.source)) retryedSource.push(musicInfo.source)
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source)) continue
if (retryedSource.includes(item.source) || !assertApiSupport(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return handleGetMusicUrl.call(this, item, type, retryedSource, originMusic)
}
@ -460,7 +460,7 @@ const actions = {
},
onFail(response) {
if (++tryNum[downloadInfo.key] > 2) {
commit('onError', downloadInfo)
commit('onError', { downloadInfo, errorMsg: '下载失败' })
dispatch('startTask')
return
}

View File

@ -1,6 +1,7 @@
import music from '../../utils/music'
const sourceList = {}
const sources = []
const cache = new Map()
for (const source of music.sources) {
const leaderboard = music[source.id].leaderboard
if (!leaderboard || !leaderboard.getBoards) continue
@ -55,10 +56,39 @@ const actions = {
let tabId = rootState.setting.leaderboard.tabId
let [source, bangId] = tabId.split('__')
let key = `${source}${tabId}${page}`
if (state.list.length && state.key == key) return true
if (state.list.length && state.key == key) return Promise.resolve()
commit('clearList')
// return (
// cache.has(key)
// ? Promise.resolve(cache.get(key))
// : music[source].leaderboard.getList(bangId, page)
// ).then(result => commit('setList', { result, key }))
return music[source].leaderboard.getList(bangId, page).then(result => commit('setList', { result, key }))
},
getListAll({ state, rootState }, id) {
// console.log(source, id)
let [source, bangId] = id.split('__')
const loadData = (id, page) => {
let key = `${source}${id}${page}`
return cache.has(key)
? Promise.resolve(cache.get(key))
: music[source].leaderboard.getList(bangId, page).then(result => {
cache.set(key, result)
return result
})
}
return loadData(id, 1).then(result => {
if (result.total <= result.limit) return result.list
let maxPage = Math.ceil(result.total / result.limit)
const load = (loadPage = 2) => {
return loadPage == maxPage
? loadData(id, loadPage).then(result => result.list)
: loadData(id, loadPage).then(result1 => load(++loadPage).then(result2 => [...result1.list, ...result2]))
}
return load().then(result2 => [...result.list, ...result2])
})
},
}
// mitations
@ -72,6 +102,7 @@ const mutations = {
state.limit = result.limit
state.page = result.page
state.key = key
cache.set(key, result)
},
clearList(state) {
state.list = []

View File

@ -6,7 +6,8 @@ import {
getLyric as getStoreLyric,
setLyric,
setMusicUrl,
getMusicUrl,
getMusicUrl as getStoreMusicUrl,
assertApiSupport,
} from '../../utils'
// state
@ -66,6 +67,32 @@ const filterList = async({ playedList, listInfo, savePath, commit }) => {
return list
}
const getMusicUrl = function(musicInfo, type, onToggleSource, retryedSource = [], originMusic) {
// console.log(musicInfo.source)
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getMusicUrl(musicInfo, type).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
onToggleSource()
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source) || !assertApiSupport(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return getMusicUrl.call(this, item, type, onToggleSource, retryedSource, originMusic)
}
}
return Promise.reject(err)
})
})
}
const getPic = function(musicInfo, retryedSource = [], originMusic) {
// console.log(musicInfo.source)
if (!originMusic) originMusic = musicInfo
@ -163,24 +190,17 @@ const getters = {
// actions
const actions = {
async getUrl({ commit, state }, { musicInfo, originMusic, type, isRefresh }) {
if (!musicInfo._types[type]) {
// 兼容旧版酷我源搜索列表过滤128k音质的bug
if (!(musicInfo.source == 'kw' && type == '128k')) throw new Error('该歌曲没有可播放的音频')
async getUrl({ commit, state }, { musicInfo, type, isRefresh, onToggleSource = () => {} }) {
// if (!musicInfo._types[type]) {
// // 兼容旧版酷我源搜索列表过滤128k音质的bug
// if (!(musicInfo.source == 'kw' && type == '128k')) throw new Error('该歌曲没有可播放的音频')
// return Promise.reject(new Error('该歌曲没有可播放的音频'))
}
const cachedUrl = await getMusicUrl(musicInfo, type)
// // return Promise.reject(new Error('该歌曲没有可播放的音频'))
// }
const cachedUrl = await getStoreMusicUrl(musicInfo, type)
if (cachedUrl && !isRefresh) return cachedUrl
let reqPromise
try {
reqPromise = music[musicInfo.source].getMusicUrl(musicInfo, type).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.then(({ url }) => {
if (originMusic) commit('setUrl', { musicInfo: originMusic, url, type })
return getMusicUrl.call(this, musicInfo, type, onToggleSource).then(({ url }) => {
commit('setUrl', { musicInfo, url, type })
return url
}).catch(err => {
@ -412,7 +432,7 @@ const mutations = {
playIndex = -1
} else {
let listId = playMusicInfo.listId
if (listId != '__temp__' && listId === state.listInfo.id) playIndex = state.listInfo.list.indexOf(playMusicInfo.musicInfo)
if (listId != '__temp__' && !playMusicInfo.isTempPlay && listId === state.listInfo.id) playIndex = state.listInfo.list.indexOf(playMusicInfo.musicInfo)
}
state.playMusicInfo = playMusicInfo

View File

@ -105,10 +105,10 @@ const actions = {
if (result.total <= result.limit) return filterList(result.list)
let maxPage = Math.ceil(result.total / result.limit)
const loadDetail = (loadPage = 1) => {
const loadDetail = (loadPage = 2) => {
return loadPage == maxPage
? loadData(id, ++loadPage).then(result => result.list)
: loadData(id, ++loadPage).then(result1 => loadDetail(loadPage).then(result2 => [...result1.list, ...result2]))
? loadData(id, loadPage).then(result => result.list)
: loadData(id, loadPage).then(result1 => loadDetail(++loadPage).then(result2 => [...result1.list, ...result2]))
}
return loadDetail().then(result2 => [...result.list, ...result2]).then(list => filterList(list))
})

View File

@ -1,4 +1,4 @@
import { httpGet, cancelHttp, httpFetch } from '../../request'
import { httpFetch } from '../../request'
import { decodeName, formatPlayTime, sizeFormate } from '../../index'
let boardList = [{ id: 'kg__8888', name: '酷狗TOP500', bangid: '8888' }, { id: 'kg__6666', name: '酷狗飙升榜', bangid: '6666' }, { id: 'kg__37361', name: '酷狗雷达榜', bangid: '37361' }, { id: 'kg__23784', name: '网络红歌榜', bangid: '23784' }, { id: 'kg__24971', name: 'DJ热歌榜', bangid: '24971' }, { id: 'kg__35811', name: '会员专享热歌榜', bangid: '35811' }, { id: 'kg__31308', name: '华语新歌榜', bangid: '31308' }, { id: 'kg__31310', name: '欧美新歌榜', bangid: '31310' }, { id: 'kg__31311', name: '韩国新歌榜', bangid: '31311' }, { id: 'kg__31312', name: '日本新歌榜', bangid: '31312' }, { id: 'kg__31313', name: '粤语新歌榜', bangid: '31313' }, { id: 'kg__33162', name: 'ACG新歌榜', bangid: '33162' }, { id: 'kg__21101', name: '酷狗分享榜', bangid: '21101' }, { id: 'kg__30972', name: '腾讯音乐人原创榜', bangid: '30972' }, { id: 'kg__22603', name: '5sing音乐榜', bangid: '22603' }, { id: 'kg__33160', name: '电音热歌榜', bangid: '33160' }, { id: 'kg__21335', name: '繁星音乐榜', bangid: '21335' }, { id: 'kg__33161', name: '古风新歌榜', bangid: '33161' }, { id: 'kg__33163', name: '影视金曲榜', bangid: '33163' }, { id: 'kg__33166', name: '欧美金曲榜', bangid: '33166' }, { id: 'kg__33165', name: '粤语金曲榜', bangid: '33165' }, { id: 'kg__36107', name: '小语种热歌榜', bangid: '36107' }, { id: 'kg__4681', name: '美国BillBoard榜', bangid: '4681' }, { id: 'kg__4680', name: '英国单曲榜', bangid: '4680' }, { id: 'kg__4673', name: '日本公信榜', bangid: '4673' }, { id: 'kg__38623', name: '韩国Melon音乐榜', bangid: '38623' }, { id: 'kg__42807', name: 'joox本地热歌榜', bangid: '42807' }, { id: 'kg__42808', name: '台湾KKBOX风云榜', bangid: '42808' }]
@ -71,30 +71,16 @@ export default {
listData: /global\.features = (\[.+\]);/,
},
_requestBoardsObj: null,
_requestObj: null,
_cancelPromiseCancelFn: 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._requestObj != null) {
cancelHttp(this._requestObj)
this._cancelPromiseCancelFn(new Error('取消http请求'))
}
return new Promise((resolve, reject) => {
this._cancelPromiseCancelFn = reject
this._requestObj = httpGet(url, (err, resp, body) => {
this._requestObj = null
this._cancelPromiseCancelFn = null
if (err) {
console.log(err)
reject(err)
}
resolve(body)
})
})
if (this._requestDataObj) this._requestDataObj.cancelHttp()
this._requestDataObj = httpFetch(url)
return this._requestDataObj.promise
},
filterData(rawList) {
// console.log(rawList)
@ -189,7 +175,7 @@ export default {
}
},
getList(bangid, page) {
return this.getData(this.getUrl(page, bangid)).then(html => {
return this.getData(this.getUrl(page, bangid)).then(({ body: html }) => {
let total = html.match(this.regExps.total)
if (total) total = parseInt(RegExp.$1)
page = html.match(this.regExps.page)

View File

@ -0,0 +1,101 @@
import { httpFetch } from '../../request'
import { decodeName } from '../../index'
import { formatSinger, objStr2JSON } from './util'
// let requestObj_list
let requestObj_listDetail
export default {
limit_list: 36,
limit_song: 1000,
filterListDetail(rawList, albumName, albumId) {
// console.log(rawList)
// console.log(rawList.length, rawList2.length)
return rawList.map((item, inedx) => {
let formats = item.formats.split('|')
let types = []
let _types = {}
if (formats.includes('MP3128')) {
types.push({ type: '128k', size: null })
_types['128k'] = {
size: null,
}
}
// if (formats.includes('MP3192')) {
// types.push({ type: '192k', size: null })
// _types['192k'] = {
// size: null,
// }
// }
if (formats.includes('MP3H')) {
types.push({ type: '320k', size: null })
_types['320k'] = {
size: null,
}
}
// if (formats.includes('AL')) {
// types.push({ type: 'ape', size: null })
// _types.ape = {
// size: null,
// }
// }
if (formats.includes('ALFLAC')) {
types.push({ type: 'flac', size: null })
_types.flac = {
size: null,
}
}
// types.reverse()
return {
singer: formatSinger(decodeName(item.artist)),
name: decodeName(item.name),
albumName,
albumId,
songmid: item.id,
source: 'kw',
interval: null,
img: item.pic,
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},
}
})
},
/**
* 格式化播放数量
* @param {*} num
*/
formatPlayCount(num) {
if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿'
if (num > 10000) return parseInt(num / 1000) / 10 + '万'
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`)
return requestObj_listDetail.promise.then(({ statusCode, body }) => {
if (statusCode !== 200) return this.getAlbumListDetail(id, page, ++retryNum)
body = objStr2JSON(body)
// console.log(body)
if (!body.musiclist) return this.getAlbumListDetail(id, page, ++retryNum)
return {
list: this.filterListDetail(body.musiclist, body.name, body.albumid),
page,
limit: this.limit_song,
total: parseInt(body.songnum),
source: 'kw',
info: {
name: body.name,
img: body.img || body.hts_img,
desc: body.info,
author: body.artist,
// play_count: this.formatPlayCount(body.playnum),
},
}
})
},
}

View File

@ -1,4 +1,4 @@
import { httpGet, cancelHttp } from '../../request'
import { httpFetch } from '../../request'
import tempSearch from './tempSearch'
import musicSearch from './musicSearch'
import { formatSinger, getToken } from './util'
@ -64,21 +64,10 @@ const kw = {
},
getMusicInfo(songInfo) {
if (this._musicInfoRequestObj != null) {
cancelHttp(this._musicInfoRequestObj)
this._musicInfoPromiseCancelFn(new Error('取消http请求'))
}
return new Promise((resolve, reject) => {
this._musicInfoPromiseCancelFn = reject
this._musicInfoRequestObj = httpGet(`http://www.kuwo.cn/api/www/music/musicInfo?mid=${songInfo.songmid}`, (err, resp, body) => {
this._musicInfoRequestObj = null
this._musicInfoPromiseCancelFn = null
if (err) {
console.log(err)
reject(err)
}
body.code === 200 ? resolve(body.data) : reject(new Error(body.msg))
})
if (this._musicInfoRequestObj) this._musicInfoRequestObj.cancelHttp()
this._musicInfoRequestObj = httpFetch(`http://www.kuwo.cn/api/www/music/musicInfo?mid=${songInfo.songmid}`)
return this._musicInfoRequestObj.promise.then(({ body }) => {
return body.code === 200 ? body.data : Promise.reject(new Error(body.msg))
})
},

View File

@ -1,4 +1,4 @@
import { httpGet, cancelHttp, httpFetch } from '../../request'
import { httpFetch } from '../../request'
import { formatPlayTime, decodeName } from '../../index'
import { formatSinger } from './util'
@ -69,30 +69,16 @@ export default {
limit: 100,
_requestBoardsObj: null,
_cancelRequestObj: null,
_cancelPromiseCancelFn: 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._cancelRequestObj != null) {
cancelHttp(this._cancelRequestObj)
this._cancelPromiseCancelFn(new Error('取消http请求'))
}
return new Promise((resolve, reject) => {
this._cancelPromiseCancelFn = reject
this._cancelRequestObj = httpGet(url, (err, resp) => {
this._cancelRequestObj = null
this._cancelPromiseCancelFn = null
if (err) {
console.log(err)
reject(err)
}
resolve(resp)
})
})
if (this._requestDataObj) this._requestDataObj.cancelHttp()
this._requestDataObj = httpFetch(url)
return this._requestDataObj.promise
},
filterData(rawList) {
// console.log(rawList)

View File

@ -1,6 +1,6 @@
// import '../../polyfill/array.find'
// import jshtmlencode from 'js-htmlencode'
import { httpGet, cancelHttp } from '../../request'
import { httpFetch } from '../../request'
import { formatPlayTime, decodeName } from '../../index'
// import { debug } from '../../utils/env'
import { formatSinger } from './util'
@ -10,29 +10,15 @@ export default {
mInfo: /bitrate:(\d+),format:(\w+),size:([\w.]+)/,
},
_musicSearchRequestObj: null,
_musicSearchPromiseCancelFn: null,
limit: 30,
total: 0,
page: 0,
allPage: 1,
// cancelFn: null,
musicSearch(str, page, limit) {
if (this._musicSearchRequestObj != null) {
cancelHttp(this._musicSearchRequestObj)
this._musicSearchPromiseCancelFn(new Error('取消http请求'))
}
return new Promise((resolve, reject) => {
this._musicSearchPromiseCancelFn = reject
this._musicSearchRequestObj = httpGet(`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`, (err, resp, body) => {
this._musicSearchRequestObj = null
this._musicSearchPromiseCancelFn = null
if (err) {
console.log(err)
reject(err)
}
resolve(body)
})
})
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
},
// getImg(songId) {
// return httpGet(`http://player.kuwo.cn/webmusic/sj/dtflagdate?flag=6&rid=MUSIC_${songId}`)
@ -127,7 +113,7 @@ export default {
if (retryNum > 2) return Promise.reject(new Error('try max num'))
if (limit == null) limit = this.limit
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
return this.musicSearch(str, page, limit).then(result => {
return this.musicSearch(str, page, limit).then(({ body: result }) => {
// console.log(result)
if (!result || (result.TOTAL !== '0' && result.SHOW === '0')) return this.search(str, page, { limit }, ++retryNum)
let list = this.handleResult(result.abslist)

View File

@ -1,6 +1,7 @@
import { httpFetch } from '../../request'
import { formatPlayTime, decodeName } from '../../index'
import { formatSinger } from './util'
import album from './album'
export default {
_requestObj_tags: null,
@ -133,7 +134,7 @@ export default {
filterList(rawData) {
return rawData.map(item => ({
play_count: this.formatPlayCount(item.listencnt),
id: item.id,
id: `digest-${item.digest}__${item.id}`,
author: item.uname,
name: item.name,
// time: item.publish_time,
@ -144,32 +145,31 @@ export default {
}))
},
filterList2(rawData) {
// console.log(rawData)
const list = []
rawData.forEach(item => {
if (!item.label) return
list.push(...item.list.map(item => ({
play_count: item.play_count === undefined ? null : this.formatPlayCount(item.listencnt),
id: item.id,
play_count: item.play_count && this.formatPlayCount(item.listencnt),
id: `digest-${item.digest}__${item.id}`,
author: item.uname,
name: item.name,
// time: item.publish_time,
img: item.img,
grade: item.favorcnt / 10,
grade: item.favorcnt && item.favorcnt / 10,
desc: item.desc,
source: 'kw',
})))
})
return list
},
// 获取歌曲列表内的音乐
getListDetail(id, page, tryNum = 0) {
getListDetailDigest8(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 }) => {
if (body.result !== 'ok') return this.getListDetail(id, page, ++tryNum)
@ -189,6 +189,66 @@ 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 }) => {
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 }) => {
// console.log(body)
if (body.result !== 'ok') return this.getListDetail(id, page, ++tryNum)
return {
list: this.filterListDetail(body.musiclist),
page,
limit: body.rn,
total: body.total,
source: 'kw',
info: {
name: body.title,
img: body.pic,
desc: body.info,
author: body.uname,
play_count: this.formatPlayCount(body.playnum),
},
}
})
},
async getListDetailDigest5(id, page) {
const detailId = await this.getListDetailDigest5Info(id)
return this.getListDetailDigest5Music(detailId, page)
},
// 获取歌曲列表内的音乐
getListDetail(id, page) {
// console.log(id)
if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
else if (/^digest-/.test(id)) {
let [digest, _id] = id.split('__')
digest = digest.replace('digest-', '')
id = _id
switch (digest) {
case '8':
break
case '13': return album.getAlbumListDetail(id, page)
case '5':
default: return this.getListDetailDigest5(id, page)
}
}
return this.getListDetailDigest8(id, page)
},
filterListDetail(rawData) {
// console.log(rawData)
return rawData.map(item => {

View File

@ -1,6 +1,6 @@
import { httpFetch } from '../../request'
// import { httpFetch } from '../../request'
import { decodeName } from '../../index'
import { getToken, matchToken } from './util'
import { tokenRequest } from './util'
export default {
@ -8,18 +8,11 @@ export default {
relWord: /RELWORD=(.+)/,
},
requestObj: null,
tempSearch(str, token) {
async tempSearch(str) {
this.cancelTempSearch()
this.requestObj = httpFetch(`http://www.kuwo.cn/api/www/search/searchKey?key=${encodeURIComponent(str)}`, {
headers: {
Referer: 'http://www.kuwo.cn/',
csrf: token,
cookie: 'kw_token=' + token,
},
})
return this.requestObj.promise.then(({ statusCode, body, headers }) => {
if (statusCode != 200) return Promise.reject(new Error('请求失败'))
window.kw_token.token = matchToken(headers)
this.requestObj = await tokenRequest(`http://www.kuwo.cn/api/www/search/searchKey?key=${encodeURIComponent(str)}`)
return this.requestObj.promise.then(({ body }) => {
// console.log(body)
if (body.code !== 200) return Promise.reject(new Error('请求失败'))
return body
})
@ -34,8 +27,6 @@ export default {
if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp()
},
async search(str) {
let token = window.kw_token.token
if (!token) token = await getToken()
return this.tempSearch(str, token).then(result => this.handleResult(result.data))
return this.tempSearch(str).then(result => this.handleResult(result.data))
},
}

View File

@ -1,11 +1,29 @@
import { httpGet } from '../../request'
import { httpGet, httpFetch } from '../../request'
import { rendererInvoke, NAMES } from '../../../../common/ipc'
if (!window.kw_token) {
window.kw_token = {
token: null,
isGetingToken: false,
}
const kw_token = {
token: null,
isGetingToken: false,
}
const translationMap = {
"{'": '{"',
"'}\n": '"}',
"'}": '"}',
"':'": '":"',
"','": '","',
"':{'": '":{"',
"':['": '":["',
"'}],'": '"}],"',
"':[{'": '":[{"',
"'},'": '"},"',
"'},{'": '"},{"',
"':[],'": '":[],"',
"':{},'": '":{},"',
}
export const objStr2JSON = str => {
return JSON.parse(str.replace(/(^{'|'}\n$|'}$|':'|','|':\[{'|'}\],'|':{'|'},'|'},{'|':\['|':\[\],'|':{},')/g, s => translationMap[s]))
}
export const formatSinger = rawData => rawData.replace(/&/g, '、')
@ -21,17 +39,40 @@ export const matchToken = headers => {
const wait = time => new Promise(resolve => setTimeout(() => resolve(), time))
export const getToken = () => new Promise((resolve, reject) => {
if (window.kw_token.isGetingToken) return wait(1000).then(() => getToken().then(token => resolve(token)))
if (window.kw_token.token) return resolve(window.kw_token.token)
window.kw_token.isGetingToken = true
export const getToken = (retryNum = 0) => new Promise((resolve, reject) => {
if (retryNum > 2) return Promise.reject(new Error('try max num'))
if (kw_token.isGetingToken) return wait(1000).then(() => getToken(retryNum).then(token => resolve(token)))
if (kw_token.token) return resolve(kw_token.token)
kw_token.isGetingToken = true
httpGet('http://www.kuwo.cn/', (err, resp) => {
window.kw_token.isGetingToken = false
if (err) return reject(err)
kw_token.isGetingToken = false
if (err) return getToken(++retryNum)
if (resp.statusCode != 200) return reject(new Error('获取失败'))
const token = window.kw_token.token = matchToken(resp.headers)
const token = kw_token.token = matchToken(resp.headers)
resolve(token)
})
})
export const decodeLyric = base64Data => rendererInvoke(NAMES.mainWindow.handle_kw_decode_lyric, base64Data)
export const tokenRequest = async(url, options = {}) => {
let token = kw_token.token
if (!token) token = await getToken()
if (!options.headers) {
options.headers = {
Referer: 'http://www.kuwo.cn/',
csrf: token,
cookie: 'kw_token=' + token,
}
}
const requestObj = httpFetch(url, options)
requestObj.promise = requestObj.promise.then(resp => {
// console.log(resp)
if (resp.statusCode == 200) {
kw_token.token = matchToken(resp.headers)
}
return resp
})
return requestObj
}

View File

@ -1,5 +1,5 @@
import { apis } from '../api-source'
import leaderboard from './leaderboard'
import leaderboard from './leaderboard2'
import songList from './songList'
import musicSearch from './musicSearch'
import pic from './pic'

View File

@ -0,0 +1,197 @@
import { httpFetch } from '../../request'
import { formatPlayTime } from '../../index'
// import { sizeFormate } from '../../index'
// import jshtmlencode from 'js-htmlencode'
// const boardList = [{ id: 'mg__27553319', name: '咪咕尖叫新歌榜', bangid: '27553319' }, { id: 'mg__27186466', name: '咪咕尖叫热歌榜', bangid: '27186466' }, { id: 'mg__27553408', name: '咪咕尖叫原创榜', bangid: '27553408' }, { id: 'mg__23189800', name: '咪咕港台榜', bangid: '23189800' }, { id: 'mg__23189399', name: '咪咕内地榜', bangid: '23189399' }, { id: 'mg__19190036', name: '咪咕欧美榜', bangid: '19190036' }, { id: 'mg__23189813', name: '咪咕日韩榜', bangid: '23189813' }, { id: 'mg__23190126', name: '咪咕彩铃榜', bangid: '23190126' }, { id: 'mg__15140045', name: '咪咕KTV榜', bangid: '15140045' }, { id: 'mg__15140034', name: '咪咕网络榜', bangid: '15140034' }, { id: 'mg__23217754', name: 'MV榜', bangid: '23217754' }, { id: 'mg__23218151', name: '新专辑榜', bangid: '23218151' }, { id: 'mg__21958042', name: 'iTunes榜', bangid: '21958042' }, { id: 'mg__21975570', name: 'billboard榜', bangid: '21975570' }, { id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815' }, { id: 'mg__22272904', name: '中国TOP排行榜', bangid: '22272904' }, { id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943' }, { id: 'mg__22273437', name: '英国UK榜', bangid: '22273437' }]
const boardList = [
{ id: 'mg__27553319', name: '尖叫新歌榜', bangid: '27553319', webId: 'jianjiao_newsong' },
{ id: 'mg__27186466', name: '尖叫热歌榜', bangid: '27186466', webId: 'jianjiao_hotsong' },
{ id: 'mg__27553408', name: '尖叫原创榜', bangid: '27553408', webId: 'jianjiao_original' },
{ id: 'mg__migumusic', name: '音乐榜', bangid: 'migumusic', webId: 'migumusic' },
{ id: 'mg__movies', name: '影视榜', bangid: 'movies', webId: 'movies' },
{ id: 'mg__23189800', name: '港台榜', bangid: '23189800', webId: 'hktw' },
{ id: 'mg__23189399', name: '内地榜', bangid: '23189399', webId: 'mainland' },
{ id: 'mg__19190036', name: '欧美榜', bangid: '19190036', webId: 'eur_usa' },
{ id: 'mg__23189813', name: '日韩榜', bangid: '23189813', webId: 'jpn_kor' },
{ id: 'mg__23190126', name: '彩铃榜', bangid: '23190126', webId: 'coloring' },
{ id: 'mg__15140045', name: 'KTV榜', bangid: '15140045', webId: 'ktv' },
{ id: 'mg__15140034', name: '网络榜', bangid: '15140034', webId: 'network' },
{ id: 'mg__23217754', name: 'MV榜', bangid: '23217754', webId: 'mv' },
{ id: 'mg__23218151', name: '新专辑榜', bangid: '23218151', webId: 'newalbum' },
{ id: 'mg__21958042', name: '美国iTunes榜', bangid: '21958042', webId: 'itunes' },
{ id: 'mg__21975570', name: '美国billboard榜', bangid: '21975570', webId: 'billboard' },
{ id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815', webId: 'hito' },
{ id: 'mg__22272904', name: '中国TOP排行榜', bangid: '22272904' },
{ id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943', webId: 'mnet' },
{ id: 'mg__22273437', name: '英国UK榜', bangid: '22273437', webId: 'uk' },
]
// const boardList = [
// { id: 'mg__jianjiao_newsong', bangid: 'jianjiao_newsong', name: '尖叫新歌榜' },
// { id: 'mg__jianjiao_hotsong', bangid: 'jianjiao_hotsong', name: '尖叫热歌榜' },
// { id: 'mg__jianjiao_original', bangid: 'jianjiao_original', name: '尖叫原创榜' },
// { id: 'mg__migumusic', bangid: 'migumusic', name: '音乐榜' },
// { id: 'mg__movies', bangid: 'movies', name: '影视榜' },
// { id: 'mg__mainland', bangid: 'mainland', name: '内地榜' },
// { id: 'mg__hktw', bangid: 'hktw', name: '港台榜' },
// { id: 'mg__eur_usa', bangid: 'eur_usa', name: '欧美榜' },
// { id: 'mg__jpn_kor', bangid: 'jpn_kor', name: '日韩榜' },
// { id: 'mg__coloring', bangid: 'coloring', name: '彩铃榜' },
// { id: 'mg__ktv', bangid: 'ktv', name: 'KTV榜' },
// { id: 'mg__network', bangid: 'network', name: '网络榜' },
// { id: 'mg__newalbum', bangid: 'newalbum', name: '新专辑榜' },
// { id: 'mg__mv', bangid: 'mv', name: 'MV榜' },
// { id: 'mg__itunes', bangid: 'itunes', name: '美国iTunes榜' },
// { id: 'mg__billboard', bangid: 'billboard', name: '美国billboard榜' },
// { id: 'mg__hito', bangid: 'hito', name: 'Hito中文榜' },
// { id: 'mg__mnet', bangid: 'mnet', name: '韩国Melon榜' },
// { id: 'mg__uk', bangid: 'uk', name: '英国UK榜' },
// ]
export default {
limit: 10000,
getUrl(id, page) {
const targetBoard = boardList.find(board => board.bangid == id)
return `https://music.migu.cn/v3/music/top/${targetBoard.webId}`
// return `http://m.music.migu.cn/migu/remoting/cms_list_tag?nid=${id}&pageSize=${this.limit}&pageNo=${page - 1}`
},
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
},
getSinger(singers) {
let arr = []
singers.forEach(singer => {
arr.push(singer.name)
})
return arr.join('、')
},
getIntv(interval) {
let intvArr = interval.split(':')
let intv = 0
let unit = 1
while (intvArr.length) {
intv += (intvArr.pop()) * unit
unit *= 60
}
return parseInt(intv)
},
formateIntv() {
},
filterData(rawData) {
// console.log(JSON.stringify(rawData))
// console.log(rawData)
let ids = new Set()
const list = []
rawData.forEach(item => {
if (ids.has(item.copyrightId)) return
ids.add(item.copyrightId)
const types = []
const _types = {}
const size = null
types.push({ type: '128k', size })
_types['128k'] = { size }
if (item.hq) {
const size = null
types.push({ type: '320k', size })
_types['320k'] = { size }
}
if (item.sq) {
const size = null
types.push({ type: 'flac', size })
_types.flac = { size }
}
list.push({
singer: this.getSinger(item.singers),
name: item.name,
albumName: item.album && item.album.albumName,
albumId: item.album && item.album.albumId,
songmid: item.copyrightId,
songId: item.id,
copyrightId: item.copyrightId,
source: 'mg',
interval: item.duration ? formatPlayTime(this.getIntv(item.duration)) : null,
img: item.mediumPic ? `https:${item.mediumPic}` : null,
lrc: null,
// lrcUrl: item.lrcUrl,
otherSource: null,
types,
_types,
typeUrl: {},
})
})
return list
},
filterBoardsData(rawList) {
// console.log(rawList)
let list = []
for (const board of rawList) {
if (board.template != 'group1') continue
for (const item of board.itemList) {
if ((item.template != 'row1' && item.template != 'grid1' && !item.actionUrl) || !item.actionUrl.includes('rank-info')) continue
let data = item.displayLogId.param
list.push({
id: 'mg__' + data.rankId,
name: data.rankName,
bangid: String(data.rankId),
})
}
}
return list
},
async getBoards(retryNum = 0) {
// if (++retryNum > 3) return Promise.reject(new Error('try max num'))
// let response
// try {
// response = await this.getBoardsData()
// } catch (error) {
// return this.getBoards(retryNum)
// }
// // console.log(response.body.data.contentItemList)
// if (response.statusCode !== 200 || response.body.code !== this.successCode) return this.getBoards(retryNum)
// const list = this.filterBoardsData(response.body.data.contentItemList)
// // console.log(list)
// // console.log(JSON.stringify(list))
// this.list = list
// return {
// list,
// source: 'mg',
// }
this.list = boardList
return {
list: boardList,
source: 'mg',
}
},
getList(bangid, page, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
return this.getData(this.getUrl(bangid, page)).then(({ statusCode, body }) => {
if (statusCode !== 200) return this.getList(bangid, page, retryNum)
let listData = body.match(this.regExps.listData)
if (!listData) return this.getList(bangid, page, retryNum)
const datas = JSON.parse(RegExp.$1)
// console.log(datas)
listData = this.filterData(datas.songs.items)
return {
total: datas.songs.itemTotal,
list: this.filterData(datas.songs.items),
limit: this.limit,
page,
source: 'mg',
}
})
},
}

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
import { httpGet, cancelHttp, httpFetch } from '../../request'
import { httpFetch } from '../../request'
import { formatPlayTime, sizeFormate } from '../../index'
let boardList = [{ id: 'tx__4', name: '流行指数榜', bangid: '4' }, { id: 'tx__26', name: '热歌榜', bangid: '26' }, { id: 'tx__27', name: '新歌榜', bangid: '27' }, { id: 'tx__62', name: '飙升榜', bangid: '62' }, { id: 'tx__58', name: '说唱榜', bangid: '58' }, { id: 'tx__57', name: '电音榜', bangid: '57' }, { id: 'tx__28', name: '网络歌曲榜', bangid: '28' }, { id: 'tx__5', name: '内地榜', bangid: '5' }, { id: 'tx__3', name: '欧美榜', bangid: '3' }, { id: 'tx__59', name: '香港地区榜', bangid: '59' }, { id: 'tx__16', name: '韩国榜', bangid: '16' }, { id: 'tx__60', name: '抖音排行榜', bangid: '60' }, { id: 'tx__29', name: '影视金曲榜', bangid: '29' }, { id: 'tx__17', name: '日本榜', bangid: '17' }, { id: 'tx__52', name: '腾讯音乐人原创榜', bangid: '52' }, { id: 'tx__36', name: 'K歌金曲榜', bangid: '36' }, { id: 'tx__61', name: '台湾地区榜', bangid: '61' }, { id: 'tx__63', name: 'DJ舞曲榜', bangid: '63' }, { id: 'tx__64', name: '综艺新歌榜', bangid: '64' }, { id: 'tx__65', name: '国风热歌榜', bangid: '65' }, { id: 'tx__66', name: 'ACG新歌榜', bangid: '66' }, { id: 'tx__67', name: '听歌识曲榜', bangid: '67' }, { id: 'tx__70', name: '达人音乐榜', bangid: '70' }]
@ -86,30 +86,16 @@ export default {
periods: {},
periodUrl: 'https://c.y.qq.com/node/pc/wk_v15/top.html',
_requestBoardsObj: null,
_cancelRequestObj: null,
_cancelPromiseCancelFn: 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&notice=0&format=json&uin=0&needNewCode=1&platform=h5')
return this._requestBoardsObj.promise
},
getData(url) {
if (this._cancelRequestObj != null) {
cancelHttp(this._cancelRequestObj)
this._cancelPromiseCancelFn(new Error('取消http请求'))
}
return new Promise((resolve, reject) => {
this._cancelPromiseCancelFn = reject
this._cancelRequestObj = httpGet(url, (err, resp, body) => {
this._cancelRequestObj = null
this._cancelPromiseCancelFn = null
if (err) {
console.log(err)
reject(err)
}
resolve(body)
})
})
if (this._requestDataObj) this._requestDataObj.cancelHttp()
this._requestDataObj = httpFetch(url)
return this._requestDataObj.promise
},
getSinger(singers) {
let arr = []
@ -175,9 +161,9 @@ export default {
})
},
getPeriods(bangid) {
return this.getData(this.periodUrl).then(html => {
return this.getData(this.periodUrl).then(({ body: html }) => {
let result = html.match(this.regExps.periodList)
if (!result) return Promise.reject()
if (!result) return Promise.reject(new Error('get data failed'))
result.forEach(item => {
let result = item.match(this.regExps.period)
if (!result) return
@ -239,12 +225,11 @@ export default {
let info = this.periods[bangid]
let p = info ? Promise.resolve(info.period) : this.getPeriods(bangid)
return p.then(period => {
return this.getData(this.getUrl(bangid, period, this.limit)).then(data => {
// console.log(data)
if (data.code !== 0) return this.getList(bangid, page, retryNum)
return this.getData(this.getUrl(bangid, period, this.limit)).then(resp => {
if (resp.body.code !== 0) return this.getList(bangid, page, retryNum)
return {
total: data.toplist.data.songInfoList.length,
list: this.filterData(data.toplist.data.songInfoList),
total: resp.body.toplist.data.songInfoList.length,
list: this.filterData(resp.body.toplist.data.songInfoList),
limit: this.limit,
page: 1,
source: 'tx',

View File

@ -13,7 +13,7 @@ export default {
return arr.join('、')
},
filterList({ songs, privileges }) {
// console.log(tracks, privileges)
// console.log(songs, privileges)
const list = []
songs.forEach((item, index) => {
const types = []
@ -38,6 +38,7 @@ export default {
size,
}
}
case 192000:
case 128000:
if (item.l) {
size = sizeFormate(item.l.size)

View File

@ -24,8 +24,9 @@ export default {
offset: limit * (page - 1),
}),
})
return searchRequest.promise.then(({ body }) =>
body && body.code === 200
return searchRequest.promise.then(({ body }) => {
// console.log(body)
return body && body.code === 200
? musicDetailApi.getList(body.result.songs.map(s => s.id)).then(({ list }) => {
this.total = body.result.songCount || 0
this.page = page
@ -41,7 +42,8 @@ export default {
},
}
})
: body)
: body
})
},
getSinger(singers) {
let arr = []

View File

@ -139,6 +139,7 @@ export default {
size,
}
}
case 192000:
case 128000:
if (item.l) {
size = sizeFormate(item.l.size)

View File

@ -109,7 +109,7 @@ export const httpFetch = (url, options = { method: 'get' }) => {
export const cancelHttp = requestObj => {
// console.log(requestObj)
if (!requestObj) return
console.log('cancel:', requestObj)
// console.log('cancel:', requestObj)
if (!requestObj.abort) return
requestObj.abort()
}

View File

@ -11,14 +11,17 @@
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='70%' viewBox='0 0 24 24' space='preserve')
use(xlink:href='#icon-list-add')
ul.scroll(:class="$style.listsContent" ref="dom_lists_list")
li(:class="[$style.listsItem, item.id == tabId ? $style.active : null]" :tips="item.name" v-for="item in boardList" :key="item.id" @click="handleToggleList(item.id)")
li(:class="[$style.listsItem, item.id == tabId ? $style.active : null, { [$style.clicked]: boardListData.rightClickItemIndex == index }]"
:tips="item.name" v-for="(item, index) in boardList" :key="item.id" @click="handleToggleList(item.id)"
@contextmenu="handleListsItemRigthClick($event, index)")
span(:class="$style.listsLabel") {{item.name}}
div(:class="$style.list")
material-song-list(v-model="selectedData" :rowWidth="{r1: '5%', r2: 'auto', r3: '22%', r4: '22%', r5: '9%', r6: '15%'}" @action="handleSongListAction" :source="source" :page="page" :limit="info.limit" :total="info.total" :noItem="$t('material.song_list.loding_list')" :list="list")
material-song-list(v-model="selectedData" ref="songList" :hideListsMenu="hideListsMenu" :rowWidth="{r1: '5%', r2: 'auto', r3: '22%', r4: '22%', r5: '9%', r6: '15%'}" @action="handleSongListAction" :source="source" :page="page" :limit="info.limit" :total="info.total" :noItem="$t('material.song_list.loding_list')" :list="list")
material-download-modal(:show="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false")
material-download-multiple-modal(:show="isShowDownloadMultiple" :list="selectedData" @select="handleAddDownloadMultiple" @close="isShowDownloadMultiple = false")
material-list-add-modal(:show="isShowListAdd" :musicInfo="musicInfo" @close="isShowListAdd = false")
material-list-add-multiple-modal(:show="isShowListAddMultiple" :musicList="selectedData" @close="handleListAddModalClose")
material-menu(:menus="listsItemMenu" :location="boardListData.menuLocation" item-name="name" :isShow="boardListData.isShowItemMenu" @menu-click="handleListsItemMenuClick")
</template>
<script>
@ -38,6 +41,21 @@ export default {
isShowDownloadMultiple: false,
isShowListAdd: false,
isShowListAddMultiple: false,
boardListData: {
isShowItemMenu: false,
itemMenuControl: {
rename: true,
sync: false,
moveup: true,
movedown: true,
remove: true,
},
rightClickItemIndex: -1,
menuLocation: {
x: 0,
y: 0,
},
},
}
},
computed: {
@ -47,6 +65,20 @@ export default {
boardList() {
return this.source && this.boards[this.source] ? this.boards[this.source] : []
},
listsItemMenu() {
return [
{
name: this.$t('view.leaderboard.play'),
action: 'play',
disabled: false,
},
{
name: this.$t('view.leaderboard.collect'),
action: 'collect',
disabled: false,
},
]
},
},
watch: {
tabId(n, o) {
@ -74,9 +106,9 @@ export default {
},
methods: {
...mapMutations(['setLeaderboard']),
...mapActions('leaderboard', ['getBoardsList', 'getList']),
...mapActions('leaderboard', ['getBoardsList', 'getList', 'getListAll']),
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
...mapMutations('list', ['listAdd', 'listAddMultiple']),
...mapMutations('list', ['listAdd', 'listAddMultiple', 'createUserList']),
...mapMutations('player', ['setList', 'setTempPlayList']),
handleListBtnClick(info) {
switch (info.action) {
@ -228,6 +260,55 @@ export default {
resetSelect() {
this.selectedData = []
},
handleListsItemRigthClick(event, index) {
// const board = this.boardList[index]
// this.boardListData.itemMenuControl.sync = !!source && !!musicSdk[source].songList
// this.boardListData.itemMenuControl.moveup = index > 0
// this.boardListData.itemMenuControl.movedown = index < this.userList.length - 1
this.boardListData.rightClickItemIndex = index
this.boardListData.menuLocation.x = event.currentTarget.offsetLeft + event.offsetX
this.boardListData.menuLocation.y = event.currentTarget.offsetTop + event.offsetY - this.$refs.dom_lists_list.scrollTop
// this.hideListsMenu()
this.$refs.songList.hideListMenu()
this.$nextTick(() => {
this.boardListData.isShowItemMenu = true
})
},
hideListsMenu() {
this.boardListData.isShowItemMenu = false
this.boardListData.rightClickItemIndex = -1
},
async handleListsItemMenuClick(action) {
let index = this.boardListData.rightClickItemIndex
this.hideListsMenu()
this.boardListData.isShowItemMenu = false
if (action) {
const board = this.boardList[index]
const list = await this.getListAll(board.id)
if (!list.length) return
switch (action && action.action) {
case 'play':
this.setList({
list: {
list,
id: null,
},
index: 0,
})
break
case 'collect':
this.createUserList({
name: board.name,
id: `board__${this.source}__${board.id}`,
list,
source: this.source,
sourceListId: `board__${board.id}`,
})
break
}
}
},
},
}
</script>

View File

@ -358,6 +358,9 @@ export default {
'sortList',
]),
...mapActions('songList', ['getListDetailAll']),
...mapActions('leaderboard', {
getBoardListAll: 'getListAll',
}),
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
...mapMutations('player', {
setPlayList: 'setList',
@ -902,7 +905,15 @@ export default {
} else {
this.fetchingListStatus[id] = true
}
return this.getListDetailAll({ source, id: sourceListId }).finally(() => {
let promise
if (/board__/.test(sourceListId)) {
const id = sourceListId.replace(/board__/, '')
promise = this.getBoardListAll(id)
} else {
promise = this.getListDetailAll({ source, id: sourceListId })
}
return promise.finally(() => {
this.fetchingListStatus[id] = false
})
},

View File

@ -237,7 +237,7 @@ div(:class="$style.main")
span.hover.underline(:tips="$t('view.setting.click_open')" @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop#readme')") https://github.com/lyswhut/lx-music-desktop
p.small
| 最新版网盘下载地址网盘内有WindowsMAC版
span.hover.underline(:tips="$t('view.setting.click_open')" @click="handleOpenUrl('https://www.lanzous.com/b0bf2cfa/')") 网盘地址
span.hover.underline(:tips="$t('view.setting.click_open')" @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')") 网盘地址
| &nbsp;&nbsp;密码
span.hover(:tips="$t('view.setting.click_copy')" @click="clipboardWriteText('glqw')") glqw
p.small
@ -255,7 +255,6 @@ div(:class="$style.main")
span.hover.underline(:tips="$t('view.setting.click_open')" @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/issues')") issue
br
p.small 感谢以前捐赠过的人现在软件不再接受捐赠建议把你们的爱心用来支持正版音乐
p.small 由于软件开发的初衷仅是为了对新技术的学习与研究因此软件直至停止维护都将会一直保持纯净
p.small
@ -983,7 +982,12 @@ export default {
await rendererInvoke(NAMES.hotKey.enable, true)
window.isEditingHotKey = false
this.isEditHotKey = false
const prevInput = hotKeyTargetInput
hotKeyTargetInput = null
if (prevInput.value == this.$t('view.setting.hot_key_tip_input')) {
prevInput.value = newHotKey ? this.formatHotKeyName(newHotKey) : ''
return
}
let config = this.hotKeyConfig[type][info.name]
let originKey
if (newHotKey) {