aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/graphql/anime/resolvers.ts7
-rw-r--r--src/graphql/anime/schema.graphql1
-rw-r--r--src/lib/Locale/english.ts1
-rw-r--r--src/lib/Locale/japanese.ts1
-rw-r--r--src/lib/Locale/layout.ts1
-rw-r--r--src/lib/Media/Anime/Airing/animeSchedule.ts36
-rw-r--r--src/lib/Media/Anime/Airing/classify.test.ts2
-rw-r--r--src/lib/Schedule/Days.svelte20
-rw-r--r--src/routes/+layout.svelte4
-rw-r--r--src/routes/api/animeschedule/+server.ts6
10 files changed, 55 insertions, 24 deletions
diff --git a/src/graphql/anime/resolvers.ts b/src/graphql/anime/resolvers.ts
index 8d87eb6c..d3d7801e 100644
--- a/src/graphql/anime/resolvers.ts
+++ b/src/graphql/anime/resolvers.ts
@@ -13,11 +13,12 @@ export const resolvers: WithIndex<AnimeResolvers> = {
const token = env.ANIMESCHEDULE_CLIENT_TOKEN;
const generatedAt = Math.floor(Date.now() / 1000);
- if (!token) return { airing: { generatedAt, sub: [], dub: [] } };
+ if (!token)
+ return { airing: { generatedAt, native: [], sub: [], dub: [] } };
- const { sub, dub } = await fetchTimetables(token);
+ const { native, sub, dub } = await fetchTimetables(token);
- return { airing: { generatedAt, sub, dub } };
+ return { airing: { generatedAt, native, sub, dub } };
},
},
};
diff --git a/src/graphql/anime/schema.graphql b/src/graphql/anime/schema.graphql
index aad7afec..7ec6d6be 100644
--- a/src/graphql/anime/schema.graphql
+++ b/src/graphql/anime/schema.graphql
@@ -8,6 +8,7 @@ type Anime {
type Airing {
generatedAt: Int
+ native: [AiringRelease]
sub: [AiringRelease]
dub: [AiringRelease]
}
diff --git a/src/lib/Locale/english.ts b/src/lib/Locale/english.ts
index fafcf5ef..8e7b5ffa 100644
--- a/src/lib/Locale/english.ts
+++ b/src/lib/Locale/english.ts
@@ -707,6 +707,7 @@ const English: Locale = {
tracks: {
sub: "Sub",
dub: "Dub",
+ native: "Native",
},
},
events: {
diff --git a/src/lib/Locale/japanese.ts b/src/lib/Locale/japanese.ts
index 60b92506..cd4cf879 100644
--- a/src/lib/Locale/japanese.ts
+++ b/src/lib/Locale/japanese.ts
@@ -22,6 +22,7 @@ const Japanese: Locale = {
tracks: {
sub: "字幕",
dub: "吹き替え",
+ native: "ネイティブ",
},
},
settings: {
diff --git a/src/lib/Locale/layout.ts b/src/lib/Locale/layout.ts
index e53d0884..ec66889f 100644
--- a/src/lib/Locale/layout.ts
+++ b/src/lib/Locale/layout.ts
@@ -639,6 +639,7 @@ export interface Locale {
tracks?: {
sub: LocaleValue;
dub: LocaleValue;
+ native: LocaleValue;
};
};
events?: {
diff --git a/src/lib/Media/Anime/Airing/animeSchedule.ts b/src/lib/Media/Anime/Airing/animeSchedule.ts
index f3f6f85d..7bfe5ac3 100644
--- a/src/lib/Media/Anime/Airing/animeSchedule.ts
+++ b/src/lib/Media/Anime/Airing/animeSchedule.ts
@@ -1,9 +1,11 @@
// Data model for AnimeSchedule.net's weekly timetable, the source of truth for
-// when subbed and dubbed episodes actually release. Unlike a fansub schedule,
-// every release carries an absolute timestamp, an episode number, delay windows,
-// and the streaming platforms it lands on.
+// when native, subbed, and dubbed episodes actually release. Unlike a fansub
+// schedule, every release carries an absolute timestamp, an episode number,
+// delay windows, and the streaming platforms it lands on.
-export type AirType = "sub" | "dub";
+// A release track. "native" is AnimeSchedule's "raw" (original-language)
+// broadcast; "sub"/"dub" are the localised releases.
+export type AirType = "native" | "sub" | "dub";
export interface Stream {
platform: string;
@@ -25,9 +27,10 @@ export interface AiringEntry {
streams: Stream[];
}
-// The merged sub + dub schedule for the current week.
+// The merged native + sub + dub schedule for the current week.
export interface AiringSchedule {
generatedAt: number;
+ native: AiringEntry[];
sub: AiringEntry[];
dub: AiringEntry[];
}
@@ -91,12 +94,19 @@ export const parseTimetable = (raw: unknown): AiringEntry[] => {
const TIMETABLE_ENDPOINT = "https://animeschedule.net/api/v3/timetables";
-// Fetch and parse the current week's sub and dub timetables in one shot. The
-// caller supplies the AnimeSchedule application token.
+// Fetch and parse the current week's native, sub, and dub timetables in one
+// shot. The caller supplies the AnimeSchedule application token. AnimeSchedule
+// names the native broadcast "raw".
export const fetchTimetables = async (
token: string,
-): Promise<{ sub: AiringEntry[]; dub: AiringEntry[] }> => {
- const fetchOne = async (airType: AirType): Promise<AiringEntry[]> => {
+): Promise<{
+ native: AiringEntry[];
+ sub: AiringEntry[];
+ dub: AiringEntry[];
+}> => {
+ const fetchOne = async (
+ airType: "raw" | "sub" | "dub",
+ ): Promise<AiringEntry[]> => {
try {
const response = await fetch(`${TIMETABLE_ENDPOINT}?airType=${airType}`, {
headers: { Authorization: `Bearer ${token}` },
@@ -108,7 +118,11 @@ export const fetchTimetables = async (
}
};
- const [sub, dub] = await Promise.all([fetchOne("sub"), fetchOne("dub")]);
+ const [native, sub, dub] = await Promise.all([
+ fetchOne("raw"),
+ fetchOne("sub"),
+ fetchOne("dub"),
+ ]);
- return { sub, dub };
+ return { native, sub, dub };
};
diff --git a/src/lib/Media/Anime/Airing/classify.test.ts b/src/lib/Media/Anime/Airing/classify.test.ts
index 1019b303..eeff2036 100644
--- a/src/lib/Media/Anime/Airing/classify.test.ts
+++ b/src/lib/Media/Anime/Airing/classify.test.ts
@@ -16,6 +16,7 @@ import settings from "$stores/settings";
// sub at `airingAt`.
const subScheduleFor = (media: Media, airingAt: number): AiringSchedule => ({
generatedAt: Math.floor(Date.now() / 1000),
+ native: [],
sub: [
{
route: `fixture-${media.id}`,
@@ -196,6 +197,7 @@ describe("countdown source fallback", () => {
const schedule: AiringSchedule = {
generatedAt: Math.floor(Date.now() / 1000),
+ native: [],
sub: [],
dub: [],
};
diff --git a/src/lib/Schedule/Days.svelte b/src/lib/Schedule/Days.svelte
index 7fe09d4e..ac27dd17 100644
--- a/src/lib/Schedule/Days.svelte
+++ b/src/lib/Schedule/Days.svelte
@@ -43,14 +43,14 @@ const trackParameter: string | null = parseOrDefault(
null,
);
+const isAirType = (value: string | null): value is AirType =>
+ value === "native" || value === "sub" || value === "dub";
+
// The view track defaults to the countdown source but is overridable via the
// in-page toggle and a ?type= query param, independent of the global setting.
-let selectedTrack: AirType =
- trackParameter === "sub" || trackParameter === "dub"
- ? trackParameter
- : $settings.countdownSource === "dub"
- ? "dub"
- : "sub";
+let selectedTrack: AirType = isAirType(trackParameter)
+ ? trackParameter
+ : $settings.countdownSource;
$: source = selectedTrack;
@@ -216,6 +216,14 @@ const episode = (media: Media, weekday: string) => {
>
{$locale().schedule?.tracks?.dub ?? 'Dub'}
</button>
+ <button
+ type="button"
+ aria-pressed={source === 'native'}
+ class:button-action={source === 'native'}
+ onclick={() => selectTrack('native')}
+ >
+ {$locale().schedule?.tracks?.native ?? 'Native'}
+ </button>
</div>
{#await mediaListPromise}
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index be594460..fbc2ff8e 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -289,7 +289,9 @@ $: {
fetch(root("/api/animeschedule"))
.then((r) => r.json())
.then((r) => airingSchedule.set(r))
- .catch(() => airingSchedule.set({ generatedAt: 0, sub: [], dub: [] }));
+ .catch(() =>
+ airingSchedule.set({ generatedAt: 0, native: [], sub: [], dub: [] }),
+ );
}
</script>
diff --git a/src/routes/api/animeschedule/+server.ts b/src/routes/api/animeschedule/+server.ts
index c596bf41..75257569 100644
--- a/src/routes/api/animeschedule/+server.ts
+++ b/src/routes/api/animeschedule/+server.ts
@@ -8,14 +8,14 @@ export const GET = async () => {
if (!token)
return Response.json(
- { generatedAt, sub: [], dub: [] },
+ { generatedAt, native: [], sub: [], dub: [] },
{ headers: appOriginHeaders({ "Cache-Control": "max-age=60" }) },
);
- const { sub, dub } = await fetchTimetables(token);
+ const { native, sub, dub } = await fetchTimetables(token);
return Response.json(
- { generatedAt, sub, dub },
+ { generatedAt, native, sub, dub },
{
headers: appOriginHeaders({
"Cache-Control": "max-age=86400, s-maxage=86400",