import { DataCache } from "../../maze-utils/src/cache"; import { getHash, HashedValue } from "../../maze-utils/src/hash"; import Config, { } from "../config"; import * as CompileConfig from "../../config.json"; import { ActionTypes, SponsorSourceType, SponsorTime, VideoID } from "../types"; import { getHashParams } from "./pageUtils"; import { asyncRequestToServer } from "./requests"; import { extensionUserAgent } from "../../maze-utils/src"; import { logRequest, serializeOrStringify } from "../../maze-utils/src/background-request-proxy"; const segmentDataCache = new DataCache(() => { return { segments: null, status: 200 }; }, 5); const pendingList: Record> = {}; export interface SegmentResponse { segments: SponsorTime[] | null; status: number | Error | string; } export async function getSegmentsForVideo(videoID: VideoID, ignoreCache: boolean): Promise { if (!ignoreCache) { const cachedData = segmentDataCache.getFromCache(videoID); if (cachedData) { segmentDataCache.cacheUsed(videoID); return cachedData; } } if (pendingList[videoID]) { return await pendingList[videoID]; } const pendingData = fetchSegmentsForVideo(videoID); pendingList[videoID] = pendingData; let result: Awaited; try { result = await pendingData; } catch (e) { console.error("[SB] Caught error while fetching segments", e); return { segments: null, status: serializeOrStringify(e), } } finally { delete pendingList[videoID]; } return result; } async function fetchSegmentsForVideo(videoID: VideoID): Promise { const extraRequestData: Record = {}; const hashParams = getHashParams(); if (hashParams.requiredSegment) extraRequestData.requiredSegment = hashParams.requiredSegment; const hashPrefix = (await getHash(videoID, 1)).slice(0, 5) as VideoID & HashedValue; const hasDownvotedSegments = !!Config.local.downvotedSegments[hashPrefix.slice(0, 4)]; const response = await asyncRequestToServer('GET', "/api/skipSegments/" + hashPrefix, { categories: CompileConfig.categoryList, actionTypes: ActionTypes, trimUUIDs: hasDownvotedSegments ? null : 5, ...extraRequestData }, { "X-CLIENT-NAME": extensionUserAgent(), }); if (response.ok) { const receivedSegments: SponsorTime[] = JSON.parse(response.responseText) ?.filter((video) => video.videoID === videoID) ?.map((video) => video.segments)?.[0] ?.map((segment) => ({ ...segment, source: SponsorSourceType.Server })) ?.sort((a, b) => a.segment[0] - b.segment[0]); if (receivedSegments && receivedSegments.length) { const result = { segments: receivedSegments, status: response.status }; segmentDataCache.setupCache(videoID).segments = result.segments; return result; } else { // Setup with null data segmentDataCache.setupCache(videoID); } } else if (response.status !== 404) { logRequest(response, "SB", "skip segments"); } return { segments: null, status: response.status }; }