新增列表多选操作功能
parent
8817318a53
commit
601e1a67a1
|
@ -10,7 +10,7 @@ const { mergeCSSLoaderDev } = require('../utils')
|
|||
|
||||
module.exports = merge(baseConfig, {
|
||||
mode: 'development',
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
devtool: 'eval-source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ module.exports = merge(baseConfig, {
|
|||
NODE_ENV: '"development"',
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 'true',
|
||||
},
|
||||
'__static': `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
__static: `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
],
|
||||
performance: {
|
||||
|
|
|
@ -9,7 +9,7 @@ const { mergeCSSLoaderDev } = require('../utils')
|
|||
|
||||
module.exports = merge(baseConfig, {
|
||||
mode: 'development',
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
devtool: 'eval-source-map',
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: path.join(__dirname, '../../dist/web'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.4",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
### 新增
|
||||
|
||||
- 新增搜索列表批量试听与下载功能
|
||||
- 新增排行榜列表批量试听与下载功能
|
||||
- 新增试听列表批量移除与下载功能
|
||||
- 新增下载列表批量开始、暂停与移除功能
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化歌曲切换机制
|
|
@ -16,7 +16,7 @@ const run = async() => {
|
|||
try {
|
||||
console.log(chalk.blue('Clearing assets...'))
|
||||
await clearAssets()
|
||||
console.log(chalk.green('Assets clear complated...'))
|
||||
console.log(chalk.green('Assets clear completed...'))
|
||||
|
||||
// console.log(chalk.blue('Compileing assets...'))
|
||||
// await compileAssets()
|
||||
|
|
|
@ -38,6 +38,7 @@ export default {
|
|||
...mapGetters('list', ['defaultList']),
|
||||
...mapGetters('download', {
|
||||
downloadList: 'list',
|
||||
downloadStatus: 'downloadStatus',
|
||||
}),
|
||||
},
|
||||
mounted() {
|
||||
|
@ -119,6 +120,12 @@ export default {
|
|||
initDownloadList() {
|
||||
let downloadList = this.electronStore.get('download.list')
|
||||
if (downloadList) {
|
||||
downloadList.forEach(item => {
|
||||
if (item.status == this.downloadStatus.RUN || item.status == this.downloadStatus.WAITING) {
|
||||
item.status = this.downloadStatus.PAUSE
|
||||
item.statusText = '暂停下载'
|
||||
}
|
||||
})
|
||||
this.updateDownloadList(downloadList)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -252,36 +252,43 @@ export default {
|
|||
},
|
||||
handleNext() {
|
||||
// if (this.list.listName === null) return
|
||||
const list = this.isAPITemp ? this.list.filter(s => s.source == 'kw') : this.list
|
||||
if (!list.length) return
|
||||
let list
|
||||
if (this.listId == 'download') {
|
||||
list = this.list.filter(s => !(!checkPath(s.filePath) || !s.isComplate || /\.ape$/.test(s.filePath)))
|
||||
} else if (this.isAPITemp) {
|
||||
list = this.list.filter(s => s.source == 'kw')
|
||||
} else {
|
||||
list = this.list
|
||||
}
|
||||
if (!list.length) return this.setPlayIndex(-1)
|
||||
let playIndex = this.list === list ? this.playIndex : list.indexOf(this.list[this.playIndex])
|
||||
|
||||
let index
|
||||
switch (this.setting.player.togglePlayMethod) {
|
||||
case 'listLoop':
|
||||
index = this.hanldeListLoop()
|
||||
index = this.hanldeListLoop(list, playIndex)
|
||||
break
|
||||
case 'random':
|
||||
index = this.hanldeListRandom()
|
||||
index = this.hanldeListRandom(list, playIndex)
|
||||
break
|
||||
case 'list':
|
||||
index = this.hanldeListNext()
|
||||
index = this.hanldeListNext(list, playIndex)
|
||||
break
|
||||
default:
|
||||
return
|
||||
}
|
||||
if (index < 0) return
|
||||
if (this.list !== list) index = this.list.indexOf(list[index])
|
||||
this.setPlayIndex(index)
|
||||
},
|
||||
hanldeListLoop(index = this.playIndex) {
|
||||
index = index === this.list.length - 1 ? 0 : index + 1
|
||||
return this.isAPITemp && this.list[index].source != 'kw' ? this.hanldeListLoop(index) : index
|
||||
hanldeListLoop(list, index) {
|
||||
return index === list.length - 1 ? 0 : index + 1
|
||||
},
|
||||
hanldeListNext(index = this.playIndex) {
|
||||
index = index === this.list.length - 1 ? -1 : index + 1
|
||||
return this.isAPITemp && this.list[index].source != 'kw' ? this.hanldeListNext(index) : index
|
||||
hanldeListNext(list, index) {
|
||||
return index === list.length - 1 ? -1 : index + 1
|
||||
},
|
||||
hanldeListRandom(index = this.playIndex) {
|
||||
index = getRandom(0, this.list.length)
|
||||
return this.isAPITemp && this.list[index].source != 'kw' ? this.hanldeListRandom(index) : index
|
||||
hanldeListRandom(list, index) {
|
||||
return getRandom(0, list.length)
|
||||
},
|
||||
startPlay() {
|
||||
this.isPlay = true
|
||||
|
@ -333,6 +340,9 @@ export default {
|
|||
this.audio.src = this.musicInfo.url
|
||||
}).catch(err => {
|
||||
this.status = err.message
|
||||
setTimeout(() => {
|
||||
this.handleNext()
|
||||
}, 2000)
|
||||
})
|
||||
},
|
||||
setImg(targetSong) {
|
||||
|
|
|
@ -10,7 +10,7 @@ div(:class="$style.checkbox")
|
|||
div(v-else)
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' width="100%" viewBox='0 32 448 448' space='preserve')
|
||||
use(xlink:href='#icon-check-true')
|
||||
span(v-if="label != null") {{label}}
|
||||
span(v-if="label != null" v-html="label")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
<template lang="pug">
|
||||
material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
||||
main(:class="$style.main")
|
||||
h2
|
||||
| 已选择 {{list.length}} 首歌曲
|
||||
br
|
||||
| 请选择要优先下载的音质
|
||||
material-btn(:class="$style.btn" @click="handleClick('128k')") 普通音质 - 128K
|
||||
material-btn(:class="$style.btn" @click="handleClick('320k')") 高品音质 - 320K
|
||||
material-btn(:class="$style.btn" @click="handleClick('ape')") 无损音质 - APE
|
||||
material-btn(:class="$style.btn" @click="handleClick('flac')") 无损音质 - FLAC
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
bgClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClick(type) {
|
||||
this.$emit('select', type)
|
||||
},
|
||||
handleClose() {
|
||||
this.$emit('close')
|
||||
},
|
||||
getTypeName(type) {
|
||||
switch (type) {
|
||||
case 'flac':
|
||||
case 'ape':
|
||||
return '无损音质'
|
||||
case '320k':
|
||||
return '高品音质'
|
||||
case '192k':
|
||||
case '128k':
|
||||
return '普通音质'
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
padding: 15px;
|
||||
max-width: 300px;
|
||||
min-width: 200px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
h2 {
|
||||
font-size: 13px;
|
||||
color: @color-theme_2-font;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
margin-bottom: 15px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.main {
|
||||
h2 {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
|
@ -0,0 +1,122 @@
|
|||
<template lang="pug">
|
||||
transition(enter-active-class="animated-fast zoomIn" leave-active-class="animated zoomOut")
|
||||
div(:class="$style.btns" v-show="show")
|
||||
button(type="button" v-if="playBtn" title="播放" @click.stop="handleClick('play')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 287.386 287.386' space='preserve')
|
||||
use(xlink:href='#icon-testPlay')
|
||||
button(type="button" v-if="addBtn" title="添加" @click.stop="handleClick('add')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve')
|
||||
use(xlink:href='#icon-addTo')
|
||||
button(type="button" v-if="downloadBtn" title="下载" @click.stop="handleClick('download')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 475.078 475.077' space='preserve')
|
||||
use(xlink:href='#icon-download')
|
||||
button(type="button" v-if="startBtn" title="开始" @click.stop="handleClick('start')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
button(type="button" v-if="pauseBtn" title="暂停" @click.stop="handleClick('pause')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
button(type="button" v-if="removeBtn" title="移除" @click.stop="handleClick('remove')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
|
||||
use(xlink:href='#icon-delete')
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: {
|
||||
removeBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
startBtn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
pauseBtn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
downloadBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
addBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
playBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClick(action) {
|
||||
this.$emit('btn-click', action)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.btns {
|
||||
position: fixed;
|
||||
bottom: 80px;
|
||||
right: 30px;
|
||||
background-color: @color-search-form-background;
|
||||
border-radius: 5px;
|
||||
// padding: 3px 5px;
|
||||
box-shadow: 0 1px 5px 0 rgba(0,0,0,.2);
|
||||
button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
padding: 4px 7px;
|
||||
color: @color-btn;
|
||||
outline: none;
|
||||
transition: background-color 0.2s ease;
|
||||
line-height: 0;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 1.2em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @color-theme_2-hover;
|
||||
}
|
||||
&:active {
|
||||
background-color: @color-theme_2-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.btns {
|
||||
background-color: ~'@{color-@{value}-search-form-background}';
|
||||
button {
|
||||
color: ~'@{color-@{value}-btn}';
|
||||
&:hover {
|
||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||
}
|
||||
&:active {
|
||||
background-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
|
@ -9,6 +9,12 @@ div(:class="$style.btns")
|
|||
button(type="button" title="添加" v-if="userInfo" @click.stop="handleClick('add')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve')
|
||||
use(xlink:href='#icon-addTo')
|
||||
button(type="button" v-if="startBtn" title="开始" @click.stop="handleClick('start')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
button(type="button" v-if="pauseBtn" title="暂停" @click.stop="handleClick('pause')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
button(type="button" v-if="removeBtn" title="移除" @click.stop="handleClick('remove')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
|
||||
use(xlink:href='#icon-delete')
|
||||
|
@ -27,6 +33,14 @@ export default {
|
|||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
startBtn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
pauseBtn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
removeBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
|
|
|
@ -2,18 +2,30 @@ import download from '../../utils/download'
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import music from '../../utils/music'
|
||||
import { getMusicType } from '../../utils/music/utils'
|
||||
|
||||
// state
|
||||
const state = {
|
||||
list: [],
|
||||
waitingList: [],
|
||||
downloadStatus: {
|
||||
RUN: 'run',
|
||||
WAITING: 'waiting',
|
||||
PAUSE: 'pause',
|
||||
ERROR: 'error',
|
||||
COMPLETED: 'completed',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
const dls = {}
|
||||
const tryNum = {}
|
||||
|
||||
// getters
|
||||
const getters = {
|
||||
list: state => state.list || [],
|
||||
dls: () => dls || {},
|
||||
downloadStatus: state => state.downloadStatus,
|
||||
}
|
||||
|
||||
const checkPath = path => {
|
||||
|
@ -40,19 +52,37 @@ const getExt = type => {
|
|||
|
||||
const checkList = (list, musicInfo, type) => list.some(s => s.musicInfo.songmid === musicInfo.songmid && s.type === type)
|
||||
|
||||
const getStartTask = (list, downloadStatus, maxDownloadNum) => {
|
||||
let downloadCount = 0
|
||||
const waitList = list.filter(item => item.status == downloadStatus.WAITING ? true : (item.status === downloadStatus.RUN && ++downloadCount && false))
|
||||
console.log(downloadCount, waitList)
|
||||
return downloadCount < maxDownloadNum && waitList.length > 0 && waitList.shift()
|
||||
}
|
||||
|
||||
const addTask = (list, type, store) => {
|
||||
window.requestAnimationFrame(() => {
|
||||
let item = list.shift()
|
||||
store.dispatch('download/createDownload', {
|
||||
musicInfo: item,
|
||||
type: getMusicType(item, type),
|
||||
})
|
||||
if (list.length) addTask(list, type, store)
|
||||
})
|
||||
}
|
||||
|
||||
const refreshUrl = downloadInfo => {
|
||||
return music[downloadInfo.musicInfo.source].getMusicUrl(downloadInfo.musicInfo, downloadInfo.type).promise
|
||||
}
|
||||
|
||||
// actions
|
||||
const actions = {
|
||||
createDownload({ state, rootState }, { musicInfo, type }) {
|
||||
createDownload({ state, rootState, commit }, { musicInfo, type }) {
|
||||
if (checkList(state.list, musicInfo, type)) return
|
||||
let ext = getExt(type)
|
||||
const downloadInfo = {
|
||||
isComplate: false,
|
||||
isDownloading: false,
|
||||
statusText: '任务初始化中',
|
||||
status: state.downloadStatus.WAITING,
|
||||
statusText: '待下载',
|
||||
url: null,
|
||||
fileName: `${rootState.setting.download.fileName
|
||||
.replace('歌名', musicInfo.name)
|
||||
|
@ -68,19 +98,33 @@ const actions = {
|
|||
key: `${musicInfo.songmid}${ext}`,
|
||||
}
|
||||
downloadInfo.filePath = path.join(rootState.setting.download.savePath, downloadInfo.fileName)
|
||||
commit('addTask', downloadInfo)
|
||||
if (dls[downloadInfo.key]) {
|
||||
dls[downloadInfo.key].stop().finally(() => {
|
||||
this.dispatch('download/addTask', downloadInfo)
|
||||
delete dls[downloadInfo.key]
|
||||
this.dispatch('download/startTask', downloadInfo)
|
||||
})
|
||||
} else {
|
||||
// console.log(downloadInfo)
|
||||
this.dispatch('download/addTask', downloadInfo)
|
||||
this.dispatch('download/startTask', downloadInfo)
|
||||
}
|
||||
},
|
||||
addTask({ commit, rootState }, downloadInfo) {
|
||||
commit('addTask', downloadInfo)
|
||||
createDownloadMultiple({ state, rootState }, { list, type }) {
|
||||
addTask([...list], type, this)
|
||||
},
|
||||
startTask({ commit, state, rootState }, downloadInfo) {
|
||||
// 检查是否可以开始任务
|
||||
if (downloadInfo && downloadInfo != state.downloadStatus.WAITING) commit('setStatus', { downloadInfo, status: state.downloadStatus.WAITING })
|
||||
let result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum)
|
||||
if (!result) return downloadInfo && commit('setStatus', { downloadInfo, status: state.downloadStatus.WAITING })
|
||||
if (!downloadInfo) downloadInfo = result
|
||||
|
||||
// 开始任务
|
||||
commit('setStatusText', { downloadInfo, text: '任务初始化中' })
|
||||
commit('onDownload', downloadInfo)
|
||||
let msg = checkPath(rootState.setting.download.savePath)
|
||||
if (msg) return commit('setStatusText', '检查下载目录出错: ' + msg)
|
||||
const _this = this
|
||||
const options = {
|
||||
url: downloadInfo.url,
|
||||
path: rootState.setting.download.savePath,
|
||||
|
@ -89,37 +133,46 @@ const actions = {
|
|||
override: true,
|
||||
onEnd() {
|
||||
commit('onEnd', downloadInfo)
|
||||
_this.dispatch('download/startTask')
|
||||
console.log('on complate')
|
||||
},
|
||||
onError(err) {
|
||||
console.log(err)
|
||||
if (err.message.includes('Response status was')) {
|
||||
const code = err.message.replace(/Response status was (\d+)$/, '$1')
|
||||
switch (code) {
|
||||
case '401':
|
||||
case '403':
|
||||
case '410':
|
||||
commit('setStatusText', { downloadInfo, text: '链接失效,正在刷新链接' })
|
||||
refreshUrl(downloadInfo).then(result => {
|
||||
commit('updateUrl', { downloadInfo, url: result.url })
|
||||
commit('setStatusText', { downloadInfo, text: '链接刷新成功' })
|
||||
dls[downloadInfo.key].url = dls[downloadInfo.key].requestURL = result.url
|
||||
dls[downloadInfo.key].__initProtocol(result.url)
|
||||
dls[downloadInfo.key].resume()
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
return
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
console.log(err.message)
|
||||
commit('onError', downloadInfo)
|
||||
// console.log(tryNum[downloadInfo.key])
|
||||
if (++tryNum[downloadInfo.key] > 5) return
|
||||
let code
|
||||
if (err.message.includes('Response status was')) {
|
||||
code = err.message.replace(/Response status was (\d+)$/, '$1')
|
||||
} if (err.code === 'ETIMEDOUT') {
|
||||
code = 'ETIMEDOUT'
|
||||
} else {
|
||||
console.log('Download failed, Attempting Retry')
|
||||
dls[downloadInfo.key].resume()
|
||||
commit('setStatusText', { downloadInfo, text: '正在重试' })
|
||||
return
|
||||
}
|
||||
switch (code) {
|
||||
case '401':
|
||||
case '403':
|
||||
case '410':
|
||||
case 'ETIMEDOUT':
|
||||
commit('setStatusText', { downloadInfo, text: '链接失效,正在刷新链接' })
|
||||
refreshUrl(downloadInfo).then(result => {
|
||||
commit('updateUrl', { downloadInfo, url: result.url })
|
||||
commit('setStatusText', { downloadInfo, text: '链接刷新成功' })
|
||||
dls[downloadInfo.key].url = dls[downloadInfo.key].requestURL = result.url
|
||||
dls[downloadInfo.key].__initProtocol(result.url)
|
||||
dls[downloadInfo.key].resume()
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
_this.dispatch('download/startTask')
|
||||
})
|
||||
}
|
||||
},
|
||||
onStateChanged(state) {
|
||||
console.log(state)
|
||||
},
|
||||
// onStateChanged(state) {
|
||||
// console.log(state)
|
||||
// },
|
||||
onDownload() {
|
||||
commit('onDownload', downloadInfo)
|
||||
console.log('on download')
|
||||
|
@ -130,6 +183,7 @@ const actions = {
|
|||
},
|
||||
onPause() {
|
||||
commit('pauseTask', downloadInfo)
|
||||
_this.dispatch('download/startTask')
|
||||
},
|
||||
onResume() {
|
||||
commit('resumeTask', downloadInfo)
|
||||
|
@ -138,80 +192,52 @@ const actions = {
|
|||
let p = options.url ? Promise.resolve() : refreshUrl(downloadInfo).then(result => {
|
||||
commit('updateUrl', { downloadInfo, url: result.url })
|
||||
options.url = result.url
|
||||
}).catch(err => {
|
||||
commit('onError', downloadInfo)
|
||||
commit('setStatusText', { downloadInfo, text: err.message })
|
||||
return Promise.reject(err)
|
||||
})
|
||||
p.then(() => {
|
||||
tryNum[downloadInfo.key] = 0
|
||||
dls[downloadInfo.key] = download(options)
|
||||
})
|
||||
},
|
||||
startTaskMultiple({ state, rootState }, list) {
|
||||
|
||||
},
|
||||
removeTask({ commit, state }, index) {
|
||||
let info = state.list[index]
|
||||
if (state.list[index].isDownloading) {
|
||||
dls[info.key].stop().finally(() => {
|
||||
delete dls[info.key]
|
||||
})
|
||||
if (state.list[index].status == state.downloadStatus.RUN) {
|
||||
if (dls[info.key]) {
|
||||
dls[info.key].stop().finally(() => {
|
||||
delete dls[info.key]
|
||||
})
|
||||
}
|
||||
}
|
||||
commit('removeTask', index)
|
||||
if (dls[info.key]) delete dls[info.key]
|
||||
this.dispatch('download/startTask')
|
||||
},
|
||||
resumeTask({ commit, rootState }, downloadInfo) {
|
||||
let msg = checkPath(rootState.setting.download.savePath)
|
||||
if (msg) return commit('setStatusText', '检查下载目录出错: ' + msg)
|
||||
const options = {
|
||||
url: downloadInfo.url,
|
||||
path: rootState.setting.download.savePath,
|
||||
fileName: downloadInfo.fileName,
|
||||
method: 'get',
|
||||
override: true,
|
||||
onEnd() {
|
||||
commit('onEnd', downloadInfo)
|
||||
console.log('on complate')
|
||||
},
|
||||
onError(err) {
|
||||
commit('onError', downloadInfo)
|
||||
commit('setStatusText', { downloadInfo, text: '链接失效,正在刷新链接' })
|
||||
refreshUrl(downloadInfo).then(result => {
|
||||
commit('updateUrl', { downloadInfo, url: result.url })
|
||||
commit('setStatusText', { downloadInfo, text: '链接刷新成功' })
|
||||
dls[downloadInfo.key].url = dls[downloadInfo.key].requestURL = result.url
|
||||
dls[downloadInfo.key].__initProtocol(result.url)
|
||||
dls[downloadInfo.key].resume()
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
console.log(err)
|
||||
},
|
||||
onStateChanged(state) {
|
||||
console.log(state)
|
||||
},
|
||||
onDownload() {
|
||||
commit('onDownload', downloadInfo)
|
||||
console.log('on download')
|
||||
},
|
||||
onProgress(status) {
|
||||
commit('onProgress', { downloadInfo, status })
|
||||
console.log(status)
|
||||
},
|
||||
onPause() {
|
||||
commit('pauseTask', downloadInfo)
|
||||
},
|
||||
onResume() {
|
||||
commit('resumeTask', downloadInfo)
|
||||
},
|
||||
}
|
||||
|
||||
let p = options.url ? Promise.resolve() : refreshUrl(downloadInfo).then(result => {
|
||||
commit('updateUrl', { downloadInfo, url: result.url })
|
||||
options.url = result.url
|
||||
})
|
||||
|
||||
if (fs.existsSync(downloadInfo.filePath)) {
|
||||
options.resumeInfo = {
|
||||
totalFileSize: downloadInfo.progress.total,
|
||||
removeTaskMultiple({ commit, rootState, state }, list) {
|
||||
list.forEach(item => {
|
||||
let index = state.list.indexOf(item)
|
||||
if (index < 0) return
|
||||
// this.dispatch('download/removeTask', index)
|
||||
if (state.list[index].status == state.downloadStatus.RUN) {
|
||||
if (dls[item.key]) {
|
||||
dls[item.key].stop().finally(() => {
|
||||
delete dls[item.key]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
p.then(() => {
|
||||
dls[downloadInfo.key] = download(options)
|
||||
commit('removeTask', index)
|
||||
if (dls[item.key]) delete dls[item.key]
|
||||
})
|
||||
let result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum)
|
||||
while (result) {
|
||||
this.dispatch('download/startTask', result)
|
||||
result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -224,29 +250,57 @@ const mutations = {
|
|||
state.list.splice(index, 1)
|
||||
},
|
||||
pauseTask(state, downloadInfo) {
|
||||
downloadInfo.isDownloading = false
|
||||
downloadInfo.status = state.downloadStatus.PAUSE
|
||||
downloadInfo.statusText = '暂停下载'
|
||||
},
|
||||
resumeTask(state, downloadInfo) {
|
||||
downloadInfo.statusText = '恢复下载'
|
||||
downloadInfo.statusText = '开始下载'
|
||||
},
|
||||
setStatusText(state, { downloadInfo, index, text }) {
|
||||
setStatusText(state, { downloadInfo, index, text }) { // 设置状态文本
|
||||
if (downloadInfo) {
|
||||
downloadInfo.statusText = text
|
||||
} else {
|
||||
state.list[index].statusText = text
|
||||
}
|
||||
},
|
||||
setStatus(state, { downloadInfo, index, status }) { // 设置状态及状态文本
|
||||
let text
|
||||
switch (status) {
|
||||
case state.downloadStatus.RUN:
|
||||
text = '正在下载'
|
||||
break
|
||||
case state.downloadStatus.WAITING:
|
||||
text = '等待下载'
|
||||
break
|
||||
case state.downloadStatus.PAUSE:
|
||||
text = '暂停下载'
|
||||
break
|
||||
case state.downloadStatus.ERROR:
|
||||
text = '任务出错'
|
||||
break
|
||||
case state.downloadStatus.COMPLETED:
|
||||
text = '下载完成'
|
||||
break
|
||||
}
|
||||
if (downloadInfo) {
|
||||
downloadInfo.statusText = text
|
||||
downloadInfo.status = status
|
||||
} else {
|
||||
state.list[index].statusText = text
|
||||
state.list[index].status = status
|
||||
}
|
||||
},
|
||||
onEnd(state, downloadInfo) {
|
||||
downloadInfo.isComplate = true
|
||||
downloadInfo.isDownloading = false
|
||||
downloadInfo.status = state.downloadStatus.COMPLETED
|
||||
downloadInfo.statusText = '下载完成'
|
||||
},
|
||||
onError(state, downloadInfo) {
|
||||
downloadInfo.isDownloading = false
|
||||
downloadInfo.status = state.downloadStatus.ERROR
|
||||
downloadInfo.statusText = '任务出错'
|
||||
},
|
||||
onDownload(state, downloadInfo) {
|
||||
downloadInfo.isDownloading = true
|
||||
downloadInfo.status = state.downloadStatus.RUN
|
||||
downloadInfo.statusText = '正在下载'
|
||||
},
|
||||
onProgress(state, { downloadInfo, status }) {
|
||||
|
|
|
@ -30,9 +30,22 @@ const mutations = {
|
|||
if (state.defaultList.list.some(s => s.songmid === musicInfo.songmid)) return
|
||||
state.defaultList.list.push(musicInfo)
|
||||
},
|
||||
defaultListAddMultiple(state, list) {
|
||||
list.forEach(musicInfo => {
|
||||
if (state.defaultList.list.some(s => s.songmid === musicInfo.songmid)) return
|
||||
state.defaultList.list.push(musicInfo)
|
||||
})
|
||||
},
|
||||
defaultListRemove(state, index) {
|
||||
state.defaultList.list.splice(index, 1)
|
||||
},
|
||||
defaultListRemoveMultiple(state, list) {
|
||||
list.forEach(musicInfo => {
|
||||
let index = state.defaultList.list.indexOf(musicInfo)
|
||||
if (index < 0) return
|
||||
state.defaultList.list.splice(index, 1)
|
||||
})
|
||||
},
|
||||
defaultListClear(state) {
|
||||
state.defaultList.list.length = 0
|
||||
},
|
||||
|
|
|
@ -45,9 +45,8 @@ export default ({
|
|||
onEnd()
|
||||
debugDownload && console.log('Download Completed')
|
||||
}).on('error', err => {
|
||||
if (err.message === 'socket hang up') return
|
||||
onError(err)
|
||||
dl.resume()
|
||||
console.log('Download failed, Attempting Retry')
|
||||
debugDownload && console.error('Something happend', err)
|
||||
}).on('stateChanged', state => {
|
||||
onStateChanged(state)
|
||||
|
|
|
@ -156,8 +156,12 @@ export const isChildren = (parent, children) => {
|
|||
return children.parentNode ? children.parentNode === parent ? true : isChildren(parent, children.parentNode) : false
|
||||
}
|
||||
|
||||
/**
|
||||
* 升级设置
|
||||
* @param {*} setting
|
||||
*/
|
||||
export const updateSetting = setting => {
|
||||
const defaultVersion = '1.0.2'
|
||||
const defaultVersion = '1.0.3'
|
||||
const defaultSetting = {
|
||||
version: defaultVersion,
|
||||
player: {
|
||||
|
@ -170,6 +174,7 @@ export const updateSetting = setting => {
|
|||
download: {
|
||||
savePath: path.join(os.homedir(), 'Desktop'),
|
||||
fileName: '歌名 - 歌手',
|
||||
maxDownloadNum: 3,
|
||||
},
|
||||
leaderboard: {
|
||||
source: 'kw',
|
||||
|
@ -203,3 +208,4 @@ export const updateSetting = setting => {
|
|||
export const openUrl = url => {
|
||||
shell.openExternal(url)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export const requestMsg = {
|
||||
fail: '请求异常😮,可以多试几次,若还是不行就换一首吧。。。',
|
||||
unachievable: '哦No😱...接口无法访问了!已帮你切换到临时接口,重试下看能不能播放吧~',
|
||||
notConnectNetwork: '无法连接网络',
|
||||
cancelRequest: '取消http请求',
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
|
@ -7,7 +8,7 @@ const api_messoer = {
|
|||
timeout: 5000,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(body.msg))
|
||||
return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
|
@ -17,7 +18,7 @@ const api_messoer = {
|
|||
timeout: 5000,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(body.msg))
|
||||
return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
|
|
|
@ -7,11 +7,6 @@ const api_temp = {
|
|||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(body.msg))
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
if (err.message === 'socket hang up') return Promise.reject(new Error('接口挂了'))
|
||||
if (err.code === 'ENOTFOUND') return Promise.reject(new Error('无法连接网络'))
|
||||
return Promise.reject(err)
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
|
@ -21,10 +16,6 @@ const api_temp = {
|
|||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(body.msg))
|
||||
}).catch(err => {
|
||||
if (err.message === 'socket hang up') return Promise.reject(new Error('接口挂了'))
|
||||
if (err.code === 'ENOTFOUND') return Promise.reject(new Error('无法连接网络'))
|
||||
return Promise.reject(err)
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
|
||||
const api_messoer = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
|
@ -7,7 +8,7 @@ const api_messoer = {
|
|||
timeout: 5000,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(body.msg))
|
||||
return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* 获取音乐音质
|
||||
* @param {*} info
|
||||
* @param {*} type
|
||||
*/
|
||||
const types = ['flac', 'ape', '320k', '192k', '128k']
|
||||
export const getMusicType = (info, type) => {
|
||||
const rangeType = types.slice(types.indexOf(type))
|
||||
for (const type of rangeType) {
|
||||
if (info._types[type]) return type
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import request from 'request'
|
||||
// import progress from 'request-progress'
|
||||
import { debugRequest } from './env'
|
||||
import { requestMsg } from './message'
|
||||
// import fs from 'fs'
|
||||
|
||||
const headers = {
|
||||
|
@ -9,7 +10,7 @@ const headers = {
|
|||
|
||||
const fatchData = (url, method, options, callback) => {
|
||||
// console.log(url, options)
|
||||
// console.log('---start---', url)
|
||||
console.log('---start---', url)
|
||||
return request(url, {
|
||||
method,
|
||||
headers: Object.assign({}, headers, options.headers || {}),
|
||||
|
@ -60,7 +61,7 @@ const buildHttpPromose = (url, options) => {
|
|||
console.log('cancel')
|
||||
if (!requestObj) return
|
||||
cancelHttp(requestObj)
|
||||
cancelFn(new Error('取消http请求'))
|
||||
cancelFn(new Error(requestMsg.cancelRequest))
|
||||
requestObj = null
|
||||
cancelFn = null
|
||||
},
|
||||
|
@ -84,9 +85,9 @@ export const httpFatch = (url, options = { method: 'get' }) => {
|
|||
}
|
||||
if (err.message === 'socket hang up') {
|
||||
window.globalObj.apiSource = 'temp'
|
||||
return Promise.reject(new Error('哦No😱...接口无法访问了!已帮你切换到临时接口,重试下看能不能播放吧~'))
|
||||
return Promise.reject(new Error(requestMsg.unachievable))
|
||||
}
|
||||
if (err.code === 'ENOTFOUND') return Promise.reject(new Error('无法连接网络'))
|
||||
if (err.code === 'ENOTFOUND') return Promise.reject(new Error(requestMsg.notConnectNetwork))
|
||||
return Promise.reject(err)
|
||||
})
|
||||
return requestObj
|
||||
|
|
|
@ -6,8 +6,11 @@ div(:class="$style.download")
|
|||
table
|
||||
thead
|
||||
tr
|
||||
th.nobreak(style="width: 30%;") 歌曲名
|
||||
th.nobreak(style="width: 25%;") 进度
|
||||
th.nobreak.center(style="width: 37px;")
|
||||
material-checkbox(id="search_select_all" v-model="isSelectAll" @change="handleSelectAllData"
|
||||
:indeterminate="isIndeterminate" :title="isSelectAll && !isIndeterminate ? '全不选' : '全选'")
|
||||
th.nobreak(style="width: 28%;") 歌曲名
|
||||
th.nobreak(style="width: 22%;") 进度
|
||||
th.nobreak(style="width: 15%;") 状态
|
||||
th.nobreak(style="width: 10%;") 品质
|
||||
th.nobreak(style="width: 20%;") 操作
|
||||
|
@ -15,12 +18,17 @@ div(:class="$style.download")
|
|||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.key' @click="handleDoubleClick(index)" :class="isPlayList && playIndex === index ? $style.active : ''")
|
||||
td.break(style="width: 30%;") {{item.musicInfo.name}} - {{item.musicInfo.singer}}
|
||||
td.break(style="width: 25%;") {{item.progress.progress}}%
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
td.break(style="width: 28%;") {{item.musicInfo.name}} - {{item.musicInfo.singer}}
|
||||
td.break(style="width: 22%;") {{item.progress.progress}}%
|
||||
td.break(style="width: 15%;") {{item.statusText}}
|
||||
td.break(style="width: 10%;") {{item.type.toUpperCase()}}
|
||||
td(style="width: 20%; padding-left: 0; padding-right: 0;")
|
||||
material-list-buttons(:index="index" :downloadBtn="false" @btn-click="handleBtnClick")
|
||||
material-list-buttons(:index="index" :download-btn="false" :start-btn="!item.isComplate && item.status != downloadStatus.WAITING && (item.status != downloadStatus.RUN)"
|
||||
:pause-btn="!item.isComplate && (item.status == downloadStatus.RUN || item.status == downloadStatus.WAITING)"
|
||||
:play-btn="item.status == downloadStatus.COMPLETED" @btn-click="handleListBtnClick")
|
||||
material-flow-btn(:show="isShowEditBtn" :play-btn="false" :download-btn="false" :add-btn="false" :start-btn="true" :pause-btn="true" @btn-click="handleFlowBtnClick")
|
||||
div(:class="$style.noItem" v-else)
|
||||
</template>
|
||||
|
||||
|
@ -34,26 +42,51 @@ export default {
|
|||
return {
|
||||
clickTime: window.performance.now(),
|
||||
clickIndex: -1,
|
||||
selectdData: [],
|
||||
isSelectAll: false,
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
isShowDownloadMultiple: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('download', ['list', 'dls']),
|
||||
...mapGetters('download', ['list', 'dls', 'downloadStatus']),
|
||||
...mapGetters('player', ['listId', 'playIndex']),
|
||||
isPlayList() {
|
||||
return this.listId == 'download'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('download', ['removeTask', 'resumeTask']),
|
||||
...mapMutations('player', ['setList']),
|
||||
pauseTask(index) {
|
||||
let info = this.list[index]
|
||||
this.dls[info.key].pause()
|
||||
watch: {
|
||||
selectdData(n) {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isShowEditBtn = true
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
}
|
||||
},
|
||||
startTask(index) {
|
||||
list() {
|
||||
this.resetSelect()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('download', ['removeTask', 'removeTaskMultiple', 'startTask']),
|
||||
...mapMutations('player', ['setList']),
|
||||
...mapMutations('download', ['pauseTask']),
|
||||
handlePauseTask(index) {
|
||||
let info = this.list[index]
|
||||
let dl = this.dls[info.key]
|
||||
dl ? dl.resume() : this.resumeTask(info)
|
||||
dl ? dl.pause() : this.pauseTask(info)
|
||||
console.log('pause')
|
||||
},
|
||||
handleStartTask(index) {
|
||||
console.log('start')
|
||||
let info = this.list[index]
|
||||
let dl = this.dls[info.key]
|
||||
dl ? dl.resume() : this.startTask(info)
|
||||
},
|
||||
handleDoubleClick(index) {
|
||||
if (
|
||||
|
@ -72,26 +105,71 @@ export default {
|
|||
let info = this.list[index]
|
||||
if (info.isComplate) {
|
||||
this.handlePlay(index)
|
||||
} else if (info.isDownloading) {
|
||||
this.pauseTask(index)
|
||||
} else if (info.status === this.downloadStatus.RUN) {
|
||||
this.handlePauseTask(index)
|
||||
} else {
|
||||
this.startTask(index)
|
||||
this.handleStartTask(index)
|
||||
}
|
||||
},
|
||||
handlePlay(index) {
|
||||
if (!checkPath(this.list[index].filePath)) return
|
||||
this.setList({ list: this.list, listId: 'download', index })
|
||||
},
|
||||
handleBtnClick(info) {
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
case 'play':
|
||||
this.handlePlay(info.index)
|
||||
break
|
||||
case 'start':
|
||||
this.handleStartTask(info.index)
|
||||
break
|
||||
case 'pause':
|
||||
this.handlePauseTask(info.index)
|
||||
break
|
||||
case 'remove':
|
||||
this.removeTask(info.index)
|
||||
break
|
||||
}
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdData = isSelect ? [...this.list] : []
|
||||
},
|
||||
resetSelect() {
|
||||
this.isSelectAll = false
|
||||
this.selectdData = []
|
||||
},
|
||||
handleFlowBtnClick(action) {
|
||||
switch (action) {
|
||||
case 'start':
|
||||
this.selectdData.forEach(item => {
|
||||
if (item.isComplate || item.status == this.downloadStatus.RUN) return
|
||||
let index = this.list.indexOf(item)
|
||||
if (index < 0) return
|
||||
this.handleStartTask(index)
|
||||
})
|
||||
break
|
||||
case 'pause':
|
||||
let runs = []
|
||||
this.selectdData.forEach(item => {
|
||||
if (item.isComplate || item.status == this.downloadStatus.PAUSE) return
|
||||
if (item.status == this.downloadStatus.RUN) return runs.push(item)
|
||||
let index = this.list.indexOf(item)
|
||||
if (index < 0) return
|
||||
this.handlePauseTask(index)
|
||||
})
|
||||
runs.forEach(item => {
|
||||
if (item.isComplate || item.status == this.downloadStatus.PAUSE) return
|
||||
let index = this.list.indexOf(item)
|
||||
if (index < 0) return
|
||||
this.handlePauseTask(index)
|
||||
})
|
||||
break
|
||||
case 'remove':
|
||||
this.removeTaskMultiple(this.selectdData)
|
||||
break
|
||||
}
|
||||
this.resetSelect()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -9,30 +9,37 @@
|
|||
table
|
||||
thead
|
||||
tr
|
||||
th.nobreak(style="width: 27%;") 歌曲名
|
||||
th.nobreak.center(style="width: 37px;")
|
||||
material-checkbox(id="search_select_all" v-model="isSelectAll" @change="handleSelectAllData"
|
||||
:indeterminate="isIndeterminate" :title="isSelectAll && !isIndeterminate ? '全不选' : '全选'")
|
||||
th.nobreak(style="width: 25%;") 歌曲名
|
||||
th.nobreak(style="width: 20%;") 歌手
|
||||
th.nobreak(style="width: 25%;") 专辑
|
||||
th.nobreak(style="width: 22%;") 专辑
|
||||
th.nobreak(style="width: 18%;") 操作
|
||||
th.nobreak(style="width: 10%;") 时长
|
||||
div.scroll(:class="$style.tbody" ref="dom_scrollContent")
|
||||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid' @click="handleDoubleClick(index)")
|
||||
td.break(style="width: 27%;")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
td.break(style="width: 25%;")
|
||||
| {{item.name}}
|
||||
//- span.badge.badge-info(v-if="item._types['320k']") 高品质
|
||||
//- span.badge.badge-success(v-if="item._types.ape || item._types.flac") 无损
|
||||
td.break(style="width: 20%;") {{item.singer}}
|
||||
td.break(style="width: 25%;") {{item.albumName}}
|
||||
td.break(style="width: 22%;") {{item.albumName}}
|
||||
td(style="width: 18%;")
|
||||
material-list-buttons(:index="index" :search-btn="true" :play-btn="item.source == 'kw' || (!isAPITemp && item.source == 'tx')" :download-btn="item.source == 'kw' || (!isAPITemp && item.source == 'tx')" :remove-btn="false" @btn-click="handleBtnClick")
|
||||
material-list-buttons(:index="index" :search-btn="true" :play-btn="item.source == 'kw' || (!isAPITemp && item.source == 'tx')" :download-btn="item.source == 'kw' || (!isAPITemp && item.source == 'tx')" :remove-btn="false" @btn-click="handleListBtnClick")
|
||||
//- button.btn-info(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k'] || item._types.flac" @click.stop='openDownloadModal(index)') 下载
|
||||
//- button.btn-secondary(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k']" @click.stop='testPlay(index)') 试听
|
||||
//- button.btn-success(type='button' v-if="(item._types['128k'] || item._types['192k'] || item._types['320k']) && userInfo" @click.stop='showListModal(index)') +
|
||||
td(style="width: 10%;") {{item.interval}}
|
||||
div(:class="$style.pagination")
|
||||
material-pagination(:count="info.total" :limit="info.limit" :page="info.page" @btn-click="handleTogglePage")
|
||||
material-download-modal(:show="showDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="showDownload = false")
|
||||
material-download-modal(:show="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false")
|
||||
material-download-multiple-modal(:show="isShowDownloadMultiple" :list="selectdData" @select="handleAddDownloadMultiple" @close="isShowDownloadMultiple = false")
|
||||
material-flow-btn(:show="isShowEditBtn" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -48,8 +55,13 @@ export default {
|
|||
page: 1,
|
||||
clickTime: 0,
|
||||
clickIndex: -1,
|
||||
showDownload: false,
|
||||
isShowDownload: false,
|
||||
musicInfo: null,
|
||||
selectdData: [],
|
||||
isSelectAll: false,
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
isShowDownloadMultiple: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -76,6 +88,20 @@ export default {
|
|||
this.setLeaderboard({ source: n })
|
||||
if (o) this.tabId = this.types[0] && this.types[0].id
|
||||
},
|
||||
selectdData(n) {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isShowEditBtn = true
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
}
|
||||
},
|
||||
list() {
|
||||
this.resetSelect()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.source = this.setting.leaderboard.source
|
||||
|
@ -85,8 +111,8 @@ export default {
|
|||
methods: {
|
||||
...mapMutations(['setLeaderboard']),
|
||||
...mapActions('leaderboard', ['getList']),
|
||||
...mapActions('download', ['createDownload']),
|
||||
...mapMutations('list', ['defaultListAdd']),
|
||||
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
|
||||
...mapMutations('list', ['defaultListAdd', 'defaultListAddMultiple']),
|
||||
...mapMutations('player', ['setList']),
|
||||
handleDoubleClick(index) {
|
||||
if (
|
||||
|
@ -101,12 +127,12 @@ export default {
|
|||
this.clickTime = 0
|
||||
this.clickIndex = -1
|
||||
},
|
||||
handleBtnClick(info) {
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
case 'download':
|
||||
this.musicInfo = this.list[info.index]
|
||||
this.$nextTick(() => {
|
||||
this.showDownload = true
|
||||
this.isShowDownload = true
|
||||
})
|
||||
break
|
||||
case 'play':
|
||||
|
@ -120,8 +146,14 @@ export default {
|
|||
}
|
||||
},
|
||||
testPlay(index) {
|
||||
let targetSong = this.list[index]
|
||||
this.defaultListAdd(targetSong)
|
||||
let targetSong
|
||||
if (index == null) {
|
||||
targetSong = this.selectdData[0]
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
} else {
|
||||
targetSong = this.list[index]
|
||||
this.defaultListAdd(targetSong)
|
||||
}
|
||||
let targetIndex = this.defaultList.list.findIndex(
|
||||
s => s.songmid === targetSong.songmid
|
||||
)
|
||||
|
@ -150,9 +182,36 @@ export default {
|
|||
})
|
||||
})
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdData = isSelect ? [...this.list] : []
|
||||
},
|
||||
resetSelect() {
|
||||
this.isSelectAll = false
|
||||
this.selectdData = []
|
||||
},
|
||||
handleAddDownload(type) {
|
||||
this.createDownload({ musicInfo: this.musicInfo, type })
|
||||
this.showDownload = false
|
||||
this.isShowDownload = false
|
||||
},
|
||||
handleAddDownloadMultiple(type) {
|
||||
this.createDownloadMultiple({ list: [...this.selectdData], type })
|
||||
this.resetSelect()
|
||||
this.isShowDownloadMultiple = false
|
||||
},
|
||||
handleFlowBtnClick(action) {
|
||||
switch (action) {
|
||||
case 'download':
|
||||
this.isShowDownloadMultiple = true
|
||||
break
|
||||
case 'play':
|
||||
this.testPlay()
|
||||
this.resetSelect()
|
||||
break
|
||||
case 'add':
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
this.resetSelect()
|
||||
break
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -6,9 +6,12 @@
|
|||
table
|
||||
thead
|
||||
tr
|
||||
th.nobreak.center(style="width: 37px;")
|
||||
material-checkbox(id="search_select_all" v-model="isSelectAll" @change="handleSelectAllData"
|
||||
:indeterminate="isIndeterminate" :title="isSelectAll && !isIndeterminate ? '全不选' : '全选'")
|
||||
th.nobreak(style="width: 25%;") 歌曲名
|
||||
th.nobreak(style="width: 20%;") 歌手
|
||||
th.nobreak(style="width: 25%;" v-if="setting.list.isShowAlbumName") 专辑
|
||||
th.nobreak(style="width: 20%;" v-if="setting.list.isShowAlbumName") 专辑
|
||||
th.nobreak(style="width: 20%;") 操作
|
||||
th.nobreak(style="width: 10%;") 时长
|
||||
div.scroll(:class="$style.tbody")
|
||||
|
@ -16,6 +19,8 @@
|
|||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid'
|
||||
@click="handleDoubleClick(index)" :class="[isPlayList && playIndex === index ? $style.active : '', isAPITemp && item.source != 'kw' ? $style.disabled : '']")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
td.break(style="width: 25%;") {{item.name}}
|
||||
//- span.badge.badge-light(v-if="item._types['128k']") 128K
|
||||
//- span.badge.badge-light(v-if="item._types['192k']") 192K
|
||||
|
@ -23,16 +28,18 @@
|
|||
//- span.badge.badge-info(v-if="item._types.ape") APE
|
||||
//- span.badge.badge-success(v-if="item._types.flac") FLAC
|
||||
td.break(style="width: 20%;") {{item.singer}}
|
||||
td.break(style="width: 25%;" v-if="setting.list.isShowAlbumName") {{item.albumName}}
|
||||
td.break(style="width: 20%;" v-if="setting.list.isShowAlbumName") {{item.albumName}}
|
||||
td(style="width: 20%; padding-left: 0; padding-right: 0;")
|
||||
material-list-buttons(:index="index" @btn-click="handleBtnClick")
|
||||
material-list-buttons(:index="index" @btn-click="handleListBtnClick")
|
||||
//- button.btn-info(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k'] || item._types.flac" @click.stop='openDownloadModal(index)') 下载
|
||||
//- button.btn-secondary(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k']" @click.stop='testPlay(index)') 试听
|
||||
//- button.btn-secondary(type='button' @click.stop='handleRemove(index)') 删除
|
||||
//- button.btn-success(type='button' v-if="(item._types['128k'] || item._types['192k'] || item._types['320k']) && userInfo" @click.stop='showListModal(index)') +
|
||||
td(style="width: 10%;") {{item.interval}}
|
||||
div(:class="$style.noItem" v-else)
|
||||
material-download-modal(:show="showDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="showDownload = false")
|
||||
material-download-modal(:show="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false")
|
||||
material-download-multiple-modal(:show="isShowDownloadMultiple" :list="selectdData" @select="handleAddDownloadMultiple" @close="isShowDownloadMultiple = false")
|
||||
material-flow-btn(:show="isShowEditBtn" :add-btn="false" :play-btn="false" @btn-click="handleFlowBtnClick")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -43,8 +50,13 @@ export default {
|
|||
return {
|
||||
clickTime: window.performance.now(),
|
||||
clickIndex: -1,
|
||||
showDownload: false,
|
||||
isShowDownload: false,
|
||||
musicInfo: null,
|
||||
selectdData: [],
|
||||
isSelectAll: false,
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
isShowDownloadMultiple: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -66,6 +78,22 @@ export default {
|
|||
return this.setting.apiSource == 'temp'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectdData(n) {
|
||||
const len = n.length
|
||||
if (len) {
|
||||
this.isSelectAll = true
|
||||
this.isIndeterminate = len !== this.list.length
|
||||
this.isShowEditBtn = true
|
||||
} else {
|
||||
this.isSelectAll = false
|
||||
this.isShowEditBtn = false
|
||||
}
|
||||
},
|
||||
list() {
|
||||
this.resetSelect()
|
||||
},
|
||||
},
|
||||
// beforeRouteUpdate(to, from, next) {
|
||||
// // if (to.query.id === undefined) return
|
||||
// // if (to.query.text === '') {
|
||||
|
@ -92,9 +120,9 @@ export default {
|
|||
// }
|
||||
// },
|
||||
methods: {
|
||||
...mapMutations('list', ['defaultListRemove']),
|
||||
...mapMutations('list', ['defaultListRemove', 'defaultListRemoveMultiple']),
|
||||
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
|
||||
...mapMutations('player', ['setList']),
|
||||
...mapActions('download', ['createDownload']),
|
||||
handleDoubleClick(index) {
|
||||
if (
|
||||
window.performance.now() - this.clickTime > 400 ||
|
||||
|
@ -115,12 +143,12 @@ export default {
|
|||
handleRemove(index) {
|
||||
this.defaultListRemove(index)
|
||||
},
|
||||
handleBtnClick(info) {
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
case 'download':
|
||||
this.musicInfo = this.list[info.index]
|
||||
this.$nextTick(() => {
|
||||
this.showDownload = true
|
||||
this.isShowDownload = true
|
||||
})
|
||||
break
|
||||
case 'play':
|
||||
|
@ -135,7 +163,30 @@ export default {
|
|||
},
|
||||
handleAddDownload(type) {
|
||||
this.createDownload({ musicInfo: this.musicInfo, type })
|
||||
this.showDownload = false
|
||||
this.isShowDownload = false
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdData = isSelect ? [...this.list] : []
|
||||
},
|
||||
resetSelect() {
|
||||
this.isSelectAll = false
|
||||
this.selectdData = []
|
||||
},
|
||||
handleAddDownloadMultiple(type) {
|
||||
this.createDownloadMultiple({ list: [...this.selectdData], type })
|
||||
this.resetSelect()
|
||||
this.isShowDownloadMultiple = false
|
||||
},
|
||||
handleFlowBtnClick(action) {
|
||||
switch (action) {
|
||||
case 'download':
|
||||
this.isShowDownloadMultiple = true
|
||||
break
|
||||
case 'remove':
|
||||
this.defaultListRemoveMultiple(this.selectdData)
|
||||
this.resetSelect()
|
||||
break
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -27,13 +27,15 @@
|
|||
td.break(style="width: 20%;") {{item.singer}}
|
||||
td.break(style="width: 25%;") {{item.albumName}}
|
||||
td(style="width: 15%;")
|
||||
material-list-buttons(:index="index" :remove-btn="false" @btn-click="handleBtnClick")
|
||||
material-list-buttons(:index="index" :remove-btn="false" @btn-click="handleListBtnClick")
|
||||
td(style="width: 10%;") {{item.interval}}
|
||||
div(:class="$style.pagination")
|
||||
material-pagination(:count="listInfo.total" :limit="limit" :page="page" @btn-click="handleTogglePage")
|
||||
div(v-else :class="$style.noitem")
|
||||
p 搜我所想~~😉
|
||||
material-download-modal(:show="showDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="showDownload = false")
|
||||
material-download-modal(:show="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false")
|
||||
material-download-multiple-modal(:show="isShowDownloadMultiple" :list="selectdData" @select="handleAddDownloadMultiple" @close="isShowDownloadMultiple = false")
|
||||
material-flow-btn(:show="isShowEditBtn" :remove-btn="false" @btn-click="handleFlowBtnClick")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -48,12 +50,13 @@ export default {
|
|||
text: '',
|
||||
clickTime: 0,
|
||||
clickIndex: -1,
|
||||
showDownload: false,
|
||||
isShowDownload: false,
|
||||
musicInfo: null,
|
||||
selectdData: [],
|
||||
isSelectAll: false,
|
||||
isIndeterminate: false,
|
||||
isShowEditBtn: false,
|
||||
isShowDownloadMultiple: false,
|
||||
}
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
|
@ -104,9 +107,9 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
...mapActions('search', ['search']),
|
||||
...mapActions('download', ['createDownload']),
|
||||
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
|
||||
...mapMutations('search', ['clearList', 'setPage']),
|
||||
...mapMutations('list', ['defaultListAdd']),
|
||||
...mapMutations('list', ['defaultListAdd', 'defaultListAddMultiple']),
|
||||
...mapMutations('player', ['setList']),
|
||||
handleSearch(text, page) {
|
||||
this.search({ text, page, limit: this.limit }).then(data => {
|
||||
|
@ -129,12 +132,12 @@ export default {
|
|||
this.clickTime = 0
|
||||
this.clickIndex = -1
|
||||
},
|
||||
handleBtnClick(info) {
|
||||
handleListBtnClick(info) {
|
||||
switch (info.action) {
|
||||
case 'download':
|
||||
this.musicInfo = this.list[info.index]
|
||||
this.$nextTick(() => {
|
||||
this.showDownload = true
|
||||
this.isShowDownload = true
|
||||
})
|
||||
break
|
||||
case 'play':
|
||||
|
@ -145,8 +148,14 @@ export default {
|
|||
}
|
||||
},
|
||||
testPlay(index) {
|
||||
let targetSong = this.list[index]
|
||||
this.defaultListAdd(targetSong)
|
||||
let targetSong
|
||||
if (index == null) {
|
||||
targetSong = this.selectdData[0]
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
} else {
|
||||
targetSong = this.list[index]
|
||||
this.defaultListAdd(targetSong)
|
||||
}
|
||||
let targetIndex = this.defaultList.list.findIndex(
|
||||
s => s.songmid === targetSong.songmid
|
||||
)
|
||||
|
@ -163,7 +172,12 @@ export default {
|
|||
},
|
||||
handleAddDownload(type) {
|
||||
this.createDownload({ musicInfo: this.musicInfo, type })
|
||||
this.showDownload = false
|
||||
this.isShowDownload = false
|
||||
},
|
||||
handleAddDownloadMultiple(type) {
|
||||
this.createDownloadMultiple({ list: [...this.selectdData], type })
|
||||
this.resetSelect()
|
||||
this.isShowDownloadMultiple = false
|
||||
},
|
||||
handleSelectAllData(isSelect) {
|
||||
this.selectdData = isSelect ? [...this.list] : []
|
||||
|
@ -172,6 +186,21 @@ export default {
|
|||
this.isSelectAll = false
|
||||
this.selectdData = []
|
||||
},
|
||||
handleFlowBtnClick(action) {
|
||||
switch (action) {
|
||||
case 'download':
|
||||
this.isShowDownloadMultiple = true
|
||||
break
|
||||
case 'play':
|
||||
this.testPlay()
|
||||
this.resetSelect()
|
||||
break
|
||||
case 'add':
|
||||
this.defaultListAddMultiple(this.selectdData)
|
||||
this.resetSelect()
|
||||
break
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -142,7 +142,7 @@ export default {
|
|||
apiSources: [
|
||||
{
|
||||
id: 'messoer',
|
||||
label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)',
|
||||
label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)<br><span style="line-height: 1.5;"><strong>注意:</strong>本接口10秒内请求数超过100次会封10小时的IP</span>',
|
||||
},
|
||||
{
|
||||
id: 'temp',
|
||||
|
|
Loading…
Reference in New Issue