存档:TS 重构前基线(lx 聚合源 = isolated-vm 加载器,签名方案已移除)
This commit is contained in:
commit
f289df4cd7
124 files changed
+14110
No files matched your search
@@ -0,0 +1,362 @@
|
||||
import { httpFetch } from '../request.js'
|
||||
import { formatPlayCount } from '../index.js'
|
||||
import { filterMusicInfoListV5 } from './musicInfo.js'
|
||||
import { createSignature } from './musicSearch.js'
|
||||
import { createHttpFetch } from './utils/index.js'
|
||||
|
||||
// const tagData = { code: '000000', info: 'SUCCESS', columnInfo: { columnTitle: '分类', columnId: '15244430', columnPid: '15031270', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 6, columnStatus: 1, columnCreateTime: '2016-11-10 10:53:05.077', columntype: 2011, contents: [{ contentId: '18464615', relationType: 2011, objectInfo: { columnTitle: '热门', columnId: '18464615', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 8, columnStatus: 1, columnCreateTime: '2017-02-20 16:09:13.400', columntype: 2011, contents: [{ contentId: '1000001672', relationType: 4034, objectInfo: { tagId: '1000001672', tagName: '流行', resourceType: '2034' }, relationSort: 9 }, { contentId: '1003449727', relationType: 4034, objectInfo: { tagId: '1003449727', tagName: '厂牌', resourceType: '2034' }, relationSort: 8 }, { contentId: '1000001795', relationType: 4034, objectInfo: { tagId: '1000001795', tagName: '伤感', resourceType: '2034' }, relationSort: 7 }, { contentId: '1001076080', relationType: 4034, objectInfo: { tagId: '1001076080', tagName: '电影', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001675', relationType: 4034, objectInfo: { tagId: '1000001675', tagName: '中国风', resourceType: '2034' }, relationSort: 5 }, { contentId: '1000001635', relationType: 4034, objectInfo: { tagId: '1000001635', tagName: '经典老歌', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001831', relationType: 4034, objectInfo: { tagId: '1000001831', tagName: '翻唱', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000001762', relationType: 4034, objectInfo: { tagId: '1000001762', tagName: '国语', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266029', customizedPicUrls: [] }, relationSort: 6 }, { contentId: '15244503', relationType: 2011, objectInfo: { columnTitle: '主题', columnId: '15244503', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 23, columnStatus: 1, columnCreateTime: '2016-11-10 10:54:10.261', columntype: 2011, contents: [{ contentId: '1003449727', relationType: 4034, objectInfo: { tagId: '1003449727', tagName: '厂牌', resourceType: '2034' }, relationSort: 29 }, { contentId: '1001076080', relationType: 4034, objectInfo: { tagId: '1001076080', tagName: '电影', resourceType: '2034' }, relationSort: 28 }, { contentId: '1001076078', relationType: 4034, objectInfo: { tagId: '1001076078', tagName: '电视剧', resourceType: '2034' }, relationSort: 27 }, { contentId: '1001076083', relationType: 4034, objectInfo: { tagId: '1001076083', tagName: '综艺', resourceType: '2034' }, relationSort: 26 }, { contentId: '1000001827', relationType: 4034, objectInfo: { tagId: '1000001827', tagName: 'KTV', resourceType: '2034' }, relationSort: 23 }, { contentId: '1000001698', relationType: 4034, objectInfo: { tagId: '1000001698', tagName: '爱情', resourceType: '2034' }, relationSort: 22 }, { contentId: '1000001635', relationType: 4034, objectInfo: { tagId: '1000001635', tagName: '经典老歌', resourceType: '2034' }, relationSort: 21 }, { contentId: '1001076096', relationType: 4034, objectInfo: { tagId: '1001076096', tagName: '网络热歌', resourceType: '2034' }, relationSort: 20 }, { contentId: '1000001780', relationType: 4034, objectInfo: { tagId: '1000001780', tagName: '儿童歌曲', resourceType: '2034' }, relationSort: 19 }, { contentId: '1000587702', relationType: 4034, objectInfo: { tagId: '1000587702', tagName: '广场舞', resourceType: '2034' }, relationSort: 18 }, { contentId: '1000587717', relationType: 4034, objectInfo: { tagId: '1000587717', tagName: '70后', resourceType: '2034' }, relationSort: 17 }, { contentId: '1000587718', relationType: 4034, objectInfo: { tagId: '1000587718', t
Line truncated
|
||||
|
||||
export default {
|
||||
_requestObj_tags: null,
|
||||
_requestObj_list: null,
|
||||
limit_list: 30,
|
||||
limit_song: 50,
|
||||
successCode: '000000',
|
||||
cachedDetailInfo: {},
|
||||
cachedUrl: {},
|
||||
sortList: [
|
||||
{
|
||||
name: '推荐',
|
||||
id: '15127315',
|
||||
// id: '1',
|
||||
},
|
||||
// {
|
||||
// name: '最新',
|
||||
// id: '15127272',
|
||||
// // id: '2',
|
||||
// },
|
||||
],
|
||||
regExps: {
|
||||
list: /<li><div class="thumb">.+?<\/li>/g,
|
||||
listInfo: /.+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+)(?:\?.*|&.*$|#.*$|$)/,
|
||||
},
|
||||
tagsUrl: 'https://app.c.nf.migu.cn/pc/v1.0/template/musiclistplaza-taglist/release',
|
||||
// tagsUrl: 'https://app.c.nf.migu.cn/MIGUM2.0/v1.0/content/indexTagPage.do?needAll=0',
|
||||
getSongListUrl(sortId, tagId, page) {
|
||||
// if (tagId == null) {
|
||||
// return sortId == 'recommend'
|
||||
// ? `https://music.migu.cn/v3/music/playlist?page=${page}&from=migu`
|
||||
// : `https://music.migu.cn/v3/music/playlist?sort=${sortId}&page=${page}&from=migu`
|
||||
// }
|
||||
// return `https://music.migu.cn/v3/music/playlist?tagId=${tagId}&page=${page}&from=migu`
|
||||
if (!tagId) {
|
||||
// return `https://app.c.nf.migu.cn/MIGUM2.0/v2.0/content/getMusicData.do?count=${this.limit_list}&start=${page}&templateVersion=5&type=1`
|
||||
// return `https://c.musicapp.migu.cn/MIGUM2.0/v2.0/content/getMusicData.do?count=${this.limit_list}&start=${page}&templateVersion=5&type=${sortId}`
|
||||
// https://app.c.nf.migu.cn/MIGUM2.0/v2.0/content/getMusicData.do?count=50&start=2&templateVersion=5&type=1
|
||||
// return `https://m.music.migu.cn/migu/remoting/playlist_bycolumnid_tag?playListType=2&type=1&columnId=${sortId}&startIndex=${(page - 1) * 10}`
|
||||
return `https://app.c.nf.migu.cn/pc/bmw/page-data/playlist-square-recommend/v1.0?templateVersion=2&pageNo=${page}`
|
||||
}
|
||||
// return `https://app.c.nf.migu.cn/MIGUM2.0/v2.0/content/getMusicData.do?area=2&count=${this.limit_list}&start=${page}&tags=${tagId}&templateVersion=5&type=3`
|
||||
return `https://app.c.nf.migu.cn/pc/v1.0/template/musiclistplaza-listbytag/release?pageNumber=${page}&templateVersion=2&tagId=${tagId}`
|
||||
// return `https://m.music.migu.cn/migu/remoting/playlist_bycolumnid_tag?playListType=2&type=1&tagId=${tagId}&startIndex=${(page - 1) * 10}`
|
||||
},
|
||||
getSongListDetailUrl(id, page) {
|
||||
return `https://app.c.nf.migu.cn/MIGUM3.0/resource/playlist/song/v2.0?pageNo=${page}&pageSize=${this.limit_song}&playlistId=${id}`
|
||||
// return `https://app.c.nf.migu.cn/MIGUM2.0/v1.0/user/queryMusicListSongs.do?musicListId=${id}&pageNo=${page}&pageSize=${this.limit_song}`
|
||||
},
|
||||
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/',
|
||||
// language: 'Chinese',
|
||||
// ua: 'Android_migu',
|
||||
// mode: 'android',
|
||||
// version: '6.8.5',
|
||||
},
|
||||
|
||||
getListDetailList(id, page, tryNum = 0) {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
// https://h5.nf.migu.cn/app/v4/p/share/playlist/index.html?id=184187437&channel=0146921
|
||||
|
||||
// if (/playlist\/index\.html\?/.test(id)) {
|
||||
// id = id.replace(/.*(?:\?|&)id=(\d+)(?:&.*|$)/, '$1')
|
||||
// } else if ((/[?&:/]/.test(id))) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
|
||||
const requestObj_listDetail = httpFetch(this.getSongListDetailUrl(id, page), { headers: this.defaultHeaders })
|
||||
return requestObj_listDetail.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getListDetailList(id, page, ++tryNum)
|
||||
// console.log(JSON.stringify(body))
|
||||
// console.log(body)
|
||||
return {
|
||||
list: filterMusicInfoListV5(body.data.songList),
|
||||
page,
|
||||
limit: this.limit_song,
|
||||
total: body.data.totalCount,
|
||||
source: 'mg',
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getListDetailInfo(id, tryNum = 0) {
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
|
||||
if (this.cachedDetailInfo[id]) return Promise.resolve(this.cachedDetailInfo[id])
|
||||
const requestObj_listDetailInfo = httpFetch(`https://c.musicapp.migu.cn/MIGUM3.0/resource/playlist/v2.0?playlistId=${id}`, {
|
||||
headers: this.defaultHeaders,
|
||||
})
|
||||
return requestObj_listDetailInfo.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getListDetail(id, ++tryNum)
|
||||
// console.log(JSON.stringify(body))
|
||||
// console.log(body)
|
||||
const cachedDetailInfo = this.cachedDetailInfo[id] = {
|
||||
name: body.data.title,
|
||||
img: body.data.imgItem.img,
|
||||
desc: body.data.summary,
|
||||
author: body.data.ownerName,
|
||||
play_count: formatPlayCount(body.data.opNumItem.playNum),
|
||||
}
|
||||
return cachedDetailInfo
|
||||
})
|
||||
},
|
||||
|
||||
async getDetailUrl(link, page, retryNum = 0) {
|
||||
if (retryNum > 3) return Promise.reject(new Error('link try max num'))
|
||||
|
||||
const requestObj_listDetailLink = httpFetch(link, {
|
||||
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,
|
||||
},
|
||||
})
|
||||
const { headers: { location }, statusCode } = await requestObj_listDetailLink.promise
|
||||
// console.log(body, location)
|
||||
if (statusCode > 400) return this.getDetailUrl(link, page, ++retryNum)
|
||||
if (location) {
|
||||
this.cachedUrl[link] = location
|
||||
return this.getListDetail(location, page)
|
||||
}
|
||||
return Promise.reject(new Error('link get failed'))
|
||||
},
|
||||
|
||||
getListDetail(id, page, retryNum = 0) { // 获取歌曲列表内的音乐
|
||||
// https://h5.nf.migu.cn/app/v4/p/share/playlist/index.html?id=184187437&channel=0146921
|
||||
// http://c.migu.cn/00bTY6?ifrom=babddaadfde4ebeda289d671ab62f236
|
||||
// https://music.migu.cn/v5/#/playlist?playlistId=221573417
|
||||
if (/\/playlist[/?]/.test(id)) {
|
||||
id = /(?:playlistId|id)=(\d+)/.exec(id)?.[1]
|
||||
if (!id) throw new Error('list detail id parse failed')
|
||||
} else if (this.regExps.listDetailLink.test(id)) {
|
||||
id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
} else if ((/[?&:/]/.test(id))) {
|
||||
const url = this.cachedUrl[id]
|
||||
return url ? this.getListDetail(url, page) : this.getDetailUrl(id, page)
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
this.getListDetailList(id, page, retryNum),
|
||||
this.getListDetailInfo(id, retryNum),
|
||||
]).then(([listData, info]) => {
|
||||
listData.info = info
|
||||
return listData
|
||||
})
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page, tryNum = 0) {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
this._requestObj_list = httpFetch(this.getSongListUrl(sortId, tagId, page), {
|
||||
headers: this.defaultHeaders,
|
||||
// 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',
|
||||
// },
|
||||
})
|
||||
// return this._requestObj_list.promise.then(({ statusCode, body }) => {
|
||||
// if (statusCode !== 200) return this.getList(sortId, tagId, page)
|
||||
// let list = body.replace(/[\r\n]/g, '').match(this.regExps.list)
|
||||
// if (!list) return Promise.reject(new Error('获取列表失败'))
|
||||
// return list.map(item => {
|
||||
// let info = item.match(this.regExps.listInfo)
|
||||
// return {
|
||||
// play_count: info[4],
|
||||
// id: info[2],
|
||||
// author: '',
|
||||
// name: info[3],
|
||||
// time: '',
|
||||
// img: info[1],
|
||||
// grade: 0,
|
||||
// desc: '',
|
||||
// source: 'mg',
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// return this._requestObj_list.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
// if (body.retCode !== '100000' || body.retMsg.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
|
||||
// return {
|
||||
// list: this.filterList(body.retMsg.playlist),
|
||||
// total: parseInt(body.retMsg.countSize),
|
||||
// page,
|
||||
// limit: this.limit_list,
|
||||
// source: 'mg',
|
||||
// }
|
||||
// })
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
// console.log(body)
|
||||
// if (body.retCode !== '000000') return this.getList(sortId, tagId, page, ++tryNum)
|
||||
if (body.code !== '000000') return this.getList(sortId, tagId, page, ++tryNum)
|
||||
const list = body.data.contents ? this.filterList2(body.data.contents) : this.filterList(body.data.contentItemList[1].itemList)
|
||||
return {
|
||||
list,
|
||||
total: 99999,
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'mg',
|
||||
}
|
||||
})
|
||||
},
|
||||
filterList2(listData, list = [], ids = new Set()) {
|
||||
for (const item of listData) {
|
||||
if (item.contents) this.filterList2(item.contents, list, ids)
|
||||
else if (item.resType == '2021' && !ids.has(item.resId)) {
|
||||
ids.add(item.resId)
|
||||
list.push({
|
||||
id: String(item.resId),
|
||||
author: '',
|
||||
name: item.txt,
|
||||
// time: dateFormat(item.createTime, 'Y-M-D'),
|
||||
img: item.img,
|
||||
// grade: item.grade,
|
||||
// total: item.contentCount,
|
||||
desc: item.txt2,
|
||||
source: 'mg',
|
||||
})
|
||||
}
|
||||
}
|
||||
return list
|
||||
},
|
||||
filterList(rawData) {
|
||||
// console.log(rawData)
|
||||
return rawData.map(item => ({
|
||||
play_count: item.barList[0]?.title,
|
||||
id: String(item.logEvent.contentId),
|
||||
author: '',
|
||||
name: item.title,
|
||||
// time: dateFormat(item.createTime, 'Y-M-D'),
|
||||
img: item.imageUrl,
|
||||
// grade: item.grade,
|
||||
// total: item.contentCount,
|
||||
desc: '',
|
||||
source: 'mg',
|
||||
}))
|
||||
},
|
||||
|
||||
// 获取标签
|
||||
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(this.tagsUrl, { headers: this.defaultHeaders })
|
||||
return this._requestObj_tags.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getTag(++tryNum)
|
||||
// console.log(body)
|
||||
return this.filterTagInfo(body.data)
|
||||
})
|
||||
// return Promise.resolve(this.filterTagInfo(tagData.columnInfo.contents))
|
||||
},
|
||||
filterTagInfo(rawList) {
|
||||
return {
|
||||
hotTag: rawList[0].content.map(({ texts: [name, id] }) => ({
|
||||
id,
|
||||
name,
|
||||
source: 'mg',
|
||||
})),
|
||||
tags: rawList.slice(1).map(({ header, content }) => ({
|
||||
name: header.title,
|
||||
list: content.map(({ texts: [name, id] }) => ({
|
||||
// parent_id: objectInfo.columnId,
|
||||
// parent_name: objectInfo.columnTitle,
|
||||
id,
|
||||
name,
|
||||
source: 'mg',
|
||||
})),
|
||||
})),
|
||||
source: 'mg',
|
||||
}
|
||||
// return {
|
||||
// hotTag: rawList[0].objectInfo.contents.map(item => ({
|
||||
// id: item.objectInfo.tagId,
|
||||
// name: item.objectInfo.tagName,
|
||||
// source: 'mg',
|
||||
// })),
|
||||
// tags: rawList.slice(1).map(({ objectInfo }) => ({
|
||||
// name: objectInfo.columnTitle,
|
||||
// list: objectInfo.contents.map(item => ({
|
||||
// parent_id: objectInfo.columnId,
|
||||
// parent_name: objectInfo.columnTitle,
|
||||
// id: item.objectInfo.tagId,
|
||||
// name: item.objectInfo.tagName,
|
||||
// source: 'mg',
|
||||
// })),
|
||||
// })),
|
||||
// source: 'mg',
|
||||
// }
|
||||
},
|
||||
getTags() {
|
||||
return this.getTag()
|
||||
},
|
||||
|
||||
getDetailPageUrl(id) {
|
||||
if (/playlist\/index\.html\?/.test(id)) {
|
||||
id = id.replace(/.*(?:\?|&)id=(\d+)(?:&.*|$)/, '$1')
|
||||
} else if (this.regExps.listDetailLink.test(id)) {
|
||||
id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
}
|
||||
return `https://music.migu.cn/v3/music/playlist/${id}`
|
||||
},
|
||||
|
||||
filterSongListResult(raw) {
|
||||
const list = []
|
||||
raw.forEach(item => {
|
||||
if (!item.id) return
|
||||
|
||||
const playCount = parseInt(item.playNum)
|
||||
list.push({
|
||||
play_count: isNaN(playCount) ? 0 : formatPlayCount(playCount),
|
||||
id: item.id,
|
||||
author: item.userName,
|
||||
name: item.name,
|
||||
img: item.musicListPicUrl,
|
||||
total: item.musicNum,
|
||||
source: 'mg',
|
||||
})
|
||||
})
|
||||
return list
|
||||
},
|
||||
search(text, page, limit = 20) {
|
||||
const timeStr = Date.now().toString()
|
||||
const signResult = createSignature(timeStr, text)
|
||||
return createHttpFetch(`https://jadeite.migu.cn/music_search/v3/search/searchAll?isCorrect=1&isCopyright=1&searchSwitch=%7B%22song%22%3A0%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22bestShow%22%3A0%2C%22songlist%22%3A1%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(text)}&pageNo=${page}&sort=0&sid=USS`, {
|
||||
headers: {
|
||||
uiVersion: 'A_music_3.6.1',
|
||||
deviceId: signResult.deviceId,
|
||||
timestamp: timeStr,
|
||||
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',
|
||||
},
|
||||
}).then(body => {
|
||||
if (!body.songListResultData) throw new Error('get song list faild.')
|
||||
|
||||
const list = this.filterSongListResult(body.songListResultData.result)
|
||||
return {
|
||||
list,
|
||||
limit,
|
||||
total: parseInt(body.songListResultData.totalCount),
|
||||
source: 'mg',
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
// getList
|
||||
// getTags
|
||||
// getListDetail
|
||||
Reference in new issue
Block a user