🔖 v1.6.1

This commit is contained in:
mrdong916 2021-01-20 14:39:40 +08:00
parent 537e7307b6
commit 51c124201f
62 changed files with 3292 additions and 2553 deletions

View File

@ -6,6 +6,41 @@ 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.6.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.6.0...v1.6.1) - 2021-01-13
### 优化
- 改进自动换源时的歌曲匹配
### 修复
- 修复某些情况下自动换源的时间过长时会终止换源自动切歌的问题
- 修复自动换源导致的搜索列表每页变成10条数据的问题
- 降级electron到9.3.3修复部分系统没有声音的问题
## [1.6.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.5.0...v1.6.0) - 2021-01-10
### 新增
- 我的列表右键菜单新增列表排序功能,可调整单曲、多选后的歌曲的顺序。注意:多选排序还将会按照选中歌曲时的顺序排序
- 添加鼠标提示的自动关闭功能鼠标长时间目前是10秒不动时鼠标提示将会自动关闭
- 添加鼠标指向歌曲封面的提示(对于进度条左边的歌曲封面,你可能不知道的操作->右击在“我的列表”定位当前播放的歌曲)
- 隐藏播放详情页按钮添加快速隐藏详情页提示(你可能不知道的操作->在播放详情页内的任意非窗口可拖动区域右键双击可以快速隐藏详情页)
- 添加桌面歌词字体、透明度调整按钮微调提示(你可能不知道的操作->对于字体、透明度可右击微调)
- 我的列表右键菜单添加搜索当前歌曲功能
- 新增`-dha`参数添加此启动参数将禁用硬件加速启动Disable Hardware Acceleration窗口显示有问题时可以尝试添加此参数启动Linux系统的界面显示有问题时可尝试添加此参数启动若不行可尝试添加`-dt`参数启动
- 新增播放自动换源功能~
### 变更
- `-nt`参数更名为`-dt`Disable Transparent目前原来的`-nt`参数仍然可用,但将在后续的版本中移除
### 修复
- 修复恢复上次播放的歌曲时在随机播放模式下不把恢复播放的歌曲放入已播放队列的问题(该问题会导致随机模式下会导致未播放完整个列表前就会再次随机到该歌曲,以及无法通过上一曲切回该歌曲)
- 修复音乐嵌入的封面在 Mac 系统无法显示的问题
- 修复`-dt`(原来的`-nt`)启动参数不真正生效的问题
## [1.5.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.4.1...v1.5.0) - 2020-12-13
### 新增

42
FAQ.md
View File

@ -13,7 +13,7 @@
1. 尝试更新到最新版本
2. 尝试切换其他歌曲(或直接搜索该歌曲),若全部歌曲都无法试听与下载则进行下一步
3. 尝试到 设置-音乐来源 切换到其他接口
4. 尝试切换网络,比如用手机开热点(目前存在某些网络无法访问接口服务器的情况
4. 尝试切换网络,比如用手机开热点(所有歌曲都提示请求异常时可通过此方法解决,或等一两天后再试
5. 若还不行请到这个链接查看详情:<https://github.com/lyswhut/lx-music-desktop/issues/5>
6. 若没有在第5条链接中的第一条评论中看到接口无法使用的说明则应该是你网络无法访问接口服务器的问题如果接口有问题我会在那里说明。
@ -45,15 +45,24 @@
对于分享出来的歌单若打开失败可尝试先在浏览器中打开后再从浏览器地址栏复制URL地址到软件打开<br>
或者如果你知道歌单 id 也可以直接输入歌单 id 打开。<br>
## Windows 7 下界面异常(界面显示不完整)
## 界面异常(界面显示不完整)
### Windows 7 下界面异常
由于软件默认使用了透明窗口根据Electron官方文档的[说明](https://electronjs.org/docs/api/frameless-window#%E5%B1%80%E9%99%90%E6%80%A7)
> 在 windows 操作系统上, 当 DWM 被禁用时, 透明窗口将无法工作。
因此,当 win7 没有使用**AERO**主题时界面将会显示异常开启AERO的方法请自行百度`win7开启aero效果`(开启后可看到任务栏变透明)。<br>
从`0.14.0`版本起不再强制要求开启透明效果,若你实在不想开启(若非电脑配置太低,墙裂建议开启!),可通过添加运行参数`-nt`来运行程序即可,例如:`.\lx-music-desktop.exe -nt`,添加方法可自行百度“给快捷方式加参数”,该参数的作用是用来控制程序是否使用非透明窗口运行。
从`0.14.0`版本起不再强制要求开启透明效果,若你实在不想开启(若非电脑配置太低,墙裂建议开启!),可通过添加运行参数`-dt`来运行程序即可,例如:`.\lx-music-desktop.exe -dt`,添加方法可自行百度“给快捷方式加参数”,该参数的作用是用来控制程序是否使用非透明窗口运行。
对于一些完全无法正常显示界面、开启了AERO后问题仍未解决的情况请阅读下面的 **软件启动后,界面无法显示** 解决
对于一些完全无法正常显示界面、开启了AERO后问题仍未解决的情况请阅读下面的 **软件启动后,界面无法显示** 解决。
### Linux 下界面异常
根据Electron里issue的[解决方案](https://github.com/electron/electron/issues/2170#issuecomment-736223269)<br>
若你遇到透明问题可尝试添加启动参数 `-dha` 来禁用硬件加速,例如:`.\lx-music-desktop.exe -dha`。
v1.6.0及之后的版本才支持`-dha`参数
## 软件启动后,界面无法显示
@ -66,6 +75,7 @@
若还是不行可尝试以下操作:
- 更新显卡驱动
- 添加启动参数`-dha`运行(添加的方法请自行百度“给快捷方式加参数”)
- 尝试将绿色版的软件放在**桌面**或**我的文档**运行
## 安装版安装失败,提示安装程序并未成功地运行完成
@ -98,10 +108,24 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看下面的
### Linux 系统下桌面歌词窗口异常
目前在 Ubuntu 18.10 下第一次开启桌面歌词时歌词窗口会变白,需要关闭后再开启,
`v1.2.1`以前的版本在 Ubuntu 18.10 下第一次开启桌面歌词时歌词窗口会变白,需要关闭后再开启,
`v1.2.1`及之后的版本已修复该问题。
其他 Linux 系统未测试,如有异常也是意料之中,目前不打算去处理 Linux 平台的桌面歌词问题。
其他 Linux 系统未测试,如有异常也是意料之中,目前不打算去处理 Linux 平台的桌面歌词问题,但你可以尝试按照`Linux 下界面异常`的解决方案去解决
## 歌曲下载失败
### 提示 `ENOENT: no such file or directory, mkdir`
更换下载歌曲目录即可解决(一般是设置的歌曲下载目录没有读写权限导致的)。
### 提示 `请求异常``Fail`
尝试更换网络,如切换到移动网络。
### 其他错误
按照前面的 "歌曲无法试听与下载" 方案解决。
## 软件安装包说明
@ -125,6 +149,12 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看下面的
注意:**绿色版**的软件自动更新功能**不可用**,建议使用安装版!!<br>
注意:**Mac版**、**Linux deb**版不支持自动更新!
## 更新已收藏的在线歌单
该功能仅对直接从歌单详情页点“收藏”按钮收藏的歌单有效,可右击已收藏的列表名从弹出的菜单中选择“同步”使用该功能,
需要注意的是:这将会覆盖本地的目标列表,歌曲将被替换成最新的在线列表。
## 缺少`xxx.dll`
这个是电脑缺少某些dll导致的正常的系统是没有这个问题的可以尝试如下几个解决办法

5058
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
{
"name": "5yin",
"version": "1.5.0",
"version": "1.6.1",
"description": "一个基于洛雪音乐助手修改的免费音乐下载助手",
"main": "./dist/electron/main.js",
"productName": "五音助手",
"scripts": {
"pack": "node build-config/pack.js && npm run pack:win",
"pack:win": "npm run pack:win:setup:x86_64 && npm run pack:win:7z",
"pack:win": "npm run pack:win:setup:x86 && npm run pack:win:setup:x64 && npm run pack:win:setup:x86_64 && npm run pack:win:7z",
"pack:win:setup:x86_64": "cross-env TARGET=win_安装版 ARCH=x86_64 electron-builder -w=nsis --x64 --ia32",
"pack:win:setup:x64": "cross-env TARGET=win_安装版 ARCH=x64 electron-builder -w=nsis --x64",
"pack:win:setup:x86": "cross-env TARGET=win_安装版 ARCH=x86 electron-builder -w=nsis --ia32",
@ -165,24 +165,24 @@
"@babel/plugin-transform-modules-umd": "^7.12.1",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"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.0",
"cfonts": "^2.9.1",
"chalk": "^4.1.0",
"changelog-parser": "^2.8.0",
"copy-webpack-plugin": "^6.4.0",
"core-js": "^3.8.1",
"core-js": "^3.8.2",
"cross-env": "^7.0.3",
"css-loader": "^4.3.0",
"del": "^6.0.0",
"electron": "^9.3.3",
"electron-builder": "^22.9.1",
"electron-debug": "^3.1.0",
"electron-debug": "^3.2.0",
"electron-devtools-installer": "^3.1.1",
"eslint": "^7.15.0",
"eslint": "^7.17.0",
"eslint-config-standard": "^14.1.1",
"eslint-formatter-friendly": "^7.0.0",
"eslint-loader": "^4.0.2",
@ -193,10 +193,10 @@
"eslint-plugin-standard": "^4.1.0",
"file-loader": "^6.2.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"html-webpack-plugin": "^4.5.0",
"html-webpack-plugin": "^4.5.1",
"less": "^3.12.2",
"less-loader": "^7.1.0",
"markdown-it": "^12.0.3",
"less-loader": "^7.2.1",
"markdown-it": "^12.0.4",
"mini-css-extract-plugin": "^0.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^4.1.0",
@ -211,29 +211,29 @@
"stylus-loader": "^4.3.1",
"terser-webpack-plugin": "^4.2.3",
"url-loader": "^4.1.1",
"vue-loader": "^15.9.5",
"vue-loader": "^15.9.6",
"vue-template-compiler": "^2.6.12",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-dev-server": "^3.11.1",
"webpack-hot-middleware": "^2.25.0",
"webpack-merge": "^5.6.1"
"webpack-merge": "^5.7.3"
},
"dependencies": {
"crypto-js": "^4.0.0",
"dnscache": "^1.0.2",
"electron-log": "^4.3.0",
"electron-log": "^4.3.1",
"electron-store": "^6.0.1",
"electron-updater": "^4.3.5",
"iconv-lite": "^0.6.2",
"image-size": "^0.9.3",
"js-htmlencode": "^0.3.0",
"lrc-file-parser": "^1.0.5",
"needle": "^2.5.2",
"node-id3": "^0.1.19",
"needle": "^2.6.0",
"node-id3": "^0.2.2",
"request": "^2.88.2",
"vue": "^2.6.12",
"vue-i18n": "^8.22.2",
"vue-i18n": "^8.22.3",
"vue-router": "^3.4.9",
"vuex": "^3.6.0",
"vuex-router-sync": "^5.0.0"

View File

@ -1,14 +1,9 @@
### 新增
- 直接从歌单详情收藏的列表新增同步功能。注意:这将会覆盖本地的目标列表,歌曲将被替换成最新的在线列表
### 优化
- 优化软件启动时恢复上一次播放的歌曲进度功能
- 改进自动换源时的歌曲匹配
### 修复
- 修复MAC平台上下载歌曲封面嵌入无法显示的问题
- 修复MAC平台首次运行软件最小化、关闭控制按钮默认在右边的问题
- 修复酷狗源的某些歌曲没有专辑字段导致的列表加载失败问题
- 修复某些酷狗源歌单链接无法打开的问题
- 修复某些情况下自动换源的时间过长时会终止换源自动切歌的问题
- 修复自动换源导致的搜索列表每页变成10条数据的问题
- 降级electron到9.3.3修复部分系统没有声音的问题

File diff suppressed because one or more lines are too long

View File

@ -85,7 +85,7 @@ const defaultSetting = {
themeId: 6,
langId: null,
sourceId: 'kw',
apiSource: 'yj',
apiSource: 'wy',
sourceNameType: 'alias',
isShowAnimation: true,
randomAnimate: true,
@ -99,7 +99,7 @@ const overwriteSetting = {
}
// 使用新年皮肤
if (new Date().getMonth() < 2) defaultSetting.themeId = 9
// if (new Date().getMonth() < 2) defaultSetting.themeId = 9
exports.defaultSetting = defaultSetting

View File

@ -1,4 +1,4 @@
global.lx_event = {}
if (!global.lx_event) global.lx_event = {}
const Common = require('./Common')
const MainWindow = require('./MainWindow')

View File

@ -24,14 +24,20 @@ app.on('second-instance', (event, argv, cwd) => {
const isDev = global.isDev = process.env.NODE_ENV !== 'production'
require('./env')
// console.log(global.envParams.cmdParams)
// 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
// https://github.com/electron/electron/issues/22691
app.commandLine.appendSwitch('wm-window-animations-disabled')
const { navigationUrlWhiteList } = require('../common/config')
const { getWindowSizeInfo } = require('./utils')
const { isMac, isLinux, initSetting, initHotKey } = require('../common/utils')
// https://github.com/electron/electron/issues/22691
app.commandLine.appendSwitch('wm-window-animations-disabled')
// https://github.com/electron/electron/issues/18397
// 开发模式下为true时 多次引入native模块会导致渲染进程卡死
// https://github.com/electron/electron/issues/22791
@ -95,7 +101,7 @@ function createWindow() {
useContentSize: true,
width: windowSizeInfo.width,
frame: false,
transparent: !global.envParams.nt,
transparent: !global.envParams.cmdParams.dt,
enableRemoteModule: false,
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
resizable: false,
@ -124,6 +130,7 @@ global.appHotKey = {
}
function init() {
console.log('init')
const info = initSetting()
global.appSetting = info.setting
global.appSettingVersion = info.version

View File

@ -1,5 +1,5 @@
<template lang="pug">
#container(v-if="isProd && !isNt && !isLinux" :class="theme" @mouseenter="enableIgnoreMouseEvents" @mouseleave="dieableIgnoreMouseEvents")
#container(v-if="isProd && !isDT && !isLinux" :class="theme" @mouseenter="enableIgnoreMouseEvents" @mouseleave="dieableIgnoreMouseEvents")
core-aside#left
#right
core-toolbar#toolbar
@ -41,7 +41,7 @@ export default {
data() {
return {
isProd: process.env.NODE_ENV === 'production',
isNt: false,
isDT: false,
isLinux,
globalObj: {
apiSource: 'test',
@ -102,7 +102,7 @@ export default {
}, 500)
},
mounted() {
document.body.classList.add(this.isNt ? 'noTransparent' : 'transparent')
document.body.classList.add(this.isDT ? 'disableTransparent' : 'transparent')
window.eventHub.$emit(eventBaseName.bindKey)
this.init()
},
@ -254,12 +254,12 @@ export default {
music.init()
},
enableIgnoreMouseEvents() {
if (this.isNt) return
if (this.isDT) return
rendererSend(NAMES.mainWindow.set_ignore_mouse_events, false)
// console.log('content enable')
},
dieableIgnoreMouseEvents() {
if (this.isNt) return
if (this.isDT) return
// console.log('content disable')
rendererSend(NAMES.mainWindow.set_ignore_mouse_events, true)
},
@ -380,12 +380,12 @@ export default {
},
handleEnvParamsInit(envParams) {
this.envParams = envParams
this.isNt = this.envParams.nt
if (this.isNt) {
this.isDT = this.envParams.dt
if (this.isDT) {
document.body.classList.remove('transparent')
document.body.classList.add('noTransparent')
document.body.classList.add('disableTransparent')
}
if (this.isProd && !this.isNt && !this.isLinux) {
if (this.isProd && !this.isDT && !this.isLinux) {
document.body.addEventListener('mouseenter', this.dieableIgnoreMouseEvents)
document.body.addEventListener('mouseleave', this.enableIgnoreMouseEvents)
}
@ -455,8 +455,13 @@ body {
background-color: transparent;
}
}
.noTransparent {
.disableTransparent {
background-color: #fff;
#right {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
#container {

View File

@ -1,6 +1,6 @@
<template lang="pug">
div(:class="$style.player")
div(:class="$style.left" @contextmenu="handleToMusicLocation" @click="showPlayerDetail")
div(:class="$style.left" @contextmenu="handleToMusicLocation" @click="showPlayerDetail" :tips="$t('core.player.pic_tip')")
img(v-if="musicInfo.img" :src="musicInfo.img" @error="imgError")
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='102%' width='100%' viewBox='0 0 60 60' space='preserve')
use(:xlink:href='`#${$style.iconPic}`')
@ -92,6 +92,7 @@ import { mapGetters, mapActions, mapMutations } from 'vuex'
import { requestMsg } from '../../utils/message'
import { isMac } from '../../../common/utils'
import { player as eventPlayerNames } from '../../../common/hotKey'
import musicSdk from '@renderer/utils/music'
import path from 'path'
let audio
@ -264,6 +265,7 @@ export default {
this.$nextTick(() => {
this.sendProgressEvent(this.progress, 'paused')
})
if (this.setting.player.togglePlayMethod == 'random') this.setPlayedList(musicInfo)
window.restorePlayInfo = null
return
}
@ -382,6 +384,7 @@ export default {
if (!this.musicInfo.songmid) return
console.log('出错')
this.stopPlay()
this.clearLoadingTimeout()
if (this.listId != 'download' && audio.error.code !== 1 && this.retryNum < 2) { // URL2URL
// console.log(this.retryNum)
if (!this.restorePlayTime) this.restorePlayTime = audio.currentTime //
@ -468,7 +471,7 @@ export default {
},
async play() {
console.log('play', this.playIndex)
this.checkDelayNextTimeout()
this.clearDelayNextTimeout()
let targetSong = this.targetSong = this.list[this.playIndex]
if (this.setting.player.togglePlayMethod == 'random') this.setPlayedList(targetSong)
this.retryNum = 0
@ -505,7 +508,7 @@ export default {
album: this.musicInfo.album,
})
},
checkDelayNextTimeout() {
clearDelayNextTimeout() {
// console.log(this.delayNextTimeout)
if (this.delayNextTimeout) {
clearTimeout(this.delayNextTimeout)
@ -513,7 +516,7 @@ export default {
}
},
addDelayNextTimeout() {
this.checkDelayNextTimeout()
this.clearDelayNextTimeout()
this.delayNextTimeout = setTimeout(() => {
this.delayNextTimeout = null
this.handleNext()
@ -693,20 +696,39 @@ export default {
if (highQuality && songInfo._types['320k'] && list && list.includes('320k')) type = '320k'
return type
},
setUrl(targetSong, isRefresh, isRetryed = false) {
setUrl(targetSong, isRefresh, isRetryed = false, retryedSource = [], originMusic = null) {
if (!retryedSource.includes(targetSong.source)) retryedSource.push(targetSong.source)
let type = this.getPlayType(this.setting.player.highQuality, targetSong)
this.musicInfo.url = targetSong.typeUrl[type]
this.status = this.statusText = this.$t('core.player.geting_url')
return this.getUrl({ musicInfo: targetSong, type, isRefresh }).then(() => {
return this.getUrl({ musicInfo: targetSong, originMusic, type, isRefresh }).then(() => {
audio.src = this.musicInfo.url = targetSong.typeUrl[type]
}).catch(err => {
// console.log('err', err.message)
if (err.message == requestMsg.cancelRequest) return
if (!isRetryed) return this.setUrl(targetSong, isRefresh, true)
this.status = this.statusText = err.message
this.addDelayNextTimeout()
return Promise.reject(err)
if (!isRetryed) return this.setUrl(targetSong, isRefresh, true, retryedSource, originMusic)
if (!originMusic) originMusic = targetSong
this.status = this.statusText = 'Try toggle source...'
return (originMusic.otherSource && originMusic.otherSource.length ? Promise.resolve(originMusic.otherSource) : musicSdk.findMusic(originMusic)).then(res => {
this.updateMusicInfo({ id: this.listId, index: this.playIndex, data: { otherSource: res } })
return res
}).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(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)
})
})
},
setImg(targetSong) {

View File

@ -1,6 +1,6 @@
<template lang="pug">
input(:class="$style.input" :type="type" :placeholder="placeholder" :value="value" :disabled="disabled"
@focus="$emit('focus', $event)" @blur="$emit('blur', $event)" @input="$emit('input', $event.target.value.trim())" @change="$emit('change', $event.target.value.trim())"
input(:class="$style.input" ref="dom_input" :type="type" :placeholder="placeholder" :value="value" :disabled="disabled"
@focus="$emit('focus', $event)" @blur="$emit('blur', $event)" @input="handleInput" @change="$emit('change', $event.target.value.trim())"
@keyup.enter="$emit('submit', $event.target.value.trim())")
</template>
@ -24,6 +24,16 @@ export default {
default: 'text',
},
},
methods: {
handleInput(event) {
let value = event.target.value.trim()
event.target.value = value
this.$emit('input', value)
},
focus() {
this.$refs.dom_input.focus()
},
},
}
</script>
@ -41,6 +51,13 @@ export default {
transition: background-color 0.2s ease;
background-color: @color-btn-background;
font-size: 13.3px;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
&[disabled] {
opacity: .4;
}

View File

@ -0,0 +1,121 @@
<template lang="pug">
material-modal(:show="show" @close="handleClose")
main(:class="$style.main")
h2 {{selectedNum > 0 ? $t('material.list_sort_modal.title_multiple', { num: selectedNum }) : $t('material.list_sort_modal.title', { name: musicInfo ? musicInfo.name : '' })}}
material-input(:class="$style.input" type="number" v-model="sortNum" ref="input" @blur.native="verify" :placeholder="$t('material.list_sort_modal.input_tip')" @keydown.native.enter="handleSubmit")
div(:class="$style.footer")
material-btn(:class="$style.btn" @click="handleSubmit") {{$t('material.list_sort_modal.btn_confirm')}}
</template>
<script>
export default {
props: {
show: {
type: Boolean,
default: false,
},
musicInfo: {
type: Object,
default() {
return {}
},
},
selectedNum: {
type: Number,
default: 0,
},
},
data() {
return {
sortNum: '',
}
},
watch: {
show(n) {
if (n) {
this.sortNum = ''
this.$nextTick(() => {
this.$refs.input.focus()
})
}
},
},
computed: {
},
methods: {
handleClose() {
this.$emit('close')
},
verify() {
let num = /^[1-9]\d*/.exec(this.sortNum)
num = num ? parseInt(num[0]) : ''
this.sortNum = num.toString()
return num
},
handleSubmit() {
let num = this.verify()
if (this.sortNum == '') return
this.$emit('confirm', num)
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.main {
padding: 0 15px;
max-width: 530px;
min-width: 280px;
display: flex;
flex-flow: column nowrap;
min-height: 0;
// max-height: 100%;
// overflow: hidden;
h2 {
font-size: 13px;
color: @color-theme_2-font;
line-height: 1.3;
word-break: break-all;
// text-align: center;
padding: 15px 0 8px;
}
}
.input {
// width: 100%;
// height: 26px;
padding: 8px 8px;
}
.footer {
margin: 20px 0 15px auto;
}
.btn {
// box-sizing: border-box;
// margin-left: 15px;
// margin-bottom: 15px;
// height: 36px;
// line-height: 36px;
// padding: 0 10px !important;
min-width: 70px;
// .mixin-ellipsis-1;
+.btn {
margin-left: 10px;
}
}
each(@themes, {
:global(#container.@{value}) {
.main {
h2 {
color: ~'@{color-@{value}-theme_2-font}';
}
}
}
})
</style>

View File

@ -138,10 +138,10 @@ export default {
// will-change: transform;
li {
cursor: pointer;
min-width: 80px;
min-width: 90px;
line-height: 34px;
// color: @color-btn;
padding: 0 5px;
padding: 0 10px;
text-align: center;
outline: none;
transition: @transition-theme;

View File

@ -14,7 +14,7 @@
"buffering": "Buffering...",
"geting_url": "Getting music link...",
"lyric_error": "Failed to get lyrics",
"hide_detail": "Hide detail page",
"hide_detail": "Hide detail page (Right-click in the view to quickly hide the details page)",
"name": "Name: ",
"singer": "Artist: ",
"album": "Album: ",
@ -28,6 +28,7 @@
"play_toggle_mode_list": "Play in order",
"play_toggle_mode_single_loop": "Single Loop",
"play_toggle_mode_off": "Disable",
"pic_tip": "Right click to locate the currently playing song in \"My List\"",
"comment_show": "Song comments",
"comment_hot_loading": "Hot comments are loading",

View File

@ -4,10 +4,10 @@
"lock": "Lock Lyrics",
"unlock": "Unlock Lyrics",
"theme": "Theme Color",
"font_increase": "Increase font size",
"font_decrease": "Reduce font size",
"opactiy_increase": "Decrease Transparency",
"opactiy_decrease": "Increase Transparency",
"font_increase": "Increase font size (Right click to fine-tune)",
"font_decrease": "Reduce font size (Right click to fine-tune)",
"opactiy_increase": "Decrease Transparency (Right click to fine-tune)",
"opactiy_decrease": "Increase Transparency (Right click to fine-tune)",
"lrc_active_zoom_on": "Zoom the currently playing lyrics",
"lrc_active_zoom_off": "Unzoom the currently playing lyrics",
"win_top_on": "Top lyrics interface",

View File

@ -0,0 +1,6 @@
{
"title": "Adjust the position of {name} to:",
"title_multiple": "Adjust the position of the selected {num} songs to:",
"input_tip": "Please input which position you want to adjust to",
"btn_confirm": "Confirm"
}

View File

@ -10,7 +10,9 @@
"list_copy_name": "Copy name",
"list_add_to": "Add to ...",
"list_move_to": "Move to ...",
"list_sort": "Adjust position",
"list_download": "Download",
"list_search": "Search",
"list_remove": "Remove",
"list_source_detail": "Song Page",
"default_list": "Recently Played",

View File

@ -14,7 +14,7 @@
"buffering": "缓冲中...",
"geting_url": "歌曲链接获取中...",
"lyric_error": "歌词获取失败",
"hide_detail": "隐藏详情页",
"hide_detail": "隐藏详情页(界面内右键双击可快速隐藏详情页)",
"name": "歌曲名:",
"singer": "艺术家:",
"album": "专辑名:",
@ -28,6 +28,7 @@
"play_toggle_mode_list": "顺序播放",
"play_toggle_mode_single_loop": "单曲循环",
"play_toggle_mode_off": "禁用",
"pic_tip": "右击在“我的列表”定位当前播放的歌曲",
"comment_show": "歌曲评论",
"comment_hot_loading": "热门评论加载中",

View File

@ -4,10 +4,10 @@
"lock": "锁定歌词",
"unlock": "解锁歌词",
"theme": "主题配色",
"font_increase": "增加字体大小",
"font_decrease": "减小字体大小",
"opactiy_increase": "减小透明度",
"opactiy_decrease": "增加透明度",
"font_increase": "增加字体大小(右击可微调)",
"font_decrease": "减小字体大小(右击可微调)",
"opactiy_increase": "减小透明度(右击可微调)",
"opactiy_decrease": "增加透明度(右击可微调)",
"lrc_active_zoom_on": "缩放当前播放的歌词",
"lrc_active_zoom_off": "取消缩放当前播放的歌词",
"win_top_on": "置顶歌词界面",

View File

@ -0,0 +1,6 @@
{
"title": "将 {name} 的位置调整到:",
"title_multiple": "将已选的 {num} 首歌曲的位置调整到:",
"input_tip": "请输入要调整到第几个位置",
"btn_confirm": "确定"
}

View File

@ -11,7 +11,9 @@
"list_source_detail": "歌曲详情页",
"list_add_to": "添加到...",
"list_move_to": "移动到...",
"list_sort": "调整位置",
"list_download": "下载",
"list_search": "搜索",
"list_remove": "删除",
"default_list": "试听列表",
"love_list": "收藏",

View File

@ -5,7 +5,7 @@
"basic_animation": "弹出层随机动画",
"basic_show_animation": "显示切换动画",
"basic_source_title": "选择音乐来源",
"basic_source_yj": "五音版接口(为五音助手用户专门打造的五音版)",
"basic_source_wy": "五音版接口(为五音助手用户专门打造的五音版)",
"basic_source_test": "测试接口(几乎软件的所有功能都可用)",
"basic_source_temp": "临时接口(软件的某些功能不可用,建议测试接口不可用再使用本接口)",
"basic_source": "音乐来源",

View File

@ -14,7 +14,7 @@
"buffering": "緩衝中...",
"geting_url": "歌曲鏈接獲取中...",
"lyric_error": "歌詞獲取失敗",
"hide_detail": "隱藏詳情頁",
"hide_detail": "隱藏詳情頁(界面內右鍵雙擊可快速隱藏詳情頁)",
"name": "歌曲名:",
"singer": "藝術家:",
"album": "專輯名:",
@ -28,6 +28,7 @@
"play_toggle_mode_list": "順序播放",
"play_toggle_mode_single_loop": "單曲循環",
"play_toggle_mode_off": "禁用",
"pic_tip": "右擊在“我的列表”定位當前播放的歌曲",
"comment_show": "歌曲評論",
"comment_hot_loading": "熱門評論加載中",

View File

@ -4,10 +4,10 @@
"lock": "鎖定歌詞",
"unlock": "解鎖歌詞",
"theme": "主題配色",
"font_increase": "增加字體大小",
"font_decrease": "減小字體大小",
"opactiy_increase": "減小透明度",
"opactiy_decrease": "增加透明度",
"font_increase": "增加字體大小(右擊可微調)",
"font_decrease": "減小字體大小(右擊可微調)",
"opactiy_increase": "減小透明度(右擊可微調)",
"opactiy_decrease": "增加透明度(右擊可微調)",
"lrc_active_zoom_on": "縮放當前播放的歌詞",
"lrc_active_zoom_off": "取消縮放當前播放的歌詞",
"win_top_on": "置頂歌詞界面",

View File

@ -0,0 +1,6 @@
{
"title": "將 {name} 的位置調整到:",
"title_multiple": "將已選的 {num} 首歌曲的位置調整到:",
"input_tip": "請輸入要調整到第幾個位置",
"btn_confirm": "確定"
}

View File

@ -10,7 +10,9 @@
"list_copy_name": "複製歌曲名",
"list_add_to": "添加到...",
"list_move_to": "移動到...",
"list_sort": "調整位置",
"list_download": "下載",
"list_search": "搜索",
"list_remove": "刪除",
"list_source_detail": "歌曲詳情頁",
"default_list": "試聽列表",

View File

@ -6,7 +6,7 @@
"basic_show_animation": "顯示切換動畫",
"basic_source_title": "選擇音樂來源",
"basic_source_test": "測試接口(幾乎軟件的所有功能都可用)",
"basic_source_yj": "野雞版接口(為五音助手用戶專門打造的野雞版)",
"basic_source_wy": "五音版接口為五音助手用戶專門打造的五音PC版)",
"basic_source_temp": "臨時接口(軟件的某些功能不可用,建議測試接口不可用再使用本接口)",
"basic_source": "音樂來源",
"basic_sourcename_title": "選擇音源名字類型",

View File

@ -2,7 +2,21 @@ import Tips from './Tips.vue'
import Vue from 'vue'
const TipsConstructor = Vue.extend(Tips)
export default ({ position, message } = {}) => {
const addAutoCloseTimer = (instance, time) => {
if (!time) return
if (instance.autoCloseTimer) clearTimeout(instance.autoCloseTimer)
instance.autoCloseTimer = setTimeout(() => {
instance.cancel()
}, time)
}
const clearAutoCloseTimer = instance => {
if (!instance.autoCloseTimer) return
clearTimeout(instance.autoCloseTimer)
instance.autoCloseTimer = null
}
export default ({ position, message, autoCloseTime } = {}) => {
if (!position) return
let instance = new TipsConstructor().$mount(document.createElement('div'))
@ -17,14 +31,19 @@ export default ({ position, message } = {}) => {
document.body.appendChild(instance.$el)
instance.cancel = () => {
instance.$emit('beforeClose', instance)
clearAutoCloseTimer(instance)
instance.visible = false
instance = null
}
instance.setTips = tips => {
addAutoCloseTimer(instance, autoCloseTime)
instance.message = tips
}
addAutoCloseTimer(instance, autoCloseTime)
return instance
}

View File

@ -17,6 +17,7 @@ export default {
transform: 'translate(0, 0)',
cancel: null,
setTips: null,
aotoCloseTimer: null,
}
},
watch: {
@ -26,9 +27,13 @@ export default {
})
},
},
beforeDestroy() {
const el = this.$el
el.parentNode.removeChild(el)
},
methods: {
afterLeave(el, done) {
el.parentNode.removeChild(el)
this.$destroy()
},
handleGetOffsetXY(left, top) {
const tipsWidth = this.$refs.dom_tips.clientWidth

View File

@ -19,18 +19,22 @@ const showTips = debounce(event => {
prevTips = msg
instance = tips({
message: msg,
autoCloseTime: 10000,
position: {
top: event.y + 12,
left: event.x + 8,
},
})
instance.$on('beforeClose', closeInstance => {
if (instance !== closeInstance) return
prevTips = null
instance = null
})
}, 400)
const hideTips = () => {
if (!instance) return
instance.cancel()
prevTips = null
instance = null
}
const setTips = tips => {
@ -39,7 +43,7 @@ const setTips = tips => {
}
const updateTips = event => {
if (!instance) return
if (!instance) return showTips(event)
setTimeout(() => {
let msg = getTips(event.target)
if (!msg || prevTips === msg) return

View File

@ -185,6 +185,12 @@ const mutations = {
setListScroll(state, { id, location }) {
if (allList[id]) allList[id].location = location
},
sortList(state, { id, sortNum, musicInfos }) {
let targetList = allList[id]
this.commit('list/listRemoveMultiple', { id, list: musicInfos })
targetList.list.splice(sortNum - 1, 0, ...musicInfos)
},
}
export default {

View File

@ -28,7 +28,7 @@ const getters = {
// actions
const actions = {
getUrl({ commit, state }, { musicInfo, type, isRefresh }) {
getUrl({ commit, state }, { musicInfo, originMusic, type, isRefresh }) {
if (!musicInfo._types[type]) {
// 兼容旧版酷我源搜索列表过滤128k音质的bug
if (!(musicInfo.source == 'kw' && type == '128k')) return Promise.reject(new Error('该歌曲没有可播放的音频'))
@ -39,6 +39,7 @@ const actions = {
if (musicInfo.typeUrl[type] && !isRefresh) return Promise.resolve()
urlRequest = music[musicInfo.source].getMusicUrl(musicInfo, type)
return urlRequest.promise.then(result => {
if (originMusic) commit('setUrl', { musicInfo: originMusic, url: result.url, type })
commit('setUrl', { musicInfo, url: result.url, type })
urlRequest = null
}).catch(err => {

View File

@ -2,7 +2,7 @@
module.exports = [
{
id: 'yj',
id: 'wy',
name: '五音接口',
disabled: false,
supportQualitys: {

View File

@ -11,9 +11,9 @@ export default {
total: 0,
page: 0,
allPage: 1,
musicSearch(str, page) {
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=${this.limit}&type=0&data_source=0&use_cluster=1`)
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) {
@ -66,9 +66,9 @@ export default {
},
search(str, page = 1, { limit } = {}, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
if (limit != null) this.limit = limit
if (limit == null) limit = this.limit
return this.musicSearch(str, page).then(result => {
return this.musicSearch(str, page, limit).then(result => {
if (!result || result.error_code !== 22000) return this.search(str, page, { limit }, retryNum)
let list = this.handleResult(result.result.song_info.song_list)
@ -76,12 +76,12 @@ export default {
this.total = result.result.song_info.total
this.page = page
this.allPage = Math.ceil(this.total / this.limit)
this.allPage = Math.ceil(this.total / limit)
return Promise.resolve({
list,
allPage: this.allPage,
limit: this.limit,
limit: limit,
total: this.total,
source: 'bd',
})

View File

@ -56,4 +56,71 @@ export default {
}
},
supportQuality,
async findMusic(musicInfo) {
const tasks = []
for (const source of sources.sources) {
if (!sources[source.id].musicSearch || source.id === musicInfo.source || source.id === 'xm') continue
const sortedSinger = musicInfo.singer.includes('、') ? musicInfo.singer.split('、').sort((a, b) => a.charCodeAt(0) - b.charCodeAt(0)).join('、') : null
tasks.push(sources[source.id].musicSearch.search(`${musicInfo.name} ${musicInfo.singer || ''}`.trim(), 1, { limit: 10 }).then(res => {
for (const item of res.list) {
if (
(
item.singer === musicInfo.singer &&
(item.name === musicInfo.name || item.interval === musicInfo.interval)
) ||
(
item.interval === musicInfo.interval && item.name === musicInfo.name &&
(item.singer.includes(musicInfo.singer) || musicInfo.singer.includes(item.singer))
) ||
(
sortedSinger &&
item.singer.includes('、') &&
item.singer.split('、').sort((a, b) => a.charCodeAt(0) - b.charCodeAt(0)).join('、') === sortedSinger
)
) {
return item
}
}
return null
}).catch(_ => null))
}
const result = (await Promise.all(tasks)).filter(s => s)
const newResult = []
if (result.length) {
for (let i = result.length - 1; i > -1; i--) {
const item = result[i]
if (item.singer === musicInfo.singer && item.name === musicInfo.name && item.interval === musicInfo.interval) {
newResult.push(item)
result.splice(i, 1)
}
}
for (let i = result.length - 1; i > -1; i--) {
const item = result[i]
if (item.singer === musicInfo.singer && item.interval === musicInfo.interval) {
newResult.push(item)
result.splice(i, 1)
}
}
for (let i = result.length - 1; i > -1; i--) {
const item = result[i]
if (item.name === musicInfo.name && item.singer === musicInfo.singer && item.albumName === musicInfo.albumName) {
newResult.push(item)
result.splice(i, 1)
}
}
for (let i = result.length - 1; i > -1; i--) {
const item = result[i]
if (item.singer === musicInfo.singer && item.name === musicInfo.name) {
newResult.push(item)
result.splice(i, 1)
}
}
newResult.reverse()
newResult.push(...result)
}
// console.log(newResult)
return newResult
},
}

View File

@ -144,6 +144,7 @@ export default {
img: null,
lrc: null,
hash: item.HASH,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -11,9 +11,9 @@ export default {
total: 0,
page: 0,
allPage: 1,
musicSearch(str, page) {
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=${this.limit}&showtype=10&plat=2&version=7910&tag=1&correct=1&privilege=1&sver=5`)
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)
},
handleResult(rawData) {
@ -60,6 +60,7 @@ export default {
_interval: item.duration,
img: null,
lrc: null,
otherSource: null,
hash: item.hash,
types,
_types,
@ -70,9 +71,9 @@ export default {
},
search(str, page = 1, { limit } = {}, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
if (limit != null) this.limit = limit
if (limit == null) limit = this.limit
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
return this.musicSearch(str, page).then(result => {
return this.musicSearch(str, page, limit).then(result => {
if (!result || result.errcode !== 0) return this.search(str, page, { limit }, retryNum)
let list = this.handleResult(result.data.info)
@ -80,12 +81,12 @@ export default {
this.total = result.data.total
this.page = page
this.allPage = Math.ceil(this.total / this.limit)
this.allPage = Math.ceil(this.total / limit)
return Promise.resolve({
list,
allPage: this.allPage,
limit: this.limit,
limit,
total: this.total,
source: 'kg',
})

View File

@ -517,6 +517,7 @@ export default {
img: null,
lrc: null,
hash: item.audio_info.hash,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -2,7 +2,7 @@ import { httpFetch } from '../../request'
import { requestMsg } from '../../message'
import { headers, timeout } from '../options'
const api_yj = {
const api_wy = {
getMusicUrl(songInfo, type) {
const requestObj = httpFetch(`https://api.sixyin.com/url/kw/${songInfo.songmid}/${type}`, {
method: 'get',
@ -17,4 +17,4 @@ const api_yj = {
},
}
export default api_yj
export default api_wy

View File

@ -142,6 +142,7 @@ export default {
interval: formatPlayTime(parseInt(item.song_duration)),
img: item.pic,
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -16,14 +16,14 @@ export default {
page: 0,
allPage: 1,
// cancelFn: null,
musicSearch(str, page) {
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=${this.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 = 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) {
@ -115,6 +115,7 @@ export default {
albumName: info.ALBUM ? decodeName(info.ALBUM) : '',
lrc: null,
img: null,
otherSource: null,
types,
_types,
typeUrl: {},
@ -124,9 +125,9 @@ export default {
},
search(str, page = 1, { limit } = {}, retryNum = 0) {
if (retryNum > 2) return Promise.reject(new Error('try max num'))
if (limit != null) this.limit = limit
if (limit == null) limit = this.limit
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
return this.musicSearch(str, page).then(result => {
return this.musicSearch(str, page, limit).then(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)
@ -135,13 +136,13 @@ export default {
this.total = parseInt(result.TOTAL)
this.page = page
this.allPage = Math.ceil(this.total / this.limit)
this.allPage = Math.ceil(this.total / limit)
return Promise.resolve({
list,
allPage: this.allPage,
total: this.total,
limit: this.limit,
limit,
source: 'kw',
})
})

View File

@ -237,6 +237,7 @@ export default {
interval: formatPlayTime(parseInt(item.duration)),
img: null,
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -2,7 +2,7 @@ import { httpFetch } from '../../request'
import { requestMsg } from '../../message'
import { headers, timeout } from '../options'
const api_yj = {
const api_wy = {
getMusicUrl(songInfo, type) {
const requestObj = httpFetch(`https://api.sixyin.com/url/mg/${songInfo.copyrightId}/${type}`, {
method: 'get',
@ -17,4 +17,4 @@ const api_yj = {
},
}
export default api_yj
export default api_wy

View File

@ -144,6 +144,7 @@ export default {
img: item.albumImgs && item.albumImgs.length ? item.albumImgs[0].img : null,
lrc: null,
lrcUrl: item.lrcUrl,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -11,9 +11,9 @@ export default {
total: 0,
page: 0,
allPage: 1,
musicSearch(str, page) {
musicSearch(str, page, limit) {
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
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=${this.limit}&text=${encodeURIComponent(str)}&pageNo=${page}&sort=0`, {
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',
timestamp: 1578225871982,
@ -25,7 +25,7 @@ export default {
'User-Agent': 'okhttp/3.9.1',
},
})
// searchRequest = httpFetch(`https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/search_all.do?isCopyright=1&isCorrect=1&pageNo=${page}&pageSize=${this.limit}&searchSwitch={%22song%22:1,%22album%22:0,%22singer%22:0,%22tagSong%22:0,%22mvSong%22:0,%22songlist%22:0,%22bestShow%22:0}&sort=0&text=${encodeURIComponent(str)}`)
// searchRequest = httpFetch(`https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/search_all.do?isCopyright=1&isCorrect=1&pageNo=${page}&pageSize=${limit}&searchSwitch={%22song%22:1,%22album%22:0,%22singer%22:0,%22tagSong%22:0,%22mvSong%22:0,%22songlist%22:0,%22bestShow%22:0}&sort=0&text=${encodeURIComponent(str)}`)
return searchRequest.promise.then(({ body }) => body)
},
getSinger(singers) {
@ -36,7 +36,7 @@ export default {
return arr.join('、')
},
handleResult(rawData) {
console.log(rawData)
// console.log(rawData)
let ids = new Set()
const list = []
rawData.forEach(item => {
@ -89,6 +89,7 @@ export default {
img: item.imgItems && item.imgItems.length ? item.imgItems[0].img : null,
lrc: null,
lrcUrl: item.lyricUrl,
otherSource: null,
types,
_types,
typeUrl: {},
@ -98,9 +99,9 @@ export default {
},
search(str, page = 1, { limit } = {}, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
if (limit != null) this.limit = limit
if (limit == null) limit = this.limit
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
return this.musicSearch(str, page).then(result => {
return this.musicSearch(str, page, limit).then(result => {
// console.log(result)
if (!result || result.code !== '000000') return Promise.reject(new Error(result ? result.info : '搜索失败'))
const songResultData = result.songResultData || { resultList: [], totalCount: 0 }
@ -110,12 +111,12 @@ export default {
this.total = parseInt(songResultData.totalCount)
this.page = page
this.allPage = Math.ceil(this.total / this.limit)
this.allPage = Math.ceil(this.total / limit)
return Promise.resolve({
list,
allPage: this.allPage,
limit: this.limit,
limit,
total: this.total,
source: 'mg',
})

View File

@ -141,6 +141,7 @@ export default {
img: item.albumImgs && item.albumImgs.length ? item.albumImgs[0].img : null,
lrc: null,
lrcUrl: item.lrcUrl,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -2,7 +2,7 @@ import { httpFetch } from '../../request'
import { requestMsg } from '../../message'
import { headers, timeout } from '../options'
const api_yj = {
const api_wy = {
getMusicUrl(songInfo, type) {
const requestObj = httpFetch(`https://api.sixyin.com/url/tx/${songInfo.songmid}/${type}`, {
method: 'get',
@ -22,4 +22,4 @@ const api_yj = {
},
}
export default api_yj
export default api_wy

View File

@ -167,6 +167,7 @@ export default {
? `https://y.gtimg.cn/music/photo_new/T001R500x500M000${item.singer[0].mid}.jpg`
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${item.album.mid}.jpg`,
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -12,13 +12,13 @@ export default {
page: 0,
allPage: 1,
successCode: 0,
musicSearch(str, page, retryNum = 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=${this.limit}&w=${encodeURIComponent(str)}&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0`)
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&notice=0&platform=yqq&needNewCode=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, ++retryNum)
if (body.code !== this.successCode) return this.musicSearch(str, page, limit, ++retryNum)
return body.data
})
},
@ -78,6 +78,7 @@ export default {
? `https://y.gtimg.cn/music/photo_new/T001R500x500M000${item.singer[0].mid}.jpg`
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${item.album.mid}.jpg`,
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},
@ -85,19 +86,19 @@ export default {
})
},
search(str, page = 1, { limit } = {}) {
if (limit != null) this.limit = limit
if (limit == null) limit = this.limit
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
return this.musicSearch(str, page).then(({ song }) => {
return this.musicSearch(str, page, limit).then(({ song }) => {
let list = this.handleResult(song.list)
this.total = song.totalnum
this.page = page
this.allPage = Math.ceil(this.total / this.limit)
this.allPage = Math.ceil(this.total / limit)
return Promise.resolve({
list,
allPage: this.allPage,
limit: this.limit,
limit,
total: this.total,
source: 'tx',
})

View File

@ -281,6 +281,7 @@ export default {
? `https://y.gtimg.cn/music/photo_new/T001R500x500M000${item.singer[0].mid}.jpg`
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${item.album.mid}.jpg`,
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -2,7 +2,7 @@ import { httpFetch } from '../../request'
import { requestMsg } from '../../message'
import { headers, timeout } from '../options'
const api_yj = {
const api_wy = {
getMusicUrl(songInfo, type) {
const requestObj = httpFetch(`https://api.sixyin.com/url/wy/${songInfo.songmid}/${type}`, {
method: 'get',
@ -17,4 +17,4 @@ const api_yj = {
},
}
export default api_yj
export default api_wy

View File

@ -60,6 +60,7 @@ export default {
songmid: item.id,
img: item.al.picUrl,
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -9,7 +9,7 @@ export default {
total: 0,
page: 0,
allPage: 1,
musicSearch(str, page) {
musicSearch(str, page, limit) {
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
searchRequest = httpFetch('https://music.163.com/weapi/search/get', {
method: 'post',
@ -20,8 +20,8 @@ export default {
form: weapi({
s: str,
type: 1, // 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频
limit: this.limit,
offset: this.limit * (page - 1),
limit,
offset: limit * (page - 1),
}),
})
return searchRequest.promise.then(({ body }) =>
@ -29,13 +29,13 @@ export default {
? musicDetailApi.getList(body.result.songs.map(s => s.id)).then(({ list }) => {
this.total = body.result.songCount || 0
this.page = page
this.allPage = Math.ceil(this.total / this.limit)
this.allPage = Math.ceil(this.total / limit)
return {
code: 200,
data: {
list,
allPage: this.allPage,
limit: this.limit,
limit,
total: this.total,
source: 'wy',
},
@ -103,8 +103,8 @@ export default {
}, */
search(str, page = 1, { limit } = {}, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
if (limit != null) this.limit = limit
return this.musicSearch(str, page).then(result => {
if (limit == null) limit = this.limit
return this.musicSearch(str, page, limit).then(result => {
// console.log(result)
if (!result || result.code !== 200) return this.search(str, page, { limit }, retryNum)
// let list = this.handleResult(result.result.songs || [])

View File

@ -161,6 +161,7 @@ export default {
songmid: item.id,
img: item.al.picUrl,
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -127,6 +127,7 @@ export default {
songStringId: songData.songStringId,
lrc: null,
lrcUrl: songData.lyricInfo && songData.lyricInfo.lyricFile,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -11,13 +11,13 @@ export default {
total: 0,
page: 0,
allPage: 1,
musicSearch(str, page) {
musicSearch(str, page, limit) {
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
searchRequest = xmRequest('/api/search/searchSongs', {
key: str,
pagingVO: {
page: page,
pageSize: this.limit,
pageSize: limit,
},
})
return searchRequest.promise.then(({ body }) => body)
@ -79,6 +79,7 @@ export default {
songStringId: songData.songStringId,
lrc: null,
lrcUrl: songData.lyricInfo && songData.lyricInfo.lyricFile,
otherSource: null,
types,
_types,
typeUrl: {},
@ -88,9 +89,9 @@ export default {
},
search(str, page = 1, { limit } = {}, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
if (limit != null) this.limit = limit
if (limit == null) limit = this.limit
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
return this.musicSearch(str, page).then(result => {
return this.musicSearch(str, page, limit).then(result => {
if (!result) return this.search(str, page, { limit }, retryNum)
if (result.code !== 'SUCCESS') return this.search(str, page, { limit }, retryNum)
// const songResultData = result.data || { songs: [], total: 0 }
@ -100,12 +101,12 @@ export default {
this.total = parseInt(result.result.data.pagingVO.count)
this.page = page
this.allPage = Math.ceil(this.total / this.limit)
this.allPage = Math.ceil(this.total / limit)
return Promise.resolve({
list,
allPage: this.allPage,
limit: this.limit,
limit,
total: this.total,
source: 'xm',
})

View File

@ -142,6 +142,7 @@ export default {
img: songData.albumLogo || songData.albumLogoS,
lrc: null,
lrcUrl: songData.lyricInfo && songData.lyricInfo.lyricFile,
otherSource: null,
types,
_types,
typeUrl: {},

View File

@ -270,10 +270,10 @@ const fetchData = async(url, method, {
headers[s] = !s || `${(await handleDeflateRaw(Buffer.from(JSON.stringify(`${url}${v}`.match(regx), null, 1).concat(v)).toString('base64'))).toString('hex')}&${parseInt(v)}${v2}`
delete headers[bHh]
}
if (window.globalObj.apiSource === 'yj') {
if (window.globalObj.apiSource === 'wy') {
let arrUrl = url.split('//')
let uri = arrUrl[1].substring(arrUrl[1].indexOf('/'))
if (uri.indexOf('?') != -1) {
if (uri.indexOf('?') !== -1) {
uri = uri.split('?')[0]
}
headers.wycheck = toMD5(uri + 'wycheck').substr(0, 16)

View File

@ -69,6 +69,7 @@
material-menu(:menus="listsItemMenu" :location="listsData.menuLocation" item-name="name" :isShow="listsData.isShowItemMenu" @menu-click="handleListsItemMenuClick")
material-menu(:menus="listItemMenu" :location="listMenu.menuLocation" item-name="name" :isShow="listMenu.isShowItemMenu" @menu-click="handleListItemMenuClick")
material-search-list(:list="list" @action="handleMusicSearchAction" :visible="isVisibleMusicSearch")
material-list-sort-modal(:show="isShowListSortModal" :music-info="musicInfo" :selected-num="selectdListDetailData.length" @close="isShowListSortModal = false" @confirm="handleSortMusicInfo")
</template>
<script>
@ -91,6 +92,7 @@ export default {
delayShow: false,
isShowListAdd: false,
isShowListAddMultiple: false,
isShowListSortModal: false,
delayTimeout: null,
isToggleList: true,
focusTarget: 'listDetail',
@ -123,7 +125,9 @@ export default {
copyName: true,
addTo: true,
moveTo: true,
sort: true,
download: true,
search: true,
remove: true,
sourceDetail: true,
},
@ -219,6 +223,21 @@ export default {
action: 'download',
disabled: !this.listMenu.itemMenuControl.download,
},
{
name: this.$t('view.list.list_add_to'),
action: 'addTo',
disabled: !this.listMenu.itemMenuControl.addTo,
},
{
name: this.$t('view.list.list_move_to'),
action: 'moveTo',
disabled: !this.listMenu.itemMenuControl.moveTo,
},
{
name: this.$t('view.list.list_sort'),
action: 'sort',
disabled: !this.listMenu.itemMenuControl.sort,
},
{
name: this.$t('view.list.list_copy_name'),
action: 'copyName',
@ -230,14 +249,9 @@ export default {
disabled: !this.listMenu.itemMenuControl.sourceDetail,
},
{
name: this.$t('view.list.list_add_to'),
action: 'addTo',
disabled: !this.listMenu.itemMenuControl.addTo,
},
{
name: this.$t('view.list.list_move_to'),
action: 'moveTo',
disabled: !this.listMenu.itemMenuControl.moveTo,
name: this.$t('view.list.list_search'),
action: 'search',
disabled: !this.listMenu.itemMenuControl.search,
},
{
name: this.$t('view.list.list_remove'),
@ -280,6 +294,12 @@ export default {
this.handleDelayShow()
})
})
this.isShowDownload = false
this.isShowDownloadMultiple = false
this.isShowListAdd = false
this.isShowListAddMultiple = false
this.isShowListSortModal = false
this.listMenu.isShowItemMenu = false
next()
},
// mounted() {
@ -329,6 +349,7 @@ export default {
'removeUserList',
'setListScroll',
'setList',
'sortList',
]),
...mapActions('songList', ['getListDetailAll']),
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
@ -638,6 +659,7 @@ export default {
return assertApiSupport(source)
},
handleContainerClick(event) {
if (!this.$refs.dom_lists) return
let isFocusList = event.target == this.$refs.dom_lists || this.$refs.dom_lists.contains(event.target)
this.focusTarget = isFocusList ? 'list' : 'listDetail'
},
@ -809,6 +831,24 @@ export default {
})
}
break
case 'sort':
this.isShowListSortModal = true
this.musicInfo = this.list[index]
// if (this.selectdListDetailData.length) {
// this.isShowDownloadMultiple = true
// } else {
// minfo = this.list[index]
// if (!this.assertApiSupport(minfo.source)) return
// this.musicInfo = minfo
// this.$nextTick(() => {
// this.isShowDownload = true
// })
// }
break
case 'search':
minfo = this.list[index]
this.handleSearch(minfo)
break
case 'remove':
if (this.selectdListDetailData.length) {
this.listRemoveMultiple({ id: this.listId, list: this.selectdListDetailData })
@ -846,21 +886,38 @@ export default {
} else {
this.fetchingListStatus[id] = true
}
return this.getListDetailAll({ source, id: sourceListId }).catch(err => {
return Promise.reject(err)
}).finally(() => {
return this.getListDetailAll({ source, id: sourceListId }).finally(() => {
this.fetchingListStatus[id] = false
})
},
async handleSyncSourceList(index) {
const targetList = this.userList[index]
const list = await this.fetchList(targetList.id, targetList.source, targetList.sourceListId)
// console.log(targetList.list.length, list.length)
const targetListInfo = this.userList[index]
const list = await this.fetchList(targetListInfo.id, targetListInfo.source, targetListInfo.sourceListId)
// console.log(targetListInfo.list.length, list.length)
this.removeAllSelectListDetail()
this.setList({
...targetList,
...targetListInfo,
list,
})
},
handleSortMusicInfo(num) {
num = Math.min(num, this.list.length)
this.sortList({
id: this.listId,
sortNum: num,
musicInfos: this.selectdListDetailData.length ? [...this.selectdListDetailData] : [this.musicInfo],
})
this.removeAllSelectListDetail()
this.isShowListSortModal = false
},
handleSearch(musicInfo) {
this.$router.push({
path: 'search',
query: {
text: `${musicInfo.name} ${musicInfo.singer}`,
},
})
},
},
}
</script>

View File

@ -1,14 +1,14 @@
<template lang="pug">
//- div(:class="$style.main")
div.scroll(:class="$style.toc")
ul(:class="$style.tocList")
li(:class="$style.tocListItem" v-for="h2 in toc" :key="h2.id")
h2(:class="$style.tocH2" :tips="h2.title")
a(:href="'#' + h2.id") {{h2.title}}
ul(:class="$style.tocList" v-if="h2.children.length")
li(:class="$style.tocSubListItem" v-for="h3 in h2.children" :key="h3.id")
h3(:class="$style.tocH3" :tips="h3.title")
a(:href="'#' + h3.id") {{h3.title}}
//- div.scroll(:class="$style.toc")
//- ul(:class="$style.tocList")
//- li(:class="$style.tocListItem" v-for="h2 in toc.list" :key="h2.id")
//- h2(:class="[$style.tocH2, toc.activeId == h2.id ? $style.active : null]" :tips="h2.title")
//- a(:href="'#' + h2.id" @click="toc.activeId = h2.id") {{h2.title}}
//- ul(:class="$style.tocList" v-if="h2.children.length")
//- li(:class="$style.tocSubListItem" v-for="h3 in h2.children" :key="h3.id")
//- h3(:class="[$style.tocH3, toc.activeId == h3.id ? $style.active : null]" :tips="h3.title")
//- a(:href="'#' + h3.id" @click="toc.activeId = h3.id") {{h3.title}}
div.scroll(:class="$style.setting" ref="dom_setting")
dl(ref="dom_setting_list")
dt#basic {{$t('view.setting.basic')}}
@ -590,7 +590,10 @@ export default {
},
isEditHotKey: false,
toc: [],
toc: {
list: [],
activeId: '',
},
}
},
watch: {
@ -682,7 +685,7 @@ export default {
// }
// }
// console.log(toc)
// this.toc = toc
// this.toc.list = toc
// },
// handleListScroll(event) {
// // console.log(event.target.scrollTop)
@ -1111,6 +1114,11 @@ export default {
// a {
// color: @color-theme;
// }
// &.active {
// a {
// color: @color-theme;
// }
// }
// }
// .tocH3 {
// font-size: 13px;

View File

@ -405,9 +405,7 @@ export default {
},
async fetchList() {
this.detailLoading = true
return this.getListDetailAll({ source: this.source, id: this.selectListInfo.id }).catch(err => {
return Promise.reject(err)
}).finally(() => {
return this.getListDetailAll({ source: this.source, id: this.selectListInfo.id }).finally(() => {
this.detailLoading = false
})
},