From b661b59078060356d1bd92ffcd1d2b636d9f3d36 Mon Sep 17 00:00:00 2001 From: Rushil Perera Date: Sun, 26 May 2024 13:22:03 -0400 Subject: [PATCH] feat: add Amvstrm as source for /episodes Summary: Test Plan: --- src/controllers/episodes/amvstrm.ts | 60 ++++++++++++++++++++++++++ src/controllers/episodes/consumet.ts | 2 +- src/controllers/episodes/index.spec.ts | 26 +++++++++++ src/controllers/episodes/index.ts | 4 ++ src/mocks/amvstrm/episodes.ts | 31 +++++++++++++ src/mocks/anify/episodes.ts | 2 +- src/mocks/handlers.ts | 2 + 7 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 src/controllers/episodes/amvstrm.ts create mode 100644 src/mocks/amvstrm/episodes.ts diff --git a/src/controllers/episodes/amvstrm.ts b/src/controllers/episodes/amvstrm.ts new file mode 100644 index 0000000..f8cd27f --- /dev/null +++ b/src/controllers/episodes/amvstrm.ts @@ -0,0 +1,60 @@ +import { Episode, type EpisodesResponse } from "./episode"; + +export async function getEpisodesFromAmvstrm( + aniListId: number, +): Promise { + try { + const episodes: Episode[] | null = await fetch( + `https://api-amvstrm.nyt92.eu.org/api/v2/episode/${aniListId}`, + ) + .then((res) => res.json()) + .then(({ code, message, episodes }) => { + if (code >= 400) { + console.error( + `Error trying to load episodes from amvstrm; aniListId: ${aniListId}, code: ${code}, message: ${message}`, + ); + return null; + } + + return episodes.map( + ({ id, description, image, title, episode, airDate }) => ({ + id, + number: episode, + description, + img: image, + title, + updatedAt: airDate ?? 0, + }), + ); + }); + if (!episodes || episodes.length === 0) { + return null; + } + + return { providerId: "amvstrm", episodes }; + } catch (error) { + console.error( + new Error( + `Error trying to load episodes from amvstrm; aniListId: ${aniListId}`, + { cause: error }, + ), + ); + } + + return null; +} + +interface AmvstrmEpisodesResponse { + code: number; + message: string; + episodes: AmvstrmEpisode[]; +} + +interface AmvstrmEpisode { + id: string; + title: string; + description: string | null; + episode: number; + image: string; + airDate: null; +} diff --git a/src/controllers/episodes/consumet.ts b/src/controllers/episodes/consumet.ts index ad67d4a..53dde83 100644 --- a/src/controllers/episodes/consumet.ts +++ b/src/controllers/episodes/consumet.ts @@ -10,7 +10,7 @@ export async function getEpisodesFromConsumet( const aniList = new META.Anilist(gogoAnime, undefined, fetchAdapter); try { - const episodes = await aniList + const episodes: Episode[] = await aniList .fetchEpisodesListById(aniListId.toString()) .then((episodes) => episodes.map( diff --git a/src/controllers/episodes/index.spec.ts b/src/controllers/episodes/index.spec.ts index 771bb68..70d214c 100644 --- a/src/controllers/episodes/index.spec.ts +++ b/src/controllers/episodes/index.spec.ts @@ -186,6 +186,32 @@ describe('requests the "/episodes" route', () => { }); }); + it("with list of episodes from Amvstrm", async () => { + const response = await app.request( + "/episodes/4", + {}, + { + ENABLE_ANIFY: "true", + }, + ); + + expect(response.json()).resolves.toEqual({ + success: true, + result: { + providerId: "amvstrm", + episodes: [ + { + id: "amvstrm-1", + number: 1, + title: "EP 1", + updatedAt: 0, + img: null, + }, + ], + }, + }); + }); + it("with no episodes from all sources", async () => { const response = await app.request("/episodes/-1"); diff --git a/src/controllers/episodes/index.ts b/src/controllers/episodes/index.ts index 7de8754..4fad00e 100644 --- a/src/controllers/episodes/index.ts +++ b/src/controllers/episodes/index.ts @@ -57,6 +57,10 @@ app.openapi(route, async (c) => { import("./consumet").then(({ getEpisodesFromConsumet }) => getEpisodesFromConsumet(aniListId), ), + () => + import("./amvstrm").then(({ getEpisodesFromAmvstrm }) => + getEpisodesFromAmvstrm(aniListId), + ), ]); if (!episodes) { diff --git a/src/mocks/amvstrm/episodes.ts b/src/mocks/amvstrm/episodes.ts new file mode 100644 index 0000000..03177d9 --- /dev/null +++ b/src/mocks/amvstrm/episodes.ts @@ -0,0 +1,31 @@ +import { HttpResponse, http } from "msw"; + +export function getAmvstrmEpisodes() { + return http.get( + "https://api-amvstrm.nyt92.eu.org/api/v2/episode/:aniListId", + ({ params }) => { + const aniListId = Number(params["aniListId"]); + if (aniListId === 4) { + return HttpResponse.json({ + code: 200, + message: "success", + episodes: [ + { + id: "amvstrm-1", + episode: 1, + title: "EP 1", + isFiller: false, + isDub: false, + image: null, + }, + ], + }); + } + + return HttpResponse.json( + { code: 500, message: "Server error", episodes: [] }, + { status: 500 }, + ); + }, + ); +} diff --git a/src/mocks/anify/episodes.ts b/src/mocks/anify/episodes.ts index d8bbc25..000bfb7 100644 --- a/src/mocks/anify/episodes.ts +++ b/src/mocks/anify/episodes.ts @@ -3,7 +3,7 @@ import { HttpResponse, http } from "msw"; export function getAnifyEpisodes() { return http.get("https://api.anify.tv/episodes/:aniListId", ({ params }) => { const aniListId = Number(params["aniListId"]); - if (aniListId === 3 || aniListId < 0) { + if (aniListId === 3 || aniListId === 4 || aniListId < 0) { return HttpResponse.json([]); } diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 445eda8..ae0b743 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1,3 +1,4 @@ +import { getAmvstrmEpisodes } from "./amvstrm/episodes"; import { getAmvstrmSearchResults } from "./amvstrm/search"; import { getAmvstrmTitle } from "./amvstrm/title"; import { getAnifyEpisodes } from "./anify/episodes"; @@ -8,6 +9,7 @@ import { getAnilistTitle } from "./anilist/title"; export const handlers = [ getAnilistSearchResults(), getAnilistTitle(), + getAmvstrmEpisodes(), getAmvstrmSearchResults(), getAmvstrmTitle(), getAnifyEpisodes(),