mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-25 08:58:23 +03:00
Merge pull request #533 from mchangrh/cache-control
add ETag to skipSegments byHash
This commit is contained in:
75
src/utils/parseSkipSegments.ts
Normal file
75
src/utils/parseSkipSegments.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Request } from "express";
|
||||
import { ActionType, SegmentUUID, Category, Service } from "../types/segments.model";
|
||||
import { getService } from "./getService";
|
||||
|
||||
type fn = (req: Request) => any[];
|
||||
|
||||
const syntaxErrorWrapper = (fn: fn, req: Request) => {
|
||||
try { return fn(req); }
|
||||
catch (e) { return undefined; }
|
||||
};
|
||||
|
||||
// Default to sponsor
|
||||
const getCategories = (req: Request): Category[] =>
|
||||
req.query.categories
|
||||
? JSON.parse(req.query.categories as string)
|
||||
: req.query.category
|
||||
? Array.isArray(req.query.category)
|
||||
? req.query.category
|
||||
: [req.query.category]
|
||||
: ["sponsor"];
|
||||
|
||||
// Default to skip
|
||||
const getActionTypes = (req: Request): ActionType[] =>
|
||||
req.query.actionTypes
|
||||
? JSON.parse(req.query.actionTypes as string)
|
||||
: req.query.actionType
|
||||
? Array.isArray(req.query.actionType)
|
||||
? req.query.actionType
|
||||
: [req.query.actionType]
|
||||
: [ActionType.Skip];
|
||||
|
||||
// Default to empty array
|
||||
const getRequiredSegments = (req: Request): SegmentUUID[] =>
|
||||
req.query.requiredSegments
|
||||
? JSON.parse(req.query.requiredSegments as string)
|
||||
: req.query.requiredSegment
|
||||
? Array.isArray(req.query.requiredSegment)
|
||||
? req.query.requiredSegment
|
||||
: [req.query.requiredSegment]
|
||||
: [];
|
||||
|
||||
const errorMessage = (parameter: string) => `${parameter} parameter does not match format requirements.`;
|
||||
|
||||
export function parseSkipSegments(req: Request): {
|
||||
categories: Category[];
|
||||
actionTypes: ActionType[];
|
||||
requiredSegments: SegmentUUID[];
|
||||
service: Service;
|
||||
errors: string[];
|
||||
} {
|
||||
let categories: Category[] = syntaxErrorWrapper(getCategories, req);
|
||||
const actionTypes: ActionType[] = syntaxErrorWrapper(getActionTypes, req);
|
||||
const requiredSegments: SegmentUUID[] = syntaxErrorWrapper(getRequiredSegments, req);
|
||||
const service: Service = getService(req.query.service, req.body.services);
|
||||
const errors: string[] = [];
|
||||
if (!Array.isArray(categories)) errors.push(errorMessage("categories"));
|
||||
else {
|
||||
// check category names for invalid characters
|
||||
// and none string elements
|
||||
categories = categories
|
||||
.filter((item: any) => typeof item === "string")
|
||||
.filter((category) => !(/[^a-z|_|-]/.test(category)));
|
||||
if (categories.length === 0) errors.push("No valid categories provided.");
|
||||
}
|
||||
if (!Array.isArray(actionTypes)) errors.push(errorMessage("actionTypes"));
|
||||
if (!Array.isArray(requiredSegments)) errors.push(errorMessage("requiredSegments"));
|
||||
// finished parsing
|
||||
return {
|
||||
categories,
|
||||
actionTypes,
|
||||
requiredSegments,
|
||||
service,
|
||||
errors
|
||||
};
|
||||
}
|
||||
@@ -87,6 +87,17 @@ function clearSegmentCache(videoInfo: { videoID: VideoID; hashedVideoID: VideoID
|
||||
}
|
||||
}
|
||||
|
||||
async function getKeyLastModified(key: string): Promise<Date> {
|
||||
if (!config.redis?.enabled) return Promise.reject("ETag - Redis not enabled");
|
||||
return await redis.ttl(key)
|
||||
.then(ttl => {
|
||||
const sinceLive = config.redis?.expiryTime - ttl;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
return new Date((now-sinceLive) * 1000);
|
||||
})
|
||||
.catch(() => Promise.reject("ETag - Redis error"));
|
||||
}
|
||||
|
||||
function clearRatingCache(videoInfo: { hashedVideoID: VideoIDHash; service: Service;}): void {
|
||||
if (videoInfo) {
|
||||
redis.del(ratingHashKey(videoInfo.hashedVideoID, videoInfo.service)).catch((err) => Logger.error(err));
|
||||
@@ -101,6 +112,7 @@ export const QueryCacher = {
|
||||
get,
|
||||
getAndSplit,
|
||||
clearSegmentCache,
|
||||
getKeyLastModified,
|
||||
clearRatingCache,
|
||||
clearFeatureCache
|
||||
clearFeatureCache,
|
||||
};
|
||||
@@ -19,6 +19,7 @@ interface RedisSB {
|
||||
del(...keys: [RedisCommandArgument]): Promise<number>;
|
||||
increment?(key: RedisCommandArgument): Promise<RedisCommandRawReply[]>;
|
||||
sendCommand(args: RedisCommandArguments, options?: RedisClientOptions): Promise<RedisReply>;
|
||||
ttl(key: RedisCommandArgument): Promise<number>;
|
||||
quit(): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -30,6 +31,7 @@ let exportClient: RedisSB = {
|
||||
increment: () => new Promise((resolve) => resolve(null)),
|
||||
sendCommand: () => new Promise((resolve) => resolve(null)),
|
||||
quit: () => new Promise((resolve) => resolve(null)),
|
||||
ttl: () => new Promise((resolve) => resolve(null)),
|
||||
};
|
||||
|
||||
let lastClientFail = 0;
|
||||
|
||||
Reference in New Issue
Block a user