mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2024-11-10 09:07:47 +01:00
Only return one segment for highlight category
This commit is contained in:
parent
7bf09906d3
commit
8088f37632
7 changed files with 48 additions and 11 deletions
|
@ -4,7 +4,8 @@ import { config } from '../config';
|
||||||
import { db, privateDB } from '../databases/databases';
|
import { db, privateDB } from '../databases/databases';
|
||||||
import { skipSegmentsHashKey, skipSegmentsKey } from '../middleware/redisKeys';
|
import { skipSegmentsHashKey, skipSegmentsKey } from '../middleware/redisKeys';
|
||||||
import { SBRecord } from '../types/lib.model';
|
import { SBRecord } from '../types/lib.model';
|
||||||
import { Category, DBSegment, HashedIP, IPAddress, OverlappingSegmentGroup, Segment, SegmentCache, Service, VideoData, VideoID, VideoIDHash, Visibility, VotableObject } from "../types/segments.model";
|
import { Category, CategoryActionType, DBSegment, HashedIP, IPAddress, OverlappingSegmentGroup, Segment, SegmentCache, Service, VideoData, VideoID, VideoIDHash, Visibility, VotableObject } from "../types/segments.model";
|
||||||
|
import { getCategoryActionType } from '../utils/categoryInfo';
|
||||||
import { getHash } from '../utils/getHash';
|
import { getHash } from '../utils/getHash';
|
||||||
import { getIP } from '../utils/getIP';
|
import { getIP } from '../utils/getIP';
|
||||||
import { Logger } from '../utils/logger';
|
import { Logger } from '../utils/logger';
|
||||||
|
@ -40,7 +41,8 @@ async function prepareCategorySegments(req: Request, videoID: VideoID, category:
|
||||||
|
|
||||||
const filteredSegments = segments.filter((_, index) => shouldFilter[index]);
|
const filteredSegments = segments.filter((_, index) => shouldFilter[index]);
|
||||||
|
|
||||||
return chooseSegments(filteredSegments).map((chosenSegment) => ({
|
const maxSegments = getCategoryActionType(category) === CategoryActionType.Skippable ? 32 : 1
|
||||||
|
return chooseSegments(filteredSegments, maxSegments).map((chosenSegment) => ({
|
||||||
category,
|
category,
|
||||||
segment: [chosenSegment.startTime, chosenSegment.endTime],
|
segment: [chosenSegment.startTime, chosenSegment.endTime],
|
||||||
UUID: chosenSegment.UUID,
|
UUID: chosenSegment.UUID,
|
||||||
|
@ -206,7 +208,7 @@ function getWeightedRandomChoice<T extends VotableObject>(choices: T[], amountOf
|
||||||
//Only one similar time will be returned, randomly generated based on the sqrt of votes.
|
//Only one similar time will be returned, randomly generated based on the sqrt of votes.
|
||||||
//This allows new less voted items to still sometimes appear to give them a chance at getting votes.
|
//This allows new less voted items to still sometimes appear to give them a chance at getting votes.
|
||||||
//Segments with less than -1 votes are already ignored before this function is called
|
//Segments with less than -1 votes are already ignored before this function is called
|
||||||
function chooseSegments(segments: DBSegment[]): DBSegment[] {
|
function chooseSegments(segments: DBSegment[], max: number): DBSegment[] {
|
||||||
//Create groups of segments that are similar to eachother
|
//Create groups of segments that are similar to eachother
|
||||||
//Segments must be sorted by their startTime so that we can build groups chronologically:
|
//Segments must be sorted by their startTime so that we can build groups chronologically:
|
||||||
//1. As long as the segments' startTime fall inside the currentGroup, we keep adding them to that group
|
//1. As long as the segments' startTime fall inside the currentGroup, we keep adding them to that group
|
||||||
|
@ -240,8 +242,8 @@ function chooseSegments(segments: DBSegment[]): DBSegment[] {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//if there are too many groups, find the best 8
|
//if there are too many groups, find the best ones
|
||||||
return getWeightedRandomChoice(overlappingSegmentsGroups, 32).map(
|
return getWeightedRandomChoice(overlappingSegmentsGroups, max).map(
|
||||||
//randomly choose 1 good segment per group and return them
|
//randomly choose 1 good segment per group and return them
|
||||||
group => getWeightedRandomChoice(group.segments, 1)[0],
|
group => getWeightedRandomChoice(group.segments, 1)[0],
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,8 +13,9 @@ import {dispatchEvent} from '../utils/webhookUtils';
|
||||||
import {Request, Response} from 'express';
|
import {Request, Response} from 'express';
|
||||||
import { skipSegmentsHashKey, skipSegmentsKey } from '../middleware/redisKeys';
|
import { skipSegmentsHashKey, skipSegmentsKey } from '../middleware/redisKeys';
|
||||||
import redis from '../utils/redis';
|
import redis from '../utils/redis';
|
||||||
import { Category, IncomingSegment, Segment, SegmentUUID, Service, VideoDuration, VideoID } from '../types/segments.model';
|
import { Category, CategoryActionType, IncomingSegment, Segment, SegmentUUID, Service, VideoDuration, VideoID } from '../types/segments.model';
|
||||||
import { deleteNoSegments } from './deleteNoSegments';
|
import { deleteNoSegments } from './deleteNoSegments';
|
||||||
|
import { getCategoryActionType } from '../utils/categoryInfo';
|
||||||
|
|
||||||
interface APIVideoInfo {
|
interface APIVideoInfo {
|
||||||
err: string | boolean,
|
err: string | boolean,
|
||||||
|
@ -426,7 +427,8 @@ export async function postSkipSegments(req: Request, res: Response) {
|
||||||
|
|
||||||
if (isNaN(startTime) || isNaN(endTime)
|
if (isNaN(startTime) || isNaN(endTime)
|
||||||
|| startTime === Infinity || endTime === Infinity || startTime < 0 || startTime > endTime
|
|| startTime === Infinity || endTime === Infinity || startTime < 0 || startTime > endTime
|
||||||
|| (segments[i].category !== "highlight" && startTime === endTime) || (segments[i].category === "highlight" && startTime !== endTime)) {
|
|| (getCategoryActionType(segments[i].category) === CategoryActionType.Skippable && startTime === endTime)
|
||||||
|
|| (getCategoryActionType(segments[i].category) === CategoryActionType.POI && startTime !== endTime)) {
|
||||||
//invalid request
|
//invalid request
|
||||||
res.status(400).send("One of your segments times are invalid (too short, startTime before endTime, etc.)");
|
res.status(400).send("One of your segments times are invalid (too short, startTime before endTime, etc.)");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,7 +13,8 @@ import {config} from '../config';
|
||||||
import { UserID } from '../types/user.model';
|
import { UserID } from '../types/user.model';
|
||||||
import redis from '../utils/redis';
|
import redis from '../utils/redis';
|
||||||
import { skipSegmentsHashKey, skipSegmentsKey } from '../middleware/redisKeys';
|
import { skipSegmentsHashKey, skipSegmentsKey } from '../middleware/redisKeys';
|
||||||
import { Category, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash } from '../types/segments.model';
|
import { Category, CategoryActionType, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash } from '../types/segments.model';
|
||||||
|
import { getCategoryActionType } from '../utils/categoryInfo';
|
||||||
|
|
||||||
const voteTypes = {
|
const voteTypes = {
|
||||||
normal: 0,
|
normal: 0,
|
||||||
|
@ -170,7 +171,7 @@ async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, i
|
||||||
res.status(400).send("Category doesn't exist.");
|
res.status(400).send("Category doesn't exist.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (category === "highlight") {
|
if (getCategoryActionType(category) !== CategoryActionType.Skippable) {
|
||||||
res.status(400).send("Cannot vote for this category");
|
res.status(400).send("Cannot vote for this category");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,3 +73,8 @@ export interface SegmentCache {
|
||||||
shadowHiddenSegmentIPs: SBRecord<VideoID, {hashedIP: HashedIP}[]>,
|
shadowHiddenSegmentIPs: SBRecord<VideoID, {hashedIP: HashedIP}[]>,
|
||||||
userHashedIP?: HashedIP
|
userHashedIP?: HashedIP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CategoryActionType {
|
||||||
|
Skippable,
|
||||||
|
POI
|
||||||
|
}
|
10
src/utils/categoryInfo.ts
Normal file
10
src/utils/categoryInfo.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { Category, CategoryActionType } from "../types/segments.model";
|
||||||
|
|
||||||
|
export function getCategoryActionType(category: Category): CategoryActionType {
|
||||||
|
switch (category) {
|
||||||
|
case "highlight":
|
||||||
|
return CategoryActionType.POI;
|
||||||
|
default:
|
||||||
|
return CategoryActionType.Skippable;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,9 @@ describe('getSegmentsByHash', () => {
|
||||||
await db.prepare("run", startOfQuery + "('getSegmentsByHash-noMatchHash', 40, 50, 2, 'getSegmentsByHash-noMatchHash', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 'fdaffnoMatchHash')"); // hash = fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910
|
await db.prepare("run", startOfQuery + "('getSegmentsByHash-noMatchHash', 40, 50, 2, 'getSegmentsByHash-noMatchHash', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 'fdaffnoMatchHash')"); // hash = fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910
|
||||||
await db.prepare("run", startOfQuery + "('getSegmentsByHash-1', 60, 70, 2, 'getSegmentsByHash-1', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, '" + getHash('getSegmentsByHash-1', 1) + "')"); // hash = 3272fa85ee0927f6073ef6f07ad5f3146047c1abba794cfa364d65ab9921692b
|
await db.prepare("run", startOfQuery + "('getSegmentsByHash-1', 60, 70, 2, 'getSegmentsByHash-1', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, '" + getHash('getSegmentsByHash-1', 1) + "')"); // hash = 3272fa85ee0927f6073ef6f07ad5f3146047c1abba794cfa364d65ab9921692b
|
||||||
await db.prepare("run", startOfQuery + "('onlyHidden', 60, 70, 2, 'onlyHidden', 'testman', 0, 50, 'sponsor', 'YouTube', 1, 0, '" + getHash('onlyHidden', 1) + "')"); // hash = f3a199e1af001d716cdc6599360e2b062c2d2b3fa2885f6d9d2fd741166cbbd3
|
await db.prepare("run", startOfQuery + "('onlyHidden', 60, 70, 2, 'onlyHidden', 'testman', 0, 50, 'sponsor', 'YouTube', 1, 0, '" + getHash('onlyHidden', 1) + "')"); // hash = f3a199e1af001d716cdc6599360e2b062c2d2b3fa2885f6d9d2fd741166cbbd3
|
||||||
|
await db.prepare("run", startOfQuery + "('highlightVid', 60, 60, 2, 'highlightVid-1', 'testman', 0, 50, 'highlight', 'YouTube', 0, 0, '" + getHash('highlightVid', 1) + "')"); // hash = c962d387a9e50170c9118405d20b1081cee8659cd600b856b511f695b91455cb
|
||||||
|
await db.prepare("run", startOfQuery + "('highlightVid', 70, 70, 2, 'highlightVid-2', 'testman', 0, 50, 'highlight', 'YouTube', 0, 0, '" + getHash('highlightVid', 1) + "')"); // hash = c962d387a9e50170c9118405d20b1081cee8659cd600b856b511f695b91455cb
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to get a 200', (done: Done) => {
|
it('Should be able to get a 200', (done: Done) => {
|
||||||
|
@ -158,7 +161,7 @@ describe('getSegmentsByHash', () => {
|
||||||
if (res.status !== 200) done("non 200 status code, was " + res.status);
|
if (res.status !== 200) done("non 200 status code, was " + res.status);
|
||||||
else {
|
else {
|
||||||
const body = await res.json();
|
const body = await res.json();
|
||||||
if (body.length !== 1) done("expected 2 videos, got " + body.length);
|
if (body.length !== 1) done("expected 1 video, got " + body.length);
|
||||||
else if (body[0].segments.length !== 1) done("expected 1 segments for first video, got " + body[0].segments.length);
|
else if (body[0].segments.length !== 1) done("expected 1 segments for first video, got " + body[0].segments.length);
|
||||||
else if (body[0].segments[0].UUID !== 'getSegmentsByHash-0-0-1') done("both segments are not sponsor");
|
else if (body[0].segments[0].UUID !== 'getSegmentsByHash-0-0-1') done("both segments are not sponsor");
|
||||||
else done();
|
else done();
|
||||||
|
@ -167,6 +170,20 @@ describe('getSegmentsByHash', () => {
|
||||||
.catch(err => done("Couldn't call endpoint"));
|
.catch(err => done("Couldn't call endpoint"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should only return one segment when fetching highlight segments', (done: Done) => {
|
||||||
|
fetch(getbaseURL() + '/api/skipSegments/c962?category=highlight')
|
||||||
|
.then(async res => {
|
||||||
|
if (res.status !== 200) done("non 200 status code, was " + res.status);
|
||||||
|
else {
|
||||||
|
const body = await res.json();
|
||||||
|
if (body.length !== 1) done("expected 1 video, got " + body.length);
|
||||||
|
else if (body[0].segments.length !== 1) done("expected 1 segment, got " + body[0].segments.length);
|
||||||
|
else done();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => done("Couldn't call endpoint"));
|
||||||
|
});
|
||||||
|
|
||||||
it('Should be able to post a segment and get it using endpoint', (done: Done) => {
|
it('Should be able to post a segment and get it using endpoint', (done: Done) => {
|
||||||
let testID = 'abc123goodVideo';
|
let testID = 'abc123goodVideo';
|
||||||
fetch(getbaseURL() + "/api/postVideoSponsorTimes", {
|
fetch(getbaseURL() + "/api/postVideoSponsorTimes", {
|
||||||
|
|
Loading…
Reference in a new issue