mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-26 21:27:48 -05:00
87 lines
2.0 KiB
TypeScript
87 lines
2.0 KiB
TypeScript
import { cachified } from "@epic-web/cachified";
|
|
import * as v from "valibot";
|
|
import { cache } from "~/utils/cache.server";
|
|
import { IS_E2E_TEST_RUN } from "~/utils/e2e";
|
|
import { logger } from "~/utils/logger";
|
|
import { twitchFetch } from "./fetch";
|
|
import { type RawStream, type StreamsResponse, streamsSchema } from "./schemas";
|
|
|
|
export async function getStreams() {
|
|
try {
|
|
const result = await cachified({
|
|
key: "twitch-streams",
|
|
cache,
|
|
ttl: 1000 * 60 * 2,
|
|
staleWhileRevalidate: 1000 * 60 * 5 * 2,
|
|
async getFreshValue() {
|
|
return (await getAllStreams())
|
|
.map(mapRawStream)
|
|
.sort((a, b) => b.viewerCount - a.viewerCount);
|
|
},
|
|
});
|
|
|
|
return result;
|
|
} catch (e) {
|
|
logger.error(e);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function mapRawStream(stream: RawStream) {
|
|
return {
|
|
thumbnailUrl: stream.thumbnail_url,
|
|
twitchUserName: stream.user_login.toLowerCase(),
|
|
viewerCount: stream.viewer_count,
|
|
};
|
|
}
|
|
|
|
const SPLATOON_3_TWITCH_GAME_ID = "1158884259";
|
|
async function getAllStreams() {
|
|
if (process.env.NODE_ENV === "test" || IS_E2E_TEST_RUN) return [];
|
|
|
|
const result: RawStream[] = [];
|
|
|
|
let cursor: string | undefined;
|
|
let count = 0;
|
|
while (true) {
|
|
if (count === 50) {
|
|
throw new Error("Stuck getting streams");
|
|
}
|
|
const { data, pagination } = await getStreamsChunk(cursor);
|
|
|
|
result.push(
|
|
...data.filter(
|
|
(stream) =>
|
|
!result.some(
|
|
(existingStream) => existingStream.user_id === stream.user_id,
|
|
),
|
|
),
|
|
);
|
|
if (!pagination.cursor) {
|
|
return result;
|
|
}
|
|
|
|
cursor = pagination.cursor;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
async function getStreamsChunk(cursor?: string): Promise<StreamsResponse> {
|
|
const searchParams = new URLSearchParams({
|
|
game_id: SPLATOON_3_TWITCH_GAME_ID,
|
|
first: "100",
|
|
after: cursor ?? "",
|
|
});
|
|
|
|
const res = await twitchFetch(
|
|
`https://api.twitch.tv/helix/streams?${searchParams}`,
|
|
);
|
|
|
|
const parsed = v.safeParse(streamsSchema, await res.json());
|
|
if (!parsed.success) {
|
|
throw new Error(v.summarize(parsed.issues));
|
|
}
|
|
|
|
return parsed.output;
|
|
}
|