From bb080c2d185b26c2028174fea8071b3a434d9e5b Mon Sep 17 00:00:00 2001 From: lyswhut <lyswhut@qq.com> Date: Sat, 14 Mar 2020 20:58:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=AD=8C=E5=8D=95=E6=89=93?= =?UTF-8?q?=E5=BC=80=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- publish/changeLog.md | 1 + src/renderer/lang/cns/view/song_list.json | 3 +- src/renderer/lang/cnt/view/song_list.json | 3 +- src/renderer/lang/en/view/song_list.json | 3 +- src/renderer/store/modules/songList.js | 19 +++++- src/renderer/utils/music/bd/songList.js | 11 +++- src/renderer/utils/music/kg/songList.js | 5 ++ src/renderer/utils/music/kw/songList.js | 7 +++ src/renderer/utils/music/mg/songList.js | 6 ++ src/renderer/utils/music/tx/songList.js | 77 +++++++++++++++-------- src/renderer/utils/music/wy/songList.js | 6 ++ src/renderer/views/SongList.vue | 65 +++++-------------- 12 files changed, 124 insertions(+), 82 deletions(-) diff --git a/publish/changeLog.md b/publish/changeLog.md index af8ae7ff..5ef6a42e 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -13,6 +13,7 @@ - 优化月里嫦娥皮肤侧栏鼠标悬浮颜色 - 优化播放进度条的动画效果 - 现在添加下载任务时,后面添加的任务会在列表顶部插入 +- 优化歌单打开机制,现在歌单加载失败时会提示加载失败了,并且支持企鹅歌单的短链接了 ### 修复 diff --git a/src/renderer/lang/cns/view/song_list.json b/src/renderer/lang/cns/view/song_list.json index df6676f5..cff89875 100644 --- a/src/renderer/lang/cns/view/song_list.json +++ b/src/renderer/lang/cns/view/song_list.json @@ -1,4 +1,5 @@ { "back": "返回", - "loding_list": "列表加載中..." + "loding_list": "列表加載中...", + "loding_list_fail": "列表加载失败" } diff --git a/src/renderer/lang/cnt/view/song_list.json b/src/renderer/lang/cnt/view/song_list.json index e5ebd831..41b47663 100644 --- a/src/renderer/lang/cnt/view/song_list.json +++ b/src/renderer/lang/cnt/view/song_list.json @@ -1,4 +1,5 @@ { "back": "返回", - "loding_list": "列表加载中..." + "loding_list": "列表加载中...", + "loding_list_fail": "列表加載失敗" } diff --git a/src/renderer/lang/en/view/song_list.json b/src/renderer/lang/en/view/song_list.json index 986f6428..6985b820 100644 --- a/src/renderer/lang/en/view/song_list.json +++ b/src/renderer/lang/en/view/song_list.json @@ -1,4 +1,5 @@ { "back": "Back", - "loding_list": "List loading..." + "loding_list": "List loading...", + "loding_list_fail": "List loading failed" } diff --git a/src/renderer/store/modules/songList.js b/src/renderer/store/modules/songList.js index 0f7af9da..ff516871 100644 --- a/src/renderer/store/modules/songList.js +++ b/src/renderer/store/modules/songList.js @@ -73,8 +73,13 @@ const actions = { getListDetail({ state, rootState, commit }, { id, page }) { let source = rootState.setting.songList.source let key = `sdetail__${source}__${id}__${page}` - if (state.listDetail.list.length && state.listDetail.key == key) return true - return (cache.has(key) ? Promise.resolve(cache.get(key)) : music[source].songList.getListDetail(id, page)).then(result => commit('setListDetail', { result, key, page })) + if (state.listDetail.list.length && state.listDetail.key == key) return Promise.resolve() + commit('clearListDetail') + return ( + cache.has(key) + ? Promise.resolve(cache.get(key)) + : music[source].songList.getListDetail(id, page) + ).then(result => commit('setListDetail', { result, key, page })) }, /* getListDetailAll({ state, rootState }, id) { let source = rootState.setting.songList.source @@ -141,7 +146,15 @@ const mutations = { state.selectListInfo = info }, clearListDetail(state) { - state.listDetail.list = [] + state.listDetail = { + list: [], + desc: null, + total: 0, + page: 1, + limit: 30, + key: null, + info: {}, + } }, } diff --git a/src/renderer/utils/music/bd/songList.js b/src/renderer/utils/music/bd/songList.js index a42f3ede..63bbdce1 100644 --- a/src/renderer/utils/music/bd/songList.js +++ b/src/renderer/utils/music/bd/songList.js @@ -20,6 +20,10 @@ export default { id: '0', }, ], + regExps: { + // http://music.taihe.com/songlist/566347741 + listDetailLink: /^.+\/songlist\/(\d+)(?:\?.*|&.*$|#.*$|$)/, + }, aesPassEncod(jsonData) { let timestamp = Math.floor(Date.now() / 1000) let privateKey = toMD5('baidu_taihe_music_secret_key' + timestamp).substr(8, 16) @@ -184,10 +188,11 @@ export default { // 获取歌曲列表内的音乐 getListDetail(id, page, tryNum = 0) { - if (this._requestObj_listDetail) { - this._requestObj_listDetail.cancelHttp() - } + if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) + + if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1') + this._requestObj_listDetail = httpFetch(this.getListDetailUrl(id, page)) return this._requestObj_listDetail.promise.then(({ body }) => { if (body.error_code !== this.successCode) return this.getListDetail(id, page, ++tryNum) diff --git a/src/renderer/utils/music/kg/songList.js b/src/renderer/utils/music/kg/songList.js index 123418ce..9a7dfcad 100644 --- a/src/renderer/utils/music/kg/songList.js +++ b/src/renderer/utils/music/kg/songList.js @@ -36,6 +36,8 @@ export default { regExps: { listData: /global\.data = (\[.+\]);/, listInfo: /global = {[\s\S]+?name: "(.+)"[\s\S]+?pic: "(.+)"[\s\S]+?};/, + // https://www.kugou.com/yy/special/single/1067062.html + listDetailLink: /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/, }, getInfoUrl(tagId) { return tagId @@ -145,6 +147,9 @@ export default { getListDetail(id, page, tryNum = 0) { // 获取歌曲列表内的音乐 if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) + + if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1') + this._requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id)) return this._requestObj_listDetail.promise.then(({ body }) => { let listData = body.match(this.regExps.listData) diff --git a/src/renderer/utils/music/kw/songList.js b/src/renderer/utils/music/kw/songList.js index 38de9bf9..192b1067 100644 --- a/src/renderer/utils/music/kw/songList.js +++ b/src/renderer/utils/music/kw/songList.js @@ -20,6 +20,10 @@ export default { id: 'hot', }, ], + regExps: { + // http://www.kuwo.cn/playlist_detail/2886046289 + listDetailLink: /^.+\/playlist_detail\/(\d+)(?:\?.*|&.*$|#.*$|$)/, + }, tagsUrl: 'http://wapi.kuwo.cn/api/pc/classify/playlist/getTagList?cmd=rcm_keyword_playlist&user=0&prod=kwplayer_pc_9.0.5.0&vipver=9.0.5.0&source=kwplayer_pc_9.0.5.0&loginUid=0&loginSid=0&appUid=76039576', hotTagUrl: 'http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmTagList?loginUid=0&loginSid=0&appUid=76039576', getListUrl({ sortId, id, type, page }) { @@ -161,6 +165,9 @@ export default { this._requestObj_listDetail.cancelHttp() } if (tryNum > 2) return Promise.reject(new Error('try max num')) + + if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1') + this._requestObj_listDetail = httpFetch(this.getListDetailUrl(id, page)) return this._requestObj_listDetail.promise.then(({ body }) => { if (body.result !== 'ok') return this.getListDetail(id, page, ++tryNum) diff --git a/src/renderer/utils/music/mg/songList.js b/src/renderer/utils/music/mg/songList.js index daff4567..e09959e8 100644 --- a/src/renderer/utils/music/mg/songList.js +++ b/src/renderer/utils/music/mg/songList.js @@ -21,6 +21,9 @@ export default { regExps: { list: /<li><div class="thumb">.+?<\/li>/g, listInfo: /.+data-original="(.+?)".*data-id="(\d+)".*<div class="song-list-name"><a\s.*?>(.+?)<\/a>.+<i class="iconfont cf-bofangliang"><\/i>(.+?)<\/div>/, + + // http://music.migu.cn/v3/music/playlist/161044573?page=1 + listDetailLink: /^.+\/playlist\/(\d+)(?:\?.*|&.*$|#.*$|$)/, }, tagsUrl: 'https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/indexTagPage.do?needAll=0', getSongListUrl(sortId, tagId, page) { @@ -58,6 +61,9 @@ export default { getListDetail(id, page, tryNum = 0) { // 获取歌曲列表内的音乐 if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) + + if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1') + this._requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id, page), { headers: this.defaultHeaders }) return this._requestObj_listDetail.promise.then(({ body }) => { if (body.code !== this.successCode) return this.getListDetail(id, page, ++tryNum) diff --git a/src/renderer/utils/music/tx/songList.js b/src/renderer/utils/music/tx/songList.js index 33be8f7a..092a5a91 100644 --- a/src/renderer/utils/music/tx/songList.js +++ b/src/renderer/utils/music/tx/songList.js @@ -7,6 +7,7 @@ export default { _requestObj_hotTags: null, _requestObj_list: null, _requestObj_listDetail: null, + _requestObj_listDetailLink: null, limit_list: 36, limit_song: 10000000, successCode: 0, @@ -20,9 +21,14 @@ export default { id: 2, }, ], - regexps: { + regExps: { hotTagHtml: /class="c_bg_link js_tag_item" data-id="\w+">.+?<\/a>/g, hotTag: /data-id="(\w+)">(.+?)<\/a>/, + + // https://y.qq.com/n/yqq/playlist/7217720898.html + // https://i.y.qq.com/n2/m/share/details/taoge.html?platform=11&appshare=android_qq&appversion=9050006&id=7217720898&ADTAG=qfshare + listDetailLink1: /^.+(?:\?|&)id=(\d+)(?:&.*$|#.*$|$)/, + listDetailLink2: /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/, }, tagsUrl: 'https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=%7B%22tags%22%3A%7B%22method%22%3A%22get_all_categories%22%2C%22param%22%3A%7B%22qq%22%3A%22%22%7D%2C%22module%22%3A%22playlist.PlaylistAllCategoriesServer%22%7D%7D', hotTagUrl: 'https://c.y.qq.com/node/pc/wk_v15/category_playlist.html', @@ -76,12 +82,12 @@ export default { }) }, filterInfoHotTag(html) { - let hotTag = html.match(this.regexps.hotTagHtml) + let hotTag = html.match(this.regExps.hotTagHtml) const hotTags = [] if (!hotTag) return hotTags hotTag.forEach(tagHtml => { - let result = tagHtml.match(this.regexps.hotTag) + let result = tagHtml.match(this.regExps.hotTag) if (!result) return hotTags.push({ id: parseInt(result[1]), @@ -167,36 +173,57 @@ export default { } }, + async handleParseId(link, retryNum = 0) { + if (this._requestObj_listDetailLink) this._requestObj_listDetailLink.cancelHttp() + if (retryNum > 2) return Promise.reject(new Error('link try max num')) + + this._requestObj_listDetailLink = httpFetch(link) + const { headers: { location }, statusCode } = await this._requestObj_listDetailLink.promise + // console.log(headers) + if (statusCode > 400) return this.handleParseId(link, ++retryNum) + return location == null ? link : location + }, + // 获取歌曲列表内的音乐 - getListDetail(id, tryNum = 0) { - if (this._requestObj_listDetail) { - this._requestObj_listDetail.cancelHttp() - } + async getListDetail(id, tryNum = 0) { + if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) + + if ((/[?&:/]/.test(id))) { + let regx = /\/\/i\.y\.qq\.com/.test(id) ? this.regExps.listDetailLink1 : this.regExps.listDetailLink2 + if (!regx.test(id)) { + id = await this.handleParseId(id) + regx = this.regExps.listDetailLink1 + console.log(id) + } + id = id.replace(regx, '$1') + // console.log(id) + } + this._requestObj_listDetail = httpFetch(this.getListDetailUrl(id), { headers: { Origin: 'https://y.qq.com', Referer: `https://y.qq.com/n/yqq/playsquare/${id}.html`, }, }) - return this._requestObj_listDetail.promise.then(({ body }) => { - if (body.code !== this.successCode) return this.getListDetail(id, ++tryNum) - const cdlist = body.cdlist[0] - return { - list: this.filterListDetail(cdlist.songlist), - page: 1, - limit: cdlist.songlist.length + 1, - total: cdlist.songlist.length, - source: 'tx', - info: { - name: cdlist.dissname, - img: cdlist.logo, - desc: jshtmlencode.htmlDecode(cdlist.desc).replace(/<br>/g, '\n'), - author: cdlist.nickname, - play_count: this.formatPlayCount(cdlist.visitnum), - }, - } - }) + const { body } = await this._requestObj_listDetail.promise + + if (body.code !== this.successCode) return this.getListDetail(id, ++tryNum) + const cdlist = body.cdlist[0] + return { + list: this.filterListDetail(cdlist.songlist), + page: 1, + limit: cdlist.songlist.length + 1, + total: cdlist.songlist.length, + source: 'tx', + info: { + name: cdlist.dissname, + img: cdlist.logo, + desc: jshtmlencode.htmlDecode(cdlist.desc).replace(/<br>/g, '\n'), + author: cdlist.nickname, + play_count: this.formatPlayCount(cdlist.visitnum), + }, + } }, getSinger(singers) { let arr = [] diff --git a/src/renderer/utils/music/wy/songList.js b/src/renderer/utils/music/wy/songList.js index ea1f4fbf..e395665e 100644 --- a/src/renderer/utils/music/wy/songList.js +++ b/src/renderer/utils/music/wy/songList.js @@ -25,6 +25,9 @@ export default { id: 'new', }, ], + regExps: { + listDetailLink: /^.+(?:\?|&)id=(\d+)(?:&.*$|#.*$|$)/, + }, /** * 格式化播放数量 * @param {*} num @@ -45,6 +48,9 @@ export default { getListDetail(id, page, tryNum = 0) { // 获取歌曲列表内的音乐 if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) + + if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1') + this._requestObj_listDetail = httpFetch('https://music.163.com/api/linux/forward', { method: 'post', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', diff --git a/src/renderer/views/SongList.vue b/src/renderer/views/SongList.vue index 42c933ac..02bb1f5c 100644 --- a/src/renderer/views/SongList.vue +++ b/src/renderer/views/SongList.vue @@ -15,7 +15,8 @@ //- material-btn(:class="$style.closeDetailButton" :disabled="detailLoading" @click="playSongListDetail") 播放 //- | material-btn(:class="$style.closeDetailButton" @click="hideListDetail") {{$t('view.song_list.back')}} - material-song-list(v-model="selectdData" @action="handleSongListAction" :source="source" :page="listDetail.page" :limit="listDetail.limit" :total="listDetail.total" :noItem="$t('material.song_list.loding_list')" :list="listDetail.list") + material-song-list(v-model="selectdData" @action="handleSongListAction" :source="source" :page="listDetail.page" :limit="listDetail.limit" + :total="listDetail.total" :noItem="isGetDetailFailed ? $t('view.song_list.loding_list_fail') : $t('view.song_list.loding_list')" :list="listDetail.list") transition(enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut") div(:class="$style.songListContainer" v-if="!isVisibleListDetail") div(:class="$style.header") @@ -74,6 +75,7 @@ export default { isShowListAddMultiple: false, importSongListText: '', listWidth: 645, + isGetDetailFailed: false, // detailLoading: true, } }, @@ -164,7 +166,7 @@ export default { methods: { ...mapMutations(['setSongList']), ...mapActions('songList', ['getTags', 'getList', 'getListDetail']), - ...mapMutations('songList', ['setVisibleListDetail', 'setSelectListInfo', 'clearListDetail']), + ...mapMutations('songList', ['setVisibleListDetail', 'setSelectListInfo']), ...mapActions('download', ['createDownload', 'createDownloadMultiple']), ...mapMutations('list', ['listAdd', 'listAddMultiple']), ...mapMutations('player', ['setList']), @@ -229,7 +231,7 @@ export default { }) }, handleToggleListDetailPage(page) { - this.getListDetail({ id: this.selectListInfo.id, page }).then(() => { + this.handleGetListDetail(this.selectListInfo.id, page).then(() => { this.$nextTick(() => { scrollTo(this.$refs.dom_scrollContent, 0) }) @@ -254,9 +256,8 @@ export default { // this.detailLoading = true this.setSelectListInfo(this.listData.list[index]) this.setVisibleListDetail(true) - this.clearListDetail() this.$nextTick(() => { - this.getListDetail({ id: this.selectListInfo.id, page: 1 }) + this.handleGetListDetail(this.selectListInfo.id, 1) }) }, handleFlowBtnClick(action) { @@ -301,13 +302,11 @@ export default { case 'submit': this.handleGetSongListDetail() break - case 'blur': - this.parseImportSongListInputText() - break + // case 'blur': + // break } }, handleGetSongListDetail() { - this.parseImportSongListInputText() this.setSelectListInfo({ play_count: null, id: this.importSongListText, @@ -317,45 +316,8 @@ export default { desc: '', source: this.source, }) - this.clearListDetail() - this.$nextTick(() => { - this.setVisibleListDetail(true) - this.getListDetail({ id: this.importSongListText, page: 1 }) - }) - }, - parseImportSongListInputText() { - if (!(/[?&:/]/.test(this.importSongListText))) return - const text = this.importSongListText - let regx - switch (this.source) { - case 'wy': - regx = /^.+(?:\?|&)id=(\d+)(?:&.*$|#.*$|$)/ - break - case 'tx': - // https://y.qq.com/n/yqq/playlist/7217720898.html - // https://i.y.qq.com/n2/m/share/details/taoge.html?platform=11&appshare=android_qq&appversion=9050006&id=7217720898&ADTAG=qfshare - regx = /\/\/i\.y\.qq\.com/.test(text) ? /^.+(?:\?|&)id=(\d+)(?:&.*$|#.*$|$)/ : /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/ - break - case 'kw': - // http://www.kuwo.cn/playlist_detail/2886046289 - regx = /^.+\/playlist_detail\/(\d+)(?:\?.*|&.*$|#.*$|$)/ - break - case 'bd': - // http://music.taihe.com/songlist/566347741 - regx = /^.+\/songlist\/(\d+)(?:\?.*|&.*$|#.*$|$)/ - break - case 'mg': - // http://music.migu.cn/v3/music/playlist/161044573?page=1 - regx = /^.+\/playlist\/(\d+)(?:\?.*|&.*$|#.*$|$)/ - break - case 'kg': - // https://www.kugou.com/yy/special/single/1067062.html - regx = /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/ - break - default: - return - } - this.importSongListText = text.replace(regx, '$1') + this.setVisibleListDetail(true) + this.handleGetListDetail(this.importSongListText, 1) }, filterList(list) { return this.setting.apiSource == 'temp' ? list.filter(s => s.source == 'kw') : [...list] @@ -363,6 +325,13 @@ export default { setTagListWidth() { this.listWidth = this.$refs.tagList.$el.clientWidth + this.$refs.tab.$el.clientWidth + 2 }, + handleGetListDetail(id, page) { + this.isGetDetailFailed = false + this.getListDetail({ id, page }).catch(err => { + this.isGetDetailFailed = true + return Promise.reject(err) + }) + }, /* addSongListDetail() { // this.detailLoading = true // this.getListDetailAll(this.selectListInfo.id).then(() => {