Files

362 lines
12 KiB
JavaScript

"use strict";
const mockGet = jest.fn();
const mockPost = jest.fn();
jest.mock("axios", () => ({
create: jest.fn(() => ({
get: mockGet,
post: mockPost,
})),
}));
const plugin = require("./netease_17000");
function makeSongUrlResponse(id, url) {
return {
data: {
data: [
{
id,
url,
time: 0,
},
],
},
};
}
describe("netease_17000 getMediaSource fallback", () => {
beforeEach(() => {
mockGet.mockReset();
mockPost.mockReset();
});
test("falls back to noCopyrightRcmd.songId when original id has no source", async () => {
const originalId = "5268162";
const fallbackId = "2035171101";
const fallbackUrl = "http://example.com/fallback.mp3";
mockPost.mockResolvedValueOnce({
data: {
primary: null,
alternates: [],
},
});
mockGet.mockImplementation((url, config) => {
const params = (config && config.params) || {};
if (url.includes("/song/url/v1") && String(params.id) === originalId) {
return Promise.resolve(makeSongUrlResponse(Number(originalId), null));
}
if (url.includes("/song/detail") && String(params.ids) === originalId) {
return Promise.resolve({
data: {
songs: [
{
id: Number(originalId),
name: "origin",
ar: [{ name: "artist" }],
al: { name: "album" },
dt: 260000,
noCopyrightRcmd: {
songId: fallbackId,
},
},
],
},
});
}
if (url.includes("/song/url/v1") && String(params.id) === fallbackId) {
return Promise.resolve(makeSongUrlResponse(Number(fallbackId), fallbackUrl));
}
throw new Error(`Unexpected request: ${url} ${JSON.stringify(params)}`);
});
const result = await plugin.getMediaSource(
{
id: originalId,
title: "origin",
artist: "artist",
album: "album",
duration: 260,
},
"standard",
);
expect(result).toEqual({ url: fallbackUrl });
const requestedIds = mockGet.mock.calls
.filter((call) => call[0].includes("/song/url/v1"))
.map((call) => String((call[1] && call[1].params && call[1].params.id) || ""));
expect(requestedIds).toContain(originalId);
expect(requestedIds).toContain(fallbackId);
});
test("upgrades 126 netease media url to https during fallback", async () => {
const originalId = "5268162";
const fallbackId = "2035171101";
const fallbackUrl =
"http://m701.music.126.net/test-path/audio.mp3?vuutv=a+b/c";
mockPost.mockResolvedValueOnce({
data: {
primary: null,
alternates: [],
},
});
mockGet.mockImplementation((url, config) => {
const params = (config && config.params) || {};
if (url.includes("/song/url/v1") && String(params.id) === originalId) {
return Promise.resolve(makeSongUrlResponse(Number(originalId), null));
}
if (url.includes("/song/detail") && String(params.ids) === originalId) {
return Promise.resolve({
data: {
songs: [
{
id: Number(originalId),
name: "origin",
ar: [{ name: "artist" }],
al: { name: "album" },
dt: 260000,
noCopyrightRcmd: {
songId: fallbackId,
},
},
],
},
});
}
if (url.includes("/song/url/v1") && String(params.id) === fallbackId) {
return Promise.resolve(makeSongUrlResponse(Number(fallbackId), fallbackUrl));
}
throw new Error(`Unexpected request: ${url} ${JSON.stringify(params)}`);
});
const result = await plugin.getMediaSource(
{
id: originalId,
title: "origin",
artist: "artist",
album: "album",
duration: 260,
},
"standard",
);
expect(result).toEqual({
url: "https://m701.music.126.net/test-path/audio.mp3?vuutv=a+b/c",
});
});
test("prefers relay source for fallback song id when relay can resolve it", async () => {
const originalId = "5268162";
const fallbackId = "2035171101";
const relayUrl = "http://111.228.62.29:17000/api/unblock/stream/fallback-token";
const officialFallbackUrl = "http://m701.music.126.net/from-official.mp3";
mockPost
.mockResolvedValueOnce({
data: {
primary: null,
alternates: [],
},
})
.mockResolvedValueOnce({
data: {
primary: {
streamUrl: relayUrl,
},
alternates: [],
},
});
mockGet.mockImplementation((url, config) => {
const params = (config && config.params) || {};
const id = String(params.id || params.ids || "");
if (url.includes("/song/url/v1") && id === originalId) {
return Promise.resolve(makeSongUrlResponse(Number(originalId), null));
}
if (url.includes("/song/detail") && String(params.ids) === originalId) {
return Promise.resolve({
data: {
songs: [
{
id: Number(originalId),
name: "origin",
ar: [{ name: "artist" }],
al: { name: "album" },
dt: 260000,
noCopyrightRcmd: {
songId: fallbackId,
},
},
],
},
});
}
if (url.includes("/song/detail") && String(params.ids) === fallbackId) {
return Promise.resolve({
data: {
songs: [
{
id: Number(fallbackId),
name: "fallback-name",
ar: [{ name: "fallback-artist" }],
al: { name: "fallback-album" },
dt: 260000,
},
],
},
});
}
if (url.includes("/song/url/v1") && id === fallbackId) {
return Promise.resolve(makeSongUrlResponse(Number(fallbackId), officialFallbackUrl));
}
throw new Error(`Unexpected request: ${url} ${JSON.stringify(params)}`);
});
const result = await plugin.getMediaSource(
{
id: originalId,
title: "origin",
artist: "artist",
album: "album",
duration: 260,
},
"standard",
);
expect(result).toEqual({ url: relayUrl });
const fallbackOfficialCalls = mockGet.mock.calls.filter(
(call) =>
call[0].includes("/song/url/v1") &&
String((call[1] && call[1].params && call[1].params.id) || "") === fallbackId,
);
expect(fallbackOfficialCalls).toHaveLength(0);
});
});
describe("netease_17000 recommend sheets", () => {
beforeEach(() => {
mockGet.mockReset();
mockPost.mockReset();
});
test("builds recommend tag groups from playlist catlist", async () => {
mockGet.mockImplementation((url) => {
if (url.includes("/playlist/catlist")) {
return Promise.resolve({
data: {
categories: {
0: "语种",
1: "风格",
},
sub: [
{ category: 0, name: "华语", hot: true },
{ category: 0, name: "欧美", hot: false },
{ category: 1, name: "流行", hot: true },
],
},
});
}
throw new Error(`Unexpected request: ${url}`);
});
const result = await plugin.getRecommendSheetTags();
expect(result).toEqual({
pinned: [
{ id: "华语", title: "华语" },
{ id: "流行", title: "流行" },
],
data: [
{
title: "语种",
data: [
{ id: "华语", title: "华语" },
{ id: "欧美", title: "欧美" },
],
},
{
title: "风格",
data: [
{ id: "流行", title: "流行" },
],
},
],
});
});
test("loads recommend sheets by tag through top playlist endpoint", async () => {
mockGet.mockImplementation((url, config) => {
const params = (config && config.params) || {};
if (url.includes("/top/playlist")) {
return Promise.resolve({
data: {
playlists: [
{
id: 101,
name: "歌单A",
creator: { nickname: "作者A" },
description: "descA",
coverImgUrl: "coverA",
trackCount: 50,
playCount: 1000,
},
],
total: 21,
more: true,
},
});
}
throw new Error(`Unexpected request: ${url} ${JSON.stringify(params)}`);
});
const result = await plugin.getRecommendSheetsByTag({ id: "华语" }, 1);
expect(result).toEqual({
isEnd: false,
data: [
{
id: "101",
title: "歌单A",
artist: "作者A",
description: "descA",
coverImg: "coverA",
worksNum: 50,
playCount: 1000,
},
],
});
const topPlaylistCall = mockGet.mock.calls.find((call) =>
call[0].includes("/top/playlist"),
);
expect(topPlaylistCall).toBeTruthy();
expect(topPlaylistCall[1].params).toMatchObject({
cat: "华语",
limit: 20,
offset: 0,
order: "hot",
});
});
});