新增启动参数-play
This commit is contained in:
@@ -396,3 +396,14 @@ export const getPlayList = () => rendererInvoke(NAMES.mainWindow.get_playlist).c
|
||||
return rendererInvoke(NAMES.mainWindow.get_playlist, true)
|
||||
})
|
||||
|
||||
// 解析URL参数为对象
|
||||
export const parseUrlParams = str => {
|
||||
const params = {}
|
||||
if (typeof str !== 'string') return params
|
||||
const paramsArr = str.split('&')
|
||||
for (const param of paramsArr) {
|
||||
let [key, value] = param.split('=')
|
||||
params[key] = value
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
@@ -50,10 +50,12 @@ const sources = {
|
||||
export default {
|
||||
...sources,
|
||||
init() {
|
||||
const tasks = []
|
||||
for (let source of sources.sources) {
|
||||
let sm = sources[source.id]
|
||||
sm && sm.init && sm.init()
|
||||
sm && sm.init && tasks.push(sm.init())
|
||||
}
|
||||
return Promise.all(tasks)
|
||||
},
|
||||
supportQuality,
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ const kw = {
|
||||
},
|
||||
|
||||
init() {
|
||||
getToken()
|
||||
return getToken()
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
const api_test = {
|
||||
getMusicUrl(songInfo, type) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusic.tk/url/xm/${songInfo.songmid}/${type}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
family: 4,
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
return body.code === 0 ? Promise.resolve({ type, url: body.data }) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}
|
||||
|
||||
export default api_test
|
||||
@@ -1,47 +0,0 @@
|
||||
import { xmRequest } from './util'
|
||||
import { dateFormat2 } from '../../'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
_requestObj2: null,
|
||||
async getComment({ songmid }, page = 1, limit = 20) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
|
||||
const _requestObj = xmRequest('/api/comment/getCommentList', { objectId: songmid, objectType: 'song', pagingVO: { page, pageSize: limit } })
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.code !== 'SUCCESS') throw new Error('获取评论失败')
|
||||
return { source: 'xm', comments: this.filterComment(body.result.data.commentList), total: body.result.data.pagingVO.count, page, limit, maxPage: Math.ceil(body.result.data.pagingVO.count / limit) || 1 }
|
||||
},
|
||||
async getHotComment({ songmid }, page = 1, limit = 100) {
|
||||
if (this._requestObj2) this._requestObj2.cancelHttp()
|
||||
if (!songmid) throw new Error('获取失败')
|
||||
const _requestObj2 = xmRequest('/api/comment/getHotCommentList', { objectId: songmid, objectType: 'song', pagingVO: { page, pageSize: limit } })
|
||||
const { body, statusCode } = await _requestObj2.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.code !== 'SUCCESS') throw new Error('获取热门评论失败')
|
||||
return { source: 'xm', comments: this.filterComment(body.result.data.hotList) }
|
||||
},
|
||||
filterComment(rawList) {
|
||||
return rawList.map(item => ({
|
||||
id: item.commentId,
|
||||
text: item.message.split('\n').filter(t => !!t),
|
||||
time: item.gmtCreate,
|
||||
timeStr: dateFormat2(item.gmtCreate),
|
||||
userName: item.nickName,
|
||||
avatar: item.avatar,
|
||||
userId: item.userId,
|
||||
likedCount: item.likes,
|
||||
reply: item.replyData ? item.replyData.map(c => ({
|
||||
id: c.commentId,
|
||||
text: c.message.split('\n').filter(t => !!t),
|
||||
time: c.gmtCreate,
|
||||
timeStr: dateFormat2(c.gmtCreate),
|
||||
userName: c.nickName,
|
||||
avatar: c.avatar,
|
||||
userId: c.userId,
|
||||
likedCount: c.likes,
|
||||
})) : [],
|
||||
}))
|
||||
},
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// import { xmRequest } from './util'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
async getList(retryNum = 0) {
|
||||
// if (this._requestObj) this._requestObj.cancelHttp()
|
||||
// if (retryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
// const _requestObj = xmRequest('/api/search/getHotSearchWords')
|
||||
// const { body, statusCode } = await _requestObj.promise
|
||||
// // console.log(body)
|
||||
// if (statusCode != 200 || body.code !== 'SUCCESS') return this.getList(++retryNum)
|
||||
// // console.log(body, statusCode)
|
||||
// return { source: 'xm', list: this.filterList(body.result.data.hotWords) }
|
||||
return { source: 'xm', list: [] }
|
||||
},
|
||||
filterList(rawList) {
|
||||
return rawList.map(item => item.word)
|
||||
},
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
import { xmRequest } from './util'
|
||||
import { formatPlayTime, sizeFormate } from '../../index'
|
||||
// import jshtmlencode from 'js-htmlencode'
|
||||
|
||||
let boardList = [{ id: 'xm__102', name: '新歌榜', bangid: '102' }, { id: 'xm__103', name: '热歌榜', bangid: '103' }, { id: 'xm__104', name: '原创榜', bangid: '104' }, { id: 'xm__306', name: 'K歌榜', bangid: '306' }, { id: 'xm__332', name: '抖音热歌榜', bangid: '332' }, { id: 'xm__305', name: '歌单收录榜', bangid: '305' }, { id: 'xm__327', name: '趴间热歌榜', bangid: '327' }, { id: 'xm__324', name: '影视原声榜', bangid: '324' }, { id: 'xm__204', name: '美国Billboard单曲榜', bangid: '204' }, { id: 'xm__206', name: '韩国MNET音乐排行榜', bangid: '206' }, { id: 'xm__201', name: 'Hito 中文排行榜', bangid: '201' }, { id: 'xm__203', name: '英国UK单曲榜', bangid: '203' }, { id: 'xm__205', name: 'oricon公信单曲榜', bangid: '205' }, { id: 'xm__328', name: '美国iTunes榜', bangid: '328' }, { id: 'xm__329', name: 'Beatport电音榜', bangid: '329' }, { id: 'xm__330', name: '香港商业电台榜', bangid: '330' }]
|
||||
|
||||
export default {
|
||||
limit: 200,
|
||||
list: [
|
||||
{
|
||||
id: 'xmrgb',
|
||||
name: '热歌榜',
|
||||
bangid: '103',
|
||||
},
|
||||
{
|
||||
id: 'xmxgb',
|
||||
name: '新歌榜',
|
||||
bangid: '102',
|
||||
},
|
||||
{
|
||||
id: 'xmrcb',
|
||||
name: '原创榜',
|
||||
bangid: '104',
|
||||
},
|
||||
{
|
||||
id: 'xmdyb',
|
||||
name: '抖音榜',
|
||||
bangid: '332',
|
||||
},
|
||||
{
|
||||
id: 'xmkgb',
|
||||
name: 'K歌榜',
|
||||
bangid: '306',
|
||||
},
|
||||
{
|
||||
id: 'xmfxb',
|
||||
name: '分享榜',
|
||||
bangid: '307',
|
||||
},
|
||||
{
|
||||
id: 'xmrdtlb',
|
||||
name: '讨论榜',
|
||||
bangid: '331',
|
||||
},
|
||||
{
|
||||
id: 'xmgdslb',
|
||||
name: '歌单榜',
|
||||
bangid: '305',
|
||||
},
|
||||
{
|
||||
id: 'xmpjrgb',
|
||||
name: '趴间榜',
|
||||
bangid: '327',
|
||||
},
|
||||
{
|
||||
id: 'xmysysb',
|
||||
name: '影视榜',
|
||||
bangid: '324',
|
||||
},
|
||||
],
|
||||
requestBoardsObj: null,
|
||||
requestObj: null,
|
||||
getBoardsData() {
|
||||
if (this.requestBoardsObj) this.requestBoardsObj.cancelHttp()
|
||||
this.requestBoardsObj = xmRequest('/api/billboard/getBillboards')
|
||||
return this.requestBoardsObj.promise
|
||||
},
|
||||
getData(id) {
|
||||
if (this.requestObj) this.requestObj.cancelHttp()
|
||||
this.requestObj = xmRequest('/api/billboard/getBillboardDetail', { billboardId: id })
|
||||
return this.requestObj.promise
|
||||
},
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
singers.forEach(singer => {
|
||||
arr.push(singer.artistName)
|
||||
})
|
||||
return arr.join('、')
|
||||
},
|
||||
filterData(rawList) {
|
||||
// console.log(rawList)
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
rawList.forEach(songData => {
|
||||
if (!songData) return
|
||||
if (ids.has(songData.songId)) return
|
||||
ids.add(songData.songId)
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
let size = null
|
||||
for (const item of songData.purviewRoleVOs) {
|
||||
if (!item.filesize) continue
|
||||
size = sizeFormate(item.filesize)
|
||||
switch (item.quality) {
|
||||
case 's':
|
||||
types.push({ type: 'wav', size })
|
||||
_types.wav = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'h':
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'l':
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
types.reverse()
|
||||
|
||||
list.push({
|
||||
singer: this.getSinger(songData.singerVOs),
|
||||
name: songData.songName,
|
||||
albumName: songData.albumName,
|
||||
albumId: songData.albumId,
|
||||
source: 'xm',
|
||||
interval: formatPlayTime(parseInt(songData.length / 1000)),
|
||||
songmid: songData.songId,
|
||||
img: songData.albumLogo || songData.albumLogoS,
|
||||
songStringId: songData.songStringId,
|
||||
lrc: null,
|
||||
lrcUrl: songData.lyricInfo && songData.lyricInfo.lyricFile,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
})
|
||||
})
|
||||
|
||||
return list
|
||||
},
|
||||
filterBoardsData(rawList) {
|
||||
// console.log(rawList)
|
||||
let list = []
|
||||
if (rawList.xiamiBillboards) {
|
||||
for (const board of rawList.xiamiBillboards) {
|
||||
if (board.itemType != 1) continue
|
||||
list.push({
|
||||
id: 'xm__' + board.billboardId,
|
||||
name: board.name,
|
||||
bangid: String(board.billboardId),
|
||||
})
|
||||
}
|
||||
}
|
||||
if (rawList.spBillboards) {
|
||||
for (const board of rawList.spBillboards) {
|
||||
if (board.itemType != 1) continue
|
||||
list.push({
|
||||
id: 'xm__' + board.billboardId,
|
||||
name: board.name,
|
||||
bangid: String(board.billboardId),
|
||||
})
|
||||
}
|
||||
}
|
||||
if (rawList.globalBillboards) {
|
||||
for (const board of rawList.globalBillboards) {
|
||||
if (board.itemType != 1) continue
|
||||
list.push({
|
||||
id: 'xm__' + board.billboardId,
|
||||
name: board.name,
|
||||
bangid: String(board.billboardId),
|
||||
})
|
||||
}
|
||||
}
|
||||
return list
|
||||
},
|
||||
async getBoards(retryNum = 0) {
|
||||
// if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
// let response
|
||||
// try {
|
||||
// response = await this.getBoardsData()
|
||||
// } catch (error) {
|
||||
// return this.getBoards(retryNum)
|
||||
// }
|
||||
// if (response.statusCode !== 200 || response.body.code !== 'SUCCESS') return this.getBoards(retryNum)
|
||||
// const list = this.filterBoardsData(response.body.result.data)
|
||||
// this.list = list
|
||||
// return {
|
||||
// list,
|
||||
// source: 'xm',
|
||||
// }
|
||||
this.list = boardList
|
||||
return {
|
||||
list: boardList,
|
||||
source: 'xm',
|
||||
}
|
||||
},
|
||||
getList(bangid, page, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
return this.getData(bangid).then(({ statusCode, body }) => {
|
||||
if (statusCode !== 200 || body.code !== 'SUCCESS') return this.getList(bangid, page, retryNum)
|
||||
// console.log(body)
|
||||
const list = this.filterData(body.result.data.billboard.songs)
|
||||
|
||||
return {
|
||||
total: parseInt(body.result.data.billboard.attributeMap.item_size),
|
||||
list,
|
||||
limit: this.limit,
|
||||
page,
|
||||
source: 'xm',
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
import { httpGet, httpFetch } from '../../request'
|
||||
import { xmRequest } from './util'
|
||||
|
||||
const parseLyric = str => {
|
||||
str = str.replace(/(?:<\d+>|\r)/g, '')
|
||||
let tlyric = []
|
||||
let lyric = str.replace(/\[[\d:.]+\].*?\n\[x-trans\].*/g, s => {
|
||||
// console.log(s)
|
||||
let [lrc, tlrc] = s.split('\n')
|
||||
tlrc = tlrc.replace('[x-trans]', lrc.replace(/^(\[[\d:.]+\]).*$/, '$1'))
|
||||
tlyric.push(tlrc)
|
||||
return lrc
|
||||
})
|
||||
tlyric = tlyric.join('\n')
|
||||
return {
|
||||
lyric,
|
||||
tlyric,
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
failTime: 0,
|
||||
expireTime: 60 * 1000 * 1000,
|
||||
getLyricFile_1(url, retryNum = 0) {
|
||||
if (retryNum > 5) return Promise.reject('歌词获取失败')
|
||||
let requestObj = httpFetch(url)
|
||||
requestObj.promise = requestObj.promise.then(({ body, statusCode }) => {
|
||||
if (statusCode !== 200) {
|
||||
let tryRequestObj = this.getLyric(url, ++retryNum)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
return url.endsWith('.xtrc') ? parseLyric(body) : {
|
||||
lyric: body,
|
||||
tlyric: '',
|
||||
}
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyricFile_2(url, retryNum = 0) {
|
||||
if (retryNum > 5) return Promise.reject('歌词获取失败')
|
||||
return new Promise((resolve, reject) => {
|
||||
httpGet(url, {
|
||||
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',
|
||||
referer: 'https://www.xiami.com',
|
||||
},
|
||||
}, function(err, resp, body) {
|
||||
if (err || resp.statusCode !== 200) return this.getLyricFile(url, ++retryNum).then(resolve).catch(reject)
|
||||
return resolve(url.endsWith('.xtrc') ? parseLyric(body) : {
|
||||
lyric: body,
|
||||
tlyric: '',
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
getLyricUrl_1(songInfo, retryNum = 0) {
|
||||
if (retryNum > 2) return Promise.reject('歌词获取失败')
|
||||
let requestObj = xmRequest('/api/lyric/getSongLyrics', { songId: songInfo.songmid })
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode !== 200) {
|
||||
let tryRequestObj = this.getLyricUrl_1(songInfo, ++retryNum)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
if (body.code !== 'SUCCESS') {
|
||||
this.failTime = Date.now()
|
||||
let tryRequestObj = this.getLyricUrl_2(songInfo)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
if (!body.result.data.lyrics.length) return Promise.reject(new Error('未找到歌词'))
|
||||
let lrc = body.result.data.lyrics.find(lyric => /\.(trc|lrc)$/.test(lyric.lyricUrl))
|
||||
return lrc
|
||||
? lrc.lyricUrl.endsWith('.trc')
|
||||
? parseLyric(lrc.content)
|
||||
: { lyric: lrc.content, tlyric: '' }
|
||||
: Promise.reject(new Error('未找到歌词'))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyricUrl_2(songInfo, retryNum = 0) {
|
||||
if (retryNum > 2) return Promise.reject('歌词获取失败')
|
||||
// https://github.com/listen1/listen1_chrome_extension/blob/2587e627d23a85e490628acc0b3c9b534bc8323d/js/provider/xiami.js#L149
|
||||
let requestObj = httpFetch(`https://emumo.xiami.com/song/playlist/id/${songInfo.songmid}/object_name/default/object_id/0/cat/json`, {
|
||||
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',
|
||||
referer: 'https://www.xiami.com',
|
||||
},
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode !== 200 || !body.status) {
|
||||
let tryRequestObj = this.getLyricUrl_2(songInfo, ++retryNum)
|
||||
requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj)
|
||||
return tryRequestObj.promise
|
||||
}
|
||||
let url = body.data.trackList[0].lyric_url
|
||||
if (!url) return Promise.reject(new Error('未找到歌词'))
|
||||
return this.getLyricFile_2(/^http:/.test(url) ? url : ('http:' + url))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
if (songInfo.lrcUrl && /\.(xtrc|lrc)$/.test(songInfo.lrcUrl)) return this.getLyricFile_1(songInfo.lrcUrl)
|
||||
return Date.now() - this.failTime > this.expireTime ? this.getLyricUrl_1(songInfo) : this.getLyricUrl_2(songInfo)
|
||||
},
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { xmRequest } from './util'
|
||||
|
||||
export default {
|
||||
_requestObj: null,
|
||||
async getMusicInfo({ songmid }, page = 1, limit = 20) {
|
||||
if (this._requestObj) this._requestObj.cancelHttp()
|
||||
|
||||
const _requestObj = xmRequest('/api/song/initialize', { songId: songmid })
|
||||
const { body, statusCode } = await _requestObj.promise
|
||||
// console.log(body)
|
||||
if (statusCode != 200 || body.code !== 'SUCCESS') throw new Error('获取歌曲信息失败')
|
||||
return { source: 'xm', data: body.result.data.songDetail }
|
||||
},
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
// import '../../polyfill/array.find'
|
||||
// import jshtmlencode from 'js-htmlencode'
|
||||
import { xmRequest } from './util'
|
||||
import { formatPlayTime, sizeFormate } from '../../index'
|
||||
// import { debug } from '../../utils/env'
|
||||
// import { formatSinger } from './util'
|
||||
// "cdcb72dc3eba41cb5bc4267f09183119_xmMain_/api/list/collect_{"pagingVO":{"page":1,"pageSize":60},"dataType":"system"}"
|
||||
let searchRequest
|
||||
export default {
|
||||
limit: 30,
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
if (searchRequest && searchRequest.cancelHttp) searchRequest.cancelHttp()
|
||||
searchRequest = xmRequest('/api/search/searchSongs', {
|
||||
key: str,
|
||||
pagingVO: {
|
||||
page: page,
|
||||
pageSize: limit,
|
||||
},
|
||||
})
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
singers.forEach(singer => {
|
||||
arr.push(singer.artistName)
|
||||
})
|
||||
return arr.join('、')
|
||||
},
|
||||
handleResult(rawData) {
|
||||
// console.log(rawData)
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
rawData.forEach(songData => {
|
||||
if (!songData) return
|
||||
if (ids.has(songData.songId)) return
|
||||
ids.add(songData.songId)
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
let size = null
|
||||
for (const item of songData.purviewRoleVOs) {
|
||||
if (!item.filesize) continue
|
||||
size = sizeFormate(item.filesize)
|
||||
switch (item.quality) {
|
||||
case 's':
|
||||
types.push({ type: 'wav', size })
|
||||
_types.wav = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'h':
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'l':
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
types.reverse()
|
||||
|
||||
list.push({
|
||||
singer: this.getSinger(songData.singerVOs),
|
||||
name: songData.songName,
|
||||
albumName: songData.albumName,
|
||||
albumId: songData.albumId,
|
||||
source: 'xm',
|
||||
interval: formatPlayTime(parseInt(songData.length / 1000)),
|
||||
songmid: songData.songId,
|
||||
img: songData.albumLogo || songData.albumLogoS,
|
||||
songStringId: songData.songStringId,
|
||||
lrc: null,
|
||||
lrcUrl: songData.lyricInfo && songData.lyricInfo.lyricFile,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
})
|
||||
})
|
||||
return list
|
||||
},
|
||||
search(str, page = 1, { limit } = {}, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
if (limit == null) limit = this.limit
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page, limit).then(result => {
|
||||
if (!result) return this.search(str, page, { limit }, retryNum)
|
||||
if (result.code !== 'SUCCESS') return this.search(str, page, { limit }, retryNum)
|
||||
// const songResultData = result.data || { songs: [], total: 0 }
|
||||
|
||||
let list = this.handleResult(result.result.data.songs)
|
||||
if (list == null) return this.search(str, page, { limit }, retryNum)
|
||||
|
||||
this.total = parseInt(result.result.data.pagingVO.count)
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / limit)
|
||||
|
||||
return Promise.resolve({
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'xm',
|
||||
})
|
||||
}).catch(err => err.message.includes('canceled verify') ? Promise.reject(err) : this.search(str, page, { limit }, retryNum))
|
||||
},
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
import { xmRequest } from './util'
|
||||
import { sizeFormate, formatPlayTime } from '../../index'
|
||||
|
||||
export default {
|
||||
_requestObj_tags: null,
|
||||
_requestObj_list: null,
|
||||
_requestObj_listDetail: null,
|
||||
limit_list: 36,
|
||||
limit_song: 100000,
|
||||
successCode: 'SUCCESS',
|
||||
sortList: [
|
||||
{
|
||||
name: '推荐',
|
||||
id: 'system',
|
||||
},
|
||||
{
|
||||
name: '精选',
|
||||
id: 'recommend',
|
||||
},
|
||||
{
|
||||
name: '最热',
|
||||
id: 'hot',
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
id: 'new',
|
||||
},
|
||||
],
|
||||
regExps: {
|
||||
// https://www.xiami.com/collect/1138092824?action=play
|
||||
listDetailLink: /^.+\/collect\/(\d+)(?:\s\(.*|\?.*|&.*$|#.*$|$)/,
|
||||
},
|
||||
tagsUrl: '/api/collect/getRecommendTags',
|
||||
songListUrl: '/api/list/collect',
|
||||
songListDetailUrl: '/api/collect/initialize',
|
||||
getSongListData(sortId, tagId, page) {
|
||||
if (tagId == null) {
|
||||
return { pagingVO: { page, pageSize: this.limit_list }, dataType: sortId }
|
||||
}
|
||||
switch (sortId) {
|
||||
case 'system':
|
||||
case 'recommend':
|
||||
sortId = 'hot'
|
||||
}
|
||||
return { pagingVO: { page, pageSize: this.limit_list }, dataType: sortId, key: tagId }
|
||||
},
|
||||
|
||||
/**
|
||||
* 格式化播放数量
|
||||
* @param {*} num
|
||||
*/
|
||||
formatPlayCount(num) {
|
||||
if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿'
|
||||
if (num > 10000) return parseInt(num / 1000) / 10 + '万'
|
||||
return num
|
||||
},
|
||||
getSinger(singers) {
|
||||
let arr = []
|
||||
singers.forEach(singer => {
|
||||
arr.push(singer.artistName)
|
||||
})
|
||||
return arr.join('、')
|
||||
},
|
||||
|
||||
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 = xmRequest('/api/collect/getCollectStaticUrl', { listId: id })
|
||||
return this._requestObj_listDetail.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getListDetail(id, page, ++tryNum)
|
||||
this._requestObj_listDetail = xmRequest(body.result.data.data.data.url)
|
||||
return this._requestObj_listDetail.promise.then(({ body }) => {
|
||||
if (!body.status) return this.getListDetail(id, page, ++tryNum)
|
||||
// console.log(JSON.stringify(body))
|
||||
return {
|
||||
list: this.filterListDetail(body.resultObj.songs),
|
||||
page,
|
||||
limit: this.limit_song,
|
||||
total: body.resultObj.songCount,
|
||||
source: 'xm',
|
||||
info: {
|
||||
name: body.resultObj.collectName,
|
||||
img: body.resultObj.collectLogo,
|
||||
desc: body.resultObj.description,
|
||||
author: body.resultObj.userName,
|
||||
play_count: this.formatPlayCount(body.resultObj.playCount),
|
||||
},
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
filterListDetail(rawList) {
|
||||
// console.log(rawList)
|
||||
let ids = new Set()
|
||||
const list = []
|
||||
rawList.forEach(songData => {
|
||||
if (!songData) return
|
||||
if (ids.has(songData.songId)) return
|
||||
ids.add(songData.songId)
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
let size = null
|
||||
for (const item of songData.purviewRoleVOs) {
|
||||
if (!item.filesize) continue
|
||||
size = sizeFormate(item.filesize)
|
||||
switch (item.quality) {
|
||||
case 's':
|
||||
types.push({ type: 'wav', size })
|
||||
_types.wav = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'h':
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'l':
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
types.reverse()
|
||||
|
||||
list.push({
|
||||
singer: this.getSinger(songData.singerVOs),
|
||||
name: songData.songName,
|
||||
albumName: songData.albumName,
|
||||
albumId: songData.albumId,
|
||||
source: 'xm',
|
||||
interval: formatPlayTime(parseInt(songData.length / 1000)),
|
||||
songmid: songData.songId,
|
||||
songStringId: songData.songStringId,
|
||||
img: songData.albumLogo || songData.albumLogoS,
|
||||
lrc: null,
|
||||
lrcUrl: songData.lyricInfo && songData.lyricInfo.lyricFile,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
})
|
||||
})
|
||||
return list
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page, tryNum = 0) {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_list = xmRequest(this.songListUrl, this.getSongListData(sortId, tagId, page))
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
|
||||
return {
|
||||
list: this.filterList(body.result.data.collects),
|
||||
total: body.result.data.pagingVO.count,
|
||||
page,
|
||||
limit: body.result.data.pagingVO.pageSize,
|
||||
source: 'xm',
|
||||
}
|
||||
})
|
||||
},
|
||||
filterList(rawData) {
|
||||
return rawData.map(item => ({
|
||||
play_count: this.formatPlayCount(item.playCount),
|
||||
id: item.listId,
|
||||
author: item.userName,
|
||||
name: item.collectName,
|
||||
time: null,
|
||||
img: item.collectLogo,
|
||||
grade: null,
|
||||
desc: null,
|
||||
source: 'xm',
|
||||
}))
|
||||
},
|
||||
|
||||
// 获取标签
|
||||
getTag(tryNum = 0) {
|
||||
if (this._requestObj_tags) this._requestObj_tags.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_tags = xmRequest(this.tagsUrl, { recommend: 1 })
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getTag(++tryNum)
|
||||
return this.filterTagInfo(body.result.data.recommendTags)
|
||||
})
|
||||
},
|
||||
filterTagInfo(rawList) {
|
||||
return {
|
||||
hotTag: rawList[0].items.map(item => ({
|
||||
id: item.name,
|
||||
name: item.name,
|
||||
source: 'xm',
|
||||
})),
|
||||
tags: rawList.slice(1).map(item => ({
|
||||
name: item.title,
|
||||
list: item.items.map(tag => ({
|
||||
parent_id: item.title,
|
||||
parent_name: item.title,
|
||||
id: tag.name,
|
||||
name: tag.name,
|
||||
source: 'xm',
|
||||
})),
|
||||
})),
|
||||
source: 'xm',
|
||||
}
|
||||
},
|
||||
getTags() {
|
||||
return this.getTag()
|
||||
},
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
@@ -1,122 +0,0 @@
|
||||
import { httpGet, httpFetch } from '../../request'
|
||||
import { toMD5 } from '../../index'
|
||||
// import crateIsg from './isg'
|
||||
import { rendererInvoke, NAMES } from '../../../../common/ipc'
|
||||
|
||||
if (!window.xm_token) {
|
||||
let data = window.localStorage.getItem('xm_token')
|
||||
window.xm_token = data ? JSON.parse(data) : {
|
||||
cookies: {},
|
||||
cookie: null,
|
||||
token: null,
|
||||
isGetingToken: false,
|
||||
}
|
||||
window.xm_token.isGetingToken = false
|
||||
}
|
||||
|
||||
export const formatSinger = rawData => rawData.replace(/&/g, '、')
|
||||
|
||||
const matchToken = headers => {
|
||||
let cookies = {}
|
||||
let token
|
||||
for (const item of headers['set-cookie']) {
|
||||
const [key, value] = item.substring(0, item.indexOf(';')).split('=')
|
||||
cookies[key] = value
|
||||
if (key == 'xm_sg_tk') token = value.substring(0, value.indexOf('_'))
|
||||
}
|
||||
// console.log(cookies)
|
||||
return { token, cookies }
|
||||
}
|
||||
|
||||
const wait = time => new Promise(resolve => setTimeout(() => resolve(), time))
|
||||
|
||||
const createToken = (token, path, params) => toMD5(`${token}_xmMain_${path}_${params}`)
|
||||
|
||||
const handleSaveToken = ({ token, cookies }) => {
|
||||
Object.assign(window.xm_token.cookies, cookies)
|
||||
// window.xm_token.cookies.isg = crateIsg()
|
||||
window.xm_token.cookie = Object.keys(window.xm_token.cookies).map(k => `${k}=${window.xm_token.cookies[k]};`).join(' ')
|
||||
if (token) window.xm_token.token = token
|
||||
|
||||
window.localStorage.setItem('xm_token', JSON.stringify(window.xm_token))
|
||||
}
|
||||
|
||||
export const getToken = (path, params) => new Promise((resolve, reject) => {
|
||||
if (window.xm_token.isGetingToken) return wait(1000).then(() => getToken(path, params).then(data => resolve(data)))
|
||||
if (window.xm_token.token) return resolve({ token: createToken(window.xm_token.token, path, params), cookie: window.xm_token.cookie })
|
||||
window.xm_token.isGetingToken = true
|
||||
httpGet('https://www.xiami.com/', (err, resp) => {
|
||||
window.xm_token.isGetingToken = false
|
||||
if (err) return reject(err)
|
||||
if (resp.statusCode != 200) return reject(new Error('获取失败'))
|
||||
|
||||
handleSaveToken(matchToken(resp.headers))
|
||||
|
||||
resolve({ token: createToken(window.xm_token.token, path, params), cookie: window.xm_token.cookie })
|
||||
})
|
||||
})
|
||||
|
||||
const baseUrl = 'https://www.xiami.com'
|
||||
export const xmRequest = (path, params = '') => {
|
||||
let query = params
|
||||
if (params != '') {
|
||||
params = JSON.stringify(params)
|
||||
query = '&_q=' + encodeURIComponent(params)
|
||||
}
|
||||
let requestObj = {
|
||||
isInited: false,
|
||||
isCancelled: false,
|
||||
cancelHttp() {
|
||||
if (!this.isInited) this.isCancelled = true
|
||||
this.requestObj && this.requestObj.cancelHttp()
|
||||
},
|
||||
}
|
||||
|
||||
requestObj.promise = getToken(path, params).then(data => {
|
||||
// console.log(data)
|
||||
if (requestObj.isCancelled) return Promise.reject('取消请求')
|
||||
let url = path
|
||||
if (!/^http/.test(path)) url = baseUrl + path
|
||||
let s = `_s=${data.token}${query}`
|
||||
url += (url.includes('?') ? '&' : '?') + s
|
||||
requestObj.requestObj = httpFetch(url, {
|
||||
headers: {
|
||||
Referer: 'https://www.xiami.com/',
|
||||
'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',
|
||||
cookie: data.cookie,
|
||||
},
|
||||
})
|
||||
return requestObj.requestObj.promise.then(resp => {
|
||||
// console.log(resp.body)
|
||||
if (resp.statusCode != 200) {
|
||||
// console.log(resp.headers)
|
||||
window.xm_token.token = null
|
||||
return Promise.reject(new Error('获取失败'))
|
||||
}
|
||||
if (resp.body.code !== 'SUCCESS' && resp.body.rgv587_flag == 'sm') {
|
||||
window.globalObj.xm.isShowVerify = true
|
||||
return wait(300).then(() => {
|
||||
return rendererInvoke(NAMES.mainWindow.handle_xm_verify_open, /^https:/.test(resp.body.url) ? resp.body.url : 'https:' + resp.body.url).then(x5sec => {
|
||||
handleSaveToken({ cookies: { x5sec } })
|
||||
// console.log(x5sec)
|
||||
window.globalObj.xm.isShowVerify = false
|
||||
return Promise.reject(new Error('获取成功'))
|
||||
}).catch(err => {
|
||||
window.globalObj.xm.isShowVerify = false
|
||||
return Promise.reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
if (resp.headers['set-cookie']) handleSaveToken(matchToken(resp.headers))
|
||||
|
||||
return Promise.resolve(resp)
|
||||
})
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
|
||||
export const closeVerifyModal = async() => {
|
||||
if (!window.globalObj.xm.isShowVerify) return
|
||||
await rendererInvoke(NAMES.mainWindow.handle_xm_verify_close)
|
||||
window.globalObj.xm.isShowVerify = false
|
||||
}
|
||||
Reference in New Issue
Block a user