aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Media/Anime/Airing/classify.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Media/Anime/Airing/classify.test.ts')
-rw-r--r--src/lib/Media/Anime/Airing/classify.test.ts187
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);