新增启动参数-play
parent
b6107b7281
commit
fa0d9ad4c3
|
@ -83,6 +83,12 @@ npm run pack:linux
|
|||
- `-search` 启动软件时自动在搜索框搜索指定的内容,例如:`-search="突然的自我 - 伍佰"`
|
||||
- `-dha` 禁用硬件加速启动(Disable Hardware Acceleration),窗口显示有问题时可以尝试添加此参数启动(v1.6.0起新增)
|
||||
- `-dt` 以非透明模式启动(Disable Transparent),对于未开启AERO效果的win7系统可加此参数启动以确保界面正常显示,原来的`-nt`参数已重命名为`-dt`(v1.6.0起重命名)
|
||||
- `-play` 启动时播放指定列表的音乐,参数说明:
|
||||
- `type`:播放类型,目前固定为`songList`
|
||||
- `source`:播放源,可用值为`kw/kg/tx/wy/mg/myList`,其中`kw/kg/tx/wy/mg`对应各源的在线列表,`myList`为本地列表
|
||||
- `link`:要播放的在线列表歌单链接、或ID,source为`kw/kg/tx/wy/mg`之一(在线列表)时必传,举例:`./lx-music-desktop -play="type=songList&source=kw&link=歌单URL or ID",注意:如果传入URL时必须对URL进行编码后再传入
|
||||
- `name`:要播放的本地列表歌单名字,source为`myList`时必传,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表"
|
||||
- `index`:从列表的哪个位置开始播放,选传,若不传默认播放第一首歌曲,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表&index=2"
|
||||
|
||||
### 常见问题
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
### 新增
|
||||
|
||||
- 新增设置-其他-列表缓存信息清理功能,注:此功能一般情况下不要使用
|
||||
- 新增启动参数`-play`,可以在启动软件时播放指定歌单,使用方法看Readme.md的"启动参数"部分
|
||||
|
||||
### 优化
|
||||
|
||||
|
|
|
@ -51,6 +51,6 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
navigationUrlWhiteList: [
|
||||
/^https:\/\/www\.xiami\.com/,
|
||||
|
||||
],
|
||||
}
|
||||
|
|
|
@ -18,6 +18,4 @@ require('./showDialog')
|
|||
require('./playList')
|
||||
require('./data')
|
||||
|
||||
// require('./xm_verify')
|
||||
|
||||
require('./kw_decodeLyric')
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
const { isMac } = require('../../../common/utils')
|
||||
|
||||
// mac下的 BrowserView 无法拖动验证栏,改用 BrowserWindow
|
||||
require(isMac ? './xm_verify_win' : './xm_verify_view')
|
|
@ -1,4 +0,0 @@
|
|||
const { isMac } = require('../../../common/utils')
|
||||
|
||||
// mac下的 BrowserView 无法拖动验证栏,改用 BrowserWindow
|
||||
require(isMac ? './xm_verify_win' : './xm_verify_view')
|
|
@ -1,79 +0,0 @@
|
|||
const { BrowserView } = require('electron')
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../../common/ipc')
|
||||
const { getWindowSizeInfo } = require('../../utils')
|
||||
|
||||
let view
|
||||
let isActioned = false
|
||||
let rejectFn
|
||||
|
||||
const closeView = async() => {
|
||||
if (!view) return
|
||||
// await view.webContents.session.clearCache()
|
||||
if (global.modules.mainWindow) global.modules.mainWindow.removeBrowserView(view)
|
||||
await view.webContents.session.clearStorageData()
|
||||
view.destroy()
|
||||
view = null
|
||||
}
|
||||
|
||||
mainHandle(ipcMainWindowNames.handle_xm_verify_open, (event, url) => new Promise((resolve, reject) => {
|
||||
if (!global.modules.mainWindow) return reject(new Error('mainWindow is undefined'))
|
||||
if (view) {
|
||||
global.modules.mainWindow.removeBrowserView(view)
|
||||
view.destroy()
|
||||
}
|
||||
|
||||
rejectFn = reject
|
||||
|
||||
isActioned = false
|
||||
|
||||
view = new BrowserView({
|
||||
webPreferences: {
|
||||
enableRemoteModule: false,
|
||||
disableHtmlFullscreenWindowResize: true,
|
||||
},
|
||||
})
|
||||
// view.webContents.on('did-finish-load', () => {
|
||||
// if (/punish\?/.test(view.webContents.getURL())) return
|
||||
// let ses = view.webContents.session
|
||||
// ses.cookies.get({ name: 'x5sec' })
|
||||
// .then(async([x5sec]) => {
|
||||
// isActioned = true
|
||||
// await closeView()
|
||||
// if (!x5sec) return reject(new Error('get x5sec failed'))
|
||||
// resolve(x5sec.value)
|
||||
// }).catch(async err => {
|
||||
// isActioned = true
|
||||
// await closeView()
|
||||
// reject(err)
|
||||
// })
|
||||
// })
|
||||
view.webContents.session.webRequest.onCompleted({ urls: ['*://www.xiami.com/*'] }, details => {
|
||||
if (/\/_____tmd_____\/slide\?/.test(details.url)) {
|
||||
for (const item of details.responseHeaders['set-cookie']) {
|
||||
if (!/^x5sec=/.test(item)) continue
|
||||
const x5sec = /x5sec=(\w+);.+$/.exec(item)
|
||||
isActioned = true
|
||||
closeView().finally(() => {
|
||||
if (!x5sec) return reject(new Error('get x5sec failed'))
|
||||
resolve(x5sec[1])
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
// console.log(url)
|
||||
global.modules.mainWindow.setBrowserView(view)
|
||||
const windowSizeInfo = getWindowSizeInfo(global.appSetting)
|
||||
view.setBounds({ x: (windowSizeInfo.width - 380) / 2, y: ((windowSizeInfo.height - 320 + 52) / 2), width: 380, height: 320 })
|
||||
view.webContents.loadURL(url, {
|
||||
httpReferrer: 'https://www.xiami.com/',
|
||||
})
|
||||
// view.webContents.openDevTools()
|
||||
}))
|
||||
|
||||
mainHandle(ipcMainWindowNames.handle_xm_verify_close, async() => {
|
||||
await closeView()
|
||||
if (!rejectFn) return
|
||||
if (!isActioned) rejectFn(new Error('canceled verify'))
|
||||
rejectFn = null
|
||||
})
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
const { BrowserWindow } = require('electron')
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../../common/ipc')
|
||||
const { getWindowSizeInfo } = require('../../utils')
|
||||
|
||||
let win
|
||||
|
||||
const closeWin = async() => {
|
||||
if (!win) return
|
||||
// await win.webContents.session.clearCache()
|
||||
// if (global.modules.mainWindow) global.modules.mainWindow.removeBrowserView(win)
|
||||
if (win.isDestroyed()) {
|
||||
win = null
|
||||
return
|
||||
}
|
||||
await win.webContents.session.clearStorageData()
|
||||
win.destroy()
|
||||
win = null
|
||||
}
|
||||
|
||||
mainHandle(ipcMainWindowNames.handle_xm_verify_open, (event, url) => new Promise((resolve, reject) => {
|
||||
if (!global.modules.mainWindow) return reject(new Error('mainWindow is undefined'))
|
||||
if (win) win.destroy()
|
||||
|
||||
let isActioned = false
|
||||
|
||||
const mainWindowSizeInfo = global.modules.mainWindow.getBounds()
|
||||
const windowSizeInfo = getWindowSizeInfo(global.appSetting)
|
||||
win = new BrowserWindow({
|
||||
parent: global.modules.mainWindow,
|
||||
width: 1000,
|
||||
height: 800,
|
||||
resizable: false,
|
||||
// transparent: true,
|
||||
x: mainWindowSizeInfo.x + (windowSizeInfo.width - 1000) / 2,
|
||||
y: mainWindowSizeInfo.y + (windowSizeInfo.height - 800 + 52) / 2,
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
// movable: false,
|
||||
// frame: false,
|
||||
// modal: true,
|
||||
webPreferences: {
|
||||
enableRemoteModule: false,
|
||||
disableHtmlFullscreenWindowResize: true,
|
||||
},
|
||||
})
|
||||
// win.webContents.on('did-finish-load', () => {
|
||||
// if (/punish\?/.test(win.webContents.getURL())) return
|
||||
// let ses = win.webContents.session
|
||||
// ses.cookies.get({ name: 'x5sec' })
|
||||
// .then(async([x5sec]) => {
|
||||
// isActioned = true
|
||||
// await closeWin()
|
||||
// if (!x5sec) return reject(new Error('get x5sec failed'))
|
||||
// resolve(x5sec.value)
|
||||
// }).catch(async err => {
|
||||
// isActioned = true
|
||||
// await closeWin()
|
||||
// reject(err)
|
||||
// })
|
||||
// })
|
||||
|
||||
win.webContents.session.webRequest.onCompleted({ urls: ['*://www.xiami.com/*'] }, details => {
|
||||
if (/\/_____tmd_____\/slide\?/.test(details.url)) {
|
||||
for (const item of details.responseHeaders['set-cookie']) {
|
||||
if (!/^x5sec=/.test(item)) continue
|
||||
const x5sec = /x5sec=(\w+);.+$/.exec(item)
|
||||
isActioned = true
|
||||
closeWin().finally(() => {
|
||||
if (!x5sec) return reject(new Error('get x5sec failed'))
|
||||
resolve(x5sec[1])
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
win.webContents.loadURL(url, {
|
||||
httpReferrer: 'https://www.xiami.com/',
|
||||
})
|
||||
|
||||
win.on('closed', async() => {
|
||||
await closeWin()
|
||||
if (isActioned) return
|
||||
reject(new Error('canceled verify'))
|
||||
})
|
||||
|
||||
// win.webContents.openDevTools()
|
||||
}))
|
||||
|
||||
mainHandle(ipcMainWindowNames.handle_xm_verify_close, async() => {
|
||||
await closeWin()
|
||||
})
|
|
@ -6,7 +6,6 @@
|
|||
core-view#view
|
||||
core-player#player
|
||||
core-icons
|
||||
material-xm-verify-modal(v-show="globalObj.xm.isShowVerify" :show="globalObj.xm.isShowVerify" :bg-close="false" @close="handleXMVerifyModalClose")
|
||||
material-version-modal(v-show="version.showModal")
|
||||
material-pact-modal(v-show="!setting.isAgreePact || globalObj.isShowPact")
|
||||
#container(v-else :class="theme")
|
||||
|
@ -16,7 +15,6 @@
|
|||
core-view#view
|
||||
core-player#player
|
||||
core-icons
|
||||
material-xm-verify-modal(v-show="globalObj.xm.isShowVerify" :show="globalObj.xm.isShowVerify" :bg-close="false" @close="handleXMVerifyModalClose")
|
||||
material-version-modal(v-show="version.showModal")
|
||||
material-pact-modal(v-show="!setting.isAgreePact || globalObj.isShowPact")
|
||||
</template>
|
||||
|
@ -27,7 +25,7 @@ import { mapMutations, mapGetters, mapActions } from 'vuex'
|
|||
import { rendererOn, rendererSend, rendererInvoke, NAMES } from '../common/ipc'
|
||||
import { isLinux } from '../common/utils'
|
||||
import music from './utils/music'
|
||||
import { throttle, openUrl, compareVer, getPlayList } from './utils'
|
||||
import { throttle, openUrl, compareVer, getPlayList, parseUrlParams } from './utils'
|
||||
import { base as eventBaseName } from './event/names'
|
||||
|
||||
window.ELECTRON_DISABLE_SECURITY_WARNINGS = process.env.ELECTRON_DISABLE_SECURITY_WARNINGS
|
||||
|
@ -62,9 +60,6 @@ export default {
|
|||
proxy: {},
|
||||
isShowPact: false,
|
||||
qualityList: {},
|
||||
xm: {
|
||||
isShowVerify: false,
|
||||
},
|
||||
},
|
||||
updateTimeout: null,
|
||||
envParams: {
|
||||
|
@ -179,10 +174,12 @@ export default {
|
|||
...mapMutations('player', {
|
||||
setPlayList: 'setList',
|
||||
}),
|
||||
...mapActions('songList', ['getListDetailAll']),
|
||||
init() {
|
||||
document.documentElement.style.fontSize = this.windowSizeActive.fontSize
|
||||
|
||||
rendererInvoke(NAMES.mainWindow.get_env_params).then(this.handleEnvParamsInit)
|
||||
const asyncTask = []
|
||||
asyncTask.push(rendererInvoke(NAMES.mainWindow.get_env_params).then(this.handleEnvParamsInit))
|
||||
|
||||
document.body.addEventListener('click', this.handleBodyClick, true)
|
||||
rendererOn(NAMES.mainWindow.update_available, (e, info) => {
|
||||
|
@ -246,14 +243,18 @@ export default {
|
|||
}, 60 * 30 * 1000)
|
||||
|
||||
this.listenEvent()
|
||||
this.initData()
|
||||
asyncTask.push(this.initData())
|
||||
this.globalObj.apiSource = this.setting.apiSource
|
||||
this.globalObj.qualityList = music.supportQuality[this.setting.apiSource]
|
||||
this.globalObj.proxy = Object.assign({}, this.setting.network.proxy)
|
||||
window.globalObj = this.globalObj
|
||||
|
||||
// 初始化音乐sdk
|
||||
music.init()
|
||||
asyncTask.push(music.init())
|
||||
Promise.all(asyncTask).then(() => {
|
||||
this.handleInitEnvParamSearch()
|
||||
this.handleInitEnvParamPlay()
|
||||
})
|
||||
},
|
||||
enableIgnoreMouseEvents() {
|
||||
if (this.isDT) return
|
||||
|
@ -267,12 +268,14 @@ export default {
|
|||
},
|
||||
|
||||
initData() { // 初始化数据
|
||||
this.initLocalList() // 初始化播放列表
|
||||
return Promise.all([
|
||||
this.initMyList(), // 初始化播放列表
|
||||
this.initSearchHistoryList(), // 初始化搜索历史列表
|
||||
])
|
||||
// this.initDownloadList() // 初始化下载列表
|
||||
this.initSearchHistoryList() // 初始化搜索历史列表
|
||||
},
|
||||
initLocalList() {
|
||||
getPlayList().then(({ defaultList, loveList, userList, downloadList }) => {
|
||||
initMyList() {
|
||||
return getPlayList().then(({ defaultList, loveList, userList, downloadList }) => {
|
||||
if (!defaultList) defaultList = this.defaultList
|
||||
if (!loveList) loveList = this.loveList
|
||||
if (userList) {
|
||||
|
@ -391,18 +394,91 @@ export default {
|
|||
document.body.addEventListener('mouseenter', this.dieableIgnoreMouseEvents)
|
||||
document.body.addEventListener('mouseleave', this.enableIgnoreMouseEvents)
|
||||
}
|
||||
this.handleInitEnvParamSearch()
|
||||
this.handleInitEnvParamPlay()
|
||||
},
|
||||
// 处理启动参数 search
|
||||
handleInitEnvParamSearch() {
|
||||
if (this.envParams.search == null) return
|
||||
this.$router.push({
|
||||
path: 'search',
|
||||
query: {
|
||||
text: this.envParams.search,
|
||||
},
|
||||
})
|
||||
},
|
||||
// 处理启动参数 play
|
||||
handleInitEnvParamPlay() {
|
||||
if (this.envParams.play == null || typeof this.envParams.play != 'string') return
|
||||
// -play="source=kw&link=链接、ID"
|
||||
// -play="source=myList&name=名字"
|
||||
// -play="source=myList&name=名字&index=位置"
|
||||
const params = parseUrlParams(this.envParams.play)
|
||||
if (params.type != 'songList') return
|
||||
this.handlePlaySongList(params)
|
||||
},
|
||||
handlePlaySongList(params) {
|
||||
switch (params.source) {
|
||||
case 'myList':
|
||||
if (params.name != null) {
|
||||
let targetList
|
||||
const lists = Object.values(window.allList)
|
||||
for (const list of lists) {
|
||||
if (list.name === params.name) {
|
||||
targetList = list
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!targetList) return
|
||||
|
||||
if (this.envParams.search != null) {
|
||||
this.$router.push({
|
||||
path: 'search',
|
||||
query: {
|
||||
text: this.envParams.search,
|
||||
},
|
||||
})
|
||||
|
||||
this.setPlayList({
|
||||
list: {
|
||||
list: targetList.list,
|
||||
id: targetList.id,
|
||||
},
|
||||
index: this.getListPlayIndex(targetList.list, params.index),
|
||||
})
|
||||
}
|
||||
break
|
||||
case 'kw':
|
||||
case 'kg':
|
||||
case 'tx':
|
||||
case 'mg':
|
||||
case 'wy':
|
||||
this.playSongListDetail(params.source, params.link, params.index)
|
||||
break
|
||||
}
|
||||
},
|
||||
handleXMVerifyModalClose() {
|
||||
music.xm.closeVerifyModal()
|
||||
async playSongListDetail(source, link, playIndex) {
|
||||
if (link == null) return
|
||||
let list
|
||||
try {
|
||||
list = await this.getListDetailAll({ source, id: decodeURIComponent(link) })
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
this.setPlayList({
|
||||
list: {
|
||||
list,
|
||||
id: null,
|
||||
},
|
||||
index: this.getListPlayIndex(list, playIndex),
|
||||
})
|
||||
},
|
||||
getListPlayIndex(list, index) {
|
||||
if (index == null) {
|
||||
index = 1
|
||||
} else {
|
||||
index = parseInt(index)
|
||||
if (Number.isNaN(index)) {
|
||||
index = 1
|
||||
} else {
|
||||
if (index < 1) index = 1
|
||||
else if (index > list.length) index = list.length
|
||||
}
|
||||
}
|
||||
return index - 1
|
||||
},
|
||||
listenEvent() {
|
||||
window.eventHub.$on('key_escape_down', this.handle_key_esc_down)
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
<template lang="pug">
|
||||
material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
||||
main.ignore-to-rem(:class="$style.main")
|
||||
h2 {{$t('material.xm_verify_modal.title')}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
bgClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClose() {
|
||||
this.$emit('close')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
background: #fff !important;
|
||||
&:global(.ignore-to-rem) {
|
||||
padding: 15px;
|
||||
width: 360px;
|
||||
height: 330px;
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 13px;
|
||||
color: @color-theme_2-font;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue