修复网易云128k直接试听
parent
a104ce688e
commit
9dc9d3b1b7
|
@ -2,3 +2,4 @@
|
|||
|
||||
- 修复QQ源歌单无法翻页Bug
|
||||
- 修复默认列表没有创建时无法显示收藏列表的Bug
|
||||
- 修复网易云128k直接试听
|
||||
|
|
|
@ -5,7 +5,7 @@ material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
|
|||
| {{ info.name }}
|
||||
br
|
||||
| {{ info.singer }}
|
||||
material-btn(:class="$style.btn" :title="!checkSource(type.type) && '目前腾讯音源仅支持下载128k音质'" :disabled="!checkSource(type.type)" :key="type.type" @click="handleClick(type.type)" v-for="type in info.types") {{getTypeName(type.type)}} {{ type.type.toUpperCase() }}{{ type.size && ` - ${type.size.toUpperCase()}` }}
|
||||
material-btn(:class="$style.btn" :title="!checkSource(type.type) && '腾讯、网易音源仅支持下载128k音质'" :disabled="!checkSource(type.type)" :key="type.type" @click="handleClick(type.type)" v-for="type in info.types") {{getTypeName(type.type)}} {{ type.type.toUpperCase() }}{{ type.size && ` - ${type.size.toUpperCase()}` }}
|
||||
|
||||
</template>
|
||||
|
||||
|
@ -52,7 +52,6 @@ export default {
|
|||
checkSource(type) {
|
||||
switch (this.musicInfo.source) {
|
||||
case 'wy':
|
||||
return false
|
||||
case 'tx':
|
||||
return type == '128k'
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ div(:class="$style.songList")
|
|||
td(style="width: 20%; padding-left: 0; padding-right: 0;")
|
||||
material-list-buttons(:index="index" :search-btn="true"
|
||||
:remove-btn="false" @btn-click="handleListBtnClick"
|
||||
:listAdd-btn="item.source == 'kw' || (!isAPITemp && item.source != 'wy')"
|
||||
:play-btn="item.source == 'kw' || (!isAPITemp && item.source != 'wy')"
|
||||
:download-btn="item.source == 'kw' || (!isAPITemp && item.source != 'wy')")
|
||||
:listAdd-btn="item.source == 'kw' || (!isAPITemp)"
|
||||
:play-btn="item.source == 'kw' || (!isAPITemp)"
|
||||
:download-btn="item.source == 'kw' || (!isAPITemp)")
|
||||
//- button.btn-info(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k'] || item._types.flac" @click.stop='openDownloadModal(index)') 下载
|
||||
//- button.btn-secondary(type='button' v-if="item._types['128k'] || item._types['192k'] || item._types['320k']" @click.stop='testPlay(index)') 试听
|
||||
//- button.btn-success(type='button' v-if="(item._types['128k'] || item._types['192k'] || item._types['320k']) && userInfo" @click.stop='showListModal(index)') +
|
||||
|
@ -140,7 +140,7 @@ export default {
|
|||
this.clickIndex = index
|
||||
return
|
||||
}
|
||||
this.emitEvent((this.source == 'kw' || (!this.isAPITemp && this.list[index].source != 'wy')) ? 'testPlay' : 'search', index)
|
||||
this.emitEvent((this.source == 'kw' || !this.isAPITemp) ? 'testPlay' : 'search', index)
|
||||
this.clickTime = 0
|
||||
this.clickIndex = -1
|
||||
},
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import { httpFatch } from '../../request'
|
||||
import { requestMsg } from '../../message'
|
||||
import { headers, timeout } from '../options'
|
||||
|
||||
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
|
|
@ -15,8 +15,8 @@ const api_test = {
|
|||
})
|
||||
return requestObj
|
||||
},
|
||||
getPic(songInfo) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusic.tk/pic/wy/${songInfo.songmid}`, {
|
||||
/* getPic(songInfo) {
|
||||
const requestObj = httpFetch(`http://localhost:3100/pic/wy/${songInfo.songmid}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
|
@ -28,7 +28,7 @@ const api_test = {
|
|||
return requestObj
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
const requestObj = httpFetch(`http://ts.tempmusic.tk/lrc/wy/${songInfo.songmid}`, {
|
||||
const requestObj = httpFetch(`http://localhost:3100/lrc/wy/${songInfo.songmid}`, {
|
||||
method: 'get',
|
||||
timeout,
|
||||
headers,
|
||||
|
@ -38,7 +38,7 @@ const api_test = {
|
|||
return body.code === 0 ? Promise.resolve(body.data) : Promise.reject(new Error(requestMsg.fail))
|
||||
})
|
||||
return requestObj
|
||||
},
|
||||
}, */
|
||||
}
|
||||
|
||||
export default api_test
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import leaderboard from './leaderboard'
|
||||
import api_source from '../api-source'
|
||||
import getLyric from './lyric'
|
||||
import getMusicInfo from './musicInfo'
|
||||
|
||||
const wy = {
|
||||
leaderboard,
|
||||
|
@ -7,10 +9,10 @@ const wy = {
|
|||
return api_source('wy').getMusicUrl(songInfo, type)
|
||||
},
|
||||
getLyric(songInfo) {
|
||||
return api_source('wy').getLyric(songInfo)
|
||||
return getLyric(songInfo.songmid)
|
||||
},
|
||||
getPic(songInfo) {
|
||||
return api_source('wy').getPic(songInfo)
|
||||
return getMusicInfo(songInfo.songmid).then(info => info.al.picUrl)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { httpFetch } from '../../request'
|
||||
import { linuxapi } from './utils/crypto'
|
||||
|
||||
export default songmid => {
|
||||
const requestObj = httpFetch('https://music.163.com/api/linux/forward', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
Referer: 'https://music.163.com/song?id=' + songmid,
|
||||
origin: 'https://music.163.com',
|
||||
},
|
||||
form: linuxapi({
|
||||
method: 'POST',
|
||||
url: 'https://music.163.com/api/song/lyric?lv=-1&kv=-1&tv=-1',
|
||||
params: {
|
||||
id: songmid,
|
||||
},
|
||||
}),
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (body.code !== 200) return Promise.reject('获取歌词失败')
|
||||
return body.lrc.lyric
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/song_detail.js
|
||||
import { httpFetch } from '../../request'
|
||||
import { weapi } from './utils/crypto'
|
||||
|
||||
export default songmid => {
|
||||
const requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
Referer: 'https://music.163.com/song?id=' + songmid,
|
||||
origin: 'https://music.163.com',
|
||||
},
|
||||
form: weapi({
|
||||
c: `[{"id":${songmid}}]`,
|
||||
ids: '[songmid]',
|
||||
}),
|
||||
})
|
||||
requestObj.promise = requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (body.code !== 200 || !body.songs.length) return Promise.reject('获取歌曲信息失败')
|
||||
return body.songs[0]
|
||||
})
|
||||
return requestObj
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/util/crypto.js
|
||||
|
||||
import { createCipheriv, publicEncrypt, constants, randomBytes } from 'crypto'
|
||||
const iv = Buffer.from('0102030405060708')
|
||||
const presetKey = Buffer.from('0CoJUm6Qyw8W8jud')
|
||||
const linuxapiKey = Buffer.from('rFgB&h#%2?^eDg:Q')
|
||||
const base62 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||
const publicKey = '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgtQn2JZ34ZC28NWYpAUd98iZ37BUrX/aKzmFbt7clFSs6sXqHauqKWqdtLkF2KexO40H1YTX8z2lSgBBOAxLsvaklV8k4cBFK9snQXE9/DDaFt6Rr7iVZMldczhC0JNgTz+SHXT6CBHuX3e9SdB1Ua44oncaTWz7OBGLbCiK45wIDAQAB\n-----END PUBLIC KEY-----'
|
||||
|
||||
const aesEncrypt = (buffer, mode, key, iv) => {
|
||||
const cipher = createCipheriv('aes-128-' + mode, key, iv)
|
||||
return Buffer.concat([cipher.update(buffer), cipher.final()])
|
||||
}
|
||||
|
||||
const rsaEncrypt = (buffer, key) => {
|
||||
buffer = Buffer.concat([Buffer.alloc(128 - buffer.length), buffer])
|
||||
return publicEncrypt({ key: key, padding: constants.RSA_NO_PADDING }, buffer)
|
||||
}
|
||||
|
||||
export const weapi = object => {
|
||||
const text = JSON.stringify(object)
|
||||
const secretKey = randomBytes(16).map(n => (base62.charAt(n % 62).charCodeAt()))
|
||||
return {
|
||||
params: aesEncrypt(Buffer.from(aesEncrypt(Buffer.from(text), 'cbc', presetKey, iv).toString('base64')), 'cbc', secretKey, iv).toString('base64'),
|
||||
encSecKey: rsaEncrypt(secretKey.reverse(), publicKey).toString('hex'),
|
||||
}
|
||||
}
|
||||
|
||||
export const linuxapi = object => {
|
||||
const text = JSON.stringify(object)
|
||||
return {
|
||||
eparams: aesEncrypt(Buffer.from(text), 'ecb', linuxapiKey, '').toString('hex').toUpperCase(),
|
||||
}
|
||||
}
|
|
@ -126,6 +126,7 @@ export default {
|
|||
handleAddDownloadMultiple(type) {
|
||||
switch (this.source) {
|
||||
// case 'kg':
|
||||
case 'tx':
|
||||
case 'wy':
|
||||
type = '128k'
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
table
|
||||
tbody
|
||||
tr(v-for='(item, index) in list' :key='item.songmid'
|
||||
@click="handleDoubleClick(index)" :class="[isPlayList && playIndex === index ? $style.active : '', (isAPITemp && item.source != 'kw') || item.source == 'wy' ? $style.disabled : '']")
|
||||
@click="handleDoubleClick(index)" :class="[isPlayList && playIndex === index ? $style.active : '', (isAPITemp && item.source != 'kw') ? $style.disabled : '']")
|
||||
td.nobreak.center(style="width: 37px;" @click.stop)
|
||||
material-checkbox(:id="index.toString()" v-model="selectdData" :value="item")
|
||||
td.break(style="width: 25%;")
|
||||
|
@ -218,7 +218,7 @@ export default {
|
|||
this.clickIndex = -1
|
||||
},
|
||||
testPlay(index) {
|
||||
if ((this.isAPITemp && this.list[index].source != 'kw') || this.list[index].source == 'wy') return
|
||||
if (this.isAPITemp && this.list[index].source != 'kw') return
|
||||
this.setPlayList({ list: this.list, listId: this.listId, index })
|
||||
},
|
||||
handleRemove(index) {
|
||||
|
@ -228,7 +228,7 @@ export default {
|
|||
switch (info.action) {
|
||||
case 'download': {
|
||||
const minfo = this.list[info.index]
|
||||
if ((this.isAPITemp && minfo.source != 'kw') || minfo.source == 'wy') return
|
||||
if (this.isAPITemp && minfo.source != 'kw') return
|
||||
this.musicInfo = minfo
|
||||
this.$nextTick(() => {
|
||||
this.isShowDownload = true
|
||||
|
@ -261,7 +261,7 @@ export default {
|
|||
this.selectdData = []
|
||||
},
|
||||
handleAddDownloadMultiple(type) {
|
||||
const list = this.setting.apiSource == 'temp' ? this.selectdData.filter(s => s.source == 'kw') : this.selectdData.filter(s => s.source != 'wy')
|
||||
const list = this.setting.apiSource == 'temp' ? this.selectdData.filter(s => s.source == 'kw') : [...this.selectdData]
|
||||
this.createDownloadMultiple({ list, type })
|
||||
this.resetSelect()
|
||||
this.isShowDownloadMultiple = false
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
td.break(style="width: 25%;") {{item.albumName}}
|
||||
td(style="width: 15%; padding-left: 0; padding-right: 0;")
|
||||
material-list-buttons(:index="index" :remove-btn="false" :class="$style.listBtn"
|
||||
:play-btn="item.source == 'kw' || (!isAPITemp && item.source != 'wy')"
|
||||
:download-btn="item.source == 'kw' || (!isAPITemp && item.source != 'wy')"
|
||||
:play-btn="item.source == 'kw' || !isAPITemp"
|
||||
:download-btn="item.source == 'kw' || !isAPITemp"
|
||||
@btn-click="handleListBtnClick")
|
||||
td(style="width: 10%;") {{item.interval || '--/--'}}
|
||||
div(:class="$style.pagination")
|
||||
|
@ -189,7 +189,7 @@ export default {
|
|||
targetSong = this.selectdData[0]
|
||||
this.listAddMultiple({ id: 'default', list: this.filterList(this.selectdData) })
|
||||
} else {
|
||||
if ((this.isAPITemp && this.listInfo.list[index].source != 'kw') || this.listInfo.list[index].source == 'wy') return
|
||||
if (this.isAPITemp && this.listInfo.list[index].source != 'kw') return
|
||||
targetSong = this.listInfo.list[index]
|
||||
this.listAdd({ id: 'default', musicInfo: targetSong })
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ export default {
|
|||
}
|
||||
},
|
||||
filterList(list) {
|
||||
return this.setting.apiSource == 'temp' ? list.filter(s => s.source == 'kw') : list.filter(s => s.source != 'wy')
|
||||
return this.setting.apiSource == 'temp' ? list.filter(s => s.source == 'kw') : [...list]
|
||||
},
|
||||
handleListAddModalClose(isSelect) {
|
||||
if (isSelect) this.resetSelect()
|
||||
|
|
|
@ -200,6 +200,7 @@ export default {
|
|||
handleAddDownloadMultiple(type) {
|
||||
switch (this.source) {
|
||||
// case 'kg':
|
||||
case 'tx':
|
||||
case 'wy':
|
||||
type = '128k'
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue