From a580cedcb1ea311250d3c35a28edcebdc7ba8bd2 Mon Sep 17 00:00:00 2001 From: lyswhut Date: Sun, 18 Aug 2019 20:36:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=88=B00.1.4=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 14 ++++++ package.json | 2 +- publish/changeLog.md | 10 ++++- publish/version.json | 8 +++- src/renderer/App.vue | 13 ++++++ src/renderer/components/core/Player.vue | 24 +++++++--- src/renderer/store/modules/player.js | 29 +++++++++--- src/renderer/utils/index.js | 3 +- src/renderer/utils/music/api-source.js | 28 ++++++++++++ src/renderer/utils/music/kw/api-messoer.js | 26 +++++++++++ src/renderer/utils/music/kw/api-temp.js | 33 ++++++++++++++ src/renderer/utils/music/kw/index.js | 51 ++-------------------- src/renderer/utils/music/kw/leaderboard.js | 3 +- src/renderer/utils/music/kw/lyric.js | 25 +++-------- src/renderer/utils/music/tx/api-messoer.js | 21 +++++++++ src/renderer/utils/music/tx/index.js | 33 ++------------ src/renderer/utils/music/tx/lyric.js | 31 ++++--------- src/renderer/utils/request.js | 45 ++++++++++++++++--- src/renderer/views/Leaderboard.vue | 7 ++- src/renderer/views/List.vue | 11 ++++- src/renderer/views/Search.vue | 3 +- src/renderer/views/Setting.vue | 47 +++++++++++++++----- 22 files changed, 306 insertions(+), 161 deletions(-) create mode 100644 src/renderer/utils/music/api-source.js create mode 100644 src/renderer/utils/music/kw/api-messoer.js create mode 100644 src/renderer/utils/music/kw/api-temp.js create mode 100644 src/renderer/utils/music/tx/api-messoer.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e6a8e92c31..5ae393fc61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,20 @@ 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/). +## [0.1.4](https://github.com/lyswhut/lx-music-desktop/compare/v0.1.3...v0.1.4) - 2019-08-18 + +### 新增 + +- 新增音乐来源切换,可到设置页面-基本设置 look look ! +- 为搜索结果列表添加多选功能。 +P.S:暂时没想好多选后的操作按钮放哪... + +### 优化 + +- 重构与改进checkbox组件,使其支持不定选中状态 +- 完善上一个版本的http请求封装并切换部分请求到该方法上 +- 优化其他一些细节 + ## [0.1.3](https://github.com/lyswhut/lx-music-desktop/compare/v0.1.2...v0.1.3) - 2019-08-17 ### 新增 diff --git a/package.json b/package.json index 2906035068..39edb0966b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lx-music-desktop", - "version": "0.1.3", + "version": "0.1.4", "description": "一个免费的音乐下载助手", "main": "./dist/electron/main.js", "scripts": { diff --git a/publish/changeLog.md b/publish/changeLog.md index 31b0e97b87..3cb0c6ea07 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -1,3 +1,11 @@ +### 新增 + +- 新增音乐来源切换,可到设置页面-基本设置 look look ! +- 为搜索结果列表添加多选功能。 +P.S:暂时没想好多选后的操作按钮放哪... + ### 优化 -- 重构checkbox组件 +- 重构与改进checkbox组件,使其支持不定选中状态 +- 完善上一个版本的http请求封装并切换部分请求到该方法上 +- 优化其他一些细节 diff --git a/publish/version.json b/publish/version.json index 7a8d641ef1..b45f25f36a 100644 --- a/publish/version.json +++ b/publish/version.json @@ -1,7 +1,11 @@ { - "version": "0.1.3", - "desc": "

新增

\n\n

修复

\n\n

移除

\n\n", + "version": "0.1.4", + "desc": "

新增

\n\n

优化

\n\n", "history": [ + { + "version": "0.1.3", + "desc": "

新增

\n\n

修复

\n\n

移除

\n\n" + }, { "version": "0.1.2", "desc": "

修复

\n\n" diff --git a/src/renderer/App.vue b/src/renderer/App.vue index a0e28c3666..66d50448b5 100644 --- a/src/renderer/App.vue +++ b/src/renderer/App.vue @@ -28,6 +28,9 @@ export default { data() { return { isProd: process.env.NODE_ENV === 'production', + globalObj: { + apiSource: 'messoer', + }, } }, computed: { @@ -59,12 +62,20 @@ export default { }, deep: true, }, + 'globalObj.apiSource'(n) { + if (n != this.setting.apiSource) { + this.setSetting(Object.assign({}, this.setting, { + apiSource: n, + })) + } + }, }, methods: { ...mapActions(['getVersionInfo']), ...mapMutations(['setNewVersion', 'setVersionVisible']), ...mapMutations('list', ['initDefaultList']), ...mapMutations('download', ['updateDownloadList']), + ...mapMutations(['setSetting']), init() { if (this.isProd) { body.addEventListener('mouseenter', this.dieableIgnoreMouseEvents) @@ -80,6 +91,8 @@ export default { }) this.initData() + this.globalObj.apiSource = this.setting.apiSource + window.globalObj = this.globalObj }, enableIgnoreMouseEvents() { win.setIgnoreMouseEvents(false) diff --git a/src/renderer/components/core/Player.vue b/src/renderer/components/core/Player.vue index 50d4c0372a..f085e9bcf8 100644 --- a/src/renderer/components/core/Player.vue +++ b/src/renderer/components/core/Player.vue @@ -90,6 +90,9 @@ export default { // return 50 return this.nowPlayTime / this.maxPlayTime || 0 }, + isAPITemp() { + return this.setting.apiSource == 'temp' + }, }, mounted() { this.setProgessWidth() @@ -249,7 +252,8 @@ export default { }, handleNext() { // if (this.list.listName === null) return - if (!this.list.length) return + const list = this.isAPITemp ? this.list.filter(s => s.source == 'kw') : this.list + if (!list.length) return let index switch (this.setting.player.togglePlayMethod) { case 'listLoop': @@ -267,14 +271,17 @@ export default { if (index < 0) return this.setPlayIndex(index) }, - hanldeListLoop() { - return this.playIndex === this.list.length - 1 ? 0 : this.playIndex + 1 + 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 }, - hanldeListNext() { - return this.playIndex === this.list.length - 1 ? -1 : this.playIndex + 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 }, - hanldeListRandom() { - return getRandom(0, this.list.length) + hanldeListRandom(index = this.playIndex) { + index = getRandom(0, this.list.length) + return this.isAPITemp && this.list[index].source != 'kw' ? this.hanldeListRandom(index) : index }, startPlay() { this.isPlay = true @@ -314,6 +321,7 @@ export default { setUrl(targetSong) { let type = this.getPlayType(this.setting.player.highQuality, targetSong) this.musicInfo.url = targetSong.typeUrl[type] + this.status = '歌曲链接获取中...' let urlP = this.musicInfo.url ? Promise.resolve() @@ -323,6 +331,8 @@ export default { urlP.then(() => { this.audio.src = this.musicInfo.url + }).catch(err => { + this.status = err.message }) }, setImg(targetSong) { diff --git a/src/renderer/store/modules/player.js b/src/renderer/store/modules/player.js index d9b04a8ed1..2ba6bd9736 100644 --- a/src/renderer/store/modules/player.js +++ b/src/renderer/store/modules/player.js @@ -8,7 +8,9 @@ const state = { changePlay: false, } -let request +let urlRequest +let picRequest +let lrcRequest // getters const getters = { @@ -21,19 +23,32 @@ const getters = { // actions const actions = { getUrl({ commit, state }, { musicInfo, type }) { - if (request && request.cancelHttp) request.cancelHttp() - request = music[musicInfo.source].getMusicUrl(musicInfo, type) - return request.promise.then(result => { + if (urlRequest && urlRequest.cancelHttp) urlRequest.cancelHttp() + urlRequest = music[musicInfo.source].getMusicUrl(musicInfo, type) + return urlRequest.promise.then(result => { commit('setUrl', { musicInfo, url: result.url, type }) }).finally(() => { - request = null + urlRequest = null }) }, getPic({ commit, state }, musicInfo) { - return music[musicInfo.source].getPic(musicInfo).then(url => commit('getPic', { musicInfo, url })) + 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 + }) }, getLrc({ commit, state }, musicInfo) { - return music[musicInfo.source].getLyric(musicInfo).then(lrc => commit('setLrc', { musicInfo, lrc })) + if (lrcRequest && lrcRequest.cancelHttp) lrcRequest.cancelHttp() + lrcRequest = music[musicInfo.source].getLyric(musicInfo) + return lrcRequest.promise.then(lrc => { + commit('setLrc', { musicInfo, lrc }) + }).finally(() => { + lrcRequest = null + }) }, } diff --git a/src/renderer/utils/index.js b/src/renderer/utils/index.js index f86d4c6be5..25699eb709 100644 --- a/src/renderer/utils/index.js +++ b/src/renderer/utils/index.js @@ -157,7 +157,7 @@ export const isChildren = (parent, children) => { } export const updateSetting = setting => { - const defaultVersion = '1.0.1' + const defaultVersion = '1.0.2' const defaultSetting = { version: defaultVersion, player: { @@ -177,6 +177,7 @@ export const updateSetting = setting => { }, themeId: 0, sourceId: 'kw', + apiSource: 'messoer', randomAnimate: true, } const overwriteSetting = { diff --git a/src/renderer/utils/music/api-source.js b/src/renderer/utils/music/api-source.js new file mode 100644 index 0000000000..4fa59fdc91 --- /dev/null +++ b/src/renderer/utils/music/api-source.js @@ -0,0 +1,28 @@ +import kw_api_messoer from './kw/api-messoer' +import kw_api_temp from './kw/api-temp' +import tx_api_messoer from './tx/api-messoer' + +const apis = { + kw_api_messoer, + tx_api_messoer, + kw_api_temp, +} + + +const getAPI = source => { + switch (window.globalObj.apiSource) { + case 'messoer': + return apis[`${source}_api_messoer`] + case 'temp': + return apis[`${source}_api_temp`] + } +} + +export default source => { + switch (source) { + case 'tx': + return getAPI('tx') + default: + return getAPI('kw') + } +} diff --git a/src/renderer/utils/music/kw/api-messoer.js b/src/renderer/utils/music/kw/api-messoer.js new file mode 100644 index 0000000000..9a4749e435 --- /dev/null +++ b/src/renderer/utils/music/kw/api-messoer.js @@ -0,0 +1,26 @@ +import { httpFatch } from '../../request' + +const api_messoer = { + getMusicUrl(songInfo, type) { + const requestObj = httpFatch(`https://v1.itooi.cn/kuwo/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(body.msg)) + }) + return requestObj + }, + getPic(songInfo) { + const requestObj = httpFatch(`https://v1.itooi.cn/kuwo/pic?id=${songInfo.songmid}&isRedirect=0`, { + method: 'get', + timeout: 5000, + }) + requestObj.promise = requestObj.promise.then(({ body }) => { + return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(body.msg)) + }) + return requestObj + }, +} + +export default api_messoer diff --git a/src/renderer/utils/music/kw/api-temp.js b/src/renderer/utils/music/kw/api-temp.js new file mode 100644 index 0000000000..d7091ae043 --- /dev/null +++ b/src/renderer/utils/music/kw/api-temp.js @@ -0,0 +1,33 @@ +import { httpFatch } from '../../request' + +const api_temp = { + getMusicUrl(songInfo, type) { + const requestObj = httpFatch(`https://www.stsky.cn/api/temp/getMusicUrl.php?id=${songInfo.songmid}&type=${type}`, { + method: 'get', + }) + 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 + }, + getPic(songInfo) { + const requestObj = httpFatch(`https://www.stsky.cn/api/temp/getPic.php?size=320&songmid=${songInfo.songmid}`, { + method: 'get', + }) + 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 + }, +} + +export default api_temp diff --git a/src/renderer/utils/music/kw/index.js b/src/renderer/utils/music/kw/index.js index d7c2bf6a81..9176328d5d 100644 --- a/src/renderer/utils/music/kw/index.js +++ b/src/renderer/utils/music/kw/index.js @@ -4,6 +4,7 @@ import musicSearch from './musicSearch' import { formatSinger } from './util' import leaderboard from './leaderboard' import lyric from './lyric' +import api_source from '../api-source' const kw = { _musicInfoRequestObj: null, @@ -52,36 +53,7 @@ const kw = { }, getMusicUrl(songInfo, type) { - let requestObj - let cancelFn - const p = new Promise((resolve, reject) => { - cancelFn = reject - // requestObj = httpGet(`https://v1.itooi.cn/kuwo/url?id=${songInfo.songmid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, (err, resp, body) => { - requestObj = httpGet(`https://www.stsky.cn/api/temp/getMusicUrl.php?id=${songInfo.songmid}&type=${type}`, (err, resp, body) => { - requestObj = null - cancelFn = null - if (err) { - if (err.message === 'socket hang up') return reject(new Error('接口挂了')) - const { promise, cancelHttp } = this.getMusicUrl(songInfo, type) - obj.cancelHttp = cancelHttp - return promise - } - // body.code === 200 ? resolve({ type, url: body.data }) : reject(new Error(body.msg)) - body.code === 0 ? resolve({ type, url: body.data }) : reject(new Error(body.msg)) - }) - }) - const obj = { - promise: p, - cancelHttp() { - console.log('cancel') - if (!requestObj) return - cancelHttp(requestObj) - cancelFn(new Error('取消http请求')) - requestObj = null - cancelFn = null - }, - } - return obj + return api_source('kw').getMusicUrl(songInfo, type) }, getMusicInfo(songInfo) { @@ -119,24 +91,7 @@ const kw = { }, getPic(songInfo) { - if (this._musicPicRequestObj != null) { - cancelHttp(this._musicPicRequestObj) - this._musicPicPromiseCancelFn(new Error('取消http请求')) - } - return new Promise((resolve, reject) => { - this._musicPicPromiseCancelFn = reject - // this._musicPicRequestObj = httpGet(`https://v1.itooi.cn/kuwo/pic?id=${songInfo.songmid}&isRedirect=0`, (err, resp, body) => { - this._musicPicRequestObj = httpGet(`https://www.stsky.cn/api/temp/getPic.php?size=320&songmid=${songInfo.songmid}`, (err, resp, body) => { - this._musicPicRequestObj = null - this._musicPicPromiseCancelFn = null - if (err) { - console.log(err) - reject(err) - } - // body.code === 200 ? resolve(body.data) : reject(new Error(body.msg)) - body.code === 0 ? resolve(body.data) : reject(new Error(body.msg)) - }) - }) + return api_source('kw').getPic(songInfo) }, } diff --git a/src/renderer/utils/music/kw/leaderboard.js b/src/renderer/utils/music/kw/leaderboard.js index 2132dac6b6..2146eb6613 100644 --- a/src/renderer/utils/music/kw/leaderboard.js +++ b/src/renderer/utils/music/kw/leaderboard.js @@ -106,6 +106,7 @@ export default { }) }, filterData(rawList, rawList2) { + // console.log(rawList.length, rawList2.length) return rawList.map((item, inedx) => { let formats = item.formats.split('|') let types = [] @@ -148,7 +149,7 @@ export default { albumId: item.albumid, songmid: item.id, source: 'kw', - interval: formatPlayTime(rawList2[inedx].duration), + interval: rawList2[inedx] && formatPlayTime(rawList2[inedx].duration), img: item.pic, lrc: null, types, diff --git a/src/renderer/utils/music/kw/lyric.js b/src/renderer/utils/music/kw/lyric.js index 8ba752c0bf..b24bbc86b2 100644 --- a/src/renderer/utils/music/kw/lyric.js +++ b/src/renderer/utils/music/kw/lyric.js @@ -1,8 +1,6 @@ -import { httpGet, cancelHttp } from '../../request' +import { httpFatch } from '../../request' export default { - _musicLrcRequestObj: null, - _musicLrcPromiseCancelFn: null, formatTime(time) { let m = parseInt(time / 60) let s = (time % 60).toFixed(2) @@ -12,23 +10,10 @@ export default { return `[ti:${songinfo.songName}]\n[ar:${songinfo.artist}]\n[al:${songinfo.album}]\n[by:]\n[offset:0]\n${lrclist ? lrclist.map(l => `[${this.formatTime(l.time)}]${l.lineLyric}\n`).join('') : '暂无歌词'}` }, getLyric(songId) { - if (this._musicLrcRequestObj != null) { - cancelHttp(this._musicLrcRequestObj) - this._musicLrcPromiseCancelFn(new Error('取消http请求')) - } - return new Promise((resolve, reject) => { - this._musicLrcPromiseCancelFn = reject - // this._musicLrcRequestObj = httpGet(`https://v1.itooi.cn/kuwo/lrc?id=${songId}`, (err, resp, body) => { - this._musicLrcRequestObj = httpGet(`http://m.kuwo.cn/newh5/singles/songinfoandlrc?musicId=${songId}`, (err, resp, body) => { - this._musicLrcRequestObj = null - this._musicLrcPromiseCancelFn = null - if (err) { - console.log(err) - reject(err) - } - // resolve(body) - resolve(this.transformLrc(body.data)) - }) + const requestObj = httpFatch(`http://m.kuwo.cn/newh5/singles/songinfoandlrc?musicId=${songId}`) + requestObj.promise = requestObj.promise.then(({ body }) => { + return this.transformLrc(body.data) }) + return requestObj }, } diff --git a/src/renderer/utils/music/tx/api-messoer.js b/src/renderer/utils/music/tx/api-messoer.js new file mode 100644 index 0000000000..0b00f62977 --- /dev/null +++ b/src/renderer/utils/music/tx/api-messoer.js @@ -0,0 +1,21 @@ +import { httpFatch } from '../../request' + +const api_messoer = { + getMusicUrl(songInfo, type) { + const requestObj = httpFatch(`https://v1.itooi.cn/tencent/url?id=${songInfo.strMediaMid}&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(body.msg)) + }) + return requestObj + }, + getPic(songInfo) { + return { + promise: Promise.resolve(`https://y.gtimg.cn/music/photo_new/T002R500x500M000${songInfo.albumId}.jpg`), + } + }, +} + +export default api_messoer diff --git a/src/renderer/utils/music/tx/index.js b/src/renderer/utils/music/tx/index.js index 62667f9ea9..54959c8f16 100644 --- a/src/renderer/utils/music/tx/index.js +++ b/src/renderer/utils/music/tx/index.js @@ -1,46 +1,19 @@ -import { httpGet, cancelHttp } from '../../request' import leaderboard from './leaderboard' import lyric from './lyric' +import api_source from '../api-source' const tx = { leaderboard, getMusicUrl(songInfo, type) { - let requestObj - let cancelFn - const p = new Promise((resolve, reject) => { - cancelFn = reject - requestObj = httpGet(`https://v1.itooi.cn/tencent/url?id=${songInfo.strMediaMid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, (err, resp, body) => { - requestObj = null - cancelFn = null - if (err) { - console.log(err) - const { promise, cancelHttp } = this.getMusicUrl(songInfo, type) - obj.cancelHttp = cancelHttp - return promise - } - body.code === 200 ? resolve({ type, url: body.data }) : reject(new Error(body.msg)) - }) - }) - const obj = { - promise: p, - cancelHttp() { - console.log('cancel') - if (!requestObj) return - cancelHttp(requestObj) - cancelFn(new Error('取消http请求')) - requestObj = null - cancelFn = null - }, - } - return obj + return api_source('tx').getMusicUrl(songInfo, type) }, getLyric(songInfo) { // let singer = songInfo.singer.indexOf('、') > -1 ? songInfo.singer.split('、')[0] : songInfo.singer return lyric.getLyric(songInfo.songmid) }, getPic(songInfo) { - return Promise.resolve(`https://y.gtimg.cn/music/photo_new/T002R500x500M000${songInfo.albumId}.jpg`) + return api_source('tx').getPic(songInfo) }, } diff --git a/src/renderer/utils/music/tx/lyric.js b/src/renderer/utils/music/tx/lyric.js index 9af8ba4be9..a94cb1e32b 100644 --- a/src/renderer/utils/music/tx/lyric.js +++ b/src/renderer/utils/music/tx/lyric.js @@ -1,32 +1,19 @@ -import { httpGet, cancelHttp } from '../../request' +import { httpFatch } from '../../request' import { b64DecodeUnicode } from '../../index' export default { - _musicLrcRequestObj: null, - _musicLrcPromiseCancelFn: null, regexps: { matchLrc: /.+"lyric":"([\w=+/]*)".+/, }, getLyric(songmid) { - if (this._musicLrcRequestObj != null) { - cancelHttp(this._musicLrcRequestObj) - this._musicLrcPromiseCancelFn(new Error('取消http请求')) - } - return new Promise((resolve, reject) => { - this._musicLrcPromiseCancelFn = reject - this._musicLrcRequestObj = httpGet(`https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid=${songmid}&g_tk=2001461048&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&platform=yqq`, { - headers: { - Referer: 'https://y.qq.com/portal/player.html', - }, - }, (err, resp, body) => { - this._musicLrcRequestObj = null - this._musicLrcPromiseCancelFn = null - if (err) { - console.log(err) - reject(err) - } - resolve(b64DecodeUnicode(body.replace(this.regexps.matchLrc, '$1'))) - }) + const requestObj = httpFatch(`https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid=${songmid}&g_tk=2001461048&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&platform=yqq`, { + headers: { + Referer: 'https://y.qq.com/portal/player.html', + }, }) + requestObj.promise = requestObj.promise.then(({ body }) => { + return b64DecodeUnicode(body.replace(this.regexps.matchLrc, '$1')) + }) + return requestObj }, } diff --git a/src/renderer/utils/request.js b/src/renderer/utils/request.js index 782dbb1037..c22d29d625 100644 --- a/src/renderer/utils/request.js +++ b/src/renderer/utils/request.js @@ -3,17 +3,26 @@ import request from 'request' import { debugRequest } from './env' // import fs from 'fs' +const headers = { + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36', +} + const fatchData = (url, method, options, callback) => { + console.log(url, options) // console.log('---start---', url) return request(url, { method, - headers: options.headers, + headers: Object.assign({}, headers, options.headers || {}), Origin: options.origin, data: options.data, - // timeout: 5000, + timeout: options.timeout || 10000, json: options.format === undefined || options.format === 'json', }, (err, resp, body) => { - if (err) return callback(err, null) + if (err) { + if (err.message === 'socket hang up') window.globalObj.apiSource = 'temp' + return callback(err, null) + } + // console.log('---end---', url) callback(null, resp, body) }) @@ -24,7 +33,7 @@ const fatchData = (url, method, options, callback) => { * @param {*} url * @param {*} options */ -export const httpFatch = (url, options = { method: 'get' }) => { +const buildHttpPromose = (url, options) => { let requestObj let cancelFn const p = new Promise((resolve, reject) => { @@ -37,12 +46,13 @@ export const httpFatch = (url, options = { method: 'get' }) => { requestObj = null cancelFn = null if (err) { - console.log(err) - if (err.code === 'ETIMEDOUT') { + console.log(err.code) + if (err.code === 'ETIMEDOUT' || err.code == 'ESOCKETTIMEDOUT') { const { promise, cancelHttp } = httpFatch(url, options) obj.cancelHttp = cancelHttp - return promise + promise.then() } + return reject(err) } resolve(resp) }) @@ -61,6 +71,27 @@ export const httpFatch = (url, options = { method: 'get' }) => { return obj } +/** + * 请求超时自动重试 + * @param {*} url + * @param {*} options + */ +export const httpFatch = (url, options = { method: 'get' }) => { + const requestObj = buildHttpPromose(url, options) + requestObj.promise = requestObj.promise.catch(err => { + if (err.code === 'ETIMEDOUT' || err.code == 'ESOCKETTIMEDOUT') { + const { promise, cancelHttp } = httpFatch(url, options) + requestObj.cancelHttp() + requestObj.cancelHttp = cancelHttp + return promise + } + if (err.message === 'socket hang up') return Promise.reject(new Error('哦No😱...接口挂了!已帮你切换到临时接口,重试下看能不能播放吧~')) + if (err.code === 'ENOTFOUND') return Promise.reject(new Error('无法连接网络')) + return Promise.reject(err) + }) + return requestObj +} + /** * 取消请求 * @param {*} index diff --git a/src/renderer/views/Leaderboard.vue b/src/renderer/views/Leaderboard.vue index 2690df87b3..9130097835 100644 --- a/src/renderer/views/Leaderboard.vue +++ b/src/renderer/views/Leaderboard.vue @@ -25,7 +25,7 @@ td.break(style="width: 20%;") {{item.singer}} td.break(style="width: 25%;") {{item.albumName}} td(style="width: 18%;") - material-list-buttons(:index="index" :search-btn="true" :play-btn="item.source == 'kw'" :download-btn="item.source == 'kw'" :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="handleBtnClick") //- 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)') + @@ -59,6 +59,9 @@ export default { types() { return this.source ? this.sourceInfo.sourceList[this.source] : [] }, + isAPITemp() { + return this.setting.apiSource == 'temp' + }, }, watch: { tabId(n, o) { @@ -94,7 +97,7 @@ export default { this.clickIndex = index return } - (this.source == 'kw') ? this.testPlay(index) : this.handleSearch(index) + (this.source == 'kw' || (!this.isAPITemp && this.source == 'tx')) ? this.testPlay(index) : this.handleSearch(index) this.clickTime = 0 this.clickIndex = -1 }, diff --git a/src/renderer/views/List.vue b/src/renderer/views/List.vue index 9ddb3b79e5..b06c5785b9 100644 --- a/src/renderer/views/List.vue +++ b/src/renderer/views/List.vue @@ -14,7 +14,8 @@ div.scroll(:class="$style.tbody") table tbody - tr(v-for='(item, index) in list' :key='item.songmid' @click="handleDoubleClick(index)" :class="isPlayList && playIndex === index ? $style.active : ''") + 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.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 @@ -61,6 +62,9 @@ export default { ? this.defaultList.list : this.userList.find(l => l._id == this.$route.query.id) || [] }, + isAPITemp() { + return this.setting.apiSource == 'temp' + }, }, // beforeRouteUpdate(to, from, next) { // // if (to.query.id === undefined) return @@ -105,6 +109,7 @@ export default { this.clickIndex = -1 }, testPlay(index) { + if (this.isAPITemp && this.list[index].source != 'kw') return this.setList({ list: this.list, listId: 'test', index }) }, handleRemove(index) { @@ -178,6 +183,10 @@ export default { } } +.disabled { + opacity: .5; +} + each(@themes, { :global(#container.@{value}) { .tbody { diff --git a/src/renderer/views/Search.vue b/src/renderer/views/Search.vue index bb960e3d00..4f6bc07bc1 100644 --- a/src/renderer/views/Search.vue +++ b/src/renderer/views/Search.vue @@ -7,7 +7,8 @@ thead tr th.nobreak.center(style="width: 37px;") - material-checkbox(id="search_select_all" v-model="isSelectAll" @change="handleSelectAllData" :indeterminate="isIndeterminate") + 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%;") 专辑 diff --git a/src/renderer/views/Setting.vue b/src/renderer/views/Setting.vue index 5c51d6e509..6280c9fa46 100644 --- a/src/renderer/views/Setting.vue +++ b/src/renderer/views/Setting.vue @@ -15,11 +15,17 @@ div.scroll(:class="$style.setting") div material-checkbox(id="setting_animate" v-model="current_setting.randomAnimate" label="是否启用") + dd(title='选择音乐来源') + h3 音乐来源 + div + material-checkbox(v-for="item in apiSources" :id="`setting_api_source_${item.id}`" @change="handleAPISourceChange(item.id)" :class="$style.gapTop" + need v-model="current_setting.apiSource" :value="item.id" :label="item.label" :key="item.id") + dt 播放设置 dd(title="都不选时播放完当前歌曲就停止播放") h3 歌曲切换方式 div - material-checkbox(:id="`setting_player_togglePlay_${item.value}`" :class="$style.gap" :value="item.value" :key="item.value" + material-checkbox(:id="`setting_player_togglePlay_${item.value}`" :class="$style.gapLeft" :value="item.value" :key="item.value" v-model="current_setting.player.togglePlayMethod" v-for="item in togglePlayMethods" :label="item.name") dd(title='启用时将优先播放320K品质的歌曲') h3 优先播放高品质音乐 @@ -37,7 +43,7 @@ div.scroll(:class="$style.setting") dd(title='下载歌曲时的命名方式') h3 文件命名方式 div - material-checkbox(:id="`setting_download_musicName_${item.value}`" :class="$style.gap" name="setting_download_musicName" :value="item.value" :key="item.value" need + material-checkbox(:id="`setting_download_musicName_${item.value}`" :class="$style.gapLeft" name="setting_download_musicName" :value="item.value" :key="item.value" need v-model="current_setting.download.fileName" v-for="item in musicNames" :label="item.name") dt 列表设置 dd(title='播放列表是否显示专辑栏') @@ -48,15 +54,15 @@ div.scroll(:class="$style.setting") dd h3 部分数据 div - material-btn(:class="[$style.btn, $style.gap]" min @click="handleImportPlayList") 导入列表 - material-btn(:class="[$style.btn, $style.gap]" min @click="handleExportPlayList") 导出列表 - material-btn(:class="[$style.btn, $style.gap]" min @click="handleImportSetting") 导入设置 - material-btn(:class="[$style.btn, $style.gap]" min @click="handleExportSetting") 导出设置 + material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleImportPlayList") 导入列表 + material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleExportPlayList") 导出列表 + material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleImportSetting") 导入设置 + material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleExportSetting") 导出设置 dd h3 所有数据(设置与试听列表) div - material-btn(:class="[$style.btn, $style.gap]" min @click="handleImportAllData") 导入 - material-btn(:class="[$style.btn, $style.gap]" min @click="handleExportAllData") 导出 + material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleImportAllData") 导入 + material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleExportAllData") 导出 dt 关于洛雪音乐 dd p.small @@ -113,6 +119,7 @@ export default { themeId: 0, sourceId: 0, randomAnimate: true, + apiSource: 'messoer', }, togglePlayMethods: [ { @@ -132,6 +139,16 @@ export default { value: 'singleLoop', }, ], + apiSources: [ + { + id: 'messoer', + label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)', + }, + { + id: 'temp', + label: '临时接口(软件的某些功能将不可用,建议在messoer不可用时再切换到本选项)', + }, + ], musicNames: [ { name: '歌名 - 歌手', @@ -310,6 +327,11 @@ export default { handleOpenUrl(url) { openUrl(url) }, + handleAPISourceChange(id) { + this.$nextTick(() => { + window.globalObj.apiSource = id + }) + }, }, } @@ -357,11 +379,16 @@ export default { } -.gap { - + .gap { +.gap-left { + + .gap-left { margin-left: 20px; } } +.gap-top { + + .gap-top { + margin-top: 10px; + } +} .theme { display: flex;