mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-07 12:07:07 +03:00
Add hasStartSegment to video label
This commit is contained in:
@@ -2,7 +2,7 @@ import { Request, Response } from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { videoLabelsHashKey, videoLabelsKey } from "../utils/redisKeys";
|
||||
import { SBRecord } from "../types/lib.model";
|
||||
import { Category, DBSegment, Segment, Service, VideoData, VideoID, VideoIDHash } from "../types/segments.model";
|
||||
import { ActionType, Category, DBSegment, Segment, Service, VideoData, VideoID, VideoIDHash } from "../types/segments.model";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { QueryCacher } from "../utils/queryCacher";
|
||||
import { getService } from "../utils/getService";
|
||||
@@ -13,6 +13,7 @@ interface FullVideoSegment {
|
||||
|
||||
interface FullVideoSegmentVideoData {
|
||||
segments: FullVideoSegment[];
|
||||
hasStartSegment: boolean;
|
||||
}
|
||||
|
||||
function transformDBSegments(segments: DBSegment[]): FullVideoSegment[] {
|
||||
@@ -21,7 +22,7 @@ function transformDBSegments(segments: DBSegment[]): FullVideoSegment[] {
|
||||
}));
|
||||
}
|
||||
|
||||
async function getLabelsByVideoID(videoID: VideoID, service: Service): Promise<FullVideoSegment[]> {
|
||||
async function getLabelsByVideoID(videoID: VideoID, service: Service): Promise<FullVideoSegmentVideoData> {
|
||||
try {
|
||||
const segments: DBSegment[] = await getSegmentsFromDBByVideoID(videoID, service);
|
||||
return chooseSegment(segments);
|
||||
@@ -53,11 +54,13 @@ async function getLabelsByHash(hashedVideoIDPrefix: VideoIDHash, service: Servic
|
||||
}, {});
|
||||
|
||||
for (const [videoID, videoData] of Object.entries(segmentPerVideoID)) {
|
||||
const result = chooseSegment(videoData.segments);
|
||||
const data: FullVideoSegmentVideoData = {
|
||||
segments: chooseSegment(videoData.segments),
|
||||
segments: result.segments,
|
||||
hasStartSegment: result.hasStartSegment
|
||||
};
|
||||
|
||||
if (data.segments.length > 0) {
|
||||
if (data.segments.length > 0 || data.hasStartSegment) {
|
||||
segments[videoID] = data;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +77,7 @@ async function getSegmentsFromDBByHash(hashedVideoIDPrefix: VideoIDHash, service
|
||||
.prepare(
|
||||
"all",
|
||||
`SELECT "startTime", "endTime", "videoID", "votes", "locked", "UUID", "userID", "category", "actionType", "hashedVideoID", "description" FROM "sponsorTimes"
|
||||
WHERE "hashedVideoID" LIKE ? AND "service" = ? AND "actionType" = 'full' AND "hidden" = 0 AND "shadowHidden" = 0`,
|
||||
WHERE "hashedVideoID" LIKE ? AND "service" = ? AND "hidden" = 0 AND "shadowHidden" = 0`,
|
||||
[`${hashedVideoIDPrefix}%`, service]
|
||||
) as Promise<DBSegment[]>;
|
||||
|
||||
@@ -90,22 +93,34 @@ async function getSegmentsFromDBByVideoID(videoID: VideoID, service: Service): P
|
||||
.prepare(
|
||||
"all",
|
||||
`SELECT "startTime", "endTime", "votes", "locked", "UUID", "userID", "category", "actionType", "description" FROM "sponsorTimes"
|
||||
WHERE "videoID" = ? AND "service" = ? AND "actionType" = 'full' AND "hidden" = 0 AND "shadowHidden" = 0`,
|
||||
WHERE "videoID" = ? AND "service" = ? AND "hidden" = 0 AND "shadowHidden" = 0`,
|
||||
[videoID, service]
|
||||
) as Promise<DBSegment[]>;
|
||||
|
||||
return await QueryCacher.get(fetchFromDB, videoLabelsKey(videoID, service));
|
||||
}
|
||||
|
||||
function chooseSegment<T extends DBSegment>(choices: T[]): FullVideoSegment[] {
|
||||
function chooseSegment<T extends DBSegment>(choices: T[]): FullVideoSegmentVideoData {
|
||||
// filter out -2 segments
|
||||
choices = choices.filter((segment) => segment.votes > -2);
|
||||
|
||||
const hasStartSegment = !!choices.some((segment) => segment.startTime < 5
|
||||
&& (segment.actionType === ActionType.Skip || segment.actionType === ActionType.Mute));
|
||||
|
||||
choices = choices.filter((segment) => segment.actionType === ActionType.Full);
|
||||
|
||||
const results = [];
|
||||
// trivial decisions
|
||||
if (choices.length === 0) {
|
||||
return [];
|
||||
return {
|
||||
segments: [],
|
||||
hasStartSegment
|
||||
};
|
||||
} else if (choices.length === 1) {
|
||||
return transformDBSegments(choices);
|
||||
return {
|
||||
segments: transformDBSegments(choices),
|
||||
hasStartSegment
|
||||
}
|
||||
}
|
||||
// if locked, only choose from locked
|
||||
const locked = choices.filter((segment) => segment.locked);
|
||||
@@ -114,7 +129,10 @@ function chooseSegment<T extends DBSegment>(choices: T[]): FullVideoSegment[] {
|
||||
}
|
||||
//no need to filter, just one label
|
||||
if (choices.length === 1) {
|
||||
return transformDBSegments(choices);
|
||||
return {
|
||||
segments: transformDBSegments(choices),
|
||||
hasStartSegment
|
||||
};
|
||||
}
|
||||
// sponsor > exclusive > selfpromo
|
||||
const findCategory = (category: string) => choices.find((segment) => segment.category === category);
|
||||
@@ -122,25 +140,36 @@ function chooseSegment<T extends DBSegment>(choices: T[]): FullVideoSegment[] {
|
||||
const categoryResult = findCategory("sponsor") ?? findCategory("exclusive_access") ?? findCategory("selfpromo");
|
||||
if (categoryResult) results.push(categoryResult);
|
||||
|
||||
return transformDBSegments(results);
|
||||
return {
|
||||
segments: transformDBSegments(results),
|
||||
hasStartSegment
|
||||
};
|
||||
}
|
||||
|
||||
async function handleGetLabel(req: Request, res: Response): Promise<FullVideoSegment[] | false> {
|
||||
async function handleGetLabel(req: Request, res: Response): Promise<FullVideoSegmentVideoData | FullVideoSegment[] | false> {
|
||||
const videoID = req.query.videoID as VideoID;
|
||||
if (!videoID) {
|
||||
res.status(400).send("videoID not specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
const hasStartSegment = !!req.query.hasStartSegment;
|
||||
|
||||
const service = getService(req.query.service, req.body.service);
|
||||
const segments = await getLabelsByVideoID(videoID, service);
|
||||
const segmentData = await getLabelsByVideoID(videoID, service);
|
||||
const segments = segmentData.segments;
|
||||
|
||||
if (!segments || segments.length === 0) {
|
||||
res.sendStatus(404);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasStartSegment) {
|
||||
return segmentData;
|
||||
} else {
|
||||
return segments;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function endpoint(req: Request, res: Response): Promise<Response> {
|
||||
|
||||
@@ -21,6 +21,7 @@ export async function getVideoLabelsByHash(req: Request, res: Response): Promise
|
||||
const output = Object.entries(segments).map(([videoID, data]) => ({
|
||||
videoID,
|
||||
segments: data.segments,
|
||||
hasStartSegment: data.hasStartSegment
|
||||
}));
|
||||
return res.status(output.length === 0 ? 404 : 200).json(output);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ export const tempVIPKey = (userID: HashedUserID): string =>
|
||||
`vip.temp.${userID}`;
|
||||
|
||||
export const videoLabelsKey = (videoID: VideoID, service: Service): string =>
|
||||
`labels.v1.${service}.videoID.${videoID}`;
|
||||
`labels.v2.${service}.videoID.${videoID}`;
|
||||
|
||||
export function videoLabelsHashKey(hashedVideoIDPrefix: VideoIDHash, service: Service): string {
|
||||
hashedVideoIDPrefix = hashedVideoIDPrefix.substring(0, 3) as VideoIDHash;
|
||||
|
||||
@@ -6,26 +6,27 @@ import { getHash } from "../../src/utils/getHash";
|
||||
describe("getVideoLabelHash", () => {
|
||||
const endpoint = "/api/videoLabels";
|
||||
before(async () => {
|
||||
const query = 'INSERT INTO "sponsorTimes" ("videoID", "hashedVideoID", "votes", "locked", "UUID", "userID", "timeSubmitted", "category", "actionType", "hidden", "shadowHidden", "startTime", "endTime", "views") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, 0)';
|
||||
await db.prepare("run", query, ["getLabelHashSponsor" , getHash("getLabelHashSponsor", 1) , 2, 0, "labelhash01", "labeluser", 0, "sponsor", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashEA" , getHash("getLabelHashEA", 1) , 2, 0, "labelhash02", "labeluser", 0, "exclusive_access", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashSelfpromo" , getHash("getLabelHashSelfpromo", 1) , 2, 0, "labelhash03", "labeluser", 0, "selfpromo", "full", 0, 0]);
|
||||
const query = 'INSERT INTO "sponsorTimes" ("videoID", "hashedVideoID", "votes", "locked", "UUID", "userID", "timeSubmitted", "category", "actionType", "hidden", "shadowHidden", "startTime", "endTime", "views") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0)';
|
||||
await db.prepare("run", query, ["getLabelHashSponsor" , getHash("getLabelHashSponsor", 1) , 2, 0, "labelhash01", "labeluser", 0, "sponsor", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashSponsor" , getHash("getLabelHashSponsor", 1) , 2, 0, "labelhash012", "labeluser", 0, "sponsor", "skip", 0, 0, 2]);
|
||||
await db.prepare("run", query, ["getLabelHashEA" , getHash("getLabelHashEA", 1) , 2, 0, "labelhash02", "labeluser", 0, "exclusive_access", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashSelfpromo" , getHash("getLabelHashSelfpromo", 1) , 2, 0, "labelhash03", "labeluser", 0, "selfpromo", "full", 0, 0, 0]);
|
||||
// priority override
|
||||
await db.prepare("run", query, ["getLabelHashPriority" , getHash("getLabelHashPriority", 1) , 2, 0, "labelhash04", "labeluser", 0, "sponsor", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority" , getHash("getLabelHashPriority", 1) , 2, 0, "labelhash05", "labeluser", 0, "exclusive_access", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority" , getHash("getLabelHashPriority", 1) , 2, 0, "labelhash06", "labeluser", 0, "selfpromo", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority" , getHash("getLabelHashPriority", 1) , 2, 0, "labelhash04", "labeluser", 0, "sponsor", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority" , getHash("getLabelHashPriority", 1) , 2, 0, "labelhash05", "labeluser", 0, "exclusive_access", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority" , getHash("getLabelHashPriority", 1) , 2, 0, "labelhash06", "labeluser", 0, "selfpromo", "full", 0, 0, 0]);
|
||||
// locked only
|
||||
await db.prepare("run", query, ["getLabelHashLocked" , getHash("getLabelHashLocked", 1) , 2, 0, "labelhash07", "labeluser", 0, "sponsor", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashLocked" , getHash("getLabelHashLocked", 1) , 2, 0, "labelhash08", "labeluser", 0, "exclusive_access", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashLocked" , getHash("getLabelHashLocked", 1) , 2, 1, "labelhash09", "labeluser", 0, "selfpromo", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashLocked" , getHash("getLabelHashLocked", 1) , 2, 0, "labelhash07", "labeluser", 0, "sponsor", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashLocked" , getHash("getLabelHashLocked", 1) , 2, 0, "labelhash08", "labeluser", 0, "exclusive_access", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashLocked" , getHash("getLabelHashLocked", 1) , 2, 1, "labelhash09", "labeluser", 0, "selfpromo", "full", 0, 0, 0]);
|
||||
// hidden segments
|
||||
await db.prepare("run", query, ["getLabelHashDownvote" , getHash("getLabelHashDownvote", 1) , -2, 0, "labelhash10", "labeluser", 0, "selfpromo", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashHidden" , getHash("getLabelHashHidden", 1) , 2, 0, "labelhash11", "labeluser", 0, "selfpromo", "full", 1, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashShHidden" , getHash("getLabelHashShHidden", 1) , 2, 0, "labelhash12", "labeluser", 0, "selfpromo", "full", 0, 1]);
|
||||
await db.prepare("run", query, ["getLabelHashDownvote" , getHash("getLabelHashDownvote", 1) , -2, 0, "labelhash10", "labeluser", 0, "selfpromo", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashHidden" , getHash("getLabelHashHidden", 1) , 2, 0, "labelhash11", "labeluser", 0, "selfpromo", "full", 1, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashShHidden" , getHash("getLabelHashShHidden", 1) , 2, 0, "labelhash12", "labeluser", 0, "selfpromo", "full", 0, 1, 0]);
|
||||
// priority override2
|
||||
await db.prepare("run", query, ["getLabelHashPriority2" , getHash("getLabelHashPriority2", 1) , -2, 0, "labelhash13", "labeluser", 0, "sponsor", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority2" , getHash("getLabelHashPriority2", 1) , 2, 0, "labelhash14", "labeluser", 0, "exclusive_access", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority2" , getHash("getLabelHashPriority2", 1) , 2, 0, "labelhash15", "labeluser", 0, "selfpromo", "full", 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority2" , getHash("getLabelHashPriority2", 1) , -2, 0, "labelhash13", "labeluser", 0, "sponsor", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority2" , getHash("getLabelHashPriority2", 1) , 2, 0, "labelhash14", "labeluser", 0, "exclusive_access", "full", 0, 0, 0]);
|
||||
await db.prepare("run", query, ["getLabelHashPriority2" , getHash("getLabelHashPriority2", 1) , 2, 0, "labelhash15", "labeluser", 0, "selfpromo", "full", 0, 0, 0]);
|
||||
|
||||
return;
|
||||
});
|
||||
@@ -46,6 +47,7 @@ describe("getVideoLabelHash", () => {
|
||||
validateLabel(data, videoID);
|
||||
const result = data[0].segments[0];
|
||||
assert.strictEqual(result.category, "sponsor");
|
||||
assert.strictEqual(data[0].hasStartSegment, true);
|
||||
done();
|
||||
})
|
||||
.catch(err => done(err));
|
||||
@@ -60,6 +62,7 @@ describe("getVideoLabelHash", () => {
|
||||
validateLabel(data, videoID);
|
||||
const result = data[0].segments[0];
|
||||
assert.strictEqual(result.category, "exclusive_access");
|
||||
assert.strictEqual(data[0].hasStartSegment, false);
|
||||
done();
|
||||
})
|
||||
.catch(err => done(err));
|
||||
|
||||
Reference in New Issue
Block a user