diff --git a/FAQ.md b/FAQ.md index f2d9b6f1..e6c4e6d2 100644 --- a/FAQ.md +++ b/FAQ.md @@ -106,4 +106,3 @@ 对于分享出来的歌单,若打开失败,可尝试先在浏览器中打开后,再从浏览器地址栏复制URL地址到软件打开;
或者如果你知道歌单 id 也可以直接输入歌单 id 打开。
-目前不支持打开**酷狗用户自定义**歌单。 diff --git a/publish/changeLog.md b/publish/changeLog.md index 39639fc5..2de9da4a 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -3,6 +3,7 @@ - 新增FLAC格式音乐标签信息写入与封面嵌入 - 添加软件启动时是否自动聚焦搜索框的设置 - 新增托盘设置,默认关闭,可到设置开启,感谢@LasyIsLazy提交的PR +- 新增打开酷狗源用户歌单 ### 优化 diff --git a/src/renderer/utils/music/kg/songList.js b/src/renderer/utils/music/kg/songList.js index 9a7dfcad..fffabd4c 100644 --- a/src/renderer/utils/music/kg/songList.js +++ b/src/renderer/utils/music/kg/songList.js @@ -7,6 +7,7 @@ export default { _requestObj_list: null, _requestObj_listRecommend: null, _requestObj_listDetail: null, + listDetailLimit: 100, currentTagInfo: { id: undefined, info: undefined, @@ -144,11 +145,106 @@ export default { })) }, + async createHttp(data, retryNum = 0) { + if (retryNum > 2) new Error('try max num') + let result + try { + result = await httpFetch('http://kmr.service.kugou.com/v2/album_audio/audio', { method: 'POST', body: data }).promise + } catch (err) { + console.log(err) + return this.createHttp(data, ++retryNum) + } + if (result.statusCode !== 200 || result.body.error_code !== 0) return this.createHttp(data, ++retryNum) + return result.body.data.map(s => s[0]) + }, + + createTaks(hashs) { + let data = { + appid: 1001, + clienttime: 639437935, + clientver: 9020, + fields: + 'album_info,author_name,audio_info,ori_audio_name', + is_publish: '1', + key: '0475af1457cd3363c7b45b871e94428a', + mid: '21511157a05844bd085308bc76ef3342', + show_privilege: 1, + } + let list = hashs + let tasks = [] + while (list.length) { + tasks.push(Object.assign({ data: list.slice(0, 20) }, data)) + if (list.length < 20) break + list = list.slice(20) + } + return tasks.map(task => this.createHttp(task)) + }, + + async getUserListDetail(link, page, retryNum = 0) { + if (link.includes('#')) link = link.replace(/#.*$/, '') + if (link.includes('zlist.html')) { + link = link.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list') + if (link.includes('pagesize')) { + link = link.replace('pagesize=30', 'pagesize=' + this.listDetailLimit).replace('page=1', 'page=' + page) + } else { + link += `&pagesize=${this.listDetailLimit}&page=${page}` + } + return this.getUserListDetail(link, page, ++retryNum) + } + 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, { + headers: { + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1', + Referer: link, + }, + }) + const { headers: { location }, statusCode, body } = await this._requestObj_listDetailLink.promise + // console.log(body) + if (statusCode > 400) return this.getUserListDetail(link, page, ++retryNum) + if (!body && location) { + // console.log('location', location) + let link = location.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list') + if (link.includes('pagesize')) { + link = link.replace('pagesize=30', 'pagesize=' + this.listDetailLimit).replace('page=1', 'page=' + page) + } else { + link += `&pagesize=${this.listDetailLimit}&page=${page}` + } + return this.getUserListDetail(link, page, ++retryNum) + } + if (body.errcode !== 0) return this.getUserListDetail(link, page, ++retryNum) + let listInfo = body.info['0'] + let result = body.list.info.map(item => ({ hash: item.hash })) + result = await Promise.all(this.createTaks(result)).then(([...datas]) => datas.flat()) + return { + list: this.filterData2(result) || [], + page, + limit: this.listDetailLimit, + total: listInfo.count, + source: 'kg', + info: { + name: listInfo.name, + img: listInfo.pic && listInfo.pic.replace('{size}', 240), + // desc: body.result.info.list_desc, + author: listInfo.list_create_username, + // play_count: this.formatPlayCount(listInfo.count), + }, + } + }, + 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') + // if ((/[?&]/.test(id))) { + // id = id.replace(this.regExps.listDetailLink, '$1') + // } else + if (/http(?:s):/.test(id)) { + return this.getUserListDetail(id, page) + } + + // if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1') this._requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id)) return this._requestObj_listDetail.promise.then(({ body }) => { @@ -233,6 +329,57 @@ export default { }) }, + // hash list filter + filterData2(rawList) { + // console.log(rawList) + let list = [] + rawList.forEach(item => { + if (!item) return + const types = [] + const _types = {} + if (item.audio_info.filesize !== '0') { + let size = sizeFormate(parseInt(item.audio_info.filesize)) + types.push({ type: '128k', size, hash: item.audio_info.hash }) + _types['128k'] = { + size, + hash: item.audio_info.hash, + } + } + if (item.audio_info.filesize_320 !== '0') { + let size = sizeFormate(parseInt(item.audio_info.filesize_320)) + types.push({ type: '320k', size, hash: item.audio_info.hash_320 }) + _types['320k'] = { + size, + hash: item.audio_info.hash_320, + } + } + if (item.audio_info.filesize_flac !== '0') { + let size = sizeFormate(parseInt(item.audio_info.filesize_flac)) + types.push({ type: 'flac', size, hash: item.audio_info.hash_flac }) + _types.flac = { + size, + hash: item.audio_info.hash_flac, + } + } + list.push({ + singer: item.author_name, + name: item.ori_audio_name, + albumName: item.album_info.album_name, + albumId: item.album_info.album_id, + songmid: item.audio_info.audio_id, + source: 'kg', + interval: formatPlayTime(parseInt(item.audio_info.timelength) / 1000), + img: null, + lrc: null, + hash: item.audio_info.hash, + types, + _types, + typeUrl: {}, + }) + }) + return list + }, + // 获取列表信息 getListInfo(tagId, tryNum = 0) { if (this._requestObj_listInfo) this._requestObj_listInfo.cancelHttp() diff --git a/src/renderer/views/SongList.vue b/src/renderer/views/SongList.vue index a1915a0d..241e4611 100644 --- a/src/renderer/views/SongList.vue +++ b/src/renderer/views/SongList.vue @@ -327,7 +327,7 @@ export default { }, handleGetListDetail(id, page) { this.isGetDetailFailed = false - this.getListDetail({ id, page }).catch(err => { + return this.getListDetail({ id, page }).catch(err => { this.isGetDetailFailed = true return Promise.reject(err) })