diff --git a/README.md b/README.md index 451ae9c0..dc970038 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ 软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)
软件下载请转到:[发布页面](https://github.com/lyswhut/lx-music-desktop/releases)
-或者到网盘下载:`https://www.lanzous.com/b906260/` 密码:`glqw` +或者到网盘下载(网盘内有MAC、windows版):`https://www.lanzous.com/b906260/` 密码:`glqw` 歌曲默认下载到桌面,可自行到设置页面更改。
若排行榜上的某些歌曲**无法播放**,可尝试**直接搜索**该歌曲后播放。 diff --git a/package-lock.json b/package-lock.json index 9ec31398..6b16ef48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "lx-music-desktop", - "version": "0.2.4", + "version": "0.3.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4229,6 +4229,11 @@ "randomfill": "^1.0.3" } }, + "crypto-js": { + "version": "3.1.9-1", + "resolved": "https://registry.npm.taobao.org/crypto-js/download/crypto-js-3.1.9-1.tgz", + "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + }, "crypto-random-string": { "version": "1.0.0", "resolved": "https://registry.npm.taobao.org/crypto-random-string/download/crypto-random-string-1.0.0.tgz", diff --git a/package.json b/package.json index 3fcb89f9..882a7556 100644 --- a/package.json +++ b/package.json @@ -195,6 +195,7 @@ }, "dependencies": { "axios": "^0.19.0", + "crypto-js": "^3.1.9-1", "electron-log": "^3.0.7", "electron-store": "^4.0.0", "electron-updater": "^4.1.2", diff --git a/publish/changeLog.md b/publish/changeLog.md index b90f87c0..eb2dc4d3 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -1,5 +1,7 @@ ### 修复 +- **messoer**的接口已经关闭,暂时切换到临时接口使用,部分功能受限。。。 - 修复设置界面更新出错时仍然显示更新下载中的问题 - 修复手动定位播放进度条时存在偏差的问题 - 屏蔽播放器中没有歌曲时对进度条的点击 + diff --git a/src/renderer/components/core/Aside.vue b/src/renderer/components/core/Aside.vue index 50e1bf9c..9d4e8c3b 100644 --- a/src/renderer/components/core/Aside.vue +++ b/src/renderer/components/core/Aside.vue @@ -9,10 +9,10 @@ div(:class="$style.aside") dt 在线音乐 dd router-link(:active-class="$style.active" to="search") 搜索 + //- dd + router-link(:active-class="$style.active" to="songList") 歌单 dd router-link(:active-class="$style.active" to="leaderboard") 排行榜 - //- dd - router-link(:active-class="$style.active" to="recommend") 歌单 dl dt 我的音乐 dd diff --git a/src/renderer/route/paths.js b/src/renderer/route/paths.js index 42e1b7ac..a211fd06 100644 --- a/src/renderer/route/paths.js +++ b/src/renderer/route/paths.js @@ -18,9 +18,9 @@ export default [ view: 'Leaderboard', }, { - path: '/recommend', - name: 'recommend', - view: 'Recommend', + path: '/songList', + name: 'songList', + view: 'SongList', }, { path: '/list', diff --git a/src/renderer/utils/index.js b/src/renderer/utils/index.js index 633a4d95..f9e0daa8 100644 --- a/src/renderer/utils/index.js +++ b/src/renderer/utils/index.js @@ -2,6 +2,7 @@ import fs from 'fs' import { shell, remote } from 'electron' import path from 'path' import os from 'os' +import crypto from 'crypto' /** * 获取两个数之间的随机整数,大于等于min,小于max @@ -184,7 +185,7 @@ export const updateSetting = setting => { }, themeId: 0, sourceId: 'kw', - apiSource: 'messoer', + apiSource: 'temp', randomAnimate: true, ignoreVersion: null, } @@ -201,7 +202,7 @@ export const updateSetting = setting => { objectDeepMerge(defaultSetting, overwriteSetting) setting = defaultSetting } - setting.apiSource = 'messoer' // 强制设置回 messoer 接口源 + if (setting.apiSource == 'messoer') setting.apiSource = 'temp' // 强制设置回 temp 接口源 return setting } @@ -220,3 +221,10 @@ let dom_title = document.getElementsByTagName('title')[0] export const setTitle = title => { dom_title.innerText = title || '洛雪音乐助手' } + + +/** + * 创建 MD5 hash + * @param {*} str + */ +export const toMD5 = str => crypto.createHash('md5').update(str).digest('hex') diff --git a/src/renderer/utils/message.js b/src/renderer/utils/message.js index d48883fd..c58656e5 100644 --- a/src/renderer/utils/message.js +++ b/src/renderer/utils/message.js @@ -2,6 +2,6 @@ export const requestMsg = { fail: '请求异常😮,可以多试几次,若还是不行就换一首吧。。。', unachievable: '哦No😱...接口无法访问了!', // unachievable: '哦No😱...接口无法访问了!已帮你切换到临时接口,重试下看能不能播放吧~', - notConnectNetwork: '无法连接网络', + notConnectNetwork: '无法连接到服务器', cancelRequest: '取消http请求', } diff --git a/src/renderer/utils/music/api-source.js b/src/renderer/utils/music/api-source.js index c293e3f7..0a41cdcd 100644 --- a/src/renderer/utils/music/api-source.js +++ b/src/renderer/utils/music/api-source.js @@ -1,24 +1,36 @@ -import kw_api_messoer from './kw/api-messoer' 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' +// import kw_api_messoer from './kw/api-messoer' +// 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' +import kw_api_internal from './kw/api-internal' +import tx_api_internal from './tx/api-internal' +import kg_api_internal from './kg/api-internal' +import wy_api_internal from './wy/api-internal' +import bd_api_internal from './bd/api-internal' const apis = { - kw_api_messoer, - tx_api_messoer, - kg_api_messoer, - wy_api_messoer, - bd_api_messoer, + // kw_api_messoer, + // tx_api_messoer, + // kg_api_messoer, + // wy_api_messoer, + // bd_api_messoer, + kw_api_internal, + tx_api_internal, + kg_api_internal, + wy_api_internal, + bd_api_internal, kw_api_temp, } const getAPI = source => { switch (window.globalObj.apiSource) { - case 'messoer': - return apis[`${source}_api_messoer`] + // case 'messoer': + // return apis[`${source}_api_messoer`] + case 'internal': + return apis[`${source}_api_internal`] case 'temp': return apis[`${source}_api_temp`] } diff --git a/src/renderer/utils/music/bd/api-internal.js b/src/renderer/utils/music/bd/api-internal.js new file mode 100644 index 00000000..9ecc51b8 --- /dev/null +++ b/src/renderer/utils/music/bd/api-internal.js @@ -0,0 +1,44 @@ +import { httpFatch } from '../../request' +import { requestMsg } from '../../message' + +const api_internal = { + successCode: 2200, + // getMusicUrl(songInfo, type) { + // const requestObj = httpFatch(`http://play.taihe.com/data/music/songlink`, { + // method: 'post', + // headers: { + // Origin: 'http://play.taihe.com', + // }, + // formData: { + // songIds: songInfo.songmid, + // }, + // }) + // requestObj.promise = requestObj.promise.then(({ body }) => { + // console.log(body) + // return Promise.reject() + // // if (body.error_code !== this.successCode) return this.getMusicUrl(songInfo, type) + // // return body.code === 200 ? Promise.resolve({ type, url: body.result.bitrate.file_link }) : Promise.reject(new Error(requestMsg.fail)) + // }) + // return requestObj + // }, + getMusicInfo(songInfo, tryNum = 0) { + const requestObj = httpFatch(`http://tingapi.ting.baidu.com/v1/restserver/ting?from=webapp_music&method=baidu.ting.song.baseInfos&song_id=${songInfo.songmid}`) + requestObj.promise = requestObj.promise.then(({ body }) => { + if (body.error_code !== this.successCode) return tryNum > 5 ? Promise.reject(new Error(requestMsg.fail)) : this.getMusicInfo(songInfo, ++tryNum) + return body ? Promise.resolve(body.result.items[0]) : Promise.reject(new Error(requestMsg.fail)) + }) + return requestObj + }, + getPic(songInfo) { + const requestObj = this.getMusicInfo(songInfo) + requestObj.promise = requestObj.promise.then(info => info.pic_premium) + return requestObj + }, + getLyric(songInfo) { + const requestObj = this.getMusicInfo(songInfo) + requestObj.promise.then(info => httpFatch(info.lrclink).promise) + return requestObj + }, +} + +export default api_internal diff --git a/src/renderer/utils/music/bd/api-messoer.js b/src/renderer/utils/music/bd/api-messoer.js index 72e267bd..80609c8b 100644 --- a/src/renderer/utils/music/bd/api-messoer.js +++ b/src/renderer/utils/music/bd/api-messoer.js @@ -1,11 +1,13 @@ import { httpFatch } from '../../request' import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' 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, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail)) @@ -15,7 +17,8 @@ const api_messoer = { getPic(songInfo, size = '500') { const requestObj = httpFatch(`https://v1.itooi.cn/baidu/pic?id=${songInfo.songmid}&imageSize=${size}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail)) @@ -25,7 +28,8 @@ const api_messoer = { getLyric(songInfo) { const requestObj = httpFatch(`https://v1.itooi.cn/baidu/lrc?id=${songInfo.songmid}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body ? Promise.resolve(body) : Promise.reject(new Error(requestMsg.fail)) diff --git a/src/renderer/utils/music/bd/songList.js b/src/renderer/utils/music/bd/songList.js index 8aa98c50..ff5593cd 100644 --- a/src/renderer/utils/music/bd/songList.js +++ b/src/renderer/utils/music/bd/songList.js @@ -4,9 +4,9 @@ import CryptoJS from 'crypto-js' export default { _requestObj_tags: null, - _requestObj_songList: null, - _requestObj_songListRecommend: null, - _requestObj_songListDetail: null, + _requestObj_list: null, + _requestObj_listRecommend: null, + _requestObj_listDetail: null, limit_list: 20, limit_song: 25, successCode: 22000, @@ -87,7 +87,7 @@ export default { version: '10.1.8', }, 'baidu.ting.ugcdiy.getChannels') }, - getSongListUrl(sortType, tagName, page) { + getListUrl(sortType, tagName, page) { return this.createUrl({ channelname: tagName, from: 'qianqianmini', @@ -139,14 +139,14 @@ export default { // 获取列表数据 getList(sortId, tagId, page) { - if (this._requestObj_songList) this._requestObj_songList.cancelHttp() - this._requestObj_songList = httpFatch( - this.getSongListUrl(sortId, tagId, page) + if (this._requestObj_list) this._requestObj_list.cancelHttp() + this._requestObj_list = httpFatch( + this.getListUrl(sortId, tagId, page) ) - return this._requestObj_songList.promise.then(({ body }) => { + return this._requestObj_list.promise.then(({ body }) => { if (body.error_code !== this.successCode) return this.getSongList(sortId, tagId, page) return { - list: this.filterSongList(body.diyInfo), + list: this.filterList(body.diyInfo), total: body.nums, page, limit: this.limit_list, @@ -164,7 +164,7 @@ export default { if (num > 10000) return parseInt(num / 1000) / 10 + '万' return num }, - filterSongList(rawData) { + filterList(rawData) { return rawData.map(item => ({ play_count: this.formatPlayCount(item.listen_num), id: item.list_id, @@ -179,11 +179,11 @@ export default { // 获取歌曲列表内的音乐 getListDetail(id, page) { - if (this._requestObj_songListDetail) { - this._requestObj_songListDetail.cancelHttp() + if (this._requestObj_listDetail) { + this._requestObj_listDetail.cancelHttp() } - this._requestObj_songListDetail = httpFatch(this.getListDetailUrl(id, page)) - return this._requestObj_songListDetail.promise.then(({ body }) => { + this._requestObj_listDetail = httpFatch(this.getListDetailUrl(id, page)) + return this._requestObj_listDetail.promise.then(({ body }) => { if (body.error_code !== this.successCode) return this.getListDetail(id, page) let listData = this.filterData(body.result.songlist) return { diff --git a/src/renderer/utils/music/kg/api-internal.js b/src/renderer/utils/music/kg/api-internal.js new file mode 100644 index 00000000..2fe074c7 --- /dev/null +++ b/src/renderer/utils/music/kg/api-internal.js @@ -0,0 +1,41 @@ +import { httpFatch } from '../../request' +import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' + +const api_messoer = { + getMusicUrl(songInfo, type) { + const requestObj = httpFatch(`https://v1.itooi.cn/kugou/url?id=${songInfo._types[type].hash}&quality=${type.replace(/k$/, '')}&isRedirect=0`, { + method: 'get', + timeout, + headers, + }) + 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) { + const requestObj = httpFatch(`https://v1.itooi.cn/kugou/pic?id=${songInfo.hash}&isRedirect=0`, { + method: 'get', + timeout, + headers, + }) + 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/kugou/lrc?id=${songInfo.hash}&isRedirect=0`, { + method: 'get', + timeout, + headers, + }) + 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/kg/api-messoer.js b/src/renderer/utils/music/kg/api-messoer.js index 017959af..2fe074c7 100644 --- a/src/renderer/utils/music/kg/api-messoer.js +++ b/src/renderer/utils/music/kg/api-messoer.js @@ -1,11 +1,13 @@ import { httpFatch } from '../../request' import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' const api_messoer = { getMusicUrl(songInfo, type) { const requestObj = httpFatch(`https://v1.itooi.cn/kugou/url?id=${songInfo._types[type].hash}&quality=${type.replace(/k$/, '')}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail)) @@ -15,7 +17,8 @@ const api_messoer = { getPic(songInfo) { const requestObj = httpFatch(`https://v1.itooi.cn/kugou/pic?id=${songInfo.hash}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail)) @@ -25,7 +28,8 @@ const api_messoer = { getLyric(songInfo) { const requestObj = httpFatch(`https://v1.itooi.cn/kugou/lrc?id=${songInfo.hash}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body ? Promise.resolve(body) : Promise.reject(new Error(requestMsg.fail)) diff --git a/src/renderer/utils/music/kg/songList.js b/src/renderer/utils/music/kg/songList.js index 9f6d4d12..82b23606 100644 --- a/src/renderer/utils/music/kg/songList.js +++ b/src/renderer/utils/music/kg/songList.js @@ -3,8 +3,8 @@ import { formatPlayTime, sizeFormate } from '../../index' export default { _requestObj_tagInfo: null, - _requestObj_songList: null, - _requestObj_songListDetail: null, + _requestObj_list: null, + _requestObj_listDetail: null, currentTagInfo: { id: null, info: null, @@ -90,18 +90,18 @@ export default { }, getSongList(sortId, tagId, page) { - if (this._requestObj_songList) this._requestObj_songList.cancelHttp() - this._requestObj_songList = httpFatch( + if (this._requestObj_list) this._requestObj_list.cancelHttp() + this._requestObj_list = httpFatch( this.getSongListUrl(sortId, tagId, page) ) - return this._requestObj_songList.promise.then(({ body }) => { + return this._requestObj_list.promise.then(({ body }) => { if (body.status !== 1) return this.getSongList(sortId, tagId, page) - return this.filterSongList(body.data) + return this.filterList(body.data) }) }, getSongListRecommend() { - if (this._requestObj_songListRecommend) this._requestObj_songListRecommend.cancelHttp() - this._requestObj_songListRecommendRecommend = httpFatch( + if (this._requestObj_listRecommend) this._requestObj_listRecommend.cancelHttp() + this._requestObj_listRecommendRecommend = httpFatch( 'http://everydayrec.service.kugou.com/guess_special_recommend', { method: 'post', @@ -121,12 +121,12 @@ export default { }, } ) - return this._requestObj_songListRecommend.promise.then(({ body }) => { + return this._requestObj_listRecommend.promise.then(({ body }) => { if (body.status !== 1) return this.getSongListRecommend() - return this.filterSongList(body.data) + return this.filterList(body.data) }) }, - filterSongList(rawData) { + filterList(rawData) { return rawData.map(item => ({ play_count: item.total_play_count, id: item.specialid, @@ -140,9 +140,9 @@ export default { }, getListDetail(id, page) { // 获取歌曲列表内的音乐 - if (this._requestObj_songListDetail) this._requestObj_songListDetail.cancelHttp() - this._requestObj_songListDetail = httpFatch(this.getSongListDetailUrl(id)) - return this._requestObj_songListDetail.promise.then(({ body }) => { + if (this._requestObj_listDetail) this._requestObj_listDetail.cancelHttp() + this._requestObj_listDetail = httpFatch(this.getSongListDetailUrl(id)) + return this._requestObj_listDetail.promise.then(({ body }) => { let listData = body.match(this.regExps.listData) if (listData) listData = this.filterData(JSON.parse(RegExp.$1)) return { diff --git a/src/renderer/utils/music/kw/api-internal.js b/src/renderer/utils/music/kw/api-internal.js new file mode 100644 index 00000000..6b22eb59 --- /dev/null +++ b/src/renderer/utils/music/kw/api-internal.js @@ -0,0 +1,30 @@ +import { httpFatch } from '../../request' +import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' + +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, + headers, + }) + 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) { + const requestObj = httpFatch(`https://v1.itooi.cn/kuwo/pic?id=${songInfo.songmid}&isRedirect=0`, { + method: 'get', + timeout, + headers, + }) + requestObj.promise = requestObj.promise.then(({ body }) => { + return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail)) + }) + return requestObj + }, +} + +export default api_messoer diff --git a/src/renderer/utils/music/kw/api-messoer.js b/src/renderer/utils/music/kw/api-messoer.js index 599c14ab..6b22eb59 100644 --- a/src/renderer/utils/music/kw/api-messoer.js +++ b/src/renderer/utils/music/kw/api-messoer.js @@ -1,11 +1,13 @@ import { httpFatch } from '../../request' import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' 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, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail)) @@ -15,7 +17,8 @@ const api_messoer = { getPic(songInfo) { const requestObj = httpFatch(`https://v1.itooi.cn/kuwo/pic?id=${songInfo.songmid}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail)) diff --git a/src/renderer/utils/music/kw/api-temp.js b/src/renderer/utils/music/kw/api-temp.js index 0c8436f2..14ac6d9a 100644 --- a/src/renderer/utils/music/kw/api-temp.js +++ b/src/renderer/utils/music/kw/api-temp.js @@ -2,7 +2,7 @@ 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}`, { + const requestObj = httpFatch(`http://45.32.53.128:3002/m/kw/u/${songInfo.songmid}/${type}`, { method: 'get', }) requestObj.promise = requestObj.promise.then(({ body }) => { @@ -11,7 +11,7 @@ const api_temp = { return requestObj }, getPic(songInfo) { - const requestObj = httpFatch(`https://www.stsky.cn/api/temp/getPic.php?size=320&songmid=${songInfo.songmid}`, { + const requestObj = httpFatch(`http://45.32.53.128:3002/m/kw/i/${songInfo.songmid}`, { method: 'get', }) requestObj.promise = requestObj.promise.then(({ body }) => { diff --git a/src/renderer/utils/music/kw/leaderboard.js b/src/renderer/utils/music/kw/leaderboard.js index 2146eb66..95a97e09 100644 --- a/src/renderer/utils/music/kw/leaderboard.js +++ b/src/renderer/utils/music/kw/leaderboard.js @@ -1,5 +1,7 @@ import { httpGet, cancelHttp } from '../../request' -import { formatPlayTime } from '../../index' +import { formatPlayTime, decodeName } from '../../index' +import { formatSinger } from './util' + export default { list: [ @@ -143,9 +145,9 @@ export default { } // types.reverse() return { - singer: item.artist, - name: item.name, - albumName: item.album, + singer: formatSinger(decodeName(item.artist)), + name: decodeName(item.name), + albumName: decodeName(item.album), albumId: item.albumid, songmid: item.id, source: 'kw', diff --git a/src/renderer/utils/music/kw/songList.js b/src/renderer/utils/music/kw/songList.js new file mode 100644 index 00000000..2a0ea23a --- /dev/null +++ b/src/renderer/utils/music/kw/songList.js @@ -0,0 +1,173 @@ +import { httpFatch } from '../../request' +import { formatPlayTime, decodeName } from '../../index' +import { formatSinger } from './util' + +export default { + _requestObj_tags: null, + _requestObj_hotTags: null, + _requestObj_list: null, + _requestObj_listDetail: null, + limit_list: 100, + limit_song: 25, + successCode: 200, + sortList: [ + { + name: '最热', + id: 'hot', + }, + { + name: '最新', + id: 'new', + }, + ], + 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({ sortType, id, page }) { + return id + ? `http://wapi.kuwo.cn/api/pc/classify/playlist/getTagPlayList?loginUid=0&loginSid=0&appUid=76039576&id=${id}&pn=${page}&rn=${this.limit}` + : `http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmPlayList?loginUid=0&loginSid=0&appUid=76039576&pn=${page}&rn=${this.limit}&order=${sortType}` + }, + getListDetailUrl(id, page) { + return `http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}&rn=${this.limit}&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1` + }, + + + // 获取标签 + getTags() { + if (this._requestObj_tags) this._requestObj_tags.cancelHttp() + this._requestObj_tags = httpFatch(this.tagsUrl) + return this._requestObj_tags.promise.then(({ body }) => { + if (body.code !== this.successCode) return this.getTags() + return this.filterTagInfo(body.data.tags) + }) + }, + // 获取标签 + getHotTags() { + if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp() + this._requestObj_hotTags = httpFatch(this.hotTagUrl) + return this._requestObj_hotTags.promise.then(({ body }) => { + if (body.code !== this.successCode) return this.getHotTags() + return this.filterInfoHotTag(body.data.data) + }) + }, + filterInfoHotTag(rawList) { + return rawList.map(item => ({ + id: item.id, + name: item.name, + })) + }, + filterTagInfo(rawList) { + return rawList.map(type => ({ + type: type.name, + list: type.data.map(item => ({ + parent_id: type.id, + parent_name: type.name, + id: item.id, + name: item.name, + })), + })) + }, + + // 获取列表数据 + getList(sortId, tagId, page) { + if (this._requestObj_list) this._requestObj_list.cancelHttp() + this._requestObj_list = httpFatch( + this.getListUrl({ sortId, id: tagId, page }) + ) + return this._requestObj_list.promise.then(({ body }) => { + if (body.code !== this.successCode) return this.getList({ sortId, id: tagId, page }) + return { + list: this.filterList(body.data.data), + total: body.data.total, + page: body.data.pn, + limit: body.data.rn, + } + }) + }, + + + /** + * 格式化播放数量 + * @param {*} num + */ + formatPlayCount(num) { + if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿' + if (num > 10000) return parseInt(num / 1000) / 10 + '万' + return num + }, + filterList(rawData) { + return rawData.map(item => ({ + play_count: this.formatPlayCount(item.listencnt), + id: item.id, + author: item.uname, + name: item.name, + // time: item.publish_time, + img: item.img, + grade: item.favorcnt / 10, + desc: item.desc, + })) + }, + + // 获取歌曲列表内的音乐 + getListDetail(id, page) { + if (this._requestObj_listDetail) { + this._requestObj_listDetail.cancelHttp() + } + this._requestObj_listDetail = httpFatch(this.getListDetailUrl(id, page)) + return this._requestObj_listDetail.promise.then(({ body }) => { + if (body.result !== 'ok') return this.getListDetail(id, page) + return { + list: this.filterListDetail(body.data.musiclist), + page, + limit: body.rn, + total: body.total, + } + }) + }, + filterListDetail(rawData) { + // console.log(rawList) + return rawData.map((item, inedx) => { + let formats = item.formats.split('|') + let types = [] + let _types = {} + if (formats.indexOf('MP3128')) { + types.push({ type: '128k', size: null }) + _types['128k'] = { + size: null, + } + } + if (formats.indexOf('MP3H')) { + types.push({ type: '320k', size: null }) + _types['320k'] = { + size: null, + } + } + if (formats.indexOf('ALFLAC')) { + types.push({ type: 'flac', size: null }) + _types['flac'] = { + size: null, + } + } + + return { + singer: formatSinger(decodeName(item.artist)), + name: decodeName(item.name), + albumName: decodeName(item.album), + albumId: item.albumid, + songmid: item.id, + source: 'kw', + interval: formatPlayTime(parseInt(item.duration)), + img: null, + lrc: null, + types, + _types, + typeUrl: {}, + } + }) + }, + +} + +// getList +// getTags +// getListDetail diff --git a/src/renderer/utils/music/messoer.js b/src/renderer/utils/music/messoer.js new file mode 100644 index 00000000..936b2964 --- /dev/null +++ b/src/renderer/utils/music/messoer.js @@ -0,0 +1,9 @@ +export const bHh = '624868746c' + +export const headers = { + 'User-Agent': 'lx-music request', + [bHh]: [bHh], +} + + +export const timeout = 10000 diff --git a/src/renderer/utils/music/tx/api-internal.js b/src/renderer/utils/music/tx/api-internal.js new file mode 100644 index 00000000..06c7536f --- /dev/null +++ b/src/renderer/utils/music/tx/api-internal.js @@ -0,0 +1,24 @@ +import { httpFatch } from '../../request' +import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' + +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, + headers, + }) + 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) { + 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/api-messoer.js b/src/renderer/utils/music/tx/api-messoer.js index 49ac2f04..06c7536f 100644 --- a/src/renderer/utils/music/tx/api-messoer.js +++ b/src/renderer/utils/music/tx/api-messoer.js @@ -1,11 +1,13 @@ import { httpFatch } from '../../request' import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' 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, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail)) diff --git a/src/renderer/utils/music/wy/api-internal.js b/src/renderer/utils/music/wy/api-internal.js new file mode 100644 index 00000000..272cc26d --- /dev/null +++ b/src/renderer/utils/music/wy/api-internal.js @@ -0,0 +1,41 @@ +import { httpFatch } from '../../request' +import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' + +const api_messoer = { + getMusicUrl(songInfo, type) { + const requestObj = httpFatch(`https://v1.itooi.cn/netease/url?id=${songInfo.songmid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, { + method: 'get', + timeout, + headers, + }) + 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) { + const requestObj = httpFatch(`https://v1.itooi.cn/netease/pic?id=${songInfo.songmid}&isRedirect=0`, { + method: 'get', + timeout, + headers, + }) + 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/netease/lrc?id=${songInfo.songmid}&isRedirect=0`, { + method: 'get', + timeout, + headers, + }) + 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/wy/api-messoer.js b/src/renderer/utils/music/wy/api-messoer.js index 2d8db5f0..272cc26d 100644 --- a/src/renderer/utils/music/wy/api-messoer.js +++ b/src/renderer/utils/music/wy/api-messoer.js @@ -1,11 +1,13 @@ import { httpFatch } from '../../request' import { requestMsg } from '../../message' +import { headers, timeout } from '../messoer' const api_messoer = { getMusicUrl(songInfo, type) { const requestObj = httpFatch(`https://v1.itooi.cn/netease/url?id=${songInfo.songmid}&quality=${type.replace(/k$/, '')}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail)) @@ -15,7 +17,8 @@ const api_messoer = { getPic(songInfo) { const requestObj = httpFatch(`https://v1.itooi.cn/netease/pic?id=${songInfo.songmid}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body.code === 200 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail)) @@ -25,7 +28,8 @@ const api_messoer = { getLyric(songInfo) { const requestObj = httpFatch(`https://v1.itooi.cn/netease/lrc?id=${songInfo.songmid}&isRedirect=0`, { method: 'get', - timeout: 5000, + timeout, + headers, }) requestObj.promise = requestObj.promise.then(({ body }) => { return body ? Promise.resolve(body) : Promise.reject(new Error(requestMsg.fail)) diff --git a/src/renderer/utils/request.js b/src/renderer/utils/request.js index 85d1ef4e..ec34f11a 100644 --- a/src/renderer/utils/request.js +++ b/src/renderer/utils/request.js @@ -2,28 +2,11 @@ import request from 'request' // import progress from 'request-progress' import { debugRequest } from './env' import { requestMsg } from './message' +import { bHh } from './music/messoer' // 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: Object.assign({}, headers, options.headers || {}), - Origin: options.origin, - data: options.data, - timeout: options.timeout || 10000, - json: options.format === undefined || options.format === 'json', - }, (err, resp, body) => { - if (err) return callback(err, null) - - // console.log('---end---', url) - callback(null, resp, body) - }) + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36', } /** @@ -231,3 +214,26 @@ export const http_jsonp = (url, options, callback) => { callback(err, resp, body) }) } + +const fatchData = (url, method, options, callback) => { + // console.log(url, options) + console.log('---start---', url) + if (options.headers && options.headers[bHh]) { + let s = Buffer.from(bHh, 'hex').toString() + s = s.replace(s.substr(-1), '') + s = Buffer.from(s, 'base64').toString() + options.headers[s] = !!s + delete options.headers[bHh] + } + return request(url, { + method, + headers: Object.assign({}, headers, options.headers || {}), + Origin: options.origin, + data: options.data, + timeout: options.timeout || 10000, + json: options.format === undefined || options.format === 'json', + }, (err, resp, body) => { + if (err) return callback(err, null) + callback(null, resp, body) + }) +} diff --git a/src/renderer/views/Setting.vue b/src/renderer/views/Setting.vue index e8496fbd..ff078eef 100644 --- a/src/renderer/views/Setting.vue +++ b/src/renderer/views/Setting.vue @@ -74,7 +74,7 @@ div.scroll(:class="$style.setting") p.small 当前版本:{{version.version}} p.small(v-if="version.newVersion") span(v-if="isLatestVer") 软件已是最新,尽情地体验吧~🥂 - material-btn(v-else-if="setting.ignoreVersion || version.isError" :class="[$style.btn, $style.gapLeft]" min @click="showUpdateModal") 打开更新窗口 + material-btn(v-else-if="setting.ignoreVersion || version.isError" :class="[$style.btn, $style.gapLeft]" min @click="showUpdateModal") 打开更新窗口 🚀 span(v-else) 发现新版本并在努力下载中,请稍等...⏳ p.small(v-else) 检查更新中... dt 关于洛雪音乐 @@ -164,14 +164,19 @@ export default { apiSources: [ { id: 'messoer', - label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)', - disabled: false, + // label: '由 messoer 提供的接口(推荐,软件的所有功能都可用)', + label: '由 messoer 提供的接口(该接口已关闭)', + disabled: true, }, + // { + // id: 'internal', + // label: '内置接口(只能试听或下载128k音质,该接口支持软件的所有功能)', + // disabled: false, + // }, { id: 'temp', - // label: '临时接口(软件的某些功能将不可用,建议在messoer不可用时再切换到本选项)', - label: '临时接口(因服务器被攻击,本接口已关闭)', - disabled: true, + label: '临时接口(软件的某些功能将不可用,但可下载无损等音质)', + disabled: false, }, ], musicNames: [ diff --git a/src/renderer/views/Recommend.vue b/src/renderer/views/SongList.vue similarity index 90% rename from src/renderer/views/Recommend.vue rename to src/renderer/views/SongList.vue index 16b5e2bd..6c2e9d97 100644 --- a/src/renderer/views/Recommend.vue +++ b/src/renderer/views/SongList.vue @@ -5,7 +5,7 @@