From 3a615a4a8784b317569f3648782a305f4bcf03cc Mon Sep 17 00:00:00 2001 From: lyswhut Date: Tue, 20 Aug 2019 13:18:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=99=BE=E5=BA=A6=E9=9F=B3?= =?UTF-8?q?=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- publish/changeLog.md | 2 + src/renderer/components/core/Player.vue | 31 ++++- src/renderer/store/modules/download.js | 1 + src/renderer/store/modules/list.js | 3 + src/renderer/store/modules/player.js | 1 - src/renderer/utils/music/api-source.js | 4 + src/renderer/utils/music/bd/api-messoer.js | 37 ++++++ src/renderer/utils/music/bd/index.js | 21 ++++ src/renderer/utils/music/bd/leaderboard.js | 132 +++++++++++++++++++++ src/renderer/utils/music/bd/musicInfo.js | 11 ++ src/renderer/utils/music/index.js | 6 + src/renderer/utils/music/wy/index.js | 1 - src/renderer/views/Leaderboard.vue | 4 +- src/renderer/views/List.vue | 2 +- 14 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 src/renderer/utils/music/bd/api-messoer.js create mode 100644 src/renderer/utils/music/bd/index.js create mode 100644 src/renderer/utils/music/bd/leaderboard.js create mode 100644 src/renderer/utils/music/bd/musicInfo.js diff --git a/publish/changeLog.md b/publish/changeLog.md index 5e1302d0..afd53f66 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -1,8 +1,10 @@ ### 新增 +- 新增**百度音乐**排行榜及其音乐直接试听与下载 - 新增网易云排行榜音乐直接试听与下载(目前仅支持128k音质) - 新增酷狗排行榜音乐直接试听与下载(目前仅支持128k音质) ### 修复 - 修复更新弹窗历史版本描述多余的换行问题 +- 修复歌曲无法播放的情况下歌词仍会播放的问题 diff --git a/src/renderer/components/core/Player.vue b/src/renderer/components/core/Player.vue index 57b4778c..dd551a68 100644 --- a/src/renderer/components/core/Player.vue +++ b/src/renderer/components/core/Player.vue @@ -61,12 +61,14 @@ export default { name: '^', singer: '^', }, + targetSong: null, pregessWidth: 0, lyric: { lrc: null, text: '', line: 0, }, + retryNum: 0, } }, computed: { @@ -137,6 +139,7 @@ export default { 'fixPlayIndex', 'resetChangePlay', ]), + ...mapMutations('list', ['updateMusicInfo']), init() { this.audio = document.createElement('audio') this.audio.controls = false @@ -161,10 +164,16 @@ export default { this.handleNext() }) this.audio.addEventListener('error', () => { + // console.log('code', this.audio.error.code) if (!this.musicInfo.songmid) return console.log('出错') + if (this.audio.error.code == 4 && this.retryNum < 5) { + // console.log(this.retryNum) + this.retryNum++ + this.setUrl(this.list[this.playIndex], true) + return + } this.stopPlay() - this.status = '加载出错' this.sendProgressEvent(this.progress, 'error') // let urls = this.player_info.targetSong.urls @@ -182,10 +191,14 @@ export default { // } else { // this.handleNext() // } - this.handleNext() + this.status = '音频加载出错,2 两秒后切换下一首' + setTimeout(() => { + this.handleNext() + }, 2000) }) this.audio.addEventListener('loadeddata', () => { this.maxPlayTime = this.audio.duration + if (!this.targetSong.interval && this.listId != 'download') this.updateMusicInfo({ index: this.playIndex, data: { interval: formatPlayTime2(this.maxPlayTime) } }) this.status = '音乐加载中...' }) // this.audio.addEventListener('loadstart', () => { @@ -228,7 +241,8 @@ export default { }, play() { console.log('play', this.playIndex) - let targetSong = this.list[this.playIndex] + let targetSong = this.targetSong = this.list[this.playIndex] + this.retryNum = 0 if (this.listId == 'download') { if (!checkPath(targetSong.filePath) || !targetSong.isComplate || /\.ape$/.test(targetSong.filePath)) { @@ -321,16 +335,21 @@ export default { this.musicInfo.img = null }, getPlayType(highQuality, songInfo) { + switch (songInfo.source) { + case 'wy': + case 'kg': + return '128k' + } let type = songInfo._types['192k'] ? '192k' : '128k' if (highQuality && songInfo._types['320k']) type = '320k' return type }, - setUrl(targetSong) { + setUrl(targetSong, isRefresh) { let type = this.getPlayType(this.setting.player.highQuality, targetSong) this.musicInfo.url = targetSong.typeUrl[type] this.status = '歌曲链接获取中...' - let urlP = this.musicInfo.url + let urlP = this.musicInfo.url && !isRefresh ? Promise.resolve() : this.getUrl({ musicInfo: targetSong, type }).then(() => { this.musicInfo.url = targetSong.typeUrl[type] @@ -366,7 +385,7 @@ export default { lrcP .then(() => { this.lyric.lrc.setLyric(this.musicInfo.lrc) - if (this.isPlay) this.lyric.lrc.play(this.audio.currentTime * 1000) + if (this.isPlay && (this.musicInfo.url || this.listId == 'download')) this.lyric.lrc.play(this.audio.currentTime * 1000) }) .catch(err => { this.status = err.message diff --git a/src/renderer/store/modules/download.js b/src/renderer/store/modules/download.js index 2e614a01..d78bec13 100644 --- a/src/renderer/store/modules/download.js +++ b/src/renderer/store/modules/download.js @@ -191,6 +191,7 @@ const actions = { commit('resumeTask', downloadInfo) }, } + commit('setStatusText', { downloadInfo, text: '获取URL中...' }) let p = options.url ? Promise.resolve() : refreshUrl(downloadInfo).then(result => { commit('updateUrl', { downloadInfo, url: result.url }) if (!result.url) return Promise.reject(new Error('获取URL失败')) diff --git a/src/renderer/store/modules/list.js b/src/renderer/store/modules/list.js index 1ec74d02..748a3e12 100644 --- a/src/renderer/store/modules/list.js +++ b/src/renderer/store/modules/list.js @@ -39,6 +39,9 @@ const mutations = { defaultListRemove(state, index) { state.defaultList.list.splice(index, 1) }, + updateMusicInfo(state, { index, data }) { + Object.assign(state.defaultList.list[index], data) + }, defaultListRemoveMultiple(state, list) { list.forEach(musicInfo => { let index = state.defaultList.list.indexOf(musicInfo) diff --git a/src/renderer/store/modules/player.js b/src/renderer/store/modules/player.js index 2ba6bd97..c173c668 100644 --- a/src/renderer/store/modules/player.js +++ b/src/renderer/store/modules/player.js @@ -35,7 +35,6 @@ const actions = { if (picRequest && picRequest.cancelHttp) picRequest.cancelHttp() picRequest = music[musicInfo.source].getPic(musicInfo) return picRequest.promise.then(url => { - console.log(url) commit('getPic', { musicInfo, url }) }).finally(() => { picRequest = null diff --git a/src/renderer/utils/music/api-source.js b/src/renderer/utils/music/api-source.js index adeb2d2a..c293e3f7 100644 --- a/src/renderer/utils/music/api-source.js +++ b/src/renderer/utils/music/api-source.js @@ -3,12 +3,14 @@ import kw_api_temp from './kw/api-temp' import tx_api_messoer from './tx/api-messoer' import kg_api_messoer from './kg/api-messoer' import wy_api_messoer from './wy/api-messoer' +import bd_api_messoer from './bd/api-messoer' const apis = { kw_api_messoer, tx_api_messoer, kg_api_messoer, wy_api_messoer, + bd_api_messoer, kw_api_temp, } @@ -30,6 +32,8 @@ export default source => { return getAPI('kg') case 'wy': return getAPI('wy') + case 'bd': + return getAPI('bd') default: return getAPI('kw') } diff --git a/src/renderer/utils/music/bd/api-messoer.js b/src/renderer/utils/music/bd/api-messoer.js new file mode 100644 index 00000000..72e267bd --- /dev/null +++ b/src/renderer/utils/music/bd/api-messoer.js @@ -0,0 +1,37 @@ +import { httpFatch } from '../../request' +import { requestMsg } from '../../message' + +const api_messoer = { + getMusicUrl(songInfo, type) { + const requestObj = httpFatch(`https://v1.itooi.cn/baidu/url?id=${songInfo.songmid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, { + method: 'get', + timeout: 5000, + }) + requestObj.promise = requestObj.promise.then(({ body }) => { + return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail)) + }) + return requestObj + }, + getPic(songInfo, size = '500') { + const requestObj = httpFatch(`https://v1.itooi.cn/baidu/pic?id=${songInfo.songmid}&imageSize=${size}&isRedirect=0`, { + method: 'get', + timeout: 5000, + }) + requestObj.promise = requestObj.promise.then(({ body }) => { + return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail)) + }) + return requestObj + }, + getLyric(songInfo) { + const requestObj = httpFatch(`https://v1.itooi.cn/baidu/lrc?id=${songInfo.songmid}&isRedirect=0`, { + method: 'get', + timeout: 5000, + }) + requestObj.promise = requestObj.promise.then(({ body }) => { + return body ? Promise.resolve(body) : Promise.reject(new Error(requestMsg.fail)) + }) + return requestObj + }, +} + +export default api_messoer diff --git a/src/renderer/utils/music/bd/index.js b/src/renderer/utils/music/bd/index.js new file mode 100644 index 00000000..97bae063 --- /dev/null +++ b/src/renderer/utils/music/bd/index.js @@ -0,0 +1,21 @@ +import leaderboard from './leaderboard' +import api_source from '../api-source' +import musicInfo from './musicInfo' + +const bd = { + leaderboard, + getMusicUrl(songInfo, type) { + return api_source('bd').getMusicUrl(songInfo, type) + }, + getLyric(songInfo) { + return api_source('bd').getLyric(songInfo) + }, + getPic(songInfo) { + return api_source('bd').getPic(songInfo) + }, + getMusicInfo(songInfo) { + return musicInfo.getMusicInfo(songInfo.songmid) + }, +} + +export default bd diff --git a/src/renderer/utils/music/bd/leaderboard.js b/src/renderer/utils/music/bd/leaderboard.js new file mode 100644 index 00000000..860d492e --- /dev/null +++ b/src/renderer/utils/music/bd/leaderboard.js @@ -0,0 +1,132 @@ +import { httpFatch } from '../../request' +// import { formatPlayTime } from '../../index' +// import jshtmlencode from 'js-htmlencode' + +export default { + limit: 20, + list: [ + { + id: 'bdrgb', + name: '热歌榜', + bangid: '2', + }, + { + id: 'bdxgb', + name: '新歌榜', + bangid: '1', + }, + { + id: 'bdycb', + name: '原创榜', + bangid: '200', + }, + { + id: 'bdhyjqb', + name: '华语榜', + bangid: '20', + }, + { + id: 'bdomjqb', + name: '欧美榜', + bangid: '21', + }, + { + id: 'bdwugqb', + name: '网络榜', + bangid: '25', + }, + { + id: 'bdjdlgb', + name: '老歌榜', + bangid: '22', + }, + { + id: 'bdysjqb', + name: '影视金曲榜', + bangid: '24', + }, + { + id: 'bdqgdcb', + name: '情歌对唱榜', + bangid: '23', + }, + { + id: 'bdygb', + name: '摇滚榜', + bangid: '11', + }, + ], + getUrl(id, p) { + return `http://musicmini.qianqian.com/2018/static/bangdan/bangdanList_${id}_${p}.html` + }, + regExps: { + item: /data-song="({.+?})"/g, + info: /{total[\s:]+"(\d+)", size[\s:]+"(\d+)", page[\s:]+"(\d+)"}/, + }, + requestObj: null, + getData(url) { + if (this.requestObj) this.requestObj.cancelHttp() + this.requestObj = httpFatch(url) + return this.requestObj.promise + }, + filterData(rawList) { + // console.log(rawList) + return rawList.map(item => { + const types = [] + const _types = {} + let size = null + types.push({ type: '128k', size }) + _types['128k'] = { + size, + } + if (item.biaoshi) { + types.push({ type: '320k', size }) + _types['320k'] = { + size, + } + types.push({ type: 'flac', size }) + _types['flac'] = { + size, + } + } + // types.reverse() + + return { + singer: item.song_artist.replace(',', '、'), + name: item.song_title, + albumName: item.album_title, + albumId: item.album_id, + source: 'bd', + interval: '', + songmid: item.song_id, + img: null, + lrc: null, + types, + _types, + typeUrl: {}, + } + }) + }, + parseData(rawData) { + // return rawData.map(item => JSON.parse(item.replace(this.regExps.item, '$1').replace(/"/g, '"').replace(/\\\//g, '/').replace(/(@s_1,w_)\d+(,h_)\d+/, '$1500$2500'))) + return rawData.map(item => JSON.parse(item.replace(this.regExps.item, '$1').replace(/"/g, '"').replace(/\\\//g, '/'))) + }, + getList(id, page) { + let type = this.list.find(s => s.id === id) + if (!type) return Promise.reject() + return this.getData(this.getUrl(type.bangid, page)).then(({ body }) => { + let result = body.match(this.regExps.item) + if (!result) return Promise.reject(new Error('匹配list失败')) + let info = body.match(this.regExps.info) + if (!info) return Promise.reject(new Error('匹配info失败')) + const list = this.filterData(this.parseData(result)) + this.limit = parseInt(info[2]) + return { + total: parseInt(info[1]), + list, + limit: this.limit, + page: parseInt(info[3]), + } + }) + }, +} diff --git a/src/renderer/utils/music/bd/musicInfo.js b/src/renderer/utils/music/bd/musicInfo.js new file mode 100644 index 00000000..5f6ebe49 --- /dev/null +++ b/src/renderer/utils/music/bd/musicInfo.js @@ -0,0 +1,11 @@ +import { httpFatch } from '../../request' + +export default { + getMusicInfo(songmid) { + const requestObj = httpFatch(`https://musicapi.qianqian.com/v1/restserver/ting?method=baidu.ting.song.getSongLink&format=json&from=bmpc&version=1.0.0&version_d=11.1.6.0&songid=${songmid}&type=1&res=1&s_protocol=1&aac=2&project=tpass`) + requestObj.promise = requestObj.promise.then(({ body }) => { + return body.error_code == 22000 ? body.reqult.songinfo : Promise.reject(new Error('获取音乐信息失败')) + }) + return requestObj + }, +} diff --git a/src/renderer/utils/music/index.js b/src/renderer/utils/music/index.js index ab336bbe..57fa475b 100644 --- a/src/renderer/utils/music/index.js +++ b/src/renderer/utils/music/index.js @@ -2,6 +2,7 @@ import kw from './kw' import kg from './kg' import tx from './tx' import wy from './wy' +import bd from './bd' export default { sources: [ { @@ -20,9 +21,14 @@ export default { name: '网易音乐', id: 'wy', }, + { + name: '百度音乐', + id: 'bd', + }, ], kw, kg, tx, wy, + bd, } diff --git a/src/renderer/utils/music/wy/index.js b/src/renderer/utils/music/wy/index.js index accfa0d2..447df0c0 100644 --- a/src/renderer/utils/music/wy/index.js +++ b/src/renderer/utils/music/wy/index.js @@ -7,7 +7,6 @@ const wy = { return api_source('wy').getMusicUrl(songInfo, type) }, getLyric(songInfo) { - console.log(api_source('wy')) return api_source('wy').getLyric(songInfo) }, getPic(songInfo) { diff --git a/src/renderer/views/Leaderboard.vue b/src/renderer/views/Leaderboard.vue index ecb1ea86..7aa6c27d 100644 --- a/src/renderer/views/Leaderboard.vue +++ b/src/renderer/views/Leaderboard.vue @@ -34,7 +34,7 @@ //- 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}} + 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="isShowDownload" :musicInfo="musicInfo" @select="handleAddDownload" @close="isShowDownload = false") @@ -170,7 +170,7 @@ export default { this.$router.push({ path: 'search', query: { - text: `${info.name} - ${info.singer}`, + text: `${info.name} ${info.singer}`, }, }) }, diff --git a/src/renderer/views/List.vue b/src/renderer/views/List.vue index 48f41bfa..44c22db1 100644 --- a/src/renderer/views/List.vue +++ b/src/renderer/views/List.vue @@ -35,7 +35,7 @@ //- 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}} + td(style="width: 10%;") {{item.interval || '--/--'}} div(:class="$style.noItem" v-else) 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")