feat: wyy母带搜索无大小修复

This commit is contained in:
ikun0014 2024-10-09 22:44:20 +08:00
parent e0e572a683
commit be4b1a372b
3 changed files with 216 additions and 257 deletions

View File

@ -1,82 +1,88 @@
import { httpFetch } from '../../request' import { httpFetch } from '../../request'
import { weapi } from './utils/crypto' import { weapi } from './utils/crypto'
import { formatPlayTime, sizeFormate } from '../../index' import { formatPlayTime, sizeFormate } from '../../index'
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/song_detail.js
export default { export default {
getSinger(singers) { getSinger(singers) {
let arr = [] try {
singers?.forEach(singer => { const arr = singers.map(singer => singer.name)
arr.push(singer.name)
})
return arr.join('、') return arr.join('、')
} catch (err) {
console.error('getSinger error:', err)
return ''
}
}, },
filterList({ songs, privileges }) {
// console.log(songs, privileges) async fetchSongDetails(songId) {
const list = [] try {
songs.forEach((item, index) => { const requestObj = httpFetch(`https://music.163.com/api/song/music/detail/get?songId=${songId}`, {
method: 'get',
headers: {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)',
origin: 'https://music.163.com',
},
})
const { body, statusCode } = await requestObj.promise
if (statusCode !== 200 || body.code !== 200) throw new Error('获取歌曲音质信息失败')
return body
} catch (err) {
console.error('Error fetching song details:', err)
return null
}
},
async filterList({ songs, privileges }) {
try {
const list = await Promise.all(
songs.map(async(item, index) => {
const types = [] const types = []
const _types = {} const _types = {}
let size let size
let privilege = privileges[index] let privilege = privileges[index]
if (privilege.id !== item.id) privilege = privileges.find(p => p.id === item.id)
if (privilege.id !== item.id) {
privilege = privileges.find(p => p.id === item.id)
}
if (!privilege) return if (!privilege) return
if (privilege.chargeInfoList.length > 4 && privilege.chargeInfoList[4].rate == 1999000 && privilege.chargeInfoList[4].chargeType == 1) { const songDetails = await this.fetchSongDetails(privilege.id)
types.push({ type: 'master' }) if (songDetails) {
_types.master = { const jmSize = songDetails.data.jm?.size
size: null, if (jmSize) {
size = sizeFormate(jmSize)
types.push({ type: 'master', size })
_types.master = { size }
} }
}
if (privilege.maxBrLevel == 'hires') { if (privilege.maxBrLevel === 'hires') {
size = item.hr ? sizeFormate(item.hr.size) : null size = item.hr ? sizeFormate(item.hr.size) : null
types.push({ type: 'flac24bit', size }) types.push({ type: 'flac24bit', size })
_types.flac24bit = { _types.flac24bit = { size }
size,
}
} }
switch (privilege.maxbr) { switch (privilege.maxbr) {
case 999000: case 999000:
size = item.sq ? sizeFormate(item.sq.size) : null size = item.sq ? sizeFormate(item.sq.size) : null
types.push({ type: 'flac', size }) types.push({ type: 'flac', size })
_types.flac = { _types.flac = { size }
size,
}
case 320000: case 320000:
size = item.h ? sizeFormate(item.h.size) : null size = item.h ? sizeFormate(item.h.size) : null
types.push({ type: '320k', size }) types.push({ type: '320k', size })
_types['320k'] = { _types['320k'] = { size }
size,
}
case 192000: case 192000:
case 128000: case 128000:
size = item.l ? sizeFormate(item.l.size) : null size = item.l ? sizeFormate(item.l.size) : null
types.push({ type: '128k', size }) types.push({ type: '128k', size })
_types['128k'] = { _types['128k'] = { size }
size,
}
} }
types.reverse() types.reverse()
}
if (item.pc) { const song = {
list.push({
singer: item.pc.ar ?? '',
name: item.pc.sn ?? '',
albumName: item.pc.alb ?? '',
albumId: item.al?.id,
source: 'wy',
interval: formatPlayTime(item.dt / 1000),
songmid: item.id,
img: item.al?.picUrl ?? '',
lrc: null,
otherSource: null,
types,
_types,
typeUrl: {},
})
} else {
list.push({
singer: this.getSinger(item.ar), singer: this.getSinger(item.ar),
name: item.name ?? '', name: item.name ?? '',
albumName: item.al?.name, albumName: item.al?.name,
@ -90,15 +96,23 @@ export default {
types, types,
_types, _types,
typeUrl: {}, typeUrl: {},
})
} }
})
// console.log(list) return song
return list }),
)
return list.filter(item => item !== undefined)
} catch (err) {
console.error('filterList error:', err)
return []
}
}, },
async getList(ids = [], retryNum = 0) { async getList(ids = [], retryNum = 0) {
if (retryNum > 2) return Promise.reject(new Error('try max num')) if (retryNum > 2) return Promise.reject(new Error('try max num'))
try {
const requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', { const requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', {
method: 'post', method: 'post',
headers: { headers: {
@ -106,13 +120,23 @@ export default {
origin: 'https://music.163.com', origin: 'https://music.163.com',
}, },
form: weapi({ form: weapi({
c: '[' + ids.map(id => ('{"id":' + id + '}')).join(',') + ']', c: '[' + ids.map(id => `{"id":${id}}`).join(',') + ']',
ids: '[' + ids.join(',') + ']', ids: '[' + ids.join(',') + ']',
}), }),
}) })
const { body, statusCode } = await requestObj.promise const { body, statusCode } = await requestObj.promise
if (statusCode != 200 || body.code !== 200) throw new Error('获取歌曲详情失败') if (statusCode !== 200 || body.code !== 200) throw new Error('获取歌曲详情失败')
// console.log(body)
return { source: 'wy', list: this.filterList(body) } const result = await this.filterList(body)
return { source: 'wy', list: result }
} catch (err) {
console.error('getList error:', err)
if (retryNum < 2) {
return this.getList(ids, retryNum + 1)
} else {
throw new Error('Failed after retrying')
}
}
}, },
} }

View File

@ -1,7 +1,5 @@
// import { httpFetch } from '../../request' import { httpFetch } from '../../request'
// import { weapi } from './utils/crypto'
import { sizeFormate, formatPlayTime } from '../../index' import { sizeFormate, formatPlayTime } from '../../index'
// import musicDetailApi from './musicDetail'
import { eapiRequest } from './utils/index' import { eapiRequest } from './utils/index'
export default { export default {
@ -9,6 +7,7 @@ export default {
total: 0, total: 0,
page: 0, page: 0,
allPage: 1, allPage: 1,
musicSearch(str, page, limit) { musicSearch(str, page, limit) {
const searchRequest = eapiRequest('/api/cloudsearch/pc', { const searchRequest = eapiRequest('/api/cloudsearch/pc', {
s: str, s: str,
@ -19,54 +18,58 @@ export default {
}) })
return searchRequest.promise.then(({ body }) => body) return searchRequest.promise.then(({ body }) => body)
}, },
getSinger(singers) { getSinger(singers) {
let arr = [] return singers.map(singer => singer.name).join('、')
singers.forEach(singer => {
arr.push(singer.name)
})
return arr.join('、')
}, },
handleResult(rawList) { handleResult(rawList) {
// console.log(rawList)
if (!rawList) return [] if (!rawList) return []
return rawList.map(item => {
return Promise.all(rawList.map(async item => {
const types = [] const types = []
const _types = {} const _types = {}
let size let size
if (item.privilege.chargeInfoList.length > 4 && item.privilege.chargeInfoList[4].rate == 1999000 && item.privilege.chargeInfoList[4].chargeType == 1) { try {
types.push({ type: 'master' }) const requestObj = httpFetch(`https://music.163.com/api/song/music/detail/get?songId=${item.id}`, {
_types.master = { method: 'get',
size: null, headers: {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
origin: 'https://music.163.com',
},
})
const { body, statusCode } = await requestObj.promise
if (statusCode !== 200 || !body || body.code !== 200) {
throw new Error('Failed to get song quality information')
} }
if (body.data.jm && body.data.jm.size) {
size = sizeFormate(body.data.jm.size)
types.push({ type: 'master', size })
_types.master = { size }
} }
if (item.privilege.maxBrLevel == 'hires') { if (item.privilege.maxBrLevel == 'hires') {
size = item.hr ? sizeFormate(item.hr.size) : null size = item.hr ? sizeFormate(item.hr.size) : null
types.push({ type: 'flac24bit', size }) types.push({ type: 'flac24bit', size })
_types.flac24bit = { _types.flac24bit = { size }
size,
}
} }
switch (item.privilege.maxbr) { switch (item.privilege.maxbr) {
case 999000: case 999000:
size = item.sq ? sizeFormate(item.sq.size) : null size = item.sq ? sizeFormate(item.sq.size) : null
types.push({ type: 'flac', size }) types.push({ type: 'flac', size })
_types.flac = { _types.flac = { size }
size,
}
case 320000: case 320000:
size = item.h ? sizeFormate(item.h.size) : null size = item.h ? sizeFormate(item.h.size) : null
types.push({ type: '320k', size }) types.push({ type: '320k', size })
_types['320k'] = { _types['320k'] = { size }
size,
}
case 192000: case 192000:
case 128000: case 128000:
size = item.l ? sizeFormate(item.l.size) : null size = item.l ? sizeFormate(item.l.size) : null
types.push({ type: '128k', size }) types.push({ type: '128k', size })
_types['128k'] = { _types['128k'] = { size }
size,
}
} }
types.reverse() types.reverse()
@ -85,18 +88,20 @@ export default {
_types, _types,
typeUrl: {}, typeUrl: {},
} }
}) } catch (error) {
console.error(error.message)
return null
}
}))
}, },
search(str, page = 1, limit, retryNum = 0) { search(str, page = 1, limit, retryNum = 0) {
if (++retryNum > 3) return Promise.reject(new Error('try max num')) if (++retryNum > 3) return Promise.reject(new Error('try max num'))
if (limit == null) limit = this.limit if (limit == null) limit = this.limit
return this.musicSearch(str, page, limit).then(result => { return this.musicSearch(str, page, limit).then(result => {
// console.log(result)
if (!result || result.code !== 200) return this.search(str, page, limit, retryNum) if (!result || result.code !== 200) return this.search(str, page, limit, retryNum)
let list = this.handleResult(result.result.songs || []) return this.handleResult(result.result.songs || []).then(list => {
// console.log(list) if (!list || list.length === 0) return this.search(str, page, limit, retryNum)
if (list == null) return this.search(str, page, limit, retryNum)
this.total = result.result.songCount || 0 this.total = result.result.songCount || 0
this.page = page this.page = page
@ -109,7 +114,7 @@ export default {
total: this.total, total: this.total,
source: 'wy', source: 'wy',
} }
// return result.data })
}) })
}, },
} }

View File

@ -1,11 +1,6 @@
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/playlist_catlist.js
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/playlist_hot.js
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/top_playlist.js
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/playlist_detail.js
import { weapi, linuxapi } from './utils/crypto' import { weapi, linuxapi } from './utils/crypto'
import { httpFetch } from '../../request' import { httpFetch } from '../../request'
import { formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../../index' import { formatPlayTime, dateFormat, formatPlayCount } from '../../index'
import musicDetailApi from './musicDetail' import musicDetailApi from './musicDetail'
import { eapiRequest } from './utils/index' import { eapiRequest } from './utils/index'
import { formatSingerName } from '../utils' import { formatSingerName } from '../utils'
@ -21,14 +16,8 @@ export default {
sortList: [ sortList: [
{ {
name: '最热', name: '最热',
tid: 'hot',
id: 'hot', id: 'hot',
}, },
// {
// name: '最新',
// tid: 'new',
// id: 'new',
// },
], ],
regExps: { regExps: {
listDetailLink: /^.+(?:\?|&)id=(\d+)(?:&.*$|#.*$|$)/, listDetailLink: /^.+(?:\?|&)id=(\d+)(?:&.*$|#.*$|$)/,
@ -39,9 +28,9 @@ export default {
if (retryNum > 2) throw new Error('link try max num') if (retryNum > 2) throw new Error('link try max num')
const requestObj_listDetailLink = httpFetch(link) const requestObj_listDetailLink = httpFetch(link)
const { url, statusCode } = await requestObj_listDetailLink.promise const { headers: { location }, statusCode } = await requestObj_listDetailLink.promise
// console.log(headers)
if (statusCode > 400) return this.handleParseId(link, ++retryNum) if (statusCode > 400) return this.handleParseId(link, ++retryNum)
const url = location == null ? link : location
return this.regExps.listDetailLink.test(url) return this.regExps.listDetailLink.test(url)
? url.replace(this.regExps.listDetailLink, '$1') ? url.replace(this.regExps.listDetailLink, '$1')
: url.replace(this.regExps.listDetailLink2, '$1') : url.replace(this.regExps.listDetailLink2, '$1')
@ -62,12 +51,11 @@ export default {
} else { } else {
id = await this.handleParseId(id) id = await this.handleParseId(id)
} }
// console.log(id)
} }
return { id, cookie } return { id, cookie }
}, },
async getListDetail(rawId, page, tryNum = 0) { // 获取歌曲列表内的音乐 async getListDetail(rawId, page, tryNum = 0) {
if (tryNum > 2) return Promise.reject(new Error('try max num')) if (tryNum > 1000) return Promise.reject(new Error('try max num'))
const { id, cookie } = await this.getListId(rawId) const { id, cookie } = await this.getListId(rawId)
if (cookie) this.cookie = cookie if (cookie) this.cookie = cookie
@ -78,8 +66,6 @@ export default {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
Cookie: this.cookie, Cookie: this.cookie,
}, },
credentials: 'omit',
cache: 'default',
form: linuxapi({ form: linuxapi({
method: 'POST', method: 'POST',
url: 'https://music.163.com/api/v3/playlist/detail', url: 'https://music.163.com/api/v3/playlist/detail',
@ -94,7 +80,6 @@ export default {
if (statusCode !== 200 || body.code !== this.successCode) return this.getListDetail(id, page, ++tryNum) if (statusCode !== 200 || body.code !== this.successCode) return this.getListDetail(id, page, ++tryNum)
let limit = 1000 let limit = 1000
let rangeStart = (page - 1) * limit let rangeStart = (page - 1) * limit
// console.log(body)
let list let list
if (body.playlist.trackIds.length == body.privileges.length) { if (body.playlist.trackIds.length == body.privileges.length) {
list = this.filterListDetail(body) list = this.filterListDetail(body)
@ -110,7 +95,6 @@ export default {
} }
} }
} }
// console.log(list)
return { return {
list, list,
page, page,
@ -126,53 +110,11 @@ export default {
}, },
} }
}, },
filterListDetail({ playlist: { tracks }, privileges }) { filterListDetail({ playlist: { tracks } }) {
// console.log(tracks, privileges)
const list = [] const list = []
tracks.forEach((item, index) => { tracks.forEach((item) => {
const types = [] const types = []
const _types = {} const _types = {}
let size
let privilege = privileges[index]
if (privilege.id !== item.id) privilege = privileges.find(p => p.id === item.id)
if (!privilege) return
if (privilege.chargeInfoList.length > 4 && privilege.chargeInfoList[4].rate == 1999000 && privilege.chargeInfoList[4].chargeType == 1) {
types.push({ type: 'master' })
_types.master = {
size: null,
}
}
if (privilege.maxBrLevel == 'hires') {
size = item.hr ? sizeFormate(item.hr.size) : null
types.push({ type: 'flac24bit', size })
_types.flac24bit = {
size,
}
}
switch (privilege.maxbr) {
case 999000:
size = null
types.push({ type: 'flac', size })
_types.flac = {
size,
}
case 320000:
size = item.h ? sizeFormate(item.h.size) : null
types.push({ type: '320k', size })
_types['320k'] = {
size,
}
case 192000:
case 128000:
size = item.l ? sizeFormate(item.l.size) : null
types.push({ type: '128k', size })
_types['128k'] = {
size,
}
}
types.reverse()
if (item.pc) { if (item.pc) {
list.push({ list.push({
@ -211,22 +153,20 @@ export default {
return list return list
}, },
// 获取列表数据
getList(sortId, tagId, page, tryNum = 0) { getList(sortId, tagId, page, tryNum = 0) {
if (tryNum > 2) return Promise.reject(new Error('try max num')) if (tryNum > 2) return Promise.reject(new Error('try max num'))
if (this._requestObj_list) this._requestObj_list.cancelHttp() if (this._requestObj_list) this._requestObj_list.cancelHttp()
this._requestObj_list = httpFetch('https://music.163.com/weapi/playlist/list', { this._requestObj_list = httpFetch('https://music.163.com/weapi/playlist/list', {
method: 'post', method: 'post',
form: weapi({ form: weapi({
cat: tagId || '全部', // 全部,华语,欧美,日语,韩语,粤语,小语种,流行,摇滚,民谣,电子,舞曲,说唱,轻音乐,爵士,乡村,R&B/Soul,古典,民族,英伦,金属,朋克,蓝调,雷鬼,世界音乐,拉丁,另类/独立,New Age,古风,后摇,Bossa Nova,清晨,夜晚,学习,工作,午休,下午茶,地铁,驾车,运动,旅行,散步,酒吧,怀旧,清新,浪漫,性感,伤感,治愈,放松,孤独,感动,兴奋,快乐,安静,思念,影视原声,ACG,儿童,校园,游戏,70后,80后,90后,网络歌曲,KTV,经典,翻唱,吉他,钢琴,器乐,榜单,00后 cat: tagId || '全部',
order: sortId, // hot,new order: sortId,
limit: this.limit_list, limit: this.limit_list,
offset: this.limit_list * (page - 1), offset: this.limit_list * (page - 1),
total: true, total: true,
}), }),
}) })
return this._requestObj_list.promise.then(({ body }) => { return this._requestObj_list.promise.then(({ body }) => {
// console.log(body)
if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum) if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
return { return {
list: this.filterList(body.playlists), list: this.filterList(body.playlists),
@ -238,7 +178,6 @@ export default {
}) })
}, },
filterList(rawData) { filterList(rawData) {
// console.log(rawData)
return rawData.map(item => ({ return rawData.map(item => ({
play_count: formatPlayCount(item.playCount), play_count: formatPlayCount(item.playCount),
id: String(item.id), id: String(item.id),
@ -253,7 +192,6 @@ export default {
})) }))
}, },
// 获取标签
getTag(tryNum = 0) { getTag(tryNum = 0) {
if (this._requestObj_tags) this._requestObj_tags.cancelHttp() if (this._requestObj_tags) this._requestObj_tags.cancelHttp()
if (tryNum > 2) return Promise.reject(new Error('try max num')) if (tryNum > 2) return Promise.reject(new Error('try max num'))
@ -262,7 +200,6 @@ export default {
form: weapi({}), form: weapi({}),
}) })
return this._requestObj_tags.promise.then(({ body }) => { return this._requestObj_tags.promise.then(({ body }) => {
// console.log(JSON.stringify(body))
if (body.code !== this.successCode) return this.getTag(++tryNum) if (body.code !== this.successCode) return this.getTag(++tryNum)
return this.filterTagInfo(body) return this.filterTagInfo(body)
}) })
@ -291,7 +228,6 @@ export default {
return list return list
}, },
// 获取热门标签
getHotTag(tryNum = 0) { getHotTag(tryNum = 0) {
if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp() if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp()
if (tryNum > 2) return Promise.reject(new Error('try max num')) if (tryNum > 2) return Promise.reject(new Error('try max num'))
@ -300,7 +236,6 @@ export default {
form: weapi({}), form: weapi({}),
}) })
return this._requestObj_hotTags.promise.then(({ body }) => { return this._requestObj_hotTags.promise.then(({ body }) => {
// console.log(JSON.stringify(body))
if (body.code !== this.successCode) return this.getTag(++tryNum) if (body.code !== this.successCode) return this.getTag(++tryNum)
return this.filterHotTagInfo(body.tags) return this.filterHotTagInfo(body.tags)
}) })
@ -325,14 +260,13 @@ export default {
search(text, page, limit = 20) { search(text, page, limit = 20) {
return eapiRequest('/api/cloudsearch/pc', { return eapiRequest('/api/cloudsearch/pc', {
s: text, s: text,
type: 1000, // 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频 type: 1000,
limit, limit,
total: page == 1, total: page == 1,
offset: limit * (page - 1), offset: limit * (page - 1),
}) })
.promise.then(({ body }) => { .promise.then(({ body }) => {
if (body.code != this.successCode) throw new Error('filed') if (body.code != this.successCode) throw new Error('filed')
// console.log(body)
return { return {
list: this.filterList(body.result.playlists), list: this.filterList(body.result.playlists),
limit, limit,
@ -342,7 +276,3 @@ export default {
}) })
}, },
} }
// getList
// getTags
// getListDetail