diff options
Diffstat (limited to 'src/lib/Media/Anime/Airing/classify.test.ts')
| -rw-r--r-- | src/lib/Media/Anime/Airing/classify.test.ts | 187 |
1 files changed, 94 insertions, 93 deletions
diff --git a/src/lib/Media/Anime/Airing/classify.test.ts b/src/lib/Media/Anime/Airing/classify.test.ts index 161787ba..1019b303 100644 --- a/src/lib/Media/Anime/Airing/classify.test.ts +++ b/src/lib/Media/Anime/Airing/classify.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "vitest"; import type { Media } from "$lib/Data/AniList/media"; +import type { AiringSchedule } from "$lib/Media/Anime/Airing/animeSchedule"; import { getAnimeEpisodeState, hasDueEpisodes, @@ -7,18 +8,29 @@ import { import { clearInjectAiringTimeCache, injectAiringTime, -} from "$lib/Media/Anime/Airing/Subtitled/match"; -import type { SubsPlease } from "$lib/Media/Anime/Airing/Subtitled/subsPlease"; +} from "$lib/Media/Anime/Airing/match"; import { season } from "$lib/Media/Anime/season"; import settings from "$stores/settings"; -const toScheduleTime = (epochSeconds: number) => { - const date = new Date(epochSeconds * 1000); - const hours = String(date.getHours()).padStart(2, "0"); - const minutes = String(date.getMinutes()).padStart(2, "0"); - - return `${hours}:${minutes}`; -}; +// A single-show schedule that joins to the given media by title, releasing the +// sub at `airingAt`. +const subScheduleFor = (media: Media, airingAt: number): AiringSchedule => ({ + generatedAt: Math.floor(Date.now() / 1000), + sub: [ + { + route: `fixture-${media.id}`, + title: media.title.romaji, + romaji: media.title.romaji, + english: media.title.english, + native: media.title.native, + episodeNumber: media.nextAiringEpisode?.episode || 0, + airingAt, + imageUrl: "", + streams: [], + }, + ], + dub: [], +}); const baseMedia = (id: number): Media => ({ @@ -117,29 +129,12 @@ describe("anime episode classification", () => { }); }); -describe("native countdown toggle parity", () => { +describe("countdown source parity", () => { for (const id of regressionIds) { - it(`keeps media ${id} due with native countdown on/off`, () => { + it(`keeps media ${id} due across native and sub countdown sources`, () => { const media = baseMedia(id); const subtitledAiringAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60; const nativeAiringAt = subtitledAiringAt + 12 * 60 * 60; - const nativeAiringDate = new Date(nativeAiringAt * 1000); - const airingDay = nativeAiringDate.toLocaleString("en-US", { - weekday: "long", - }); - const subsPlease = { - tz: "America/Los_Angeles", - schedule: { - [airingDay]: [ - { - title: media.title.romaji, - page: "", - image_url: "", - time: toScheduleTime(subtitledAiringAt), - }, - ], - }, - } as unknown as SubsPlease; media.nextAiringEpisode = { episode: 8, @@ -148,13 +143,15 @@ describe("native countdown toggle parity", () => { if (media.mediaListEntry) media.mediaListEntry.progress = 5; - settings.setKey("displayNativeCountdown", true); + const schedule = subScheduleFor(media, subtitledAiringAt); - const nativeOnly = injectAiringTime(media, subsPlease); + settings.setKey("countdownSource", "native"); - settings.setKey("displayNativeCountdown", false); + const nativeOnly = injectAiringTime(media, schedule); - const subtitled = injectAiringTime(media, subsPlease); + settings.setKey("countdownSource", "sub"); + + const subtitled = injectAiringTime(media, schedule); expect(hasDueEpisodes(nativeOnly)).toBe(true); expect(hasDueEpisodes(subtitled)).toBe(true); @@ -162,40 +159,75 @@ describe("native countdown toggle parity", () => { } }); +describe("countdown source fallback", () => { + it("falls back dub → sub when no dub release exists", () => { + clearInjectAiringTimeCache(); + + const media = baseMedia(310001); + const subtitledAiringAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60; + const nativeAiringAt = subtitledAiringAt + 12 * 60 * 60; + + media.nextAiringEpisode = { + episode: 8, + airingAt: nativeAiringAt, + }; + + // Sub-only schedule (the dub feed is empty). + const schedule = subScheduleFor(media, subtitledAiringAt); + + settings.setKey("countdownSource", "dub"); + + const injected = injectAiringTime(media, schedule); + + expect(injected.nextAiringEpisode?.airingAt).toBe(subtitledAiringAt); + expect(injected.nextAiringEpisode?.nativeAiringAt).toBe(nativeAiringAt); + }); + + it("falls back to native when neither dub nor sub exists", () => { + clearInjectAiringTimeCache(); + + const media = baseMedia(310002); + const nativeAiringAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60; + + media.nextAiringEpisode = { + episode: 8, + airingAt: nativeAiringAt, + }; + + const schedule: AiringSchedule = { + generatedAt: Math.floor(Date.now() / 1000), + sub: [], + dub: [], + }; + + settings.setKey("countdownSource", "dub"); + + const injected = injectAiringTime(media, schedule); + + expect(injected.nextAiringEpisode?.airingAt).toBe(nativeAiringAt); + }); +}); + describe("injectAiringTime cache safety", () => { it("does not let caller mutation poison cached injected media", () => { const media = baseMedia(444444); const subtitledAiringAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60; const nativeAiringAt = subtitledAiringAt + 12 * 60 * 60; - const nativeAiringDate = new Date(nativeAiringAt * 1000); - const airingDay = nativeAiringDate.toLocaleString("en-US", { - weekday: "long", - }); - const subsPlease = { - tz: "America/Los_Angeles", - schedule: { - [airingDay]: [ - { - title: media.title.romaji, - page: "", - image_url: "", - time: toScheduleTime(subtitledAiringAt), - }, - ], - }, - } as unknown as SubsPlease; media.nextAiringEpisode = { episode: 8, airingAt: nativeAiringAt, }; - settings.setKey("displayNativeCountdown", false); - const first = injectAiringTime(media, subsPlease); + const schedule = subScheduleFor(media, subtitledAiringAt); + + settings.setKey("countdownSource", "sub"); + + const first = injectAiringTime(media, schedule); first.nextAiringEpisode = { episode: -1 }; - const second = injectAiringTime(media, subsPlease); + const second = injectAiringTime(media, schedule); expect(second.nextAiringEpisode?.episode).not.toBe(-1); expect(typeof second.nextAiringEpisode?.airingAt).toBe("number"); @@ -208,30 +240,15 @@ describe("injectAiringTime cache safety", () => { const media = baseMedia(194028); const subtitledAiringAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60; const nativeAiringAt = subtitledAiringAt + 12 * 60 * 60; - const nativeAiringDate = new Date(nativeAiringAt * 1000); - const airingDay = nativeAiringDate.toLocaleString("en-US", { - weekday: "long", - }); - const subsPlease = { - tz: "America/Los_Angeles", - schedule: { - [airingDay]: [ - { - title: media.title.romaji, - page: "", - image_url: "", - time: toScheduleTime(subtitledAiringAt), - }, - ], - }, - } as unknown as SubsPlease; media.nextAiringEpisode = { episode: 10, airingAt: nativeAiringAt, }; - settings.setKey("displayNativeCountdown", false); + const schedule = subScheduleFor(media, subtitledAiringAt); + + settings.setKey("countdownSource", "sub"); const caughtUp = { ...media, @@ -247,8 +264,8 @@ describe("injectAiringTime cache safety", () => { progress: 7, }, } as Media; - const cachedCaughtUp = injectAiringTime(caughtUp, subsPlease); - const updatedBehind = injectAiringTime(behind, subsPlease); + const cachedCaughtUp = injectAiringTime(caughtUp, schedule); + const updatedBehind = injectAiringTime(behind, schedule); expect(hasDueEpisodes(cachedCaughtUp)).toBe(false); expect(hasDueEpisodes(updatedBehind)).toBe(true); @@ -259,33 +276,17 @@ describe("injectAiringTime cache safety", () => { const media = baseMedia(194028); const subtitledAiringAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60; - const nativeAiringAt = subtitledAiringAt + 12 * 60 * 60; - const nativeAiringDate = new Date(nativeAiringAt * 1000); - const airingDay = nativeAiringDate.toLocaleString("en-US", { - weekday: "long", - }); - const subsPlease = { - tz: "America/Los_Angeles", - schedule: { - [airingDay]: [ - { - title: media.title.romaji, - page: "", - image_url: "", - time: toScheduleTime(subtitledAiringAt), - }, - ], - }, - } as unknown as SubsPlease; - settings.setKey("displayNativeCountdown", false); + const schedule = subScheduleFor(media, subtitledAiringAt); + + settings.setKey("countdownSource", "sub"); const originalProgress = media.mediaListEntry?.progress || 0; - const first = injectAiringTime(media, subsPlease); + const first = injectAiringTime(media, schedule); if (first.mediaListEntry) first.mediaListEntry.progress = 999; - const second = injectAiringTime(media, subsPlease); + const second = injectAiringTime(media, schedule); expect(media.mediaListEntry?.progress).toBe(originalProgress); expect(second.mediaListEntry?.progress).toBe(originalProgress); |