556 lines
19 KiB
JavaScript
556 lines
19 KiB
JavaScript
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
const axios_1 = require("axios");
|
||
const CryptoJs = require("crypto-js");
|
||
const qs = require("qs");
|
||
const bigInt = require("big-integer");
|
||
const dayjs = require("dayjs");
|
||
const cheerio = require("cheerio");
|
||
function create_key() {
|
||
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
|
||
for (d = 0; 16 > d; d += 1)
|
||
(e = Math.random() * b.length), (e = Math.floor(e)), (c += b.charAt(e));
|
||
return c;
|
||
}
|
||
function AES(a, b) {
|
||
var c = CryptoJs.enc.Utf8.parse(b), d = CryptoJs.enc.Utf8.parse("0102030405060708"), e = CryptoJs.enc.Utf8.parse(a), f = CryptoJs.AES.encrypt(e, c, {
|
||
iv: d,
|
||
mode: CryptoJs.mode.CBC,
|
||
});
|
||
return f.toString();
|
||
}
|
||
function Rsa(text) {
|
||
text = text.split("").reverse().join("");
|
||
const d = "010001";
|
||
const e = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7";
|
||
const hexText = text
|
||
.split("")
|
||
.map((_) => _.charCodeAt(0).toString(16))
|
||
.join("");
|
||
const res = bigInt(hexText, 16)
|
||
.modPow(bigInt(d, 16), bigInt(e, 16))
|
||
.toString(16);
|
||
return Array(256 - res.length)
|
||
.fill("0")
|
||
.join("")
|
||
.concat(res);
|
||
}
|
||
function getParamsAndEnc(text) {
|
||
const first = AES(text, "0CoJUm6Qyw8W8jud");
|
||
const rand = create_key();
|
||
const params = AES(first, rand);
|
||
const encSecKey = Rsa(rand);
|
||
return {
|
||
params,
|
||
encSecKey,
|
||
};
|
||
}
|
||
function formatMusicItem(_) {
|
||
var _a, _b, _c, _d;
|
||
const album = _.al || _.album;
|
||
return {
|
||
id: _.id,
|
||
artwork: album === null || album === void 0 ? void 0 : album.picUrl,
|
||
title: _.name,
|
||
artist: (_.ar || _.artists)[0].name,
|
||
album: album === null || album === void 0 ? void 0 : album.name,
|
||
url: `https://share.duanx.cn/url/wy/${_.id}/128k`,
|
||
qualities: {
|
||
low: {
|
||
size: (_a = (_.l || {})) === null || _a === void 0 ? void 0 : _a.size,
|
||
},
|
||
standard: {
|
||
size: (_b = (_.m || {})) === null || _b === void 0 ? void 0 : _b.size,
|
||
},
|
||
high: {
|
||
size: (_c = (_.h || {})) === null || _c === void 0 ? void 0 : _c.size,
|
||
},
|
||
super: {
|
||
size: (_d = (_.sq || {})) === null || _d === void 0 ? void 0 : _d.size,
|
||
},
|
||
},
|
||
copyrightId: _ === null || _ === void 0 ? void 0 : _.copyrightId
|
||
};
|
||
}
|
||
function formatAlbumItem(_) {
|
||
return {
|
||
id: _.id,
|
||
artist: _.artist.name,
|
||
title: _.name,
|
||
artwork: _.picUrl,
|
||
description: "",
|
||
date: dayjs.unix(_.publishTime / 1000).format("YYYY-MM-DD"),
|
||
};
|
||
}
|
||
const pageSize = 30;
|
||
async function searchBase(query, page, type) {
|
||
const data = {
|
||
s: query,
|
||
limit: pageSize,
|
||
type: type,
|
||
offset: (page - 1) * pageSize,
|
||
csrf_token: "",
|
||
};
|
||
const pae = getParamsAndEnc(JSON.stringify(data));
|
||
const paeData = qs.stringify(pae);
|
||
const headers = {
|
||
authority: "music.163.com",
|
||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
"content-type": "application/x-www-form-urlencoded",
|
||
accept: "*/*",
|
||
origin: "https://music.163.com",
|
||
"sec-fetch-site": "same-origin",
|
||
"sec-fetch-mode": "cors",
|
||
"sec-fetch-dest": "empty",
|
||
referer: "https://music.163.com/search/",
|
||
"accept-language": "zh-CN,zh;q=0.9",
|
||
};
|
||
const res = (await (0, axios_1.default)({
|
||
method: "post",
|
||
url: "https://music.163.com/weapi/search/get",
|
||
headers,
|
||
data: paeData,
|
||
})).data;
|
||
return res;
|
||
}
|
||
async function searchMusic(query, page) {
|
||
const res = await searchBase(query, page, 1);
|
||
const songs = res.result.songs
|
||
.map(formatMusicItem);
|
||
return {
|
||
isEnd: res.result.songCount <= page * pageSize,
|
||
data: songs,
|
||
};
|
||
}
|
||
async function searchAlbum(query, page) {
|
||
const res = await searchBase(query, page, 10);
|
||
const albums = res.result.albums.map(formatAlbumItem);
|
||
return {
|
||
isEnd: res.result.albumCount <= page * pageSize,
|
||
data: albums,
|
||
};
|
||
}
|
||
async function searchArtist(query, page) {
|
||
const res = await searchBase(query, page, 100);
|
||
const artists = res.result.artists.map((_) => ({
|
||
name: _.name,
|
||
id: _.id,
|
||
avatar: _.img1v1Url,
|
||
worksNum: _.albumSize,
|
||
}));
|
||
return {
|
||
isEnd: res.result.artistCount <= page * pageSize,
|
||
data: artists,
|
||
};
|
||
}
|
||
async function searchMusicSheet(query, page) {
|
||
const res = await searchBase(query, page, 1000);
|
||
const playlists = res.result.playlists.map((_) => {
|
||
var _a;
|
||
return ({
|
||
title: _.name,
|
||
id: _.id,
|
||
coverImg: _.coverImgUrl,
|
||
artist: (_a = _.creator) === null || _a === void 0 ? void 0 : _a.nickname,
|
||
playCount: _.playCount,
|
||
worksNum: _.trackCount,
|
||
});
|
||
});
|
||
return {
|
||
isEnd: res.result.playlistCount <= page * pageSize,
|
||
data: playlists,
|
||
};
|
||
}
|
||
async function searchLyric(query, page) {
|
||
var _a, _b;
|
||
const res = await searchBase(query, page, 1006);
|
||
const lyrics = (_b = (_a = res.result.songs) === null || _a === void 0 ? void 0 : _a.map((it) => {
|
||
var _a, _b, _c, _d;
|
||
return ({
|
||
title: it.name,
|
||
artist: (_a = it.ar) === null || _a === void 0 ? void 0 : _a.map((_) => _.name).join(", "),
|
||
id: it.id,
|
||
artwork: (_b = it.al) === null || _b === void 0 ? void 0 : _b.picUrl,
|
||
album: (_c = it.al) === null || _c === void 0 ? void 0 : _c.name,
|
||
rawLrcTxt: (_d = it.lyrics) === null || _d === void 0 ? void 0 : _d.join("\n"),
|
||
});
|
||
})) !== null && _b !== void 0 ? _b : [];
|
||
return {
|
||
isEnd: res.result.songCount <= page * pageSize,
|
||
data: lyrics,
|
||
};
|
||
}
|
||
async function getArtistWorks(artistItem, page, type) {
|
||
const data = {
|
||
csrf_token: "",
|
||
};
|
||
const pae = getParamsAndEnc(JSON.stringify(data));
|
||
const paeData = qs.stringify(pae);
|
||
const headers = {
|
||
authority: "music.163.com",
|
||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
"content-type": "application/x-www-form-urlencoded",
|
||
accept: "*/*",
|
||
origin: "https://music.163.com",
|
||
"sec-fetch-site": "same-origin",
|
||
"sec-fetch-mode": "cors",
|
||
"sec-fetch-dest": "empty",
|
||
referer: "https://music.163.com/search/",
|
||
"accept-language": "zh-CN,zh;q=0.9",
|
||
};
|
||
if (type === "music") {
|
||
const res = (await (0, axios_1.default)({
|
||
method: "post",
|
||
url: `https://music.163.com/weapi/v1/artist/${artistItem.id}?csrf_token=`,
|
||
headers,
|
||
data: paeData,
|
||
})).data;
|
||
return {
|
||
isEnd: true,
|
||
data: res.hotSongs.map(formatMusicItem),
|
||
};
|
||
}
|
||
else if (type === "album") {
|
||
const res = (await (0, axios_1.default)({
|
||
method: "post",
|
||
url: `https://music.163.com/weapi/artist/albums/${artistItem.id}?csrf_token=`,
|
||
headers,
|
||
data: paeData,
|
||
})).data;
|
||
return {
|
||
isEnd: true,
|
||
data: res.hotAlbums.map(formatAlbumItem),
|
||
};
|
||
}
|
||
}
|
||
async function getTopListDetail(topListItem) {
|
||
const musicList = await getSheetMusicById(topListItem.id);
|
||
return Object.assign(Object.assign({}, topListItem), { musicList });
|
||
}
|
||
async function getLyric(musicItem) {
|
||
const headers = {
|
||
Referer: "https://y.music.163.com/",
|
||
Origin: "https://y.music.163.com/",
|
||
authority: "music.163.com",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
"Content-Type": "application/x-www-form-urlencoded",
|
||
};
|
||
const data = { id: musicItem.id, lv: -1, tv: -1, csrf_token: "" };
|
||
const pae = getParamsAndEnc(JSON.stringify(data));
|
||
const paeData = qs.stringify(pae);
|
||
const result = (await (0, axios_1.default)({
|
||
method: "post",
|
||
url: `https://interface.music.163.com/weapi/song/lyric?csrf_token=`,
|
||
headers,
|
||
data: paeData,
|
||
})).data;
|
||
return {
|
||
rawLrc: result.lrc.lyric,
|
||
};
|
||
}
|
||
async function getMusicInfo(musicItem) {
|
||
const headers = {
|
||
Referer: "https://y.music.163.com/",
|
||
Origin: "https://y.music.163.com/",
|
||
authority: "music.163.com",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
"Content-Type": "application/x-www-form-urlencoded",
|
||
};
|
||
const data = { id: musicItem.id, ids: `[${musicItem.id}]` };
|
||
const result = (await axios_1.get('http://music.163.com/api/song/detail',
|
||
{
|
||
headers,
|
||
params: data
|
||
})).data;
|
||
return {
|
||
artwork: result.songs[0].album.picUrl,
|
||
};
|
||
}
|
||
async function getAlbumInfo(albumItem) {
|
||
const headers = {
|
||
Referer: "https://y.music.163.com/",
|
||
Origin: "https://y.music.163.com/",
|
||
authority: "music.163.com",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
"Content-Type": "application/x-www-form-urlencoded",
|
||
};
|
||
const data = {
|
||
resourceType: 3,
|
||
resourceId: albumItem.id,
|
||
limit: 15,
|
||
csrf_token: "",
|
||
};
|
||
const pae = getParamsAndEnc(JSON.stringify(data));
|
||
const paeData = qs.stringify(pae);
|
||
const res = (await (0, axios_1.default)({
|
||
method: "post",
|
||
url: `https://interface.music.163.com/weapi/v1/album/${albumItem.id}?csrf_token=`,
|
||
headers,
|
||
data: paeData,
|
||
})).data;
|
||
return {
|
||
albumItem: { description: res.album.description },
|
||
musicList: (res.songs || [])
|
||
.map(formatMusicItem),
|
||
};
|
||
}
|
||
async function getValidMusicItems(trackIds) {
|
||
const headers = {
|
||
Referer: "https://y.music.163.com/",
|
||
Origin: "https://y.music.163.com/",
|
||
authority: "music.163.com",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
"Content-Type": "application/x-www-form-urlencoded",
|
||
};
|
||
try {
|
||
// 获取歌曲详情数据
|
||
const res = (await axios_1.default.get(`https://music.163.com/api/song/detail/?ids=[${trackIds.join(",")}]`, { headers })).data;
|
||
// 直接格式化歌曲项,不检查 URL
|
||
const validMusicItems = res.songs.map(formatMusicItem);
|
||
return validMusicItems;
|
||
}
|
||
catch (e) {
|
||
console.error(e);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
async function getSheetMusicById(id) {
|
||
const headers = {
|
||
Referer: "https://y.music.163.com/",
|
||
Origin: "https://y.music.163.com/",
|
||
authority: "music.163.com",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
};
|
||
const sheetDetail = (await axios_1.default.get(`https://music.163.com/api/v3/playlist/detail?id=${id}&n=5000`, {
|
||
headers,
|
||
})).data;
|
||
const trackIds = sheetDetail.playlist.trackIds.map((_) => _.id);
|
||
let result = [];
|
||
let idx = 0;
|
||
while (idx * 200 < trackIds.length) {
|
||
const res = await getValidMusicItems(trackIds.slice(idx * 200, (idx + 1) * 200));
|
||
result = result.concat(res);
|
||
++idx;
|
||
}
|
||
return result;
|
||
}
|
||
async function importMusicSheet(urlLike) {
|
||
const matchResult = urlLike.match(/(?:https:\/\/y\.music\.163.com\/m\/playlist\?id=([0-9]+))|(?:https?:\/\/music\.163\.com\/playlist\/([0-9]+)\/.*)|(?:https?:\/\/music.163.com(?:\/#)?\/playlist\?id=(\d+))|(?:^\s*(\d+)\s*$)/);
|
||
const id = matchResult[1] || matchResult[2] || matchResult[3] || matchResult[4];
|
||
return getSheetMusicById(id);
|
||
}
|
||
async function getTopLists() {
|
||
const res = await axios_1.default.get("https://music.163.com/discover/toplist", {
|
||
headers: {
|
||
referer: "https://music.163.com/",
|
||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54",
|
||
},
|
||
});
|
||
const $ = cheerio.load(res.data);
|
||
const children = $(".n-minelst").children();
|
||
const groups = [];
|
||
let currentGroup = {};
|
||
for (let c of children) {
|
||
if (c.tagName == "h2") {
|
||
if (currentGroup.title) {
|
||
groups.push(currentGroup);
|
||
}
|
||
currentGroup = {};
|
||
currentGroup.title = $(c).text();
|
||
currentGroup.data = [];
|
||
}
|
||
else if (c.tagName === "ul") {
|
||
let sections = $(c).children();
|
||
currentGroup.data = sections
|
||
.map((index, element) => {
|
||
const ele = $(element);
|
||
const id = ele.attr("data-res-id");
|
||
const coverImg = ele.find("img").attr("src").replace(/(\.jpg\?).*/, ".jpg?param=800y800");
|
||
const title = ele.find("p.name").text();
|
||
const description = ele.find("p.s-fc4").text();
|
||
return {
|
||
id,
|
||
coverImg,
|
||
title,
|
||
description,
|
||
};
|
||
})
|
||
.toArray();
|
||
}
|
||
}
|
||
if (currentGroup.title) {
|
||
groups.push(currentGroup);
|
||
}
|
||
return groups;
|
||
}
|
||
const qualityLevels = {
|
||
low: "128k",
|
||
standard: "320k",
|
||
high: "320k",
|
||
super: "320k",
|
||
};
|
||
async function getMediaSource(musicItem, quality) {
|
||
const res = (
|
||
await axios_1.default.get(`https://lxmusicapi.onrender.com/url/wy/${musicItem.id}/${qualityLevels[quality]}`, {
|
||
headers: {
|
||
"X-Request-Key": "share-v2"
|
||
},
|
||
})
|
||
).data;
|
||
return {
|
||
url: res.url,
|
||
};
|
||
}
|
||
const headers = {
|
||
authority: "music.163.com",
|
||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
"content-type": "application/x-www-form-urlencoded",
|
||
accept: "*/*",
|
||
origin: "https://music.163.com",
|
||
"sec-fetch-site": "same-origin",
|
||
"sec-fetch-mode": "cors",
|
||
"sec-fetch-dest": "empty",
|
||
referer: "https://music.163.com/",
|
||
"accept-language": "zh-CN,zh;q=0.9",
|
||
};
|
||
async function getRecommendSheetTags() {
|
||
const data = {
|
||
csrf_token: "",
|
||
};
|
||
const pae = getParamsAndEnc(JSON.stringify(data));
|
||
const paeData = qs.stringify(pae);
|
||
const res = (await (0, axios_1.default)({
|
||
method: "post",
|
||
url: "https://music.163.com/weapi/playlist/catalogue",
|
||
headers,
|
||
data: paeData,
|
||
})).data;
|
||
const cats = res.categories;
|
||
const map = {};
|
||
const catData = Object.entries(cats).map((_) => {
|
||
const tagData = {
|
||
title: _[1],
|
||
data: [],
|
||
};
|
||
map[_[0]] = tagData;
|
||
return tagData;
|
||
});
|
||
const pinned = [];
|
||
res.sub.forEach((tag) => {
|
||
const _tag = {
|
||
id: tag.name,
|
||
title: tag.name,
|
||
};
|
||
if (tag.hot) {
|
||
pinned.push(_tag);
|
||
}
|
||
map[tag.category].data.push(_tag);
|
||
});
|
||
return {
|
||
pinned,
|
||
data: catData,
|
||
};
|
||
}
|
||
async function getRecommendSheetsByTag(tag, page) {
|
||
const pageSize = 20;
|
||
const data = {
|
||
cat: tag.id || "全部",
|
||
order: "hot",
|
||
limit: pageSize,
|
||
offset: (page - 1) * pageSize,
|
||
total: true,
|
||
csrf_token: "",
|
||
};
|
||
const pae = getParamsAndEnc(JSON.stringify(data));
|
||
const paeData = qs.stringify(pae);
|
||
const res = (await (0, axios_1.default)({
|
||
method: "post",
|
||
url: "https://music.163.com/weapi/playlist/list",
|
||
headers,
|
||
data: paeData,
|
||
})).data;
|
||
const playLists = res.playlists.map((_) => ({
|
||
id: _.id,
|
||
artist: _.creator.nickname,
|
||
title: _.name,
|
||
artwork: _.coverImgUrl,
|
||
playCount: _.playCount,
|
||
createUserId: _.userId,
|
||
createTime: _.createTime,
|
||
description: _.description,
|
||
}));
|
||
return {
|
||
isEnd: !(res.more === true),
|
||
data: playLists,
|
||
};
|
||
}
|
||
async function getMusicSheetInfo(sheet, page) {
|
||
let trackIds = sheet._trackIds;
|
||
if (!trackIds) {
|
||
const id = sheet.id;
|
||
const headers = {
|
||
Referer: "https://y.music.163.com/",
|
||
Origin: "https://y.music.163.com/",
|
||
authority: "music.163.com",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36",
|
||
};
|
||
const sheetDetail = (await axios_1.default.get(`https://music.163.com/api/v3/playlist/detail?id=${id}&n=5000`, {
|
||
headers,
|
||
})).data;
|
||
trackIds = sheetDetail.playlist.trackIds.map((_) => _.id);
|
||
}
|
||
const pageSize = 40;
|
||
const currentPageIds = trackIds.slice((page - 1) * pageSize, page * pageSize);
|
||
const res = await getValidMusicItems(currentPageIds);
|
||
let extra = {};
|
||
if (page <= 1) {
|
||
extra = {
|
||
_trackIds: trackIds,
|
||
};
|
||
}
|
||
return Object.assign({ isEnd: trackIds.length <= page * pageSize, musicList: res }, extra);
|
||
}
|
||
module.exports = {
|
||
platform: "网易云音乐",
|
||
author: 'Huibq',
|
||
version: "0.3.0",
|
||
appVersion: ">0.1.0-alpha.0",
|
||
srcUrl: "https://raw.niuma666bet.buzz/Huibq/keep-alive/master/Music_Free/xiaoyun.js",
|
||
cacheControl: "no-store",
|
||
hints: {
|
||
importMusicSheet: [
|
||
"网易云:APP点击分享,然后复制链接",
|
||
"默认歌单无法导入,先新建一个空白歌单复制过去再导入新歌单即可"
|
||
],
|
||
},
|
||
supportedSearchType: ["music", "album", "sheet", "artist", "lyric"],
|
||
async search(query, page, type) {
|
||
if (type === "music") {
|
||
return await searchMusic(query, page);
|
||
}
|
||
if (type === "album") {
|
||
return await searchAlbum(query, page);
|
||
}
|
||
if (type === "artist") {
|
||
return await searchArtist(query, page);
|
||
}
|
||
if (type === "sheet") {
|
||
return await searchMusicSheet(query, page);
|
||
}
|
||
if (type === "lyric") {
|
||
return await searchLyric(query, page);
|
||
}
|
||
},
|
||
getMediaSource,
|
||
getMusicInfo,
|
||
getAlbumInfo,
|
||
getLyric,
|
||
getArtistWorks,
|
||
importMusicSheet,
|
||
getTopLists,
|
||
getTopListDetail,
|
||
getRecommendSheetTags,
|
||
getMusicSheetInfo,
|
||
getRecommendSheetsByTag,
|
||
}; |