mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-09 13:07:05 +03:00
Add pre-fetching on hover with a small segment data cache
This commit is contained in:
104
src/utils/segmentData.ts
Normal file
104
src/utils/segmentData.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
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 { ActionType, ActionTypes, SponsorSourceType, SponsorTime, VideoID } from "../types";
|
||||
import { getHashParams } from "./pageUtils";
|
||||
import { asyncRequestToServer } from "./requests";
|
||||
|
||||
const segmentDataCache = new DataCache<VideoID, SegmentResponse>(() => {
|
||||
return {
|
||||
segments: null,
|
||||
status: 200
|
||||
};
|
||||
}, 5);
|
||||
|
||||
const pendingList: Record<VideoID, Promise<SegmentResponse>> = {};
|
||||
|
||||
export interface SegmentResponse {
|
||||
segments: SponsorTime[] | null;
|
||||
status: number;
|
||||
}
|
||||
|
||||
export async function getSegmentsForVideo(videoID: VideoID, ignoreCache: boolean): Promise<SegmentResponse> {
|
||||
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;
|
||||
|
||||
const result = await pendingData;
|
||||
delete pendingList[videoID];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function fetchSegmentsForVideo(videoID: VideoID): Promise<SegmentResponse> {
|
||||
const categories: string[] = Config.config.categorySelections.map((category) => category.name);
|
||||
|
||||
const extraRequestData: Record<string, unknown> = {};
|
||||
const hashParams = getHashParams();
|
||||
if (hashParams.requiredSegment) extraRequestData.requiredSegment = hashParams.requiredSegment;
|
||||
|
||||
const hashPrefix = (await getHash(videoID, 1)).slice(0, 4) as VideoID & HashedValue;
|
||||
const response = await asyncRequestToServer('GET', "/api/skipSegments/" + hashPrefix, {
|
||||
categories: CompileConfig.categoryList,
|
||||
actionTypes: ActionTypes,
|
||||
...extraRequestData
|
||||
}, {
|
||||
"X-CLIENT-NAME": `${chrome.runtime.id}/v${chrome.runtime.getManifest().version}`
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const enabledActionTypes = getEnabledActionTypes();
|
||||
|
||||
const receivedSegments: SponsorTime[] = JSON.parse(response.responseText)
|
||||
?.filter((video) => video.videoID === videoID)
|
||||
?.map((video) => video.segments)?.[0]
|
||||
?.filter((segment) => enabledActionTypes.includes(segment.actionType) && categories.includes(segment.category))
|
||||
?.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);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
segments: null,
|
||||
status: response.status
|
||||
};
|
||||
}
|
||||
|
||||
function getEnabledActionTypes(forceFullVideo = false): ActionType[] {
|
||||
const actionTypes = [ActionType.Skip, ActionType.Poi, ActionType.Chapter];
|
||||
if (Config.config.muteSegments) {
|
||||
actionTypes.push(ActionType.Mute);
|
||||
}
|
||||
if (Config.config.fullVideoSegments || forceFullVideo) {
|
||||
actionTypes.push(ActionType.Full);
|
||||
}
|
||||
|
||||
return actionTypes;
|
||||
}
|
||||
Reference in New Issue
Block a user