Initial import: Music_Server, MusicFree, catalog-sync
This commit is contained in:
@@ -0,0 +1,361 @@
|
||||
"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",
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user