Spaces:
Running
Running
File size: 2,676 Bytes
3f5bd49 95e3d2a 31d3580 3f5bd49 10d4db6 31d3580 3f5bd49 31d3580 3f5bd49 31d3580 10d4db6 3f5bd49 10d4db6 3f5bd49 31d3580 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | import type { Match, PreviewChunk, Round } from '$lib/types';
import { resolveUrl, type FetchOpts } from '$lib/api/hub';
import { fetchParquetRows } from '$lib/api/parquet';
export type FetchOptions = FetchOpts;
let matchesPromise: Promise<Match[]> | null = null;
let roundsPromise: Promise<Round[]> | null = null;
const matchPreviewsCache = new Map<string, Promise<PreviewChunk[]>>();
const WEB_MAPS = 'index/web/maps.parquet';
const WEB_ROUNDS = 'index/web/rounds.parquet';
const matchPreviewsPath = (matchId: number, mapName: string) =>
`rounds/match_id=${matchId}/map_name=${mapName}/chunks-preview.parquet`;
export function listMatches(opts: FetchOptions = {}): Promise<Match[]> {
if (matchesPromise) return matchesPromise;
matchesPromise = fetchParquetRows<Match>(resolveUrl(WEB_MAPS), opts)
.then((rows) => {
rows.sort(
(a, b) =>
new Date(b.match_date).getTime() - new Date(a.match_date).getTime() ||
(a.map_index ?? 0) - (b.map_index ?? 0)
);
return rows;
})
.catch((err) => {
matchesPromise = null;
throw err;
});
return matchesPromise;
}
export function listAllRounds(opts: FetchOptions = {}): Promise<Round[]> {
if (roundsPromise) return roundsPromise;
roundsPromise = fetchParquetRows<Round>(resolveUrl(WEB_ROUNDS), opts).catch((err) => {
roundsPromise = null;
throw err;
});
return roundsPromise;
}
export async function listRounds(
matchId: number,
mapName: string,
opts: FetchOptions = {}
): Promise<Round[]> {
const all = await listAllRounds(opts);
return all
.filter((r) => r.match_id === matchId && r.map_name === mapName)
.sort((a, b) => a.round - b.round);
}
async function loadMatchPreviews(
matchId: number,
mapName: string,
opts: FetchOptions
): Promise<PreviewChunk[]> {
const key = `${matchId}/${mapName}`;
const cached = matchPreviewsCache.get(key);
if (cached) return cached;
const baseDir = `rounds/match_id=${matchId}/map_name=${mapName}`;
const promise = fetchParquetRows<PreviewChunk>(
resolveUrl(matchPreviewsPath(matchId, mapName)),
opts
)
.then((rows) => {
for (const r of rows) {
r.preview_video = {
src: resolveUrl(`${baseDir}/${r.preview_path}`)
};
}
return rows;
})
.catch((err) => {
matchPreviewsCache.delete(key);
throw err;
});
matchPreviewsCache.set(key, promise);
return promise;
}
export async function listRoundPreviews(
matchId: number,
mapName: string,
round: number,
opts: FetchOptions = {}
): Promise<PreviewChunk[]> {
const all = await loadMatchPreviews(matchId, mapName, opts);
return all
.filter((p) => p.round === round)
.sort((a, b) => a.player - b.player || a.chunk_index - b.chunk_index);
}
|