mirror of
https://github.com/timeshiftsauce/CeruMusic.git
synced 2025-11-25 03:15:07 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c512bccff |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ceru-music",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.2",
|
||||
"description": "一款简洁优雅的音乐播放器",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "sqj,wldss,star",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate } from '../index'
|
||||
import { decodeName, formatPlayTime } from '../../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
import { getBatchMusicQualityInfo } from './quality_detail'
|
||||
|
||||
export default {
|
||||
limit: 30,
|
||||
@@ -9,87 +10,72 @@ export default {
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
const searchRequest = httpFetch(
|
||||
`https://songsearch.kugou.com/song_search_v2?keyword=${encodeURIComponent(str)}&page=${page}&pagesize=${limit}&userid=0&clientver=&platform=WebFilter&filter=2&iscorrection=1&privilege_filter=0&area_code=1`
|
||||
`https://songsearch.kugou.com/song_search_v2?keyword=${encodeURIComponent(
|
||||
str
|
||||
)}&page=${page}&pagesize=${limit}&userid=0&clientver=&platform=WebFilter&filter=2&iscorrection=1&privilege_filter=0&area_code=1`
|
||||
)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
filterData(rawData) {
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (rawData.FileSize !== 0) {
|
||||
const size = sizeFormate(rawData.FileSize)
|
||||
types.push({ type: '128k', size, hash: rawData.FileHash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: rawData.FileHash
|
||||
}
|
||||
}
|
||||
if (rawData.HQFileSize !== 0) {
|
||||
const size = sizeFormate(rawData.HQFileSize)
|
||||
types.push({ type: '320k', size, hash: rawData.HQFileHash })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: rawData.HQFileHash
|
||||
}
|
||||
}
|
||||
if (rawData.SQFileSize !== 0) {
|
||||
const size = sizeFormate(rawData.SQFileSize)
|
||||
types.push({ type: 'flac', size, hash: rawData.SQFileHash })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: rawData.SQFileHash
|
||||
}
|
||||
}
|
||||
if (rawData.ResFileSize !== 0) {
|
||||
const size = sizeFormate(rawData.ResFileSize)
|
||||
types.push({ type: 'flac24bit', size, hash: rawData.ResFileHash })
|
||||
_types.flac24bit = {
|
||||
size,
|
||||
hash: rawData.ResFileHash
|
||||
}
|
||||
}
|
||||
return {
|
||||
singer: decodeName(formatSingerName(rawData.Singers, 'name')),
|
||||
name: decodeName(rawData.SongName),
|
||||
albumName: decodeName(rawData.AlbumName),
|
||||
albumId: rawData.AlbumID,
|
||||
songmid: rawData.Audioid,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(rawData.Duration),
|
||||
_interval: rawData.Duration,
|
||||
img: null,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
hash: rawData.FileHash,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
},
|
||||
handleResult(rawData) {
|
||||
const ids = new Set()
|
||||
const list = []
|
||||
async handleResult(rawData) {
|
||||
let ids = new Set()
|
||||
const items = []
|
||||
|
||||
rawData.forEach((item) => {
|
||||
const key = item.Audioid + item.FileHash
|
||||
if (ids.has(key)) return
|
||||
ids.add(key)
|
||||
list.push(this.filterData(item))
|
||||
for (const childItem of item.Grp) {
|
||||
const key = item.Audioid + item.FileHash
|
||||
if (ids.has(key)) continue
|
||||
if (!ids.has(key)) {
|
||||
ids.add(key)
|
||||
list.push(this.filterData(childItem))
|
||||
items.push(item)
|
||||
}
|
||||
|
||||
for (const childItem of item.Grp || []) {
|
||||
const childKey = childItem.Audioid + childItem.FileHash
|
||||
if (!ids.has(childKey)) {
|
||||
ids.add(childKey)
|
||||
items.push(childItem)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const hashList = items.map((item) => item.FileHash)
|
||||
|
||||
let qualityInfoMap = {}
|
||||
try {
|
||||
const qualityInfoRequest = getBatchMusicQualityInfo(hashList)
|
||||
qualityInfoMap = await qualityInfoRequest.promise
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch quality info:', error)
|
||||
}
|
||||
|
||||
return items.map((item) => {
|
||||
const { types = [], _types = {} } = qualityInfoMap[item.FileHash] || {}
|
||||
|
||||
return {
|
||||
singer: decodeName(formatSingerName(item.Singers, 'name')),
|
||||
name: decodeName(item.SongName),
|
||||
albumName: decodeName(item.AlbumName),
|
||||
albumId: item.AlbumID,
|
||||
songmid: item.Audioid,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(item.Duration),
|
||||
_interval: item.Duration,
|
||||
img: null,
|
||||
lrc: null,
|
||||
otherSource: null,
|
||||
hash: item.FileHash,
|
||||
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) => {
|
||||
|
||||
return this.musicSearch(str, page, limit).then(async (result) => {
|
||||
if (!result || result.error_code !== 0) return this.search(str, page, limit, retryNum)
|
||||
const list = this.handleResult(result.data.lists)
|
||||
|
||||
let list = await this.handleResult(result.data.lists)
|
||||
|
||||
if (list == null) return this.search(str, page, limit, retryNum)
|
||||
|
||||
@@ -102,8 +88,8 @@ export default {
|
||||
allPage: this.allPage,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'kg'
|
||||
source: 'kg',
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
190
src/main/utils/musicSdk/kg/quality_detail.js
Normal file
190
src/main/utils/musicSdk/kg/quality_detail.js
Normal file
@@ -0,0 +1,190 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { dnsLookup } from '../utils'
|
||||
import { headers, timeout } from '../options'
|
||||
import { sizeFormate, decodeName, formatPlayTime } from '../../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
console.log(headers);
|
||||
|
||||
export const getBatchMusicQualityInfo = (hashList) => {
|
||||
const resources = hashList.map((hash) => ({
|
||||
id: 0,
|
||||
type: 'audio',
|
||||
hash,
|
||||
}))
|
||||
|
||||
const requestObj = httpFetch(
|
||||
`https://gateway.kugou.com/goodsmstore/v1/get_res_privilege?appid=1005&clientver=20049&clienttime=${Date.now()}&mid=NeZha`,
|
||||
{
|
||||
method: 'post',
|
||||
timeout,
|
||||
headers,
|
||||
body: {
|
||||
behavior: 'play',
|
||||
clientver: '20049',
|
||||
resource: resources,
|
||||
area_code: '1',
|
||||
quality: '128',
|
||||
qualities: [
|
||||
'128',
|
||||
'320',
|
||||
'flac',
|
||||
'high',
|
||||
'dolby',
|
||||
'viper_atmos',
|
||||
'viper_tape',
|
||||
'viper_clear',
|
||||
],
|
||||
},
|
||||
lookup: dnsLookup,
|
||||
family: 4,
|
||||
}
|
||||
)
|
||||
|
||||
const qualityInfoMap = {}
|
||||
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
|
||||
if (statusCode != 200 || body.error_code != 0)
|
||||
return Promise.reject(new Error('获取音质信息失败'))
|
||||
|
||||
body.data.forEach((songData, index) => {
|
||||
const hash = hashList[index]
|
||||
const types = []
|
||||
const _types = {}
|
||||
|
||||
if (!songData || !songData.relate_goods) return
|
||||
|
||||
for (const quality_data of songData.relate_goods) {
|
||||
if (quality_data.quality === '128') {
|
||||
let size = sizeFormate(quality_data.info.filesize)
|
||||
types.push({ type: '128k', size, hash: quality_data.hash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: quality_data.hash,
|
||||
}
|
||||
}
|
||||
if (quality_data.quality === '320') {
|
||||
let size = sizeFormate(quality_data.info.filesize)
|
||||
types.push({ type: '320k', size, hash: quality_data.hash })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: quality_data.hash,
|
||||
}
|
||||
}
|
||||
if (quality_data.quality === 'flac') {
|
||||
let size = sizeFormate(quality_data.info.filesize)
|
||||
types.push({ type: 'flac', size, hash: quality_data.hash })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: quality_data.hash,
|
||||
}
|
||||
}
|
||||
if (quality_data.quality === 'high') {
|
||||
let size = sizeFormate(quality_data.info.filesize)
|
||||
types.push({ type: 'hires', size, hash: quality_data.hash })
|
||||
_types.hires = {
|
||||
size,
|
||||
hash: quality_data.hash,
|
||||
}
|
||||
}
|
||||
if (quality_data.quality === 'viper_clear') {
|
||||
let size = sizeFormate(quality_data.info.filesize)
|
||||
types.push({ type: 'master', size, hash: quality_data.hash })
|
||||
_types.master = {
|
||||
size,
|
||||
hash: quality_data.hash,
|
||||
}
|
||||
}
|
||||
if (quality_data.quality === 'viper_atmos') {
|
||||
let size = sizeFormate(quality_data.info.filesize)
|
||||
types.push({ type: 'atmos', size, hash: quality_data.hash })
|
||||
_types.atmos = {
|
||||
size,
|
||||
hash: quality_data.hash,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qualityInfoMap[hash] = { types, _types }
|
||||
})
|
||||
|
||||
return qualityInfoMap
|
||||
})
|
||||
|
||||
return requestObj
|
||||
}
|
||||
|
||||
export const getHashFromItem = (item) => {
|
||||
if (item.hash) return item.hash
|
||||
if (item.FileHash) return item.FileHash
|
||||
if (item.audio_info && item.audio_info.hash) return item.audio_info.hash
|
||||
return null
|
||||
}
|
||||
|
||||
export const filterData = async (rawList, options = {}) => {
|
||||
let processedList = rawList
|
||||
|
||||
if (options.removeDuplicates) {
|
||||
let ids = new Set()
|
||||
processedList = rawList.filter((item) => {
|
||||
if (!item) return false
|
||||
const audioId = item.audio_info?.audio_id || item.audio_id
|
||||
if (ids.has(audioId)) return false
|
||||
ids.add(audioId)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
const hashList = processedList.map((item) => getHashFromItem(item)).filter((hash) => hash)
|
||||
|
||||
const qualityInfoRequest = getBatchMusicQualityInfo(hashList)
|
||||
let qualityInfoMap = {}
|
||||
|
||||
try {
|
||||
qualityInfoMap = await qualityInfoRequest.promise
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch quality info:', error)
|
||||
}
|
||||
|
||||
return processedList.map((item) => {
|
||||
const hash = getHashFromItem(item)
|
||||
const { types = [], _types = {} } = qualityInfoMap[hash] || {}
|
||||
|
||||
if (item.audio_info) {
|
||||
return {
|
||||
name: decodeName(item.songname),
|
||||
singer: decodeName(item.author_name),
|
||||
albumName: decodeName(item.album_info?.album_name || item.remark),
|
||||
albumId: item.album_info.album_id,
|
||||
songmid: item.audio_info.audio_id,
|
||||
source: 'kg',
|
||||
interval: options.fix
|
||||
? formatPlayTime(parseInt(item.audio_info.timelength) / 1000)
|
||||
: formatPlayTime(parseInt(item.audio_info.timelength)),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.audio_info.hash,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: decodeName(item.songname),
|
||||
singer: decodeName(item.singername) || formatSingerName(item.authors, 'author_name'),
|
||||
albumName: decodeName(item.album_name || item.remark),
|
||||
albumId: item.album_id,
|
||||
songmid: item.audio_id,
|
||||
source: 'kg',
|
||||
interval: options.fix ? formatPlayTime(item.duration / 1000) : formatPlayTime(item.duration),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.hash,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index'
|
||||
import { decodeName, dateFormat, formatPlayCount } from '../../index'
|
||||
import './vendors/infSign.min'
|
||||
|
||||
import { signatureParams } from './util'
|
||||
import { filterData } from './quality_detail'
|
||||
|
||||
const handleSignature = (id, page, limit) =>
|
||||
new Promise((resolve, reject) => {
|
||||
@@ -14,7 +14,7 @@ const handleSignature = (id, page, limit) =>
|
||||
isCDN: !0,
|
||||
callback(i) {
|
||||
resolve(i.signature)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -27,36 +27,36 @@ export default {
|
||||
listDetailLimit: 10000,
|
||||
currentTagInfo: {
|
||||
id: undefined,
|
||||
info: undefined
|
||||
info: undefined,
|
||||
},
|
||||
sortList: [
|
||||
{
|
||||
name: '推荐',
|
||||
id: '5'
|
||||
id: '5',
|
||||
},
|
||||
{
|
||||
name: '最热',
|
||||
id: '6'
|
||||
id: '6',
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
id: '7'
|
||||
id: '7',
|
||||
},
|
||||
{
|
||||
name: '热藏',
|
||||
id: '3'
|
||||
id: '3',
|
||||
},
|
||||
{
|
||||
name: '飙升',
|
||||
id: '8'
|
||||
}
|
||||
id: '8',
|
||||
},
|
||||
],
|
||||
cache: new Map(),
|
||||
regExps: {
|
||||
listData: /global\.data = (\[.+\]);/,
|
||||
listInfo: /global = {[\s\S]+?name: "(.+)"[\s\S]+?pic: "(.+)"[\s\S]+?};/,
|
||||
// https://www.kugou.com/yy/special/single/1067062.html
|
||||
listDetailLink: /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/
|
||||
listDetailLink: /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/,
|
||||
},
|
||||
parseHtmlDesc(html) {
|
||||
const prefix = '<div class="pc_specail_text pc_singer_tab_content" id="specailIntroduceWrap">'
|
||||
@@ -71,18 +71,17 @@ export default {
|
||||
if (tryNum > 2) throw new Error('try max num')
|
||||
|
||||
const { body } = await httpFetch(this.getSongListDetailUrl(id)).promise
|
||||
const listData = body.match(this.regExps.listData)
|
||||
const listInfo = body.match(this.regExps.listInfo)
|
||||
let listData = body.match(this.regExps.listData)
|
||||
let listInfo = body.match(this.regExps.listInfo)
|
||||
if (!listData) return this.getListDetailBySpecialId(id, page, ++tryNum)
|
||||
const list = await this.getMusicInfos(JSON.parse(listData[1]))
|
||||
// listData = this.filterData(JSON.parse(listData[1]))
|
||||
let list = await this.getMusicInfos(JSON.parse(listData[1]))
|
||||
let name
|
||||
let pic
|
||||
if (listInfo) {
|
||||
name = listInfo[1]
|
||||
pic = listInfo[2]
|
||||
}
|
||||
const desc = this.parseHtmlDesc(body)
|
||||
let desc = this.parseHtmlDesc(body)
|
||||
|
||||
return {
|
||||
list,
|
||||
@@ -93,10 +92,10 @@ export default {
|
||||
info: {
|
||||
name,
|
||||
img: pic,
|
||||
desc
|
||||
desc,
|
||||
// author: body.result.info.userinfo.username,
|
||||
// play_count: formatPlayCount(body.result.listen_num),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
getInfoUrl(tagId) {
|
||||
@@ -116,11 +115,11 @@ export default {
|
||||
const result = []
|
||||
if (rawData.status !== 1) return result
|
||||
for (const key of Object.keys(rawData.data)) {
|
||||
const tag = rawData.data[key]
|
||||
let tag = rawData.data[key]
|
||||
result.push({
|
||||
id: tag.special_id,
|
||||
name: tag.special_name,
|
||||
source: 'kg'
|
||||
source: 'kg',
|
||||
})
|
||||
}
|
||||
return result
|
||||
@@ -135,8 +134,8 @@ export default {
|
||||
parent_name: tag.pname,
|
||||
id: tag.id,
|
||||
name: tag.name,
|
||||
source: 'kg'
|
||||
}))
|
||||
source: 'kg',
|
||||
})),
|
||||
})
|
||||
}
|
||||
return result
|
||||
@@ -159,7 +158,7 @@ export default {
|
||||
{
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'KuGou2012-8275-web_browser_event_handler'
|
||||
'User-Agent': 'KuGou2012-8275-web_browser_event_handler',
|
||||
},
|
||||
body: {
|
||||
appid: 1001,
|
||||
@@ -170,8 +169,8 @@ export default {
|
||||
platform: 'pc',
|
||||
userid: '262643156',
|
||||
return_min: 6,
|
||||
return_max: 15
|
||||
}
|
||||
return_max: 15,
|
||||
},
|
||||
}
|
||||
)
|
||||
return this._requestObj_listRecommend.promise.then(({ body }) => {
|
||||
@@ -190,7 +189,7 @@ export default {
|
||||
total: item.songcount,
|
||||
grade: item.grade,
|
||||
desc: item.intro,
|
||||
source: 'kg'
|
||||
source: 'kg',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -219,7 +218,7 @@ export default {
|
||||
},
|
||||
|
||||
createTask(hashs) {
|
||||
const data = {
|
||||
let data = {
|
||||
area_code: '1',
|
||||
show_privilege: 1,
|
||||
show_album_info: '1',
|
||||
@@ -230,16 +229,16 @@ export default {
|
||||
dfid: '-',
|
||||
clienttime: Date.now(),
|
||||
key: 'OIlwieks28dk2k092lksi2UIkp',
|
||||
fields: 'album_info,author_name,audio_info,ori_audio_name,base,songname'
|
||||
fields: 'album_info,author_name,audio_info,ori_audio_name,base,songname',
|
||||
}
|
||||
let list = hashs
|
||||
const tasks = []
|
||||
let tasks = []
|
||||
while (list.length) {
|
||||
tasks.push(Object.assign({ data: list.slice(0, 100) }, data))
|
||||
if (list.length < 100) break
|
||||
list = list.slice(100)
|
||||
}
|
||||
const url = 'http://gateway.kugou.com/v2/album_audio/audio'
|
||||
let url = 'http://gateway.kugou.com/v2/album_audio/audio'
|
||||
return tasks.map((task) =>
|
||||
this.createHttp(url, {
|
||||
method: 'POST',
|
||||
@@ -250,13 +249,13 @@ export default {
|
||||
'KG-Fake': '0',
|
||||
'KG-RF': '00869891',
|
||||
'User-Agent': 'Android712-AndroidPhone-11451-376-0-FeeCacheUpdate-wifi',
|
||||
'x-router': 'kmr.service.kugou.com'
|
||||
}
|
||||
'x-router': 'kmr.service.kugou.com',
|
||||
},
|
||||
}).then((data) => data.map((s) => s[0]))
|
||||
)
|
||||
},
|
||||
async getMusicInfos(list) {
|
||||
return this.filterData2(
|
||||
return await this.filterData(
|
||||
await Promise.all(
|
||||
this.createTask(this.deDuplication(list).map((item) => ({ hash: item.hash })))
|
||||
).then(([...datas]) => datas.flat())
|
||||
@@ -269,7 +268,7 @@ export default {
|
||||
headers: {
|
||||
'KG-RC': 1,
|
||||
'KG-THash': 'network_super_call.cpp:3676261689:379',
|
||||
'User-Agent': ''
|
||||
'User-Agent': '',
|
||||
},
|
||||
body: {
|
||||
appid: 1001,
|
||||
@@ -277,13 +276,13 @@ export default {
|
||||
mid: '21511157a05844bd085308bc76ef3343',
|
||||
clienttime: 640612895,
|
||||
key: '36164c4015e704673c588ee202b9ecb8',
|
||||
data: id
|
||||
}
|
||||
data: id,
|
||||
},
|
||||
})
|
||||
// console.log(songInfo)
|
||||
// type 1单曲,2歌单,3电台,4酷狗码,5别人的播放队列
|
||||
let songList
|
||||
const info = songInfo.info
|
||||
let info = songInfo.info
|
||||
switch (info.type) {
|
||||
case 2:
|
||||
if (!info.global_collection_id) return this.getListDetailBySpecialId(info.id)
|
||||
@@ -299,7 +298,7 @@ export default {
|
||||
headers: {
|
||||
'KG-RC': 1,
|
||||
'KG-THash': 'network_super_call.cpp:3676261689:379',
|
||||
'User-Agent': ''
|
||||
'User-Agent': '',
|
||||
},
|
||||
body: {
|
||||
appid: 1001,
|
||||
@@ -313,13 +312,13 @@ export default {
|
||||
userid: info.userid,
|
||||
collect_type: 0,
|
||||
page: 1,
|
||||
pagesize: info.count
|
||||
}
|
||||
}
|
||||
pagesize: info.count,
|
||||
},
|
||||
},
|
||||
})
|
||||
// console.log(songList)
|
||||
}
|
||||
const list = await this.getMusicInfos(songList || songInfo.list)
|
||||
let list = await this.getMusicInfos(songList || songInfo.list)
|
||||
return {
|
||||
list,
|
||||
page: 1,
|
||||
@@ -330,9 +329,9 @@ export default {
|
||||
name: info.name,
|
||||
img: (info.img_size && info.img_size.replace('{size}', 240)) || info.img,
|
||||
// desc: body.result.info.list_desc,
|
||||
author: info.username
|
||||
author: info.username,
|
||||
// play_count: formatPlayCount(info.count),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -342,8 +341,8 @@ export default {
|
||||
{
|
||||
headers: {
|
||||
'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'
|
||||
}
|
||||
'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',
|
||||
},
|
||||
}
|
||||
)
|
||||
if (!songInfo.list) {
|
||||
@@ -354,7 +353,7 @@ export default {
|
||||
this.getUserListDetail5(chain)
|
||||
)
|
||||
}
|
||||
const list = await this.getMusicInfos(songInfo.list)
|
||||
let list = await this.getMusicInfos(songInfo.list)
|
||||
// console.log(info, songInfo)
|
||||
return {
|
||||
list,
|
||||
@@ -366,14 +365,14 @@ export default {
|
||||
name: songInfo.info.name,
|
||||
img: songInfo.info.img,
|
||||
// desc: body.result.info.list_desc,
|
||||
author: songInfo.info.username
|
||||
author: songInfo.info.username,
|
||||
// play_count: formatPlayCount(info.count),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
deDuplication(datas) {
|
||||
const ids = new Set()
|
||||
let ids = new Set()
|
||||
return datas.filter(({ hash }) => {
|
||||
if (ids.has(hash)) return false
|
||||
ids.add(hash)
|
||||
@@ -388,29 +387,25 @@ export default {
|
||||
data: [
|
||||
{
|
||||
id: gcid,
|
||||
id_type: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
const result = await this.createHttp(
|
||||
`https://t.kugou.com/v1/songlist/batch_decode?${params}&signature=${signatureParams(params, 'android', JSON.stringify(body))}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Linux; Android 10; HUAWEI HMA-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Mobile Safari/537.36',
|
||||
Referer: 'https://m.kugou.com/'
|
||||
id_type: 2,
|
||||
},
|
||||
body
|
||||
}
|
||||
)
|
||||
],
|
||||
}
|
||||
const result = await this.createHttp(`https://t.kugou.com/v1/songlist/batch_decode?${params}&signature=${signatureParams(params, 'android', JSON.stringify(body))}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; HUAWEI HMA-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Mobile Safari/537.36',
|
||||
Referer: 'https://m.kugou.com/',
|
||||
},
|
||||
body,
|
||||
})
|
||||
return result.list[0].global_collection_id
|
||||
},
|
||||
|
||||
async getUserListDetailByLink({ info }, link) {
|
||||
const listInfo = info['0']
|
||||
let listInfo = info['0']
|
||||
let total = listInfo.count
|
||||
const tasks = []
|
||||
let tasks = []
|
||||
let page = 0
|
||||
while (total) {
|
||||
const limit = total > 90 ? 90 : total
|
||||
@@ -423,8 +418,8 @@ export default {
|
||||
headers: {
|
||||
'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',
|
||||
Referer: link
|
||||
}
|
||||
Referer: link,
|
||||
},
|
||||
}
|
||||
).then((data) => data.list.info)
|
||||
)
|
||||
@@ -442,13 +437,13 @@ export default {
|
||||
name: listInfo.name,
|
||||
img: listInfo.pic && listInfo.pic.replace('{size}', 240),
|
||||
// desc: body.result.info.list_desc,
|
||||
author: listInfo.list_create_username
|
||||
author: listInfo.list_create_username,
|
||||
// play_count: formatPlayCount(listInfo.count),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
createGetListDetail2Task(id, total) {
|
||||
const tasks = []
|
||||
let tasks = []
|
||||
let page = 0
|
||||
while (total) {
|
||||
const limit = total > 300 ? 300 : total
|
||||
@@ -464,7 +459,10 @@ export default {
|
||||
'&srcappid=2919&clientver=20000&clienttime=1586163263991&mid=1586163263991&uuid=1586163263991&dfid=-'
|
||||
tasks.push(
|
||||
this.createHttp(
|
||||
`https://mobiles.kugou.com/api/v5/special/song_v2?${params}&signature=${signatureParams(params, 'web')}`,
|
||||
`https://mobiles.kugou.com/api/v5/special/song_v2?${params}&signature=${signatureParams(
|
||||
params,
|
||||
'web'
|
||||
)}`,
|
||||
{
|
||||
headers: {
|
||||
mid: '1586163263991',
|
||||
@@ -472,8 +470,8 @@ export default {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
|
||||
dfid: '-',
|
||||
clienttime: '1586163263991'
|
||||
}
|
||||
clienttime: '1586163263991',
|
||||
},
|
||||
}
|
||||
).then((data) => data.info)
|
||||
)
|
||||
@@ -481,14 +479,17 @@ export default {
|
||||
return Promise.all(tasks).then(([...datas]) => datas.flat())
|
||||
},
|
||||
async getUserListDetail2(global_collection_id) {
|
||||
const id = global_collection_id
|
||||
let id = global_collection_id
|
||||
if (id.length > 1000) throw new Error('get list error')
|
||||
const params =
|
||||
'appid=1058&specialid=0&global_specialid=' +
|
||||
id +
|
||||
'&format=jsonp&srcappid=2919&clientver=20000&clienttime=1586163242519&mid=1586163242519&uuid=1586163242519&dfid=-'
|
||||
const info = await this.createHttp(
|
||||
`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 'web')}`,
|
||||
let info = await this.createHttp(
|
||||
`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(
|
||||
params,
|
||||
'web'
|
||||
)}`,
|
||||
{
|
||||
headers: {
|
||||
mid: '1586163242519',
|
||||
@@ -496,12 +497,12 @@ export default {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
|
||||
dfid: '-',
|
||||
clienttime: '1586163242519'
|
||||
}
|
||||
clienttime: '1586163242519',
|
||||
},
|
||||
}
|
||||
)
|
||||
const songInfo = await this.createGetListDetail2Task(id, info.songcount)
|
||||
const list = await this.getMusicInfos(songInfo)
|
||||
let list = await this.getMusicInfos(songInfo)
|
||||
// console.log(info, songInfo, list)
|
||||
return {
|
||||
list,
|
||||
@@ -514,8 +515,8 @@ export default {
|
||||
img: info.imgurl && info.imgurl.replace('{size}', 240),
|
||||
desc: info.intro,
|
||||
author: info.nickname,
|
||||
play_count: formatPlayCount(info.playcount)
|
||||
}
|
||||
play_count: formatPlayCount(info.playcount),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -524,8 +525,8 @@ export default {
|
||||
const { body } = await httpFetch(`https://m.kugou.com/share/?chain=${chain}&id=${chain}`, {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
|
||||
}
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
|
||||
},
|
||||
}).promise
|
||||
let result = body.match(/var\sphpParam\s=\s({.+?});/)
|
||||
if (result) result = JSON.parse(result[1])
|
||||
@@ -534,13 +535,13 @@ export default {
|
||||
},
|
||||
|
||||
async getUserListDetailByPcChain(chain) {
|
||||
const key = `${chain}_pc_list`
|
||||
let key = `${chain}_pc_list`
|
||||
if (this.cache.has(key)) return this.cache.get(key)
|
||||
const { body } = await httpFetch(`http://www.kugou.com/share/${chain}.html`, {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
|
||||
}
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
|
||||
},
|
||||
}).promise
|
||||
let result = body.match(/var\sdataFromSmarty\s=\s(\[.+?\])/)
|
||||
if (result) result = JSON.parse(result[1])
|
||||
@@ -554,7 +555,7 @@ export default {
|
||||
const limit = 100
|
||||
const [listInfo, list] = await Promise.all([
|
||||
this.getListInfoByChain(chain),
|
||||
this.getUserListDetailById(songInfo.id, page, limit)
|
||||
this.getUserListDetailById(songInfo.id, page, limit),
|
||||
])
|
||||
return {
|
||||
list: list || [],
|
||||
@@ -566,16 +567,16 @@ export default {
|
||||
name: listInfo.specialname,
|
||||
img: listInfo.imgurl && listInfo.imgurl.replace('{size}', 240),
|
||||
// desc: body.result.info.list_desc,
|
||||
author: listInfo.nickname
|
||||
author: listInfo.nickname,
|
||||
// play_count: formatPlayCount(info.count),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
async getUserListDetail5(chain) {
|
||||
const [listInfo, list] = await Promise.all([
|
||||
this.getListInfoByChain(chain),
|
||||
this.getUserListDetailByPcChain(chain)
|
||||
this.getUserListDetailByPcChain(chain),
|
||||
])
|
||||
return {
|
||||
list: list || [],
|
||||
@@ -587,28 +588,28 @@ export default {
|
||||
name: listInfo.specialname,
|
||||
img: listInfo.imgurl && listInfo.imgurl.replace('{size}', 240),
|
||||
// desc: body.result.info.list_desc,
|
||||
author: listInfo.nickname
|
||||
author: listInfo.nickname,
|
||||
// play_count: formatPlayCount(info.count),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
async getUserListDetailById(id, page, limit) {
|
||||
const signature = await handleSignature(id, page, limit)
|
||||
const info = await this.createHttp(
|
||||
let info = await this.createHttp(
|
||||
`https://pubsongscdn.kugou.com/v2/get_other_list_file?srcappid=2919&clientver=20000&appid=1058&type=0&module=playlist&page=${page}&pagesize=${limit}&specialid=${id}&signature=${signature}`,
|
||||
{
|
||||
headers: {
|
||||
Referer: 'https://m3ws.kugou.com/share/index.php',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
|
||||
dfid: '-'
|
||||
}
|
||||
dfid: '-',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// console.log(info)
|
||||
const result = await this.getMusicInfos(info.info)
|
||||
let result = await this.getMusicInfos(info.info)
|
||||
// console.log(info, songInfo)
|
||||
return result
|
||||
},
|
||||
@@ -616,19 +617,15 @@ export default {
|
||||
async getUserListDetail(link, page, retryNum = 0) {
|
||||
if (retryNum > 3) return Promise.reject(new Error('link try max num'))
|
||||
if (link.includes('#')) link = link.replace(/#.*$/, '')
|
||||
if (link.includes('global_collection_id'))
|
||||
return this.getUserListDetail2(
|
||||
link.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1')
|
||||
)
|
||||
if (link.includes('global_collection_id')) return this.getUserListDetail2(link.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'))
|
||||
if (link.includes('gcid_')) {
|
||||
const gcid = link.match(/gcid_\w+/)?.[0]
|
||||
let gcid = link.match(/gcid_\w+/)?.[0]
|
||||
if (gcid) {
|
||||
const global_collection_id = await this.decodeGcid(gcid)
|
||||
if (global_collection_id) return this.getUserListDetail2(global_collection_id)
|
||||
}
|
||||
}
|
||||
if (link.includes('chain='))
|
||||
return this.getUserListDetail3(link.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (link.includes('chain=')) return this.getUserListDetail3(link.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (link.includes('.html')) {
|
||||
if (link.includes('zlist.html')) {
|
||||
link = link.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
|
||||
@@ -650,34 +647,27 @@ export default {
|
||||
headers: {
|
||||
'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',
|
||||
Referer: link
|
||||
}
|
||||
Referer: link,
|
||||
},
|
||||
})
|
||||
const {
|
||||
headers: { location },
|
||||
statusCode,
|
||||
body
|
||||
body,
|
||||
} = await requestObj_listDetailLink.promise
|
||||
// console.log(body, location)
|
||||
if (statusCode > 400) return this.getUserListDetail(link, page, ++retryNum)
|
||||
if (location) {
|
||||
// console.log(location)
|
||||
if (location.includes('global_collection_id'))
|
||||
return this.getUserListDetail2(
|
||||
location.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1')
|
||||
)
|
||||
if (location.includes('global_collection_id')) return this.getUserListDetail2(location.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'))
|
||||
if (location.includes('gcid_')) {
|
||||
const gcid = link.match(/gcid_\w+/)?.[0]
|
||||
let gcid = link.match(/gcid_\w+/)?.[0]
|
||||
if (gcid) {
|
||||
const global_collection_id = await this.decodeGcid(gcid)
|
||||
if (global_collection_id) return this.getUserListDetail2(global_collection_id)
|
||||
}
|
||||
}
|
||||
if (location.includes('chain='))
|
||||
return this.getUserListDetail3(
|
||||
location.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'),
|
||||
page
|
||||
)
|
||||
if (location.includes('chain=')) return this.getUserListDetail3(location.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (location.includes('.html')) {
|
||||
if (location.includes('zlist.html')) {
|
||||
let link = location.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
|
||||
@@ -698,7 +688,7 @@ export default {
|
||||
// console.log('location', location)
|
||||
return this.getUserListDetail(location, page, ++retryNum)
|
||||
}
|
||||
if (typeof body === 'string') {
|
||||
if (typeof body == 'string') {
|
||||
let global_collection_id = body.match(/"global_collection_id":"(\w+)"/)?.[1]
|
||||
if (!global_collection_id) {
|
||||
let gcid = body.match(/"encode_gic":"(\w+)"/)?.[1]
|
||||
@@ -729,184 +719,9 @@ export default {
|
||||
|
||||
return this.getListDetailBySpecialId(id, page)
|
||||
},
|
||||
filterData(rawList) {
|
||||
// console.log(rawList)
|
||||
return rawList.map((item) => {
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.filesize !== 0) {
|
||||
const size = sizeFormate(item.filesize)
|
||||
types.push({ type: '128k', size, hash: item.hash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: item.hash
|
||||
}
|
||||
}
|
||||
if (item.filesize_320 !== 0) {
|
||||
const size = sizeFormate(item.filesize_320)
|
||||
types.push({ type: '320k', size, hash: item.hash_320 })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: item.hash_320
|
||||
}
|
||||
}
|
||||
if (item.filesize_ape !== 0) {
|
||||
const size = sizeFormate(item.filesize_ape)
|
||||
types.push({ type: 'ape', size, hash: item.hash_ape })
|
||||
_types.ape = {
|
||||
size,
|
||||
hash: item.hash_ape
|
||||
}
|
||||
}
|
||||
if (item.filesize_flac !== 0) {
|
||||
const size = sizeFormate(item.filesize_flac)
|
||||
types.push({ type: 'flac', size, hash: item.hash_flac })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: item.hash_flac
|
||||
}
|
||||
}
|
||||
return {
|
||||
singer: decodeName(item.singername),
|
||||
name: decodeName(item.songname),
|
||||
albumName: decodeName(item.album_name),
|
||||
albumId: item.album_id,
|
||||
songmid: item.audio_id,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(item.duration / 1000),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.hash,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
},
|
||||
// getSinger(singers) {
|
||||
// let arr = []
|
||||
// singers?.forEach(singer => {
|
||||
// arr.push(singer.name)
|
||||
// })
|
||||
// return arr.join('、')
|
||||
// },
|
||||
// v9 API
|
||||
// filterDatav9(rawList) {
|
||||
// console.log(rawList)
|
||||
// return rawList.map(item => {
|
||||
// const types = []
|
||||
// const _types = {}
|
||||
// item.relate_goods.forEach(qualityObj => {
|
||||
// if (qualityObj.level === 2) {
|
||||
// let size = sizeFormate(qualityObj.size)
|
||||
// types.push({ type: '128k', size, hash: qualityObj.hash })
|
||||
// _types['128k'] = {
|
||||
// size,
|
||||
// hash: qualityObj.hash,
|
||||
// }
|
||||
// } else if (qualityObj.level === 4) {
|
||||
// let size = sizeFormate(qualityObj.size)
|
||||
// types.push({ type: '320k', size, hash: qualityObj.hash })
|
||||
// _types['320k'] = {
|
||||
// size,
|
||||
// hash: qualityObj.hash,
|
||||
// }
|
||||
// } else if (qualityObj.level === 5) {
|
||||
// let size = sizeFormate(qualityObj.size)
|
||||
// types.push({ type: 'flac', size, hash: qualityObj.hash })
|
||||
// _types.flac = {
|
||||
// size,
|
||||
// hash: qualityObj.hash,
|
||||
// }
|
||||
// } else if (qualityObj.level === 6) {
|
||||
// let size = sizeFormate(qualityObj.size)
|
||||
// types.push({ type: 'flac24bit', size, hash: qualityObj.hash })
|
||||
// _types.flac24bit = {
|
||||
// size,
|
||||
// hash: qualityObj.hash,
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// const nameInfo = item.name.split(' - ')
|
||||
// return {
|
||||
// singer: this.getSinger(item.singerinfo),
|
||||
// name: decodeName((nameInfo[1] ?? nameInfo[0]).trim()),
|
||||
// albumName: decodeName(item.albuminfo.name),
|
||||
// albumId: item.albuminfo.id,
|
||||
// songmid: item.audio_id,
|
||||
// source: 'kg',
|
||||
// interval: formatPlayTime(item.timelen / 1000),
|
||||
// img: null,
|
||||
// lrc: null,
|
||||
// hash: item.hash,
|
||||
// types,
|
||||
// _types,
|
||||
// typeUrl: {},
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
|
||||
// hash list filter
|
||||
filterData2(rawList) {
|
||||
// console.log(rawList)
|
||||
const ids = new Set()
|
||||
const list = []
|
||||
rawList.forEach((item) => {
|
||||
if (!item) return
|
||||
if (ids.has(item.audio_info.audio_id)) return
|
||||
ids.add(item.audio_info.audio_id)
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.audio_info.filesize !== '0') {
|
||||
const size = sizeFormate(parseInt(item.audio_info.filesize))
|
||||
types.push({ type: '128k', size, hash: item.audio_info.hash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: item.audio_info.hash
|
||||
}
|
||||
}
|
||||
if (item.audio_info.filesize_320 !== '0') {
|
||||
const size = sizeFormate(parseInt(item.audio_info.filesize_320))
|
||||
types.push({ type: '320k', size, hash: item.audio_info.hash_320 })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: item.audio_info.hash_320
|
||||
}
|
||||
}
|
||||
if (item.audio_info.filesize_flac !== '0') {
|
||||
const size = sizeFormate(parseInt(item.audio_info.filesize_flac))
|
||||
types.push({ type: 'flac', size, hash: item.audio_info.hash_flac })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: item.audio_info.hash_flac
|
||||
}
|
||||
}
|
||||
if (item.audio_info.filesize_high !== '0') {
|
||||
const size = sizeFormate(parseInt(item.audio_info.filesize_high))
|
||||
types.push({ type: 'flac24bit', size, hash: item.audio_info.hash_high })
|
||||
_types.flac24bit = {
|
||||
size,
|
||||
hash: item.audio_info.hash_high
|
||||
}
|
||||
}
|
||||
list.push({
|
||||
singer: decodeName(item.author_name),
|
||||
name: decodeName(item.songname),
|
||||
albumName: decodeName(item.album_info.album_name),
|
||||
albumId: item.album_info.album_id,
|
||||
songmid: item.audio_info.audio_id,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(parseInt(item.audio_info.timelength) / 1000),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.audio_info.hash,
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
})
|
||||
})
|
||||
return list
|
||||
async filterData(rawList) {
|
||||
return await filterData(rawList, { removeDuplicates: true, fix: true })
|
||||
},
|
||||
|
||||
// 获取列表信息
|
||||
@@ -920,14 +735,14 @@ export default {
|
||||
limit: body.data.params.pagesize,
|
||||
page: body.data.params.p,
|
||||
total: body.data.params.total,
|
||||
source: 'kg'
|
||||
source: 'kg',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page) {
|
||||
const tasks = [this.getSongList(sortId, tagId, page)]
|
||||
let tasks = [this.getSongList(sortId, tagId, page)]
|
||||
tasks.push(
|
||||
this.currentTagInfo.id === tagId
|
||||
? Promise.resolve(this.currentTagInfo.info)
|
||||
@@ -943,7 +758,7 @@ export default {
|
||||
if (recommendList) list.unshift(...recommendList)
|
||||
return {
|
||||
list,
|
||||
...info
|
||||
...info,
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -958,13 +773,13 @@ export default {
|
||||
return {
|
||||
hotTag: this.filterInfoHotTag(body.data.hotTag),
|
||||
tags: this.filterTagInfo(body.data.tagids),
|
||||
source: 'kg'
|
||||
source: 'kg',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getDetailPageUrl(id) {
|
||||
if (typeof id === 'string') {
|
||||
if (typeof id == 'string') {
|
||||
if (/^https?:\/\//.test(id)) return id
|
||||
id = id.replace('id_', '')
|
||||
}
|
||||
@@ -975,7 +790,9 @@ export default {
|
||||
// http://msearchretry.kugou.com/api/v3/search/special?version=9209&keyword=%E5%91%A8%E6%9D%B0%E4%BC%A6&pagesize=20&filter=0&page=1&sver=2&with_res_tag=0
|
||||
// return httpFetch(`http://ioscdn.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&plat=2&version=7910&correct=1&sver=5`)
|
||||
return httpFetch(
|
||||
`http://msearchretry.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&filter=0&version=7910&sver=2`
|
||||
`http://msearchretry.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(
|
||||
text
|
||||
)}&page=${page}&pagesize=${limit}&showtype=10&filter=0&version=7910&sver=2`
|
||||
).promise.then(({ body }) => {
|
||||
if (body.errcode != 0) throw new Error('filed')
|
||||
// console.log(body.data.info)
|
||||
@@ -991,17 +808,17 @@ export default {
|
||||
grade: item.grade,
|
||||
desc: item.intro,
|
||||
total: item.songcount,
|
||||
source: 'kg'
|
||||
source: 'kg',
|
||||
}
|
||||
}),
|
||||
limit,
|
||||
total: body.data.total,
|
||||
source: 'kg'
|
||||
source: 'kg',
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
// getListDetail
|
||||
@@ -1,13 +1,13 @@
|
||||
// import '../../polyfill/array.find'
|
||||
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, decodeName } from '../index'
|
||||
import { formatPlayTime, decodeName } from '../../index'
|
||||
// import { debug } from '../../utils/env'
|
||||
import { formatSinger } from './util'
|
||||
|
||||
export default {
|
||||
regExps: {
|
||||
mInfo: /level:(\w+),bitrate:(\d+),format:(\w+),size:([\w.]+)/
|
||||
mInfo: /level:(\w+),bitrate:(\d+),format:(\w+),size:([\w.]+)/,
|
||||
},
|
||||
limit: 30,
|
||||
total: 0,
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
// console.log(rawData)
|
||||
for (let i = 0; i < rawData.length; i++) {
|
||||
const info = rawData[i]
|
||||
const songId = info.MUSICRID.replace('MUSIC_', '')
|
||||
let songId = info.MUSICRID.replace('MUSIC_', '')
|
||||
// const format = (info.FORMATS || info.formats).split('|')
|
||||
|
||||
if (!info.N_MINFO) {
|
||||
@@ -43,33 +43,39 @@ export default {
|
||||
const types = []
|
||||
const _types = {}
|
||||
|
||||
const infoArr = info.N_MINFO.split(';')
|
||||
let infoArr = info.N_MINFO.split(';')
|
||||
for (let info of infoArr) {
|
||||
info = info.match(this.regExps.mInfo)
|
||||
if (info) {
|
||||
switch (info[2]) {
|
||||
case '20900':
|
||||
types.push({ type: 'master', size: info[4] })
|
||||
_types.master = {
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '4000':
|
||||
types.push({ type: 'flac24bit', size: info[4] })
|
||||
_types.flac24bit = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
types.push({ type: 'hires', size: info[4] })
|
||||
_types.hires = {
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '2000':
|
||||
types.push({ type: 'flac', size: info[4] })
|
||||
_types.flac = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '320':
|
||||
types.push({ type: '320k', size: info[4] })
|
||||
_types['320k'] = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '128':
|
||||
types.push({ type: '128k', size: info[4] })
|
||||
_types['128k'] = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -77,7 +83,7 @@ export default {
|
||||
}
|
||||
types.reverse()
|
||||
|
||||
const interval = parseInt(info.DURATION)
|
||||
let interval = parseInt(info.DURATION)
|
||||
|
||||
result.push({
|
||||
name: decodeName(info.SONGNAME),
|
||||
@@ -95,7 +101,7 @@ export default {
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
typeUrl: {},
|
||||
})
|
||||
}
|
||||
// console.log(result)
|
||||
@@ -109,7 +115,7 @@ export default {
|
||||
// console.log(result)
|
||||
if (!result || (result.TOTAL !== '0' && result.SHOW === '0'))
|
||||
return this.search(str, page, limit, ++retryNum)
|
||||
const list = this.handleResult(result.abslist)
|
||||
let list = this.handleResult(result.abslist)
|
||||
|
||||
if (list == null) return this.search(str, page, limit, ++retryNum)
|
||||
|
||||
@@ -122,8 +128,8 @@ export default {
|
||||
allPage: this.allPage,
|
||||
total: this.total,
|
||||
limit,
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, decodeName } from '../index'
|
||||
import { formatPlayTime, decodeName } from '../../index'
|
||||
import { formatSinger, objStr2JSON } from './util'
|
||||
import album from './album'
|
||||
|
||||
@@ -13,18 +13,18 @@ export default {
|
||||
sortList: [
|
||||
{
|
||||
name: '最新',
|
||||
id: 'new'
|
||||
id: 'new',
|
||||
},
|
||||
{
|
||||
name: '最热',
|
||||
id: 'hot'
|
||||
}
|
||||
id: 'hot',
|
||||
},
|
||||
],
|
||||
regExps: {
|
||||
mInfo: /level:(\w+),bitrate:(\d+),format:(\w+),size:([\w.]+)/,
|
||||
// http://www.kuwo.cn/playlist_detail/2886046289
|
||||
// https://m.kuwo.cn/h5app/playlist/2736267853?t=qqfriend
|
||||
listDetailLink: /^.+\/playlist(?:_detail)?\/(\d+)(?:\?.*|&.*$|#.*$|$)/
|
||||
listDetailLink: /^.+\/playlist(?:_detail)?\/(\d+)(?:\?.*|&.*$|#.*$|$)/,
|
||||
},
|
||||
tagsUrl:
|
||||
'http://wapi.kuwo.cn/api/pc/classify/playlist/getTagList?cmd=rcm_keyword_playlist&user=0&prod=kwplayer_pc_9.0.5.0&vipver=9.0.5.0&source=kwplayer_pc_9.0.5.0&loginUid=0&loginSid=0&appUid=76039576',
|
||||
@@ -43,7 +43,9 @@ export default {
|
||||
},
|
||||
getListDetailUrl(id, page) {
|
||||
// http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=2858093057&pn=0&rn=100&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1
|
||||
return `http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}&rn=${this.limit_song}&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1`
|
||||
return `http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}&rn=${
|
||||
this.limit_song
|
||||
}&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1`
|
||||
// http://mobileinterfaces.kuwo.cn/er.s?type=get_pc_qz_data&f=web&id=140&prod=pc
|
||||
},
|
||||
|
||||
@@ -72,7 +74,7 @@ export default {
|
||||
return rawList.map((item) => ({
|
||||
id: `${item.id}-${item.digest}`,
|
||||
name: item.name,
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}))
|
||||
},
|
||||
filterTagInfo(rawList) {
|
||||
@@ -83,8 +85,8 @@ export default {
|
||||
parent_name: type.name,
|
||||
id: `${item.id}-${item.digest}`,
|
||||
name: item.name,
|
||||
source: 'kw'
|
||||
}))
|
||||
source: 'kw',
|
||||
})),
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -95,7 +97,7 @@ export default {
|
||||
let id
|
||||
let type
|
||||
if (tagId) {
|
||||
const arr = tagId.split('-')
|
||||
let arr = tagId.split('-')
|
||||
id = arr[0]
|
||||
type = arr[1]
|
||||
} else {
|
||||
@@ -110,7 +112,7 @@ export default {
|
||||
total: body.data.total,
|
||||
page: body.data.pn,
|
||||
limit: body.data.rn,
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}
|
||||
} else if (!body.length) {
|
||||
return this.getList(sortId, tagId, page, ++tryNum)
|
||||
@@ -120,7 +122,7 @@ export default {
|
||||
total: 1000,
|
||||
page,
|
||||
limit: 1000,
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -145,7 +147,7 @@ export default {
|
||||
img: item.img,
|
||||
grade: item.favorcnt / 10,
|
||||
desc: item.desc,
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}))
|
||||
},
|
||||
filterList2(rawData) {
|
||||
@@ -164,7 +166,7 @@ export default {
|
||||
img: item.img,
|
||||
grade: item.favorcnt && item.favorcnt / 10,
|
||||
desc: item.desc,
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}))
|
||||
)
|
||||
})
|
||||
@@ -188,8 +190,8 @@ export default {
|
||||
img: body.pic,
|
||||
desc: body.info,
|
||||
author: body.uname,
|
||||
play_count: this.formatPlayCount(body.playnum)
|
||||
}
|
||||
play_count: this.formatPlayCount(body.playnum),
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -207,7 +209,9 @@ export default {
|
||||
getListDetailDigest5Music(id, page, tryNum = 0) {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
const requestObj = httpFetch(
|
||||
`http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}}&rn=${this.limit_song}&encode=utf-8&keyset=pl2012&identity=kuwo&pcmp4=1`
|
||||
`http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}}&rn=${
|
||||
this.limit_song
|
||||
}&encode=utf-8&keyset=pl2012&identity=kuwo&pcmp4=1`
|
||||
)
|
||||
return requestObj.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
@@ -223,8 +227,8 @@ export default {
|
||||
img: body.pic,
|
||||
desc: body.info,
|
||||
author: body.uname,
|
||||
play_count: this.formatPlayCount(body.playnum)
|
||||
}
|
||||
play_count: this.formatPlayCount(body.playnum),
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -235,33 +239,33 @@ export default {
|
||||
|
||||
filterBDListDetail(rawList) {
|
||||
return rawList.map((item) => {
|
||||
const types = []
|
||||
const _types = {}
|
||||
for (const info of item.audios) {
|
||||
let types = []
|
||||
let _types = {}
|
||||
for (let info of item.audios) {
|
||||
info.size = info.size?.toLocaleUpperCase()
|
||||
switch (info.bitrate) {
|
||||
case '4000':
|
||||
types.push({ type: 'flac24bit', size: info.size })
|
||||
_types.flac24bit = {
|
||||
size: info.size
|
||||
size: info.size,
|
||||
}
|
||||
break
|
||||
case '2000':
|
||||
types.push({ type: 'flac', size: info.size })
|
||||
_types.flac = {
|
||||
size: info.size
|
||||
size: info.size,
|
||||
}
|
||||
break
|
||||
case '320':
|
||||
types.push({ type: '320k', size: info.size })
|
||||
_types['320k'] = {
|
||||
size: info.size
|
||||
size: info.size,
|
||||
}
|
||||
break
|
||||
case '128':
|
||||
types.push({ type: '128k', size: info.size })
|
||||
_types['128k'] = {
|
||||
size: info.size
|
||||
size: info.size,
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -282,7 +286,7 @@ export default {
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
typeUrl: {},
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -299,8 +303,8 @@ export default {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
|
||||
plat: 'h5'
|
||||
}
|
||||
plat: 'h5',
|
||||
},
|
||||
}
|
||||
).promise.catch(() => ({ code: 0 }))
|
||||
|
||||
@@ -311,7 +315,7 @@ export default {
|
||||
img: infoData.data.pic,
|
||||
desc: infoData.data.description,
|
||||
author: infoData.data.creatorName,
|
||||
play_count: infoData.data.playNum
|
||||
play_count: infoData.data.playNum,
|
||||
}
|
||||
},
|
||||
async getListDetailMusicListByBDUserPub(id) {
|
||||
@@ -321,8 +325,8 @@ export default {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
|
||||
plat: 'h5'
|
||||
}
|
||||
plat: 'h5',
|
||||
},
|
||||
}
|
||||
).promise.catch(() => ({ code: 0 }))
|
||||
|
||||
@@ -334,18 +338,20 @@ export default {
|
||||
img: infoData.data.userInfo.headImg,
|
||||
desc: '',
|
||||
author: infoData.data.userInfo.nickname,
|
||||
play_count: ''
|
||||
play_count: '',
|
||||
}
|
||||
},
|
||||
async getListDetailMusicListByBDList(id, source, page, tryNum = 0) {
|
||||
const { body: listData } = await httpFetch(
|
||||
`https://bd-api.kuwo.cn/api/service/playlist/${id}/musicList?reqId=${this.getReqId()}&source=${source}&pn=${page}&rn=${this.limit_song}`,
|
||||
`https://bd-api.kuwo.cn/api/service/playlist/${id}/musicList?reqId=${this.getReqId()}&source=${source}&pn=${page}&rn=${
|
||||
this.limit_song
|
||||
}`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
|
||||
plat: 'h5'
|
||||
}
|
||||
plat: 'h5',
|
||||
},
|
||||
}
|
||||
).promise.catch(() => {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
@@ -359,7 +365,7 @@ export default {
|
||||
page,
|
||||
limit: listData.data.pageSize,
|
||||
total: listData.data.total,
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}
|
||||
},
|
||||
async getListDetailMusicListByBD(id, page) {
|
||||
@@ -383,7 +389,7 @@ export default {
|
||||
img: '',
|
||||
desc: '',
|
||||
author: '',
|
||||
play_count: ''
|
||||
play_count: '',
|
||||
}
|
||||
// console.log(listData)
|
||||
return listData
|
||||
@@ -415,35 +421,53 @@ export default {
|
||||
filterListDetail(rawData) {
|
||||
// console.log(rawData)
|
||||
return rawData.map((item) => {
|
||||
const infoArr = item.N_MINFO.split(';')
|
||||
const types = []
|
||||
const _types = {}
|
||||
let infoArr = item.N_MINFO.split(';')
|
||||
let types = []
|
||||
let _types = {}
|
||||
for (let info of infoArr) {
|
||||
info = info.match(this.regExps.mInfo)
|
||||
if (info) {
|
||||
switch (info[2]) {
|
||||
case '20900':
|
||||
types.push({ type: 'master', size: info[4] })
|
||||
_types.master = {
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '20501':
|
||||
types.push({ type: 'atmos_plus', size: info[4] })
|
||||
_types.atmos_plus = {
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '20201':
|
||||
types.push({ type: 'atmos', size: info[4] })
|
||||
_types.atmos = {
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '4000':
|
||||
types.push({ type: 'flac24bit', size: info[4] })
|
||||
types.push({ type: 'hires', size: info[4] })
|
||||
_types.flac24bit = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '2000':
|
||||
types.push({ type: 'flac', size: info[4] })
|
||||
_types.flac = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '320':
|
||||
types.push({ type: '320k', size: info[4] })
|
||||
_types['320k'] = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
case '128':
|
||||
types.push({ type: '128k', size: info[4] })
|
||||
_types['128k'] = {
|
||||
size: info[4].toLocaleUpperCase()
|
||||
size: info[4].toLocaleUpperCase(),
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -464,7 +488,7 @@ export default {
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
typeUrl: {},
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -472,13 +496,13 @@ export default {
|
||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({
|
||||
tags,
|
||||
hotTag,
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}))
|
||||
},
|
||||
getDetailPageUrl(id) {
|
||||
if (/[?&:/]/.test(id)) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
else if (/^digest-/.test(id)) {
|
||||
const result = id.split('__')
|
||||
let result = id.split('__')
|
||||
id = result[1]
|
||||
}
|
||||
return `http://www.kuwo.cn/playlist_detail/${id}`
|
||||
@@ -486,7 +510,9 @@ export default {
|
||||
|
||||
search(text, page, limit = 20) {
|
||||
return httpFetch(
|
||||
`http://search.kuwo.cn/r.s?all=${encodeURIComponent(text)}&pn=${page - 1}&rn=${limit}&rformat=json&encoding=utf8&ver=mbox&vipver=MUSIC_8.7.7.0_BCS37&plat=pc&devid=28156413&ft=playlist&pay=0&needliveshow=0`
|
||||
`http://search.kuwo.cn/r.s?all=${encodeURIComponent(text)}&pn=${
|
||||
page - 1
|
||||
}&rn=${limit}&rformat=json&encoding=utf8&ver=mbox&vipver=MUSIC_8.7.7.0_BCS37&plat=pc&devid=28156413&ft=playlist&pay=0&needliveshow=0`
|
||||
).promise.then(({ body }) => {
|
||||
body = objStr2JSON(body)
|
||||
// console.log(body)
|
||||
@@ -501,17 +527,17 @@ export default {
|
||||
// time: item.publish_time,
|
||||
img: item.pic,
|
||||
desc: decodeName(item.intro),
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}
|
||||
}),
|
||||
limit,
|
||||
total: parseInt(body.TOTAL),
|
||||
source: 'kw'
|
||||
source: 'kw',
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
// getListDetail
|
||||
@@ -1,5 +1,5 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { sizeFormate, formatPlayTime } from '../index'
|
||||
import { sizeFormate, formatPlayTime } from '../../index'
|
||||
import { toMD5, formatSingerName } from '../utils'
|
||||
|
||||
export const createSignature = (time, str) => {
|
||||
@@ -17,100 +17,6 @@ export default {
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
|
||||
// 旧版API
|
||||
// musicSearch(str, page, limit) {
|
||||
// const searchRequest = httpFetch(`http://pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do?ua=Android_migu&version=5.0.1&text=${encodeURIComponent(str)}&pageNo=${page}&pageSize=${limit}&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22songlist%22%3A0%2C%22bestShow%22%3A1%7D`, {
|
||||
// searchRequest = httpFetch(`http://pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do?ua=Android_migu&version=5.0.1&text=${encodeURIComponent(str)}&pageNo=${page}&pageSize=${limit}&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22songlist%22%3A0%2C%22bestShow%22%3A1%7D`, {
|
||||
// searchRequest = httpFetch(`http://jadeite.migu.cn:7090/music_search/v2/search/searchAll?sid=4f87090d01c84984a11976b828e2b02c18946be88a6b4c47bcdc92fbd40762db&isCorrect=1&isCopyright=1&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A1%2C%22mvSong%22%3A0%2C%22bestShow%22%3A1%2C%22songlist%22%3A0%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(str)}&pageNo=${page}&sort=0`, {
|
||||
// searchRequest = httpFetch(`https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/search_all.do?isCopyright=1&isCorrect=1&pageNo=${page}&pageSize=${limit}&searchSwitch={%22song%22:1,%22album%22:0,%22singer%22:0,%22tagSong%22:0,%22mvSong%22:0,%22songlist%22:0,%22bestShow%22:0}&sort=0&text=${encodeURIComponent(str)}`)
|
||||
// // searchRequest = httpFetch(`http://jadeite.migu.cn:7090/music_search/v2/search/searchAll?sid=4f87090d01c84984a11976b828e2b02c18946be88a6b4c47bcdc92fbd40762db&isCorrect=1&isCopyright=1&searchSwitch=%7B%22song%22%3A1%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A1%2C%22mvSong%22%3A0%2C%22bestShow%22%3A1%2C%22songlist%22%3A0%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(str)}&pageNo=${page}&sort=0`, {
|
||||
// headers: {
|
||||
// // sign: 'c3b7ae985e2206e97f1b2de8f88691e2',
|
||||
// // timestamp: 1578225871982,
|
||||
// // appId: 'yyapp2',
|
||||
// // mode: 'android',
|
||||
// // ua: 'Android_migu',
|
||||
// // version: '6.9.4',
|
||||
// osVersion: 'android 7.0',
|
||||
// 'User-Agent': 'okhttp/3.9.1',
|
||||
// },
|
||||
// })
|
||||
// // searchRequest = httpFetch(`https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/search_all.do?isCopyright=1&isCorrect=1&pageNo=${page}&pageSize=${limit}&searchSwitch={%22song%22:1,%22album%22:0,%22singer%22:0,%22tagSong%22:0,%22mvSong%22:0,%22songlist%22:0,%22bestShow%22:0}&sort=0&text=${encodeURIComponent(str)}`)
|
||||
// return searchRequest.promise.then(({ body }) => body)
|
||||
// },
|
||||
// handleResult(rawData) {
|
||||
// // console.log(rawData)
|
||||
// let ids = new Set()
|
||||
// const list = []
|
||||
// rawData.forEach(item => {
|
||||
// if (ids.has(item.id)) return
|
||||
// ids.add(item.id)
|
||||
// const types = []
|
||||
// const _types = {}
|
||||
// item.newRateFormats && item.newRateFormats.forEach(type => {
|
||||
// let size
|
||||
// switch (type.formatType) {
|
||||
// case 'PQ':
|
||||
// size = sizeFormate(type.size ?? type.androidSize)
|
||||
// types.push({ type: '128k', size })
|
||||
// _types['128k'] = {
|
||||
// size,
|
||||
// }
|
||||
// break
|
||||
// case 'HQ':
|
||||
// size = sizeFormate(type.size ?? type.androidSize)
|
||||
// types.push({ type: '320k', size })
|
||||
// _types['320k'] = {
|
||||
// size,
|
||||
// }
|
||||
// break
|
||||
// case 'SQ':
|
||||
// size = sizeFormate(type.size ?? type.androidSize)
|
||||
// types.push({ type: 'flac', size })
|
||||
// _types.flac = {
|
||||
// size,
|
||||
// }
|
||||
// break
|
||||
// case 'ZQ':
|
||||
// size = sizeFormate(type.size ?? type.androidSize)
|
||||
// types.push({ type: 'flac24bit', size })
|
||||
// _types.flac24bit = {
|
||||
// size,
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
// })
|
||||
|
||||
// const albumNInfo = item.albums && item.albums.length
|
||||
// ? {
|
||||
// id: item.albums[0].id,
|
||||
// name: item.albums[0].name,
|
||||
// }
|
||||
// : {}
|
||||
|
||||
// list.push({
|
||||
// singer: this.getSinger(item.singers),
|
||||
// name: item.name,
|
||||
// albumName: albumNInfo.name,
|
||||
// albumId: albumNInfo.id,
|
||||
// songmid: item.songId,
|
||||
// copyrightId: item.copyrightId,
|
||||
// source: 'mg',
|
||||
// interval: null,
|
||||
// img: item.imgItems && item.imgItems.length ? item.imgItems[0].img : null,
|
||||
// lrc: null,
|
||||
// lrcUrl: item.lyricUrl,
|
||||
// mrcUrl: item.mrcurl,
|
||||
// trcUrl: item.trcUrl,
|
||||
// otherSource: null,
|
||||
// types,
|
||||
// _types,
|
||||
// typeUrl: {},
|
||||
// })
|
||||
// })
|
||||
// return list
|
||||
// },
|
||||
|
||||
musicSearch(str, page, limit) {
|
||||
const time = Date.now().toString()
|
||||
const signData = createSignature(time, str)
|
||||
@@ -124,8 +30,8 @@ export default {
|
||||
sign: signData.sign,
|
||||
channel: '0146921',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Linux; U; Android 11.0.0; zh-cn; MI 11 Build/OPR1.170623.032) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30'
|
||||
}
|
||||
'Mozilla/5.0 (Linux; U; Android 11.0.0; zh-cn; MI 11 Build/OPR1.170623.032) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
|
||||
},
|
||||
}
|
||||
)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
@@ -150,28 +56,28 @@ export default {
|
||||
size = sizeFormate(type.asize ?? type.isize)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'HQ':
|
||||
size = sizeFormate(type.asize ?? type.isize)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'SQ':
|
||||
size = sizeFormate(type.asize ?? type.isize)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
size,
|
||||
}
|
||||
break
|
||||
case 'ZQ24':
|
||||
size = sizeFormate(type.asize ?? type.isize)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
types.push({ type: 'hires', size })
|
||||
_types.hires = {
|
||||
size,
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -196,7 +102,7 @@ export default {
|
||||
trcUrl: data.trcUrl,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
typeUrl: {},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -212,7 +118,7 @@ export default {
|
||||
return Promise.reject(new Error(result ? result.info : '搜索失败'))
|
||||
const songResultData = result.songResultData || { resultList: [], totalCount: 0 }
|
||||
|
||||
const list = this.filterData(songResultData.resultList)
|
||||
let list = this.filterData(songResultData.resultList)
|
||||
if (list == null) return this.search(str, page, limit, retryNum)
|
||||
|
||||
this.total = parseInt(songResultData.totalCount)
|
||||
@@ -224,8 +130,8 @@ export default {
|
||||
allPage: this.allPage,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'mg'
|
||||
source: 'mg',
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { dateFormat, formatPlayCount } from '../index'
|
||||
import { dateFormat, formatPlayCount } from '../../index'
|
||||
import { filterMusicInfoList } from './musicInfo'
|
||||
import { createSignature } from './musicSearch'
|
||||
import { createHttpFetch } from './utils/index'
|
||||
@@ -17,14 +17,14 @@ export default {
|
||||
sortList: [
|
||||
{
|
||||
name: '推荐',
|
||||
id: '15127315'
|
||||
id: '15127315',
|
||||
// id: '1',
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
id: '15127272'
|
||||
id: '15127272',
|
||||
// id: '2',
|
||||
}
|
||||
},
|
||||
],
|
||||
regExps: {
|
||||
list: /<li><div class="thumb">.+?<\/li>/g,
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
/.+data-original="(.+?)".*data-id="(\d+)".*<div class="song-list-name"><a\s.*?>(.+?)<\/a>.+<i class="iconfont cf-bofangliang"><\/i>(.+?)<\/div>/,
|
||||
|
||||
// https://music.migu.cn/v3/music/playlist/161044573?page=1
|
||||
listDetailLink: /^.+\/playlist\/(\d+)(?:\?.*|&.*$|#.*$|$)/
|
||||
listDetailLink: /^.+\/playlist\/(\d+)(?:\?.*|&.*$|#.*$|$)/,
|
||||
},
|
||||
tagsUrl: 'https://app.c.nf.migu.cn/MIGUM3.0/v1.0/template/musiclistplaza-taglist/release',
|
||||
// tagsUrl: 'https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/indexTagPage.do?needAll=0',
|
||||
@@ -58,7 +58,7 @@ export default {
|
||||
defaultHeaders: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
|
||||
Referer: 'https://m.music.migu.cn/'
|
||||
Referer: 'https://m.music.migu.cn/',
|
||||
// language: 'Chinese',
|
||||
// ua: 'Android_migu',
|
||||
// mode: 'android',
|
||||
@@ -74,7 +74,7 @@ export default {
|
||||
} else if (/[?&:/]/.test(id)) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
|
||||
const requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id, page), {
|
||||
headers: this.defaultHeaders
|
||||
headers: this.defaultHeaders,
|
||||
})
|
||||
return requestObj_listDetail.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getListDetail(id, page, ++tryNum)
|
||||
@@ -85,7 +85,7 @@ export default {
|
||||
page,
|
||||
limit: this.limit_song,
|
||||
total: body.totalCount,
|
||||
source: 'mg'
|
||||
source: 'mg',
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
const requestObj_listDetailInfo = httpFetch(
|
||||
`https://c.musicapp.migu.cn/MIGUM3.0/resource/playlist/v2.0?playlistId=${id}`,
|
||||
{
|
||||
headers: this.defaultHeaders
|
||||
headers: this.defaultHeaders,
|
||||
}
|
||||
)
|
||||
return requestObj_listDetailInfo.promise.then(({ body }) => {
|
||||
@@ -109,7 +109,7 @@ export default {
|
||||
img: body.data.imgItem.img,
|
||||
desc: body.data.summary,
|
||||
author: body.data.ownerName,
|
||||
play_count: formatPlayCount(body.data.opNumItem.playNum)
|
||||
play_count: formatPlayCount(body.data.opNumItem.playNum),
|
||||
})
|
||||
return cachedDetailInfo
|
||||
})
|
||||
@@ -122,12 +122,12 @@ export default {
|
||||
headers: {
|
||||
'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',
|
||||
Referer: link
|
||||
}
|
||||
Referer: link,
|
||||
},
|
||||
})
|
||||
const {
|
||||
headers: { location },
|
||||
statusCode
|
||||
statusCode,
|
||||
} = await requestObj_listDetailLink.promise
|
||||
// console.log(body, location)
|
||||
if (statusCode > 400) return this.getDetailUrl(link, page, ++retryNum)
|
||||
@@ -153,7 +153,7 @@ export default {
|
||||
|
||||
return Promise.all([
|
||||
this.getListDetailList(id, page, retryNum),
|
||||
this.getListDetailInfo(id, retryNum)
|
||||
this.getListDetailInfo(id, retryNum),
|
||||
]).then(([listData, info]) => {
|
||||
listData.info = info
|
||||
return listData
|
||||
@@ -165,7 +165,7 @@ export default {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_list = httpFetch(this.getSongListUrl(sortId, tagId, page), {
|
||||
headers: this.defaultHeaders
|
||||
headers: this.defaultHeaders,
|
||||
// headers: {
|
||||
// sign: 'c3b7ae985e2206e97f1b2de8f88691e2',
|
||||
// timestamp: 1578225871982,
|
||||
@@ -205,7 +205,7 @@ export default {
|
||||
total: parseInt(body.retMsg.countSize),
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'mg'
|
||||
source: 'mg',
|
||||
}
|
||||
})
|
||||
// return this._requestObj_list.promise.then(({ body }) => {
|
||||
@@ -233,7 +233,7 @@ export default {
|
||||
grade: item.grade,
|
||||
total: item.contentCount,
|
||||
desc: item.summary,
|
||||
source: 'mg'
|
||||
source: 'mg',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -254,7 +254,7 @@ export default {
|
||||
hotTag: rawList[0].content.map(({ texts: [name, id] }) => ({
|
||||
id,
|
||||
name,
|
||||
source: 'mg'
|
||||
source: 'mg',
|
||||
})),
|
||||
tags: rawList.slice(1).map(({ header, content }) => ({
|
||||
name: header.title,
|
||||
@@ -263,10 +263,10 @@ export default {
|
||||
// parent_name: objectInfo.columnTitle,
|
||||
id,
|
||||
name,
|
||||
source: 'mg'
|
||||
}))
|
||||
source: 'mg',
|
||||
})),
|
||||
})),
|
||||
source: 'mg'
|
||||
source: 'mg',
|
||||
}
|
||||
// return {
|
||||
// hotTag: rawList[0].objectInfo.contents.map(item => ({
|
||||
@@ -313,7 +313,7 @@ export default {
|
||||
name: item.name,
|
||||
img: item.musicListPicUrl,
|
||||
total: item.musicNum,
|
||||
source: 'mg'
|
||||
source: 'mg',
|
||||
})
|
||||
})
|
||||
return list
|
||||
@@ -331,8 +331,8 @@ export default {
|
||||
sign: signResult.sign,
|
||||
channel: '0146921',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Linux; U; Android 11.0.0; zh-cn; MI 11 Build/OPR1.170623.032) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30'
|
||||
}
|
||||
'Mozilla/5.0 (Linux; U; Android 11.0.0; zh-cn; MI 11 Build/OPR1.170623.032) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
|
||||
},
|
||||
}
|
||||
).then((body) => {
|
||||
if (!body.songListResultData) throw new Error('get song list faild.')
|
||||
@@ -342,12 +342,12 @@ export default {
|
||||
list,
|
||||
limit,
|
||||
total: parseInt(body.songListResultData.totalCount),
|
||||
source: 'mg'
|
||||
source: 'mg',
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
// getListDetail
|
||||
@@ -1,8 +1,7 @@
|
||||
export const bHh = '624868746c'
|
||||
|
||||
export const headers = {
|
||||
'User-Agent': 'lx-music request',
|
||||
[bHh]: [bHh]
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
||||
}
|
||||
|
||||
export const timeout = 15000
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, sizeFormate } from '../index'
|
||||
import { formatPlayTime, sizeFormate } from '../../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
|
||||
export default {
|
||||
@@ -15,7 +15,7 @@ export default {
|
||||
const searchRequest = httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
|
||||
},
|
||||
body: {
|
||||
comm: {
|
||||
@@ -26,7 +26,7 @@ export default {
|
||||
phonetype: '0',
|
||||
devicelevel: '31',
|
||||
tmeAppID: 'qqmusiclight',
|
||||
nettype: 'NETWORK_WIFI'
|
||||
nettype: 'NETWORK_WIFI',
|
||||
},
|
||||
req: {
|
||||
module: 'music.search.SearchCgiService',
|
||||
@@ -37,10 +37,10 @@ export default {
|
||||
num_per_page: limit,
|
||||
page_num: page,
|
||||
nqc_flag: 0,
|
||||
grp: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
grp: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
// searchRequest = httpFetch(`http://ioscdn.kugou.com/api/v3/search/song?keyword=${encodeURIComponent(str)}&page=${page}&pagesize=${this.limit}&showtype=10&plat=2&version=7910&tag=1&correct=1&privilege=1&sver=5`)
|
||||
return searchRequest.promise.then(({ body }) => {
|
||||
@@ -56,35 +56,56 @@ export default {
|
||||
rawList.forEach((item) => {
|
||||
if (!item.file?.media_mid) return
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
let types = []
|
||||
let _types = {}
|
||||
const file = item.file
|
||||
if (file.size_128mp3 != 0) {
|
||||
const size = sizeFormate(file.size_128mp3)
|
||||
let size = sizeFormate(file.size_128mp3)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
size,
|
||||
}
|
||||
}
|
||||
if (file.size_320mp3 !== 0) {
|
||||
const size = sizeFormate(file.size_320mp3)
|
||||
let size = sizeFormate(file.size_320mp3)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
size,
|
||||
}
|
||||
}
|
||||
if (file.size_flac !== 0) {
|
||||
const size = sizeFormate(file.size_flac)
|
||||
let size = sizeFormate(file.size_flac)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
size,
|
||||
}
|
||||
}
|
||||
if (file.size_hires !== 0) {
|
||||
const size = sizeFormate(file.size_hires)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
let size = sizeFormate(file.size_hires)
|
||||
types.push({ type: 'hires', size })
|
||||
_types.hires = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
if (file.size_new[1] !== 0) {
|
||||
let size = sizeFormate(file.size_new[1])
|
||||
types.push({ type: 'atmos', size })
|
||||
_types.atmos = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
if (file.size_new[2] !== 0) {
|
||||
let size = sizeFormate(file.size_new[2])
|
||||
types.push({ type: 'atmos_plus', size })
|
||||
_types.atmos_plus = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
if (file.size_new[0] !== 0) {
|
||||
let size = sizeFormate(file.size_new[0])
|
||||
types.push({ type: 'master', size })
|
||||
_types.master = {
|
||||
size,
|
||||
}
|
||||
}
|
||||
// types.reverse()
|
||||
@@ -113,7 +134,7 @@ export default {
|
||||
: `https://y.gtimg.cn/music/photo_new/T002R500x500M000${albumId}.jpg`,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
typeUrl: {},
|
||||
})
|
||||
})
|
||||
// console.log(list)
|
||||
@@ -123,7 +144,7 @@ export default {
|
||||
if (limit == null) limit = this.limit
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page, limit).then(({ body, meta }) => {
|
||||
const list = this.handleResult(body.item_song)
|
||||
let list = this.handleResult(body.item_song)
|
||||
|
||||
this.total = meta.estimate_sum
|
||||
this.page = page
|
||||
@@ -134,8 +155,8 @@ export default {
|
||||
allPage: this.allPage,
|
||||
limit,
|
||||
total: this.total,
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
86
src/main/utils/musicSdk/tx/quality_detail.js
Normal file
86
src/main/utils/musicSdk/tx/quality_detail.js
Normal file
@@ -0,0 +1,86 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { sizeFormate } from '../../index'
|
||||
|
||||
export const getBatchMusicQualityInfo = (songList) => {
|
||||
const songIds = songList.map((item) => item.id)
|
||||
|
||||
const requestObj = httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
|
||||
},
|
||||
body: {
|
||||
comm: {
|
||||
ct: '19',
|
||||
cv: '1859',
|
||||
uin: '0',
|
||||
},
|
||||
req: {
|
||||
module: 'music.trackInfo.UniformRuleCtrl',
|
||||
method: 'CgiGetTrackInfo',
|
||||
param: {
|
||||
types: Array(songIds.length).fill(1),
|
||||
ids: songIds,
|
||||
ctx: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const qualityInfoMap = {}
|
||||
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode != 200 || body.code != 0) return Promise.reject(new Error('获取音质信息失败'))
|
||||
|
||||
// Process each track from the response
|
||||
body.req.data.tracks.forEach((track) => {
|
||||
const file = track.file
|
||||
const songId = track.id
|
||||
|
||||
const types = []
|
||||
const _types = {}
|
||||
|
||||
if (file.size_128mp3 != 0) {
|
||||
let size = sizeFormate(file.size_128mp3)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = { size }
|
||||
}
|
||||
if (file.size_320mp3 !== 0) {
|
||||
let size = sizeFormate(file.size_320mp3)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = { size }
|
||||
}
|
||||
if (file.size_flac !== 0) {
|
||||
let size = sizeFormate(file.size_flac)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = { size }
|
||||
}
|
||||
if (file.size_hires !== 0) {
|
||||
let size = sizeFormate(file.size_hires)
|
||||
types.push({ type: 'hires', size })
|
||||
_types.hires = { size }
|
||||
}
|
||||
if (file.size_new[1] !== 0) {
|
||||
let size = sizeFormate(file.size_new[1])
|
||||
types.push({ type: 'atmos', size })
|
||||
_types.atmos = { size }
|
||||
}
|
||||
if (file.size_new[2] !== 0) {
|
||||
let size = sizeFormate(file.size_new[2])
|
||||
types.push({ type: 'atmos_plus', size })
|
||||
_types.atmos_plus = { size }
|
||||
}
|
||||
if (file.size_new[0] !== 0) {
|
||||
let size = sizeFormate(file.size_new[0])
|
||||
types.push({ type: 'master', size })
|
||||
_types.master = { size }
|
||||
}
|
||||
|
||||
qualityInfoMap[songId] = { types, _types }
|
||||
})
|
||||
|
||||
return qualityInfoMap
|
||||
})
|
||||
|
||||
return requestObj
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index'
|
||||
import { decodeName, formatPlayTime, dateFormat, formatPlayCount } from '../../index'
|
||||
import { formatSingerName } from '../utils'
|
||||
import { getBatchMusicQualityInfo } from './quality_detail'
|
||||
|
||||
export default {
|
||||
_requestObj_tags: null,
|
||||
@@ -12,12 +13,12 @@ export default {
|
||||
sortList: [
|
||||
{
|
||||
name: '最热',
|
||||
id: 5
|
||||
id: 5,
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
id: 2
|
||||
}
|
||||
id: 2,
|
||||
},
|
||||
],
|
||||
regExps: {
|
||||
hotTagHtml: /class="c_bg_link js_tag_item" data-id="\w+">.+?<\/a>/g,
|
||||
@@ -26,7 +27,7 @@ export default {
|
||||
// https://y.qq.com/n/yqq/playlist/7217720898.html
|
||||
// https://i.y.qq.com/n2/m/share/details/taoge.html?platform=11&appshare=android_qq&appversion=9050006&id=7217720898&ADTAG=qfshare
|
||||
listDetailLink: /\/playlist\/(\d+)/,
|
||||
listDetailLink2: /id=(\d+)/
|
||||
listDetailLink2: /id=(\d+)/,
|
||||
},
|
||||
tagsUrl:
|
||||
'https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=%7B%22tags%22%3A%7B%22method%22%3A%22get_all_categories%22%2C%22param%22%3A%7B%22qq%22%3A%22%22%7D%2C%22module%22%3A%22playlist.PlaylistAllCategoriesServer%22%7D%7D',
|
||||
@@ -45,10 +46,10 @@ export default {
|
||||
category_id: id,
|
||||
size: this.limit_list,
|
||||
page: page - 1,
|
||||
use_page: 1
|
||||
use_page: 1,
|
||||
},
|
||||
module: 'playlist.PlayListCategoryServer'
|
||||
}
|
||||
module: 'playlist.PlayListCategoryServer',
|
||||
},
|
||||
})
|
||||
)}`
|
||||
}
|
||||
@@ -62,10 +63,10 @@ export default {
|
||||
sin: this.limit_list * (page - 1),
|
||||
size: this.limit_list,
|
||||
order: sortId,
|
||||
cur_page: page
|
||||
cur_page: page,
|
||||
},
|
||||
module: 'playlist.PlayListPlazaServer'
|
||||
}
|
||||
module: 'playlist.PlayListPlazaServer',
|
||||
},
|
||||
})
|
||||
)}`
|
||||
},
|
||||
@@ -95,17 +96,17 @@ export default {
|
||||
})
|
||||
},
|
||||
filterInfoHotTag(html) {
|
||||
const hotTag = html.match(this.regExps.hotTagHtml)
|
||||
let hotTag = html.match(this.regExps.hotTagHtml)
|
||||
const hotTags = []
|
||||
if (!hotTag) return hotTags
|
||||
|
||||
hotTag.forEach((tagHtml) => {
|
||||
const result = tagHtml.match(this.regExps.hotTag)
|
||||
let result = tagHtml.match(this.regExps.hotTag)
|
||||
if (!result) return
|
||||
hotTags.push({
|
||||
id: parseInt(result[1]),
|
||||
name: result[2],
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
})
|
||||
})
|
||||
return hotTags
|
||||
@@ -118,8 +119,8 @@ export default {
|
||||
parent_name: type.group_name,
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
source: 'tx'
|
||||
}))
|
||||
source: 'tx',
|
||||
})),
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -130,7 +131,9 @@ export default {
|
||||
this._requestObj_list = httpFetch(this.getListUrl(sortId, tagId, page))
|
||||
// console.log(this.getListUrl(sortId, tagId, page))
|
||||
return this._requestObj_list.promise.then(({ 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 tagId
|
||||
? this.filterList2(body.playlist.data, page)
|
||||
: this.filterList(body.playlist.data, page)
|
||||
@@ -149,12 +152,12 @@ export default {
|
||||
// grade: item.favorcnt / 10,
|
||||
total: item.song_ids?.length,
|
||||
desc: decodeName(item.desc).replace(/<br>/g, '\n'),
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
})),
|
||||
total: data.total,
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
}
|
||||
},
|
||||
filterList2({ content }, page) {
|
||||
@@ -169,12 +172,12 @@ export default {
|
||||
img: basic.cover.medium_url || basic.cover.default_url,
|
||||
// grade: basic.favorcnt / 10,
|
||||
desc: decodeName(basic.desc).replace(/<br>/g, '\n'),
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
})),
|
||||
total: content.total_cnt,
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
}
|
||||
},
|
||||
|
||||
@@ -184,7 +187,7 @@ export default {
|
||||
const requestObj_listDetailLink = httpFetch(link)
|
||||
const {
|
||||
headers: { location },
|
||||
statusCode
|
||||
statusCode,
|
||||
} = await requestObj_listDetailLink.promise
|
||||
// console.log(headers)
|
||||
if (statusCode > 400) return this.handleParseId(link, ++retryNum)
|
||||
@@ -215,15 +218,15 @@ export default {
|
||||
const requestObj_listDetail = httpFetch(this.getListDetailUrl(id), {
|
||||
headers: {
|
||||
Origin: 'https://y.qq.com',
|
||||
Referer: `https://y.qq.com/n/yqq/playsquare/${id}.html`
|
||||
}
|
||||
Referer: `https://y.qq.com/n/yqq/playsquare/${id}.html`,
|
||||
},
|
||||
})
|
||||
const { body } = await requestObj_listDetail.promise
|
||||
|
||||
if (body.code !== this.successCode) return this.getListDetail(id, ++tryNum)
|
||||
const cdlist = body.cdlist[0]
|
||||
return {
|
||||
list: this.filterListDetail(cdlist.songlist),
|
||||
list: await this.filterListDetail(cdlist.songlist),
|
||||
page: 1,
|
||||
limit: cdlist.songlist.length + 1,
|
||||
total: cdlist.songlist.length,
|
||||
@@ -233,44 +236,23 @@ export default {
|
||||
img: cdlist.logo,
|
||||
desc: decodeName(cdlist.desc).replace(/<br>/g, '\n'),
|
||||
author: cdlist.nickname,
|
||||
play_count: formatPlayCount(cdlist.visitnum)
|
||||
}
|
||||
play_count: formatPlayCount(cdlist.visitnum),
|
||||
},
|
||||
}
|
||||
},
|
||||
filterListDetail(rawList) {
|
||||
// console.log(rawList)
|
||||
async filterListDetail(rawList) {
|
||||
const qualityInfoRequest = getBatchMusicQualityInfo(rawList)
|
||||
let qualityInfoMap = {}
|
||||
|
||||
try {
|
||||
qualityInfoMap = await qualityInfoRequest.promise
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch quality info:', error)
|
||||
}
|
||||
|
||||
return rawList.map((item) => {
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.file.size_128mp3 !== 0) {
|
||||
const size = sizeFormate(item.file.size_128mp3)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_320mp3 !== 0) {
|
||||
const size = sizeFormate(item.file.size_320mp3)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_flac !== 0) {
|
||||
const size = sizeFormate(item.file.size_flac)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = {
|
||||
size
|
||||
}
|
||||
}
|
||||
if (item.file.size_hires !== 0) {
|
||||
const size = sizeFormate(item.file.size_hires)
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
}
|
||||
// types.reverse()
|
||||
const { types = [], _types = {} } = qualityInfoMap[item.id] || {}
|
||||
|
||||
return {
|
||||
singer: formatSingerName(item.singer, 'name'),
|
||||
name: item.title,
|
||||
@@ -292,7 +274,7 @@ export default {
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
typeUrl: {},
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -300,7 +282,7 @@ export default {
|
||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({
|
||||
tags,
|
||||
hotTag,
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -313,12 +295,16 @@ export default {
|
||||
search(text, page, limit = 20, retryNum = 0) {
|
||||
if (retryNum > 5) throw new Error('max retry')
|
||||
return httpFetch(
|
||||
`http://c.y.qq.com/soso/fcgi-bin/client_music_search_songlist?page_no=${page - 1}&num_per_page=${limit}&format=json&query=${encodeURIComponent(text)}&remoteplace=txt.yqq.playlist&inCharset=utf8&outCharset=utf-8`,
|
||||
`http://c.y.qq.com/soso/fcgi-bin/client_music_search_songlist?page_no=${
|
||||
page - 1
|
||||
}&num_per_page=${limit}&format=json&query=${encodeURIComponent(
|
||||
text
|
||||
)}&remoteplace=txt.yqq.playlist&inCharset=utf8&outCharset=utf-8`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
|
||||
Referer: 'http://y.qq.com/portal/search.html'
|
||||
}
|
||||
Referer: 'http://y.qq.com/portal/search.html',
|
||||
},
|
||||
}
|
||||
).promise.then(({ body }) => {
|
||||
if (body.code != 0) return this.search(text, page, limit, ++retryNum)
|
||||
@@ -335,17 +321,17 @@ export default {
|
||||
// grade: item.favorcnt / 10,
|
||||
total: item.song_count,
|
||||
desc: decodeName(decodeName(item.introduction)).replace(/<br>/g, '\n'),
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
}
|
||||
}),
|
||||
limit,
|
||||
total: body.data.sum,
|
||||
source: 'tx'
|
||||
source: 'tx',
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
// getListDetail
|
||||
@@ -10,16 +10,13 @@ export const getHostIp = (hostname) => {
|
||||
if (typeof result === 'object') return result
|
||||
if (result === true) return
|
||||
ipMap.set(hostname, true)
|
||||
// console.log(hostname)
|
||||
dns.lookup(
|
||||
hostname,
|
||||
{
|
||||
// family: 4,
|
||||
all: false
|
||||
all: false,
|
||||
},
|
||||
(err, address, family) => {
|
||||
if (err) return console.log(err)
|
||||
// console.log(address, family)
|
||||
ipMap.set(hostname, { address, family })
|
||||
}
|
||||
)
|
||||
@@ -42,11 +39,11 @@ export const formatSingerName = (singers, nameKey = 'name', join = '、') => {
|
||||
if (Array.isArray(singers)) {
|
||||
const singer = []
|
||||
singers.forEach((item) => {
|
||||
const name = item[nameKey]
|
||||
let name = item[nameKey]
|
||||
if (!name) return
|
||||
singer.push(name)
|
||||
})
|
||||
return decodeName(singer.join(join))
|
||||
}
|
||||
return decodeName(String(singers ?? ''))
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,23 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { weapi } from './utils/crypto'
|
||||
import { formatPlayTime, sizeFormate } from '../index'
|
||||
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/song_detail.js
|
||||
import { formatPlayTime } from '../../index'
|
||||
import { getBatchMusicQualityInfo } from './quality_detail'
|
||||
|
||||
export default {
|
||||
getSinger(singers) {
|
||||
const arr = []
|
||||
let arr = []
|
||||
singers?.forEach((singer) => {
|
||||
arr.push(singer.name)
|
||||
})
|
||||
return arr.join('、')
|
||||
},
|
||||
filterList({ songs, privileges }) {
|
||||
// console.log(songs, privileges)
|
||||
async filterList({ songs, privileges }) {
|
||||
const list = []
|
||||
const idList = songs.map((item) => item.id)
|
||||
const qualityInfoMap = await getBatchMusicQualityInfo(idList)
|
||||
|
||||
songs.forEach((item, index) => {
|
||||
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.maxBrLevel == 'hires') {
|
||||
size = item.hr ? sizeFormate(item.hr.size) : null
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
}
|
||||
}
|
||||
switch (privilege.maxbr) {
|
||||
case 999000:
|
||||
size = item.sq ? sizeFormate(item.sq.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()
|
||||
const { types, _types } = qualityInfoMap[item.id] || { types: [], _types: {} }
|
||||
|
||||
if (item.pc) {
|
||||
list.push({
|
||||
@@ -67,7 +33,7 @@ export default {
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
typeUrl: {},
|
||||
})
|
||||
} else {
|
||||
list.push({
|
||||
@@ -83,11 +49,10 @@ export default {
|
||||
otherSource: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
typeUrl: {},
|
||||
})
|
||||
}
|
||||
})
|
||||
// console.log(list)
|
||||
return list
|
||||
},
|
||||
async getList(ids = [], retryNum = 0) {
|
||||
@@ -98,16 +63,15 @@ export default {
|
||||
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'
|
||||
origin: 'https://music.163.com',
|
||||
},
|
||||
form: weapi({
|
||||
c: '[' + ids.map((id) => '{"id":' + id + '}').join(',') + ']',
|
||||
ids: '[' + ids.join(',') + ']'
|
||||
})
|
||||
ids: '[' + ids.join(',') + ']',
|
||||
}),
|
||||
})
|
||||
const { body, statusCode } = await requestObj.promise
|
||||
if (statusCode != 200 || body.code !== 200) throw new Error('获取歌曲详情失败')
|
||||
// console.log(body)
|
||||
return { source: 'wy', list: this.filterList(body) }
|
||||
}
|
||||
}
|
||||
return { source: 'wy', list: await this.filterList(body) }
|
||||
},
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
// import { httpFetch } from '../../request'
|
||||
// import { weapi } from './utils/crypto'
|
||||
import { sizeFormate, formatPlayTime } from '../index'
|
||||
// import musicDetailApi from './musicDetail'
|
||||
import { httpFetch } from '../../request'
|
||||
import { sizeFormate, formatPlayTime } from '../../index'
|
||||
import { eapiRequest } from './utils/index'
|
||||
|
||||
export default {
|
||||
@@ -9,101 +7,129 @@ export default {
|
||||
total: 0,
|
||||
page: 0,
|
||||
allPage: 1,
|
||||
|
||||
musicSearch(str, page, limit) {
|
||||
const searchRequest = eapiRequest('/api/cloudsearch/pc', {
|
||||
s: str,
|
||||
type: 1, // 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频
|
||||
limit,
|
||||
total: page == 1,
|
||||
offset: limit * (page - 1)
|
||||
offset: limit * (page - 1),
|
||||
})
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
},
|
||||
|
||||
getSinger(singers) {
|
||||
const arr = []
|
||||
singers.forEach((singer) => {
|
||||
arr.push(singer.name)
|
||||
})
|
||||
return arr.join('、')
|
||||
return singers.map((singer) => singer.name).join('、')
|
||||
},
|
||||
|
||||
handleResult(rawList) {
|
||||
// console.log(rawList)
|
||||
if (!rawList) return []
|
||||
return rawList.map((item) => {
|
||||
const types = []
|
||||
const _types = {}
|
||||
let size
|
||||
|
||||
if (item.privilege.maxBrLevel == 'hires') {
|
||||
size = item.hr ? sizeFormate(item.hr.size) : null
|
||||
types.push({ type: 'flac24bit', size })
|
||||
_types.flac24bit = {
|
||||
size
|
||||
return Promise.all(
|
||||
rawList.map(async (item) => {
|
||||
const types = []
|
||||
const _types = {}
|
||||
let size
|
||||
|
||||
try {
|
||||
const requestObj = httpFetch(
|
||||
`https://music.163.com/api/song/music/detail/get?songId=${item.id}`,
|
||||
{
|
||||
method: 'get',
|
||||
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 (body.data.db && body.data.db.size) {
|
||||
size = sizeFormate(body.data.db.size)
|
||||
types.push({ type: 'dolby', size })
|
||||
_types.dolby = { size }
|
||||
}
|
||||
if (body.data.hr && body.data.hr.size) {
|
||||
size = sizeFormate(body.data.hr.size)
|
||||
types.push({ type: 'hires', size })
|
||||
_types.hires = { size }
|
||||
}
|
||||
if (body.data.sq && body.data.sq.size) {
|
||||
size = sizeFormate(body.data.sq.size)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = { size }
|
||||
}
|
||||
if (body.data.h && body.data.h.size) {
|
||||
size = sizeFormate(body.data.h.size)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = { size }
|
||||
}
|
||||
if (body.data.m && body.data.m.size) {
|
||||
size = sizeFormate(body.data.m.size)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = { size }
|
||||
} else if (body.data.l && body.data.l.size) {
|
||||
size = sizeFormate(body.data.l.size)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = { size }
|
||||
}
|
||||
|
||||
types.reverse()
|
||||
|
||||
return {
|
||||
singer: this.getSinger(item.ar),
|
||||
name: item.name,
|
||||
albumName: item.al.name,
|
||||
albumId: item.al.id,
|
||||
source: 'wy',
|
||||
interval: formatPlayTime(item.dt / 1000),
|
||||
songmid: item.id,
|
||||
img: item.al.picUrl,
|
||||
lrc: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error.message)
|
||||
return null
|
||||
}
|
||||
}
|
||||
switch (item.privilege.maxbr) {
|
||||
case 999000:
|
||||
size = item.sq ? sizeFormate(item.sq.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()
|
||||
|
||||
return {
|
||||
singer: this.getSinger(item.ar),
|
||||
name: item.name,
|
||||
albumName: item.al.name,
|
||||
albumId: item.al.id,
|
||||
source: 'wy',
|
||||
interval: formatPlayTime(item.dt / 1000),
|
||||
songmid: item.id,
|
||||
img: item.al.picUrl,
|
||||
lrc: null,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {}
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
},
|
||||
|
||||
search(str, page = 1, limit, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
if (limit == null) limit = this.limit
|
||||
return this.musicSearch(str, page, limit).then((result) => {
|
||||
// console.log(result)
|
||||
if (!result || result.code !== 200) return this.search(str, page, limit, retryNum)
|
||||
const list = this.handleResult(result.result.songs || [])
|
||||
// console.log(list)
|
||||
return this.handleResult(result.result.songs || []).then((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.page = page
|
||||
this.allPage = Math.ceil(this.total / this.limit)
|
||||
|
||||
this.total = result.result.songCount || 0
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / this.limit)
|
||||
|
||||
return {
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit: this.limit,
|
||||
total: this.total,
|
||||
source: 'wy'
|
||||
}
|
||||
// return result.data
|
||||
return {
|
||||
list,
|
||||
allPage: this.allPage,
|
||||
limit: this.limit,
|
||||
total: this.total,
|
||||
source: 'wy',
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
91
src/main/utils/musicSdk/wy/quality_detail.js
Normal file
91
src/main/utils/musicSdk/wy/quality_detail.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { sizeFormate } from '../../index'
|
||||
|
||||
export const getMusicQualityInfo = (id) => {
|
||||
|
||||
const requestObj = httpFetch(`https://music.163.com/api/song/music/detail/get?songId=${id}`, {
|
||||
method: 'get',
|
||||
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 types = []
|
||||
const _types = {}
|
||||
|
||||
requestObj.promise = requestObj.promise.then(({ statusCode, body }) => {
|
||||
if (statusCode != 200 && body.code != 200) return Promise.reject(new Error('获取音质信息失败' + id))
|
||||
|
||||
const data = body.data
|
||||
|
||||
types.length = 0
|
||||
Object.keys(_types).forEach((key) => delete _types[key])
|
||||
|
||||
if (data.l != null && data.l.size != null) {
|
||||
let size = sizeFormate(data.l.size)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = { size }
|
||||
} else if (data.m != null && data.m.size != null) {
|
||||
let size = sizeFormate(data.m.size)
|
||||
types.push({ type: '128k', size })
|
||||
_types['128k'] = { size }
|
||||
}
|
||||
|
||||
if (data.h != null && data.h.size != null) {
|
||||
let size = sizeFormate(data.h.size)
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = { size }
|
||||
}
|
||||
|
||||
if (data.sq != null && data.sq.size != null) {
|
||||
let size = sizeFormate(data.sq.size)
|
||||
types.push({ type: 'flac', size })
|
||||
_types.flac = { size }
|
||||
}
|
||||
|
||||
if (data.hr != null && data.hr.size != null) {
|
||||
let size = sizeFormate(data.hr.size)
|
||||
types.push({ type: 'hires', size })
|
||||
_types.hires = { size }
|
||||
}
|
||||
|
||||
if (data.jm != null && data.jm.size != null) {
|
||||
let size = sizeFormate(data.jm.size)
|
||||
types.push({ type: 'master', size })
|
||||
_types.master = { size }
|
||||
}
|
||||
|
||||
if (data.je != null && data.je.size != null) {
|
||||
let size = sizeFormate(data.je.size)
|
||||
types.push({ type: 'atmos', size })
|
||||
_types.atmos = { size }
|
||||
}
|
||||
|
||||
return { types: [...types], _types: { ..._types } }
|
||||
})
|
||||
|
||||
return { requestObj, types, _types }
|
||||
}
|
||||
|
||||
export const getBatchMusicQualityInfo = async (idList) => {
|
||||
const ids = idList.filter((id) => id)
|
||||
|
||||
const qualityPromises = ids.map((id) => {
|
||||
const result = getMusicQualityInfo(id)
|
||||
return result.requestObj.promise.catch((err) => {
|
||||
console.error(`获取歌曲 ${id} 音质信息失败:`, err)
|
||||
return { types: [], _types: {} }
|
||||
})
|
||||
})
|
||||
|
||||
const qualityResults = await Promise.all(qualityPromises)
|
||||
|
||||
const qualityInfoMap = {}
|
||||
ids.forEach((id, index) => {
|
||||
qualityInfoMap[id] = qualityResults[index] || { types: [], _types: {} }
|
||||
})
|
||||
|
||||
return qualityInfoMap
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { weapi, linuxapi } from './utils/crypto'
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index'
|
||||
import { /* formatPlayTime, */ dateFormat, formatPlayCount } from '../../index'
|
||||
import musicDetailApi from './musicDetail'
|
||||
import { eapiRequest } from './utils/index'
|
||||
import { formatSingerName } from '../utils'
|
||||
// import { formatSingerName } from '../utils'
|
||||
|
||||
export default {
|
||||
_requestObj_tags: null,
|
||||
@@ -16,16 +16,12 @@ export default {
|
||||
sortList: [
|
||||
{
|
||||
name: '最热',
|
||||
id: 'hot'
|
||||
}
|
||||
// {
|
||||
// name: '最新',
|
||||
// id: 'new',
|
||||
// },
|
||||
id: 'hot',
|
||||
},
|
||||
],
|
||||
regExps: {
|
||||
listDetailLink: /^.+(?:\?|&)id=(\d+)(?:&.*$|#.*$|$)/,
|
||||
listDetailLink2: /^.+\/playlist\/(\d+)\/\d+\/.+$/
|
||||
listDetailLink2: /^.+\/playlist\/(\d+)\/\d+\/.+$/,
|
||||
},
|
||||
|
||||
async handleParseId(link, retryNum = 0) {
|
||||
@@ -34,9 +30,8 @@ export default {
|
||||
const requestObj_listDetailLink = httpFetch(link)
|
||||
const {
|
||||
headers: { location },
|
||||
statusCode
|
||||
statusCode,
|
||||
} = await requestObj_listDetailLink.promise
|
||||
// console.log(statusCode)
|
||||
if (statusCode > 400) return this.handleParseId(link, ++retryNum)
|
||||
const url = location == null ? link : location
|
||||
return this.regExps.listDetailLink.test(url)
|
||||
@@ -59,13 +54,11 @@ export default {
|
||||
} else {
|
||||
id = await this.handleParseId(id)
|
||||
}
|
||||
// console.log(id)
|
||||
}
|
||||
return { id, cookie }
|
||||
},
|
||||
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)
|
||||
if (cookie) this.cookie = cookie
|
||||
@@ -75,7 +68,7 @@ export default {
|
||||
headers: {
|
||||
'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,
|
||||
},
|
||||
form: linuxapi({
|
||||
method: 'POST',
|
||||
@@ -83,36 +76,30 @@ export default {
|
||||
params: {
|
||||
id,
|
||||
n: this.limit_song,
|
||||
s: 8
|
||||
}
|
||||
})
|
||||
s: 8,
|
||||
},
|
||||
}),
|
||||
})
|
||||
const { statusCode, body } = await requestObj_listDetail.promise
|
||||
if (statusCode !== 200 || body.code !== this.successCode)
|
||||
return this.getListDetail(id, page, ++tryNum)
|
||||
const limit = 1000
|
||||
const rangeStart = (page - 1) * limit
|
||||
// console.log(body)
|
||||
let limit = 1000
|
||||
let rangeStart = (page - 1) * limit
|
||||
let list
|
||||
if (body.playlist.trackIds.length == body.privileges.length) {
|
||||
list = this.filterListDetail(body)
|
||||
} else {
|
||||
try {
|
||||
list = (
|
||||
await musicDetailApi.getList(
|
||||
body.playlist.trackIds.slice(rangeStart, limit * page).map((trackId) => trackId.id)
|
||||
)
|
||||
).list
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
if (err.message == 'try max num') {
|
||||
throw err
|
||||
} else {
|
||||
return this.getListDetail(id, page, ++tryNum)
|
||||
}
|
||||
try {
|
||||
list = (
|
||||
await musicDetailApi.getList(
|
||||
body.playlist.trackIds.slice(rangeStart, limit * page).map((trackId) => trackId.id)
|
||||
)
|
||||
).list
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
if (err.message == 'try max num') {
|
||||
throw err
|
||||
} else {
|
||||
return this.getListDetail(id, page, ++tryNum)
|
||||
}
|
||||
}
|
||||
// console.log(list)
|
||||
return {
|
||||
list,
|
||||
page,
|
||||
@@ -124,119 +111,79 @@ export default {
|
||||
name: body.playlist.name,
|
||||
img: body.playlist.coverImgUrl,
|
||||
desc: body.playlist.description,
|
||||
author: body.playlist.creator.nickname
|
||||
}
|
||||
author: body.playlist.creator.nickname,
|
||||
},
|
||||
}
|
||||
},
|
||||
filterListDetail({ playlist: { tracks }, privileges }) {
|
||||
// console.log(tracks, privileges)
|
||||
const list = []
|
||||
tracks.forEach((item, index) => {
|
||||
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.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
|
||||
}
|
||||
// filterListDetail({ playlist: { tracks } }) {
|
||||
// const list = []
|
||||
// tracks.forEach((item) => {
|
||||
// const types = []
|
||||
// const _types = {}
|
||||
|
||||
case 320000:
|
||||
size = item.h ? sizeFormate(item.h.size) : null
|
||||
types.push({ type: '320k', size })
|
||||
_types['320k'] = {
|
||||
size
|
||||
}
|
||||
// if (item.pc) {
|
||||
// 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: formatSingerName(item.ar, 'name'),
|
||||
// name: item.name ?? '',
|
||||
// albumName: item.al?.name,
|
||||
// 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: {},
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// return list
|
||||
// },
|
||||
|
||||
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) {
|
||||
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: formatSingerName(item.ar, 'name'),
|
||||
name: item.name ?? '',
|
||||
albumName: item.al?.name,
|
||||
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: {}
|
||||
})
|
||||
}
|
||||
})
|
||||
return list
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page, tryNum = 0) {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
this._requestObj_list = httpFetch('https://music.163.com/weapi/playlist/list', {
|
||||
method: 'post',
|
||||
form: weapi({
|
||||
cat: tagId || '全部', // 全部,华语,欧美,日语,韩语,粤语,小语种,流行,摇滚,民谣,电子,舞曲,说唱,轻音乐,爵士,乡村,R&B/Soul,古典,民族,英伦,金属,朋克,蓝调,雷鬼,世界音乐,拉丁,另类/独立,New Age,古风,后摇,Bossa Nova,清晨,夜晚,学习,工作,午休,下午茶,地铁,驾车,运动,旅行,散步,酒吧,怀旧,清新,浪漫,性感,伤感,治愈,放松,孤独,感动,兴奋,快乐,安静,思念,影视原声,ACG,儿童,校园,游戏,70后,80后,90后,网络歌曲,KTV,经典,翻唱,吉他,钢琴,器乐,榜单,00后
|
||||
order: sortId, // hot,new
|
||||
cat: tagId || '全部',
|
||||
order: sortId,
|
||||
limit: this.limit_list,
|
||||
offset: this.limit_list * (page - 1),
|
||||
total: true
|
||||
})
|
||||
total: true,
|
||||
}),
|
||||
})
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
|
||||
return {
|
||||
list: this.filterList(body.playlists),
|
||||
total: parseInt(body.total),
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'wy'
|
||||
source: 'wy',
|
||||
}
|
||||
})
|
||||
},
|
||||
filterList(rawData) {
|
||||
// console.log(rawData)
|
||||
return rawData.map((item) => ({
|
||||
play_count: formatPlayCount(item.playCount),
|
||||
id: String(item.id),
|
||||
@@ -247,20 +194,18 @@ export default {
|
||||
grade: item.grade,
|
||||
total: item.trackCount,
|
||||
desc: item.description,
|
||||
source: 'wy'
|
||||
source: 'wy',
|
||||
}))
|
||||
},
|
||||
|
||||
// 获取标签
|
||||
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 = httpFetch('https://music.163.com/weapi/playlist/catalogue', {
|
||||
method: 'post',
|
||||
form: weapi({})
|
||||
form: weapi({}),
|
||||
})
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
// console.log(JSON.stringify(body))
|
||||
if (body.code !== this.successCode) return this.getTag(++tryNum)
|
||||
return this.filterTagInfo(body)
|
||||
})
|
||||
@@ -274,7 +219,7 @@ export default {
|
||||
parent_name: categories[item.category],
|
||||
id: item.name,
|
||||
name: item.name,
|
||||
source: 'wy'
|
||||
source: 'wy',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -283,22 +228,20 @@ export default {
|
||||
list.push({
|
||||
name: categories[key],
|
||||
list: subList[key],
|
||||
source: 'wy'
|
||||
source: 'wy',
|
||||
})
|
||||
}
|
||||
return list
|
||||
},
|
||||
|
||||
// 获取热门标签
|
||||
getHotTag(tryNum = 0) {
|
||||
if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_hotTags = httpFetch('https://music.163.com/weapi/playlist/hottags', {
|
||||
method: 'post',
|
||||
form: weapi({})
|
||||
form: weapi({}),
|
||||
})
|
||||
return this._requestObj_hotTags.promise.then(({ body }) => {
|
||||
// console.log(JSON.stringify(body))
|
||||
if (body.code !== this.successCode) return this.getTag(++tryNum)
|
||||
return this.filterHotTagInfo(body.tags)
|
||||
})
|
||||
@@ -307,7 +250,7 @@ export default {
|
||||
return rawList.map((item) => ({
|
||||
id: item.playlistTag.name,
|
||||
name: item.playlistTag.name,
|
||||
source: 'wy'
|
||||
source: 'wy',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -315,7 +258,7 @@ export default {
|
||||
return Promise.all([this.getTag(), this.getHotTag()]).then(([tags, hotTag]) => ({
|
||||
tags,
|
||||
hotTag,
|
||||
source: 'wy'
|
||||
source: 'wy',
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -327,23 +270,18 @@ export default {
|
||||
search(text, page, limit = 20) {
|
||||
return eapiRequest('/api/cloudsearch/pc', {
|
||||
s: text,
|
||||
type: 1000, // 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频
|
||||
type: 1000,
|
||||
limit,
|
||||
total: page == 1,
|
||||
offset: limit * (page - 1)
|
||||
offset: limit * (page - 1),
|
||||
}).promise.then(({ body }) => {
|
||||
if (body.code != this.successCode) throw new Error('filed')
|
||||
// console.log(body)
|
||||
return {
|
||||
list: this.filterList(body.result.playlists),
|
||||
limit,
|
||||
total: body.result.playlistCount,
|
||||
source: 'wy'
|
||||
source: 'wy',
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
},
|
||||
}
|
||||
144
src/renderer/auto-imports.d.ts
vendored
144
src/renderer/auto-imports.d.ts
vendored
@@ -7,90 +7,72 @@
|
||||
export {}
|
||||
declare global {
|
||||
const DialogPlugin: (typeof import('tdesign-vue-next'))['DialogPlugin']
|
||||
const EffectScope: (typeof import('vue'))['EffectScope']
|
||||
const computed: (typeof import('vue'))['computed']
|
||||
const createApp: (typeof import('vue'))['createApp']
|
||||
const customRef: (typeof import('vue'))['customRef']
|
||||
const defineAsyncComponent: (typeof import('vue'))['defineAsyncComponent']
|
||||
const defineComponent: (typeof import('vue'))['defineComponent']
|
||||
const effectScope: (typeof import('vue'))['effectScope']
|
||||
const getCurrentInstance: (typeof import('vue'))['getCurrentInstance']
|
||||
const getCurrentScope: (typeof import('vue'))['getCurrentScope']
|
||||
const getCurrentWatcher: (typeof import('vue'))['getCurrentWatcher']
|
||||
const h: (typeof import('vue'))['h']
|
||||
const inject: (typeof import('vue'))['inject']
|
||||
const isProxy: (typeof import('vue'))['isProxy']
|
||||
const isReactive: (typeof import('vue'))['isReactive']
|
||||
const isReadonly: (typeof import('vue'))['isReadonly']
|
||||
const isRef: (typeof import('vue'))['isRef']
|
||||
const isShallow: (typeof import('vue'))['isShallow']
|
||||
const markRaw: (typeof import('vue'))['markRaw']
|
||||
const nextTick: (typeof import('vue'))['nextTick']
|
||||
const onActivated: (typeof import('vue'))['onActivated']
|
||||
const onBeforeMount: (typeof import('vue'))['onBeforeMount']
|
||||
const onBeforeUnmount: (typeof import('vue'))['onBeforeUnmount']
|
||||
const onBeforeUpdate: (typeof import('vue'))['onBeforeUpdate']
|
||||
const onDeactivated: (typeof import('vue'))['onDeactivated']
|
||||
const onErrorCaptured: (typeof import('vue'))['onErrorCaptured']
|
||||
const onMounted: (typeof import('vue'))['onMounted']
|
||||
const onRenderTracked: (typeof import('vue'))['onRenderTracked']
|
||||
const onRenderTriggered: (typeof import('vue'))['onRenderTriggered']
|
||||
const onScopeDispose: (typeof import('vue'))['onScopeDispose']
|
||||
const onServerPrefetch: (typeof import('vue'))['onServerPrefetch']
|
||||
const onUnmounted: (typeof import('vue'))['onUnmounted']
|
||||
const onUpdated: (typeof import('vue'))['onUpdated']
|
||||
const onWatcherCleanup: (typeof import('vue'))['onWatcherCleanup']
|
||||
const provide: (typeof import('vue'))['provide']
|
||||
const reactive: (typeof import('vue'))['reactive']
|
||||
const readonly: (typeof import('vue'))['readonly']
|
||||
const ref: (typeof import('vue'))['ref']
|
||||
const resolveComponent: (typeof import('vue'))['resolveComponent']
|
||||
const shallowReactive: (typeof import('vue'))['shallowReactive']
|
||||
const shallowReadonly: (typeof import('vue'))['shallowReadonly']
|
||||
const shallowRef: (typeof import('vue'))['shallowRef']
|
||||
const toRaw: (typeof import('vue'))['toRaw']
|
||||
const toRef: (typeof import('vue'))['toRef']
|
||||
const toRefs: (typeof import('vue'))['toRefs']
|
||||
const toValue: (typeof import('vue'))['toValue']
|
||||
const triggerRef: (typeof import('vue'))['triggerRef']
|
||||
const unref: (typeof import('vue'))['unref']
|
||||
const useAttrs: (typeof import('vue'))['useAttrs']
|
||||
const useCssModule: (typeof import('vue'))['useCssModule']
|
||||
const useCssVars: (typeof import('vue'))['useCssVars']
|
||||
const useDialog: (typeof import('naive-ui'))['useDialog']
|
||||
const useId: (typeof import('vue'))['useId']
|
||||
const useLoadingBar: (typeof import('naive-ui'))['useLoadingBar']
|
||||
const useMessage: (typeof import('naive-ui'))['useMessage']
|
||||
const useModel: (typeof import('vue'))['useModel']
|
||||
const useNotification: (typeof import('naive-ui'))['useNotification']
|
||||
const useSlots: (typeof import('vue'))['useSlots']
|
||||
const useTemplateRef: (typeof import('vue'))['useTemplateRef']
|
||||
const watch: (typeof import('vue'))['watch']
|
||||
const watchEffect: (typeof import('vue'))['watchEffect']
|
||||
const watchPostEffect: (typeof import('vue'))['watchPostEffect']
|
||||
const watchSyncEffect: (typeof import('vue'))['watchSyncEffect']
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const getCurrentWatcher: typeof import('vue')['getCurrentWatcher']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isProxy: typeof import('vue')['isProxy']
|
||||
const isReactive: typeof import('vue')['isReactive']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const isShallow: typeof import('vue')['isShallow']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const toValue: typeof import('vue')['toValue']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useDialog: typeof import('naive-ui')['useDialog']
|
||||
const useId: typeof import('vue')['useId']
|
||||
const useLoadingBar: typeof import('naive-ui')['useLoadingBar']
|
||||
const useMessage: typeof import('naive-ui')['useMessage']
|
||||
const useModel: typeof import('vue')['useModel']
|
||||
const useNotification: typeof import('naive-ui')['useNotification']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type {
|
||||
Component,
|
||||
Slot,
|
||||
Slots,
|
||||
ComponentPublicInstance,
|
||||
ComputedRef,
|
||||
DirectiveBinding,
|
||||
ExtractDefaultPropTypes,
|
||||
ExtractPropTypes,
|
||||
ExtractPublicPropTypes,
|
||||
InjectionKey,
|
||||
PropType,
|
||||
Ref,
|
||||
ShallowRef,
|
||||
MaybeRef,
|
||||
MaybeRefOrGetter,
|
||||
VNode,
|
||||
WritableComputedRef
|
||||
} from 'vue'
|
||||
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
|
||||
@@ -33,22 +33,11 @@ const qualityKey = Object.keys(qualityMap)
|
||||
// 创建音质选择弹窗
|
||||
function createQualityDialog(songInfo: MusicItem, userQuality: string): Promise<string | null> {
|
||||
return new Promise((resolve) => {
|
||||
const LocalUserDetail = LocalUserDetailStore()
|
||||
|
||||
// 获取歌曲支持的音质列表
|
||||
const availableQualities = songInfo.types || []
|
||||
|
||||
// 检查用户设置的音质是否为特殊音质
|
||||
const isSpecialQuality = ['hires', 'atmos', 'master'].includes(userQuality)
|
||||
|
||||
// 如果是特殊音质且用户支持,添加到选项中(不管歌曲是否有这个音质)
|
||||
// 展示全部音质,但对超出用户最高音质的项做禁用呈现
|
||||
const userMaxIndex = qualityKey.indexOf(userQuality)
|
||||
const qualityOptions = [...availableQualities]
|
||||
if (isSpecialQuality && LocalUserDetail.userSource.quality === userQuality) {
|
||||
const hasSpecialQuality = availableQualities.some((q) => q.type === userQuality)
|
||||
if (!hasSpecialQuality) {
|
||||
qualityOptions.push({ type: userQuality, size: '源站无法得知此音质的文件大小' })
|
||||
}
|
||||
}
|
||||
|
||||
// 按音质优先级排序
|
||||
qualityOptions.sort((a, b) => {
|
||||
@@ -80,35 +69,48 @@ function createQualityDialog(songInfo: MusicItem, userQuality: string): Promise<
|
||||
msOverflowStyle: 'none'
|
||||
}
|
||||
},
|
||||
qualityOptions.map((quality) =>
|
||||
h(
|
||||
qualityOptions.map((quality) => {
|
||||
const idx = qualityKey.indexOf(quality.type)
|
||||
const disabled = idx !== -1 && idx > userMaxIndex
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
key: quality.type,
|
||||
class: 'quality-item',
|
||||
title: disabled ? '超出你的最高音质设置,已禁用' : undefined,
|
||||
style: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: '12px 16px',
|
||||
margin: '8px 0',
|
||||
border: '1px solid #e7e7e7',
|
||||
border: '1px solid ' + (disabled ? '#f0f0f0' : '#e7e7e7'),
|
||||
borderRadius: '6px',
|
||||
cursor: 'pointer',
|
||||
cursor: disabled ? 'not-allowed' : 'pointer',
|
||||
transition: 'all 0.2s ease',
|
||||
backgroundColor: quality.type === userQuality ? '#e6f7ff' : '#fff'
|
||||
backgroundColor:
|
||||
quality.type === userQuality ? (disabled ? '#f5faff' : '#e6f7ff') : '#fff',
|
||||
opacity: disabled ? 0.55 : 1
|
||||
},
|
||||
onClick: () => {
|
||||
if (disabled) return
|
||||
dialog.destroy()
|
||||
resolve(quality.type)
|
||||
},
|
||||
onMouseenter: (e: MouseEvent) => {
|
||||
if (disabled) return
|
||||
const target = e.target as HTMLElement
|
||||
target.style.backgroundColor = '#f0f9ff'
|
||||
target.style.borderColor = '#1890ff'
|
||||
},
|
||||
onMouseleave: (e: MouseEvent) => {
|
||||
const target = e.target as HTMLElement
|
||||
if (disabled) {
|
||||
target.style.backgroundColor =
|
||||
quality.type === userQuality ? '#f5faff' : '#fff'
|
||||
target.style.borderColor = '#f0f0f0'
|
||||
return
|
||||
}
|
||||
target.style.backgroundColor =
|
||||
quality.type === userQuality ? '#e6f7ff' : '#fff'
|
||||
target.style.borderColor = '#e7e7e7'
|
||||
@@ -122,7 +124,12 @@ function createQualityDialog(songInfo: MusicItem, userQuality: string): Promise<
|
||||
style: {
|
||||
fontWeight: '500',
|
||||
fontSize: '14px',
|
||||
color: quality.type === userQuality ? '#1890ff' : '#333'
|
||||
color:
|
||||
quality.type === userQuality
|
||||
? disabled
|
||||
? '#8fbfff'
|
||||
: '#1890ff'
|
||||
: '#333'
|
||||
}
|
||||
},
|
||||
qualityMap[quality.type] || quality.type
|
||||
@@ -132,7 +139,7 @@ function createQualityDialog(songInfo: MusicItem, userQuality: string): Promise<
|
||||
{
|
||||
style: {
|
||||
fontSize: '12px',
|
||||
color: '#999',
|
||||
color: disabled ? '#bbb' : '#999',
|
||||
marginTop: '2px'
|
||||
}
|
||||
},
|
||||
@@ -145,7 +152,7 @@ function createQualityDialog(songInfo: MusicItem, userQuality: string): Promise<
|
||||
class: 'quality-size',
|
||||
style: {
|
||||
fontSize: '12px',
|
||||
color: '#666',
|
||||
color: disabled ? '#999' : '#666',
|
||||
fontWeight: '500'
|
||||
}
|
||||
},
|
||||
@@ -153,7 +160,7 @@ function createQualityDialog(songInfo: MusicItem, userQuality: string): Promise<
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
})
|
||||
)
|
||||
]
|
||||
),
|
||||
@@ -187,58 +194,6 @@ async function downloadSingleSong(songInfo: MusicItem): Promise<void> {
|
||||
}
|
||||
|
||||
let quality = selectedQuality
|
||||
const isSpecialQuality = ['hires', 'atmos', 'master'].includes(quality)
|
||||
|
||||
// 如果选择的是特殊音质,先尝试下载
|
||||
if (isSpecialQuality) {
|
||||
try {
|
||||
console.log(`尝试下载特殊音质: ${quality} - ${qualityMap[quality]}`)
|
||||
const tip = MessagePlugin.success('开始下载歌曲:' + songInfo.name)
|
||||
|
||||
const specialResult = await window.api.music.requestSdk('downloadSingleSong', {
|
||||
pluginId: LocalUserDetail.userSource.pluginId?.toString() || '',
|
||||
source: songInfo.source,
|
||||
quality,
|
||||
songInfo: toRaw(songInfo) as any,
|
||||
tagWriteOptions: toRaw(settingsStore.settings.tagWriteOptions)
|
||||
})
|
||||
|
||||
;(await tip).close()
|
||||
|
||||
// 如果成功获取特殊音质链接,处理结果并返回
|
||||
if (specialResult) {
|
||||
if (!Object.hasOwn(specialResult, 'path')) {
|
||||
MessagePlugin.info(specialResult.message)
|
||||
} else {
|
||||
await NotifyPlugin.success({
|
||||
title: '下载成功',
|
||||
content: `${specialResult.message} 保存位置: ${specialResult.path}`
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
console.log(`下载${qualityMap[quality]}音质失败,重新选择音质`)
|
||||
MessagePlugin.error('该音质下载失败,请重新选择音质')
|
||||
|
||||
// 特殊音质下载失败,重新弹出选择框
|
||||
const retryQuality = await createQualityDialog(songInfo, userQuality)
|
||||
if (!retryQuality) {
|
||||
return
|
||||
}
|
||||
quality = retryQuality
|
||||
} catch (specialError) {
|
||||
console.log(`下载${qualityMap[quality]}音质出错:`, specialError)
|
||||
MessagePlugin.error('该音质下载失败,请重新选择音质')
|
||||
|
||||
// 特殊音质下载出错,重新弹出选择框
|
||||
const retryQuality = await createQualityDialog(songInfo, userQuality)
|
||||
if (!retryQuality) {
|
||||
return
|
||||
}
|
||||
quality = retryQuality
|
||||
}
|
||||
}
|
||||
|
||||
// 检查选择的音质是否超出歌曲支持的最高音质
|
||||
const songMaxQuality = songInfo.types[songInfo.types.length - 1]?.type
|
||||
@@ -255,7 +210,8 @@ async function downloadSingleSong(songInfo: MusicItem): Promise<void> {
|
||||
source: songInfo.source,
|
||||
quality,
|
||||
songInfo: toRaw(songInfo) as any,
|
||||
tagWriteOptions: toRaw(settingsStore.settings.tagWriteOptions)
|
||||
tagWriteOptions: toRaw(settingsStore.settings.tagWriteOptions),
|
||||
isCache: true
|
||||
})
|
||||
|
||||
;(await tip).close()
|
||||
|
||||
@@ -42,38 +42,6 @@ export async function getSongRealUrl(song: SongList): Promise<string> {
|
||||
const settingsStore = useSettingsStore()
|
||||
const isCache = settingsStore.settings.autoCacheMusic ?? true
|
||||
|
||||
// 检查是否为特殊音质(高清臻音、全景环绕或超清母带)
|
||||
const isSpecialQuality = ['hires', 'atmos', 'master'].includes(quality)
|
||||
|
||||
// 如果是特殊音质,先尝试获取对应链接
|
||||
if (isSpecialQuality) {
|
||||
try {
|
||||
console.log(`尝试获取特殊音质: ${quality} - ${qualityMap[quality]}`)
|
||||
const specialUrlData = await window.api.music.requestSdk('getMusicUrl', {
|
||||
pluginId: LocalUserDetail.userSource.pluginId as unknown as string,
|
||||
source: song.source,
|
||||
songInfo: song as any,
|
||||
quality,
|
||||
isCache
|
||||
})
|
||||
|
||||
// 如果成功获取特殊音质链接,直接返回
|
||||
if (
|
||||
typeof specialUrlData === 'string' ||
|
||||
(typeof specialUrlData === 'object' && !specialUrlData.error)
|
||||
) {
|
||||
console.log(`成功获取${qualityMap[quality]}链接`)
|
||||
return specialUrlData as string
|
||||
}
|
||||
|
||||
console.log(`获取${qualityMap[quality]}链接失败,回退到标准逻辑`)
|
||||
// 如果获取特殊音质失败,继续执行原有逻辑
|
||||
} catch (specialError) {
|
||||
console.log(`获取${qualityMap[quality]}链接出错,回退到标准逻辑:`, specialError)
|
||||
// 特殊音质获取失败,继续执行原有逻辑
|
||||
}
|
||||
}
|
||||
|
||||
// 原有逻辑:检查歌曲支持的最高音质
|
||||
if (
|
||||
qualityKey.indexOf(quality) >
|
||||
|
||||
Reference in New Issue
Block a user