mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-31 11:56:27 +03:00
32
databases/_upgrade_sponsorTimes_19.sql
Normal file
32
databases/_upgrade_sponsorTimes_19.sql
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
/* Add actionType field */
|
||||||
|
CREATE TABLE "sqlb_temp_table_19" (
|
||||||
|
"videoID" TEXT NOT NULL,
|
||||||
|
"startTime" REAL NOT NULL,
|
||||||
|
"endTime" REAL NOT NULL,
|
||||||
|
"votes" INTEGER NOT NULL,
|
||||||
|
"locked" INTEGER NOT NULL default '0',
|
||||||
|
"incorrectVotes" INTEGER NOT NULL default '1',
|
||||||
|
"UUID" TEXT NOT NULL UNIQUE,
|
||||||
|
"userID" TEXT NOT NULL,
|
||||||
|
"timeSubmitted" INTEGER NOT NULL,
|
||||||
|
"views" INTEGER NOT NULL,
|
||||||
|
"category" TEXT NOT NULL DEFAULT 'sponsor',
|
||||||
|
"actionType" TEXT NOT NULL DEFAULT 'skip',
|
||||||
|
"service" TEXT NOT NULL DEFAULT 'YouTube',
|
||||||
|
"videoDuration" REAL NOT NULL DEFAULT '0',
|
||||||
|
"hidden" INTEGER NOT NULL DEFAULT '0',
|
||||||
|
"reputation" REAL NOT NULL DEFAULT 0,
|
||||||
|
"shadowHidden" INTEGER NOT NULL,
|
||||||
|
"hashedVideoID" TEXT NOT NULL default ''
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO sqlb_temp_table_19 SELECT "videoID","startTime","endTime","votes","locked","incorrectVotes","UUID","userID","timeSubmitted","views","category",'skip',"service","videoDuration","hidden","reputation","shadowHidden","hashedVideoID" FROM "sponsorTimes";
|
||||||
|
|
||||||
|
DROP TABLE "sponsorTimes";
|
||||||
|
ALTER TABLE sqlb_temp_table_19 RENAME TO "sponsorTimes";
|
||||||
|
|
||||||
|
UPDATE "config" SET value = 19 WHERE key = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -3,7 +3,7 @@ import { config } from '../config';
|
|||||||
import { db, privateDB } from '../databases/databases';
|
import { db, privateDB } from '../databases/databases';
|
||||||
import { skipSegmentsHashKey, skipSegmentsKey } from '../utils/redisKeys';
|
import { skipSegmentsHashKey, skipSegmentsKey } from '../utils/redisKeys';
|
||||||
import { SBRecord } from '../types/lib.model';
|
import { SBRecord } from '../types/lib.model';
|
||||||
import { Category, CategoryActionType, DBSegment, HashedIP, IPAddress, OverlappingSegmentGroup, Segment, SegmentCache, SegmentUUID, Service, VideoData, VideoID, VideoIDHash, Visibility, VotableObject } from "../types/segments.model";
|
import { ActionType, Category, CategoryActionType, DBSegment, HashedIP, IPAddress, OverlappingSegmentGroup, Segment, SegmentCache, SegmentUUID, Service, VideoData, VideoID, VideoIDHash, Visibility, VotableObject } from "../types/segments.model";
|
||||||
import { getCategoryActionType } from '../utils/categoryInfo';
|
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';
|
||||||
@@ -12,7 +12,7 @@ import { QueryCacher } from '../utils/queryCacher';
|
|||||||
import { getReputation } from '../utils/reputation';
|
import { getReputation } from '../utils/reputation';
|
||||||
|
|
||||||
|
|
||||||
async function prepareCategorySegments(req: Request, videoID: VideoID, category: Category, segments: DBSegment[], cache: SegmentCache = {shadowHiddenSegmentIPs: {}}): Promise<Segment[]> {
|
async function prepareCategorySegments(req: Request, videoID: VideoID, category: Category, segments: DBSegment[],cache: SegmentCache = {shadowHiddenSegmentIPs: {}}): Promise<Segment[]> {
|
||||||
const shouldFilter: boolean[] = await Promise.all(segments.map(async (segment) => {
|
const shouldFilter: boolean[] = await Promise.all(segments.map(async (segment) => {
|
||||||
if (segment.votes < -1 && !segment.required) {
|
if (segment.votes < -1 && !segment.required) {
|
||||||
return false; //too untrustworthy, just ignore it
|
return false; //too untrustworthy, just ignore it
|
||||||
@@ -43,14 +43,16 @@ async function prepareCategorySegments(req: Request, videoID: VideoID, category:
|
|||||||
|
|
||||||
const maxSegments = getCategoryActionType(category) === CategoryActionType.Skippable ? 32 : 1;
|
const maxSegments = getCategoryActionType(category) === CategoryActionType.Skippable ? 32 : 1;
|
||||||
return (await chooseSegments(filteredSegments, maxSegments)).map((chosenSegment) => ({
|
return (await chooseSegments(filteredSegments, maxSegments)).map((chosenSegment) => ({
|
||||||
category,
|
category: chosenSegment.category,
|
||||||
|
actionType: chosenSegment.actionType,
|
||||||
segment: [chosenSegment.startTime, chosenSegment.endTime],
|
segment: [chosenSegment.startTime, chosenSegment.endTime],
|
||||||
UUID: chosenSegment.UUID,
|
UUID: chosenSegment.UUID,
|
||||||
videoDuration: chosenSegment.videoDuration
|
videoDuration: chosenSegment.videoDuration
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories: Category[], requiredSegments: SegmentUUID[], service: Service): Promise<Segment[]> {
|
async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories: Category[],
|
||||||
|
actionTypes: ActionType[], requiredSegments: SegmentUUID[], service: Service): Promise<Segment[]> {
|
||||||
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
|
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
|
||||||
const segments: Segment[] = [];
|
const segments: Segment[] = [];
|
||||||
|
|
||||||
@@ -59,16 +61,17 @@ async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories:
|
|||||||
if (categories.length === 0) return null;
|
if (categories.length === 0) return null;
|
||||||
|
|
||||||
const segmentsByCategory: SBRecord<Category, DBSegment[]> = (await getSegmentsFromDBByVideoID(videoID, service))
|
const segmentsByCategory: SBRecord<Category, DBSegment[]> = (await getSegmentsFromDBByVideoID(videoID, service))
|
||||||
.filter((segment: DBSegment) => categories.includes(segment?.category))
|
.filter((segment: DBSegment) => categories.includes(segment?.category) && actionTypes.includes(segment?.actionType))
|
||||||
.reduce((acc: SBRecord<Category, DBSegment[]>, segment: DBSegment) => {
|
.reduce((acc: SBRecord<Category, DBSegment[]>, segment: DBSegment) => {
|
||||||
if (requiredSegments.includes(segment.UUID)) segment.required = true;
|
if (requiredSegments.includes(segment.UUID)) segment.required = true;
|
||||||
|
|
||||||
acc[segment.category] = acc[segment.category] || [];
|
acc[segment.category] ??= [];
|
||||||
acc[segment.category].push(segment);
|
acc[segment.category].push(segment);
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
for (const [category, categorySegments] of Object.entries(segmentsByCategory)) {
|
for (const [category, categorySegments] of Object.entries(segmentsByCategory)) {
|
||||||
segments.push(...(await prepareCategorySegments(req, videoID, category as Category, categorySegments, cache)));
|
segments.push(...(await prepareCategorySegments(req, videoID, category as Category, categorySegments, cache)));
|
||||||
}
|
}
|
||||||
@@ -82,7 +85,8 @@ async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash, categories: Category[], requiredSegments: SegmentUUID[], service: Service): Promise<SBRecord<VideoID, VideoData>> {
|
async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash, categories: Category[],
|
||||||
|
actionTypes: ActionType[], requiredSegments: SegmentUUID[], service: Service): Promise<SBRecord<VideoID, VideoData>> {
|
||||||
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
|
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
|
||||||
const segments: SBRecord<VideoID, VideoData> = {};
|
const segments: SBRecord<VideoID, VideoData> = {};
|
||||||
|
|
||||||
@@ -93,17 +97,16 @@ async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash,
|
|||||||
if (categories.length === 0) return null;
|
if (categories.length === 0) return null;
|
||||||
|
|
||||||
const segmentPerVideoID: SegmentWithHashPerVideoID = (await getSegmentsFromDBByHash(hashedVideoIDPrefix, service))
|
const segmentPerVideoID: SegmentWithHashPerVideoID = (await getSegmentsFromDBByHash(hashedVideoIDPrefix, service))
|
||||||
.filter((segment: DBSegment) => categories.includes(segment?.category))
|
.filter((segment: DBSegment) => categories.includes(segment?.category) && actionTypes.includes(segment?.actionType))
|
||||||
.reduce((acc: SegmentWithHashPerVideoID, segment: DBSegment) => {
|
.reduce((acc: SegmentWithHashPerVideoID, segment: DBSegment) => {
|
||||||
acc[segment.videoID] = acc[segment.videoID] || {
|
acc[segment.videoID] = acc[segment.videoID] || {
|
||||||
hash: segment.hashedVideoID,
|
hash: segment.hashedVideoID,
|
||||||
segmentPerCategory: {},
|
segmentPerCategory: {}
|
||||||
};
|
};
|
||||||
if (requiredSegments.includes(segment.UUID)) segment.required = true;
|
if (requiredSegments.includes(segment.UUID)) segment.required = true;
|
||||||
|
|
||||||
const videoCategories = acc[segment.videoID].segmentPerCategory;
|
acc[segment.videoID].segmentPerCategory[segment.category] ??= [];
|
||||||
videoCategories[segment.category] = videoCategories[segment.category] || [];
|
acc[segment.videoID].segmentPerCategory[segment.category].push(segment);
|
||||||
videoCategories[segment.category].push(segment);
|
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
@@ -114,6 +117,7 @@ async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash,
|
|||||||
segments: [],
|
segments: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
for (const [category, segmentPerCategory] of Object.entries(videoData.segmentPerCategory)) {
|
for (const [category, segmentPerCategory] of Object.entries(videoData.segmentPerCategory)) {
|
||||||
segments[videoID].segments.push(...(await prepareCategorySegments(req, videoID as VideoID, category as Category, segmentPerCategory, cache)));
|
segments[videoID].segments.push(...(await prepareCategorySegments(req, videoID as VideoID, category as Category, segmentPerCategory, cache)));
|
||||||
}
|
}
|
||||||
@@ -132,7 +136,7 @@ async function getSegmentsFromDBByHash(hashedVideoIDPrefix: VideoIDHash, service
|
|||||||
const fetchFromDB = () => db
|
const fetchFromDB = () => db
|
||||||
.prepare(
|
.prepare(
|
||||||
'all',
|
'all',
|
||||||
`SELECT "videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "category", "videoDuration", "reputation", "shadowHidden", "hashedVideoID" FROM "sponsorTimes"
|
`SELECT "videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "category", "actionType", "videoDuration", "reputation", "shadowHidden", "hashedVideoID" FROM "sponsorTimes"
|
||||||
WHERE "hashedVideoID" LIKE ? AND "service" = ? AND "hidden" = 0 ORDER BY "startTime"`,
|
WHERE "hashedVideoID" LIKE ? AND "service" = ? AND "hidden" = 0 ORDER BY "startTime"`,
|
||||||
[hashedVideoIDPrefix + '%', service]
|
[hashedVideoIDPrefix + '%', service]
|
||||||
) as Promise<DBSegment[]>;
|
) as Promise<DBSegment[]>;
|
||||||
@@ -148,7 +152,7 @@ async function getSegmentsFromDBByVideoID(videoID: VideoID, service: Service): P
|
|||||||
const fetchFromDB = () => db
|
const fetchFromDB = () => db
|
||||||
.prepare(
|
.prepare(
|
||||||
'all',
|
'all',
|
||||||
`SELECT "startTime", "endTime", "votes", "locked", "UUID", "userID", "category", "videoDuration", "reputation", "shadowHidden" FROM "sponsorTimes"
|
`SELECT "startTime", "endTime", "votes", "locked", "UUID", "userID", "category", "actionType", "videoDuration", "reputation", "shadowHidden" FROM "sponsorTimes"
|
||||||
WHERE "videoID" = ? AND "service" = ? AND "hidden" = 0 ORDER BY "startTime"`,
|
WHERE "videoID" = ? AND "service" = ? AND "hidden" = 0 ORDER BY "startTime"`,
|
||||||
[videoID, service]
|
[videoID, service]
|
||||||
) as Promise<DBSegment[]>;
|
) as Promise<DBSegment[]>;
|
||||||
@@ -275,7 +279,7 @@ async function handleGetSegments(req: Request, res: Response): Promise<Segment[]
|
|||||||
const videoID = req.query.videoID as VideoID;
|
const videoID = req.query.videoID as VideoID;
|
||||||
// Default to sponsor
|
// Default to sponsor
|
||||||
// If using params instead of JSON, only one category can be pulled
|
// If using params instead of JSON, only one category can be pulled
|
||||||
const categories = req.query.categories
|
const categories: Category[] = req.query.categories
|
||||||
? JSON.parse(req.query.categories as string)
|
? JSON.parse(req.query.categories as string)
|
||||||
: req.query.category
|
: req.query.category
|
||||||
? Array.isArray(req.query.category)
|
? Array.isArray(req.query.category)
|
||||||
@@ -287,6 +291,18 @@ async function handleGetSegments(req: Request, res: Response): Promise<Segment[]
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const actionTypes: 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];
|
||||||
|
if (!Array.isArray(actionTypes)) {
|
||||||
|
res.status(400).send("actionTypes parameter does not match format requirements.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const requiredSegments: SegmentUUID[] = req.query.requiredSegments
|
const requiredSegments: SegmentUUID[] = req.query.requiredSegments
|
||||||
? JSON.parse(req.query.requiredSegments as string)
|
? JSON.parse(req.query.requiredSegments as string)
|
||||||
: req.query.requiredSegment
|
: req.query.requiredSegment
|
||||||
@@ -304,7 +320,7 @@ async function handleGetSegments(req: Request, res: Response): Promise<Segment[]
|
|||||||
service = Service.YouTube;
|
service = Service.YouTube;
|
||||||
}
|
}
|
||||||
|
|
||||||
const segments = await getSegmentsByVideoID(req, videoID, categories, requiredSegments, service);
|
const segments = await getSegmentsByVideoID(req, videoID, categories, actionTypes, requiredSegments, service);
|
||||||
|
|
||||||
if (segments === null || segments === undefined) {
|
if (segments === null || segments === undefined) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {hashPrefixTester} from '../utils/hashPrefixTester';
|
import {hashPrefixTester} from '../utils/hashPrefixTester';
|
||||||
import {getSegmentsByHash} from './getSkipSegments';
|
import {getSegmentsByHash} from './getSkipSegments';
|
||||||
import {Request, Response} from 'express';
|
import {Request, Response} from 'express';
|
||||||
import { Category, SegmentUUID, Service, VideoIDHash } from '../types/segments.model';
|
import { ActionType, Category, SegmentUUID, Service, VideoIDHash } from '../types/segments.model';
|
||||||
|
|
||||||
export async function getSkipSegmentsByHash(req: Request, res: Response): Promise<Response> {
|
export async function getSkipSegmentsByHash(req: Request, res: Response): Promise<Response> {
|
||||||
let hashPrefix = req.params.prefix as VideoIDHash;
|
let hashPrefix = req.params.prefix as VideoIDHash;
|
||||||
@@ -26,6 +26,22 @@ export async function getSkipSegmentsByHash(req: Request, res: Response): Promis
|
|||||||
return res.status(400).send("Bad parameter: categories (invalid JSON)");
|
return res.status(400).send("Bad parameter: categories (invalid JSON)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let actionTypes: ActionType[] = [];
|
||||||
|
try {
|
||||||
|
actionTypes = 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];
|
||||||
|
if (!Array.isArray(actionTypes)) {
|
||||||
|
return res.status(400).send("actionTypes parameter does not match format requirements.");
|
||||||
|
}
|
||||||
|
} catch(error) {
|
||||||
|
return res.status(400).send("Bad parameter: actionTypes (invalid JSON)");
|
||||||
|
}
|
||||||
|
|
||||||
let requiredSegments: SegmentUUID[] = [];
|
let requiredSegments: SegmentUUID[] = [];
|
||||||
try {
|
try {
|
||||||
requiredSegments = req.query.requiredSegments
|
requiredSegments = req.query.requiredSegments
|
||||||
@@ -51,7 +67,7 @@ export async function getSkipSegmentsByHash(req: Request, res: Response): Promis
|
|||||||
categories = categories.filter((item: any) => typeof item === "string");
|
categories = categories.filter((item: any) => typeof item === "string");
|
||||||
|
|
||||||
// Get all video id's that match hash prefix
|
// Get all video id's that match hash prefix
|
||||||
const segments = await getSegmentsByHash(req, hashPrefix, categories, requiredSegments, service);
|
const segments = await getSegmentsByHash(req, hashPrefix, categories, actionTypes, requiredSegments, service);
|
||||||
|
|
||||||
if (!segments) return res.status(404).json([]);
|
if (!segments) return res.status(404).json([]);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {getFormattedTime} from '../utils/getFormattedTime';
|
|||||||
import {isUserTrustworthy} from '../utils/isUserTrustworthy';
|
import {isUserTrustworthy} from '../utils/isUserTrustworthy';
|
||||||
import {dispatchEvent} from '../utils/webhookUtils';
|
import {dispatchEvent} from '../utils/webhookUtils';
|
||||||
import {Request, Response} from 'express';
|
import {Request, Response} from 'express';
|
||||||
import { Category, CategoryActionType, IncomingSegment, SegmentUUID, Service, VideoDuration, VideoID } from '../types/segments.model';
|
import { ActionType, Category, CategoryActionType, IncomingSegment, SegmentUUID, Service, VideoDuration, VideoID } from '../types/segments.model';
|
||||||
import { deleteLockCategories } from './deleteLockCategories';
|
import { deleteLockCategories } from './deleteLockCategories';
|
||||||
import { getCategoryActionType } from '../utils/categoryInfo';
|
import { getCategoryActionType } from '../utils/categoryInfo';
|
||||||
import { QueryCacher } from '../utils/queryCacher';
|
import { QueryCacher } from '../utils/queryCacher';
|
||||||
@@ -315,7 +315,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
const videoID = req.query.videoID || req.body.videoID;
|
const videoID = req.query.videoID || req.body.videoID;
|
||||||
let userID = req.query.userID || req.body.userID;
|
let userID = req.query.userID || req.body.userID;
|
||||||
let service: Service = req.query.service ?? req.body.service ?? Service.YouTube;
|
let service: Service = req.query.service ?? req.body.service ?? Service.YouTube;
|
||||||
if (!Object.values(Service).some((val) => val == service)) {
|
if (!Object.values(Service).some((val) => val === service)) {
|
||||||
service = Service.YouTube;
|
service = Service.YouTube;
|
||||||
}
|
}
|
||||||
let videoDuration: VideoDuration = (parseFloat(req.query.videoDuration || req.body.videoDuration) || 0) as VideoDuration;
|
let videoDuration: VideoDuration = (parseFloat(req.query.videoDuration || req.body.videoDuration) || 0) as VideoDuration;
|
||||||
@@ -325,9 +325,16 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
// Use query instead
|
// Use query instead
|
||||||
segments = [{
|
segments = [{
|
||||||
segment: [req.query.startTime as string, req.query.endTime as string],
|
segment: [req.query.startTime as string, req.query.endTime as string],
|
||||||
category: req.query.category as Category
|
category: req.query.category as Category,
|
||||||
|
actionType: (req.query.actionType as ActionType) ?? ActionType.Skip
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
// Add default action type
|
||||||
|
segments.forEach((segment) => {
|
||||||
|
if (!Object.values(ActionType).some((val) => val === segment.actionType)){
|
||||||
|
segment.actionType = ActionType.Skip;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const invalidFields = [];
|
const invalidFields = [];
|
||||||
if (typeof videoID !== 'string') {
|
if (typeof videoID !== 'string') {
|
||||||
@@ -518,9 +525,9 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
const startingLocked = isVIP ? 1 : 0;
|
const startingLocked = isVIP ? 1 : 0;
|
||||||
try {
|
try {
|
||||||
await db.prepare('run', `INSERT INTO "sponsorTimes"
|
await db.prepare('run', `INSERT INTO "sponsorTimes"
|
||||||
("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "videoDuration", "reputation", "shadowHidden", "hashedVideoID")
|
("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "reputation", "shadowHidden", "hashedVideoID")
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
||||||
videoID, segmentInfo.segment[0], segmentInfo.segment[1], startingVotes, startingLocked, UUID, userID, timeSubmitted, 0, segmentInfo.category, service, videoDuration, reputation, shadowBanned, hashedVideoID,
|
videoID, segmentInfo.segment[0], segmentInfo.segment[1], startingVotes, startingLocked, UUID, userID, timeSubmitted, 0, segmentInfo.category, segmentInfo.actionType, service, videoDuration, reputation, shadowBanned, hashedVideoID,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ export type VideoIDHash = VideoID & HashedValue;
|
|||||||
export type IPAddress = string & { __ipAddressBrand: unknown };
|
export type IPAddress = string & { __ipAddressBrand: unknown };
|
||||||
export type HashedIP = IPAddress & HashedValue;
|
export type HashedIP = IPAddress & HashedValue;
|
||||||
|
|
||||||
|
export enum ActionType {
|
||||||
|
Skip = "skip",
|
||||||
|
Mute = "mute",
|
||||||
|
}
|
||||||
|
|
||||||
// Uncomment as needed
|
// Uncomment as needed
|
||||||
export enum Service {
|
export enum Service {
|
||||||
YouTube = 'YouTube',
|
YouTube = 'YouTube',
|
||||||
@@ -23,11 +28,13 @@ export enum Service {
|
|||||||
|
|
||||||
export interface IncomingSegment {
|
export interface IncomingSegment {
|
||||||
category: Category;
|
category: Category;
|
||||||
|
actionType: ActionType;
|
||||||
segment: string[];
|
segment: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Segment {
|
export interface Segment {
|
||||||
category: Category;
|
category: Category;
|
||||||
|
actionType: ActionType;
|
||||||
segment: number[];
|
segment: number[];
|
||||||
UUID: SegmentUUID;
|
UUID: SegmentUUID;
|
||||||
videoDuration: VideoDuration;
|
videoDuration: VideoDuration;
|
||||||
@@ -40,6 +47,7 @@ export enum Visibility {
|
|||||||
|
|
||||||
export interface DBSegment {
|
export interface DBSegment {
|
||||||
category: Category;
|
category: Category;
|
||||||
|
actionType: ActionType;
|
||||||
startTime: number;
|
startTime: number;
|
||||||
endTime: number;
|
endTime: number;
|
||||||
UUID: SegmentUUID;
|
UUID: SegmentUUID;
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ import { UserID } from "../types/user.model";
|
|||||||
import { Logger } from "./logger";
|
import { Logger } from "./logger";
|
||||||
|
|
||||||
export function skipSegmentsKey(videoID: VideoID, service: Service): string {
|
export function skipSegmentsKey(videoID: VideoID, service: Service): string {
|
||||||
return "segments." + service + ".videoID." + videoID;
|
return "segments.v2." + service + ".videoID." + videoID;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function skipSegmentsHashKey(hashedVideoIDPrefix: VideoIDHash, service: Service): string {
|
export function skipSegmentsHashKey(hashedVideoIDPrefix: VideoIDHash, service: Service): string {
|
||||||
hashedVideoIDPrefix = hashedVideoIDPrefix.substring(0, 4) as VideoIDHash;
|
hashedVideoIDPrefix = hashedVideoIDPrefix.substring(0, 4) as VideoIDHash;
|
||||||
if (hashedVideoIDPrefix.length !== 4) Logger.warn("Redis skip segment hash-prefix key is not length 4! " + hashedVideoIDPrefix);
|
if (hashedVideoIDPrefix.length !== 4) Logger.warn("Redis skip segment hash-prefix key is not length 4! " + hashedVideoIDPrefix);
|
||||||
|
|
||||||
return "segments." + service + "." + hashedVideoIDPrefix;
|
return "segments.v2." + service + "." + hashedVideoIDPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reputationKey(userID: UserID): string {
|
export function reputationKey(userID: UserID): string {
|
||||||
|
|||||||
@@ -5,22 +5,23 @@ import {getHash} from '../../src/utils/getHash';
|
|||||||
|
|
||||||
describe('getSkipSegments', () => {
|
describe('getSkipSegments', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", views, category, "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", views, category, "actionType", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||||
await db.prepare("run", query, ['testtesttest', 1, 11, 2, 0, '1-uuid-0', 'testman', 0, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash('testtesttest', 1)]);
|
await db.prepare("run", query, ['testtesttest', 1, 11, 2, 0, '1-uuid-0', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 100, 0, 0, getHash('testtesttest', 1)]);
|
||||||
await db.prepare("run", query, ['testtesttest2', 1, 11, 2, 0, '1-uuid-0-1', 'testman', 0, 50, 'sponsor', 'PeerTube', 120, 0, 0, getHash('testtesttest2', 1)]);
|
await db.prepare("run", query, ['testtesttest2', 1, 11, 2, 0, '1-uuid-0-1', 'testman', 0, 50, 'sponsor', 'skip', 'PeerTube', 120, 0, 0, getHash('testtesttest2', 1)]);
|
||||||
await db.prepare("run", query, ['testtesttest', 20, 33, 2, 0, '1-uuid-2', 'testman', 0, 50, 'intro', 'YouTube', 101, 0, 0, getHash('testtesttest', 1)]);
|
await db.prepare("run", query, ['testtesttest', 12, 14, 2, 0, '1-uuid-0-2', 'testman', 0, 50, 'sponsor', 'mute', 'YouTube', 100, 0, 0, getHash('testtesttest', 1)]);
|
||||||
await db.prepare("run", query, ['testtesttest,test', 1, 11, 2, 0, '1-uuid-1', 'testman', 0, 50, 'sponsor', 'YouTube', 140, 0, 0, getHash('testtesttest,test', 1)]);
|
await db.prepare("run", query, ['testtesttest', 20, 33, 2, 0, '1-uuid-2', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 101, 0, 0, getHash('testtesttest', 1)]);
|
||||||
await db.prepare("run", query, ['test3', 1, 11, 2, 0, '1-uuid-4', 'testman', 0, 50, 'sponsor', 'YouTube', 200, 0, 0, getHash('test3', 1)]);
|
await db.prepare("run", query, ['testtesttest,test', 1, 11, 2, 0, '1-uuid-1', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 140, 0, 0, getHash('testtesttest,test', 1)]);
|
||||||
await db.prepare("run", query, ['test3', 7, 22, -3, 0, '1-uuid-5', 'testman', 0, 50, 'sponsor', 'YouTube', 300, 0, 0, getHash('test3', 1)]);
|
await db.prepare("run", query, ['test3', 1, 11, 2, 0, '1-uuid-4', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 200, 0, 0, getHash('test3', 1)]);
|
||||||
await db.prepare("run", query, ['multiple', 1, 11, 2, 0, '1-uuid-6', 'testman', 0, 50, 'intro', 'YouTube', 400, 0, 0, getHash('multiple', 1)]);
|
await db.prepare("run", query, ['test3', 7, 22, -3, 0, '1-uuid-5', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 300, 0, 0, getHash('test3', 1)]);
|
||||||
await db.prepare("run", query, ['multiple', 20, 33, 2, 0, '1-uuid-7', 'testman', 0, 50, 'intro', 'YouTube', 500, 0, 0, getHash('multiple', 1)]);
|
await db.prepare("run", query, ['multiple', 1, 11, 2, 0, '1-uuid-6', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 400, 0, 0, getHash('multiple', 1)]);
|
||||||
await db.prepare("run", query, ['locked', 20, 33, 2, 1, '1-uuid-locked-8', 'testman', 0, 50, 'intro', 'YouTube', 230, 0, 0, getHash('locked', 1)]);
|
await db.prepare("run", query, ['multiple', 20, 33, 2, 0, '1-uuid-7', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 500, 0, 0, getHash('multiple', 1)]);
|
||||||
await db.prepare("run", query, ['locked', 20, 34, 100000, 0, '1-uuid-9', 'testman', 0, 50, 'intro', 'YouTube', 190, 0, 0, getHash('locked', 1)]);
|
await db.prepare("run", query, ['locked', 20, 33, 2, 1, '1-uuid-locked-8', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 230, 0, 0, getHash('locked', 1)]);
|
||||||
await db.prepare("run", query, ['onlyHiddenSegments', 20, 34, 100000, 0, 'onlyHiddenSegments', 'testman', 0, 50, 'sponsor', 'YouTube', 190, 1, 0, getHash('onlyHiddenSegments', 1)]);
|
await db.prepare("run", query, ['locked', 20, 34, 100000, 0, '1-uuid-9', 'testman', 0, 50, 'intro', 'skip', 'YouTube', 190, 0, 0, getHash('locked', 1)]);
|
||||||
await db.prepare("run", query, ['requiredSegmentVid-raw', 60, 70, 2, 0, 'requiredSegmentVid-raw-1', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
|
await db.prepare("run", query, ['onlyHiddenSegments', 20, 34, 100000, 0, 'onlyHiddenSegments', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 190, 1, 0, getHash('onlyHiddenSegments', 1)]);
|
||||||
await db.prepare("run", query, ['requiredSegmentVid-raw', 60, 70, -2, 0, 'requiredSegmentVid-raw-2', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
|
await db.prepare("run", query, ['requiredSegmentVid-raw', 60, 70, 2, 0, 'requiredSegmentVid-raw-1', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
|
||||||
await db.prepare("run", query, ['requiredSegmentVid-raw', 80, 90, -2, 0, 'requiredSegmentVid-raw-3', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
|
await db.prepare("run", query, ['requiredSegmentVid-raw', 60, 70, -2, 0, 'requiredSegmentVid-raw-2', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
|
||||||
await db.prepare("run", query, ['requiredSegmentVid-raw', 80, 90, 2, 0, 'requiredSegmentVid-raw-4', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
|
await db.prepare("run", query, ['requiredSegmentVid-raw', 80, 90, -2, 0, 'requiredSegmentVid-raw-3', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
|
||||||
|
await db.prepare("run", query, ['requiredSegmentVid-raw', 80, 90, 2, 0, 'requiredSegmentVid-raw-4', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 0, getHash('requiredSegmentVid-raw', 1)]);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,6 +43,59 @@ describe('getSkipSegments', () => {
|
|||||||
.catch(() => "Couldn't call endpoint");
|
.catch(() => "Couldn't call endpoint");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should be able to get a time by category and action type', (done: Done) => {
|
||||||
|
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=sponsor&actionType=mute")
|
||||||
|
.then(async res => {
|
||||||
|
if (res.status !== 200) done("Status code was: " + res.status);
|
||||||
|
else {
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.length === 1 && data[0].segment[0] === 12 && data[0].segment[1] === 14
|
||||||
|
&& data[0].category === "sponsor" && data[0].UUID === "1-uuid-0-2" && data[0].videoDuration === 100) {
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
done("Received incorrect body: " + (await res.text()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => "Couldn't call endpoint");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to get a time by category and multiple action types', (done: Done) => {
|
||||||
|
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=sponsor&actionType=mute&actionType=skip")
|
||||||
|
.then(async res => {
|
||||||
|
if (res.status !== 200) done("Status code was: " + res.status);
|
||||||
|
else {
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.length === 2 && data[0].segment[0] === 1 && data[0].segment[1] === 11
|
||||||
|
&& data[0].category === "sponsor" && data[0].UUID === "1-uuid-0"
|
||||||
|
&& data[1].UUID === "1-uuid-0-2" && data[0].videoDuration === 100) {
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
done("Received incorrect body: " + (await res.text()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => "Couldn't call endpoint");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to get a time by category and multiple action types (JSON array)', (done: Done) => {
|
||||||
|
fetch(getbaseURL() + '/api/skipSegments?videoID=testtesttest&category=sponsor&actionTypes=["mute","skip"]')
|
||||||
|
.then(async res => {
|
||||||
|
if (res.status !== 200) done("Status code was: " + res.status);
|
||||||
|
else {
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.length === 2 && data[0].segment[0] === 1 && data[0].segment[1] === 11
|
||||||
|
&& data[0].category === "sponsor" && data[0].UUID === "1-uuid-0"
|
||||||
|
&& data[1].UUID === "1-uuid-0-2" && data[0].videoDuration === 100) {
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
done("Received incorrect body: " + (await res.text()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => "Couldn't call endpoint");
|
||||||
|
});
|
||||||
|
|
||||||
it('Should be able to get a time by category for a different service 1', (done: Done) => {
|
it('Should be able to get a time by category for a different service 1', (done: Done) => {
|
||||||
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest2&category=sponsor&service=PeerTube")
|
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest2&category=sponsor&service=PeerTube")
|
||||||
.then(async res => {
|
.then(async res => {
|
||||||
|
|||||||
@@ -12,19 +12,20 @@ sinonStub.callsFake(YouTubeApiMock.listVideos);
|
|||||||
|
|
||||||
describe('getSegmentsByHash', () => {
|
describe('getSegmentsByHash', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "service", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "actionType", "service", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||||
await db.prepare("run", query, ['getSegmentsByHash-0', 1, 10, 2, 'getSegmentsByHash-0-0', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
|
await db.prepare("run", query, ['getSegmentsByHash-0', 1, 10, 2, 'getSegmentsByHash-0-0', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
|
||||||
await db.prepare("run", query, ['getSegmentsByHash-0', 1, 10, 2, 'getSegmentsByHash-0-0-1', 'testman', 0, 50, 'sponsor', 'PeerTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
|
await db.prepare("run", query, ['getSegmentsByHash-0', 1, 10, 2, 'getSegmentsByHash-0-0-1', 'testman', 0, 50, 'sponsor', 'skip', 'PeerTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
|
||||||
await db.prepare("run", query, ['getSegmentsByHash-0', 20, 30, 2, 'getSegmentsByHash-0-1', 'testman', 100, 150, 'intro', 'YouTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
|
await db.prepare("run", query, ['getSegmentsByHash-0', 20, 30, 2, 'getSegmentsByHash-0-1', 'testman', 100, 150, 'intro', 'skip', 'YouTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
|
||||||
await db.prepare("run", query, ['getSegmentsByHash-noMatchHash', 40, 50, 2, 'getSegmentsByHash-noMatchHash', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 'fdaffnoMatchHash']);
|
await db.prepare("run", query, ['getSegmentsByHash-0', 40, 50, 2, 'getSegmentsByHash-0-2', 'testman', 0, 50, 'sponsor', 'mute', 'YouTube', 0, 0, 'fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910']);
|
||||||
await db.prepare("run", query, ['getSegmentsByHash-1', 60, 70, 2, 'getSegmentsByHash-1', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, '3272fa85ee0927f6073ef6f07ad5f3146047c1abba794cfa364d65ab9921692b']);
|
await db.prepare("run", query, ['getSegmentsByHash-noMatchHash', 40, 50, 2, 'getSegmentsByHash-noMatchHash', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'fdaffnoMatchHash']);
|
||||||
await db.prepare("run", query, ['onlyHidden', 60, 70, 2, 'onlyHidden', 'testman', 0, 50, 'sponsor', 'YouTube', 1, 0, 'f3a199e1af001d716cdc6599360e2b062c2d2b3fa2885f6d9d2fd741166cbbd3']);
|
await db.prepare("run", query, ['getSegmentsByHash-1', 60, 70, 2, 'getSegmentsByHash-1', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, '3272fa85ee0927f6073ef6f07ad5f3146047c1abba794cfa364d65ab9921692b']);
|
||||||
await db.prepare("run", query, ['highlightVid', 60, 60, 2, 'highlightVid-1', 'testman', 0, 50, 'highlight', 'YouTube', 0, 0, getHash('highlightVid', 1)]);
|
await db.prepare("run", query, ['onlyHidden', 60, 70, 2, 'onlyHidden', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 1, 0, 'f3a199e1af001d716cdc6599360e2b062c2d2b3fa2885f6d9d2fd741166cbbd3']);
|
||||||
await db.prepare("run", query, ['highlightVid', 70, 70, 2, 'highlightVid-2', 'testman', 0, 50, 'highlight', 'YouTube', 0, 0, getHash('highlightVid', 1)]);
|
await db.prepare("run", query, ['highlightVid', 60, 60, 2, 'highlightVid-1', 'testman', 0, 50, 'highlight', 'skip', 'YouTube', 0, 0, getHash('highlightVid', 1)]);
|
||||||
await db.prepare("run", query, ['requiredSegmentVid', 60, 70, 2, 'requiredSegmentVid-1', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
|
await db.prepare("run", query, ['highlightVid', 70, 70, 2, 'highlightVid-2', 'testman', 0, 50, 'highlight', 'skip', 'YouTube', 0, 0, getHash('highlightVid', 1)]);
|
||||||
await db.prepare("run", query, ['requiredSegmentVid', 60, 70, -2, 'requiredSegmentVid-2', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
|
await db.prepare("run", query, ['requiredSegmentVid', 60, 70, 2, 'requiredSegmentVid-1', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
|
||||||
await db.prepare("run", query, ['requiredSegmentVid', 80, 90, -2, 'requiredSegmentVid-3', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
|
await db.prepare("run", query, ['requiredSegmentVid', 60, 70, -2, 'requiredSegmentVid-2', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
|
||||||
await db.prepare("run", query, ['requiredSegmentVid', 80, 90, 2, 'requiredSegmentVid-4', 'testman', 0, 50, 'sponsor', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
|
await db.prepare("run", query, ['requiredSegmentVid', 80, 90, -2, 'requiredSegmentVid-3', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
|
||||||
|
await db.prepare("run", query, ['requiredSegmentVid', 80, 90, 2, 'requiredSegmentVid-4', 'testman', 0, 50, 'sponsor', 'skip', 'YouTube', 0, 0, 'd51822c3f681e07aef15a8855f52ad12db9eb9cf059e65b16b64c43359557f61']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to get a 200', (done: Done) => {
|
it('Should be able to get a 200', (done: Done) => {
|
||||||
@@ -158,6 +159,62 @@ describe('getSegmentsByHash', () => {
|
|||||||
.catch(() => done("Couldn't call endpoint"));
|
.catch(() => done("Couldn't call endpoint"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should be able to get 200 for no categories (default sponsor) with action type', (done: Done) => {
|
||||||
|
fetch(getbaseURL() + '/api/skipSegments/fdaf?actionType=skip')
|
||||||
|
.then(async res => {
|
||||||
|
if (res.status !== 200) done("non 200 status code, was " + res.status);
|
||||||
|
else {
|
||||||
|
const body = await res.json();
|
||||||
|
if (body.length !== 2) done("expected 2 videos, 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[1].segments.length !== 1) done("expected 1 segments for second video, got " + body[1].segments.length);
|
||||||
|
else if (body[0].segments[0].category !== 'sponsor'
|
||||||
|
|| body[0].segments[0].UUID !== 'getSegmentsByHash-0-0'
|
||||||
|
|| body[1].segments[0].category !== 'sponsor') done("both segments are not sponsor");
|
||||||
|
else done();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => done("Couldn't call endpoint"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to get 200 for no categories (default sponsor) with multiple action types', (done: Done) => {
|
||||||
|
fetch(getbaseURL() + '/api/skipSegments/fdaf?actionType=skip&actionType=mute')
|
||||||
|
.then(async res => {
|
||||||
|
if (res.status !== 200) done("non 200 status code, was " + res.status);
|
||||||
|
else {
|
||||||
|
const body = await res.json();
|
||||||
|
if (body.length !== 2) done("expected 2 videos, got " + body.length);
|
||||||
|
else if (body[0].segments.length !== 2) done("expected 2 segments for first video, got " + body[0].segments.length);
|
||||||
|
else if (body[1].segments.length !== 1) done("expected 1 segments for second video, got " + body[1].segments.length);
|
||||||
|
else if (body[0].segments[0].category !== 'sponsor'
|
||||||
|
|| body[0].segments[0].UUID !== 'getSegmentsByHash-0-0'
|
||||||
|
|| body[0].segments[1].UUID !== 'getSegmentsByHash-0-2'
|
||||||
|
|| body[1].segments[0].category !== 'sponsor') done("both segments are not sponsor");
|
||||||
|
else done();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => done("Couldn't call endpoint"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to get 200 for no categories (default sponsor) with multiple action types (JSON array)', (done: Done) => {
|
||||||
|
fetch(getbaseURL() + '/api/skipSegments/fdaf?actionTypes=["skip","mute"]')
|
||||||
|
.then(async res => {
|
||||||
|
if (res.status !== 200) done("non 200 status code, was " + res.status);
|
||||||
|
else {
|
||||||
|
const body = await res.json();
|
||||||
|
if (body.length !== 2) done("expected 2 videos, got " + body.length);
|
||||||
|
else if (body[0].segments.length !== 2) done("expected 2 segments for first video, got " + body[0].segments.length);
|
||||||
|
else if (body[1].segments.length !== 1) done("expected 1 segments for second video, got " + body[1].segments.length);
|
||||||
|
else if (body[0].segments[0].category !== 'sponsor'
|
||||||
|
|| body[0].segments[0].UUID !== 'getSegmentsByHash-0-0'
|
||||||
|
|| body[0].segments[1].UUID !== 'getSegmentsByHash-0-2'
|
||||||
|
|| body[1].segments[0].category !== 'sponsor') done("both segments are not sponsor");
|
||||||
|
else done();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => done("Couldn't call endpoint"));
|
||||||
|
});
|
||||||
|
|
||||||
it('Should be able to get 200 for no categories (default sponsor) for a non YouTube service', (done: Done) => {
|
it('Should be able to get 200 for no categories (default sponsor) for a non YouTube service', (done: Done) => {
|
||||||
fetch(getbaseURL() + '/api/skipSegments/fdaf?service=PeerTube')
|
fetch(getbaseURL() + '/api/skipSegments/fdaf?service=PeerTube')
|
||||||
.then(async res => {
|
.then(async res => {
|
||||||
@@ -287,3 +344,4 @@ describe('getSegmentsByHash', () => {
|
|||||||
.catch(() => done("Couldn't call endpoint"));
|
.catch(() => done("Couldn't call endpoint"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,38 @@ describe('postSkipSegments', () => {
|
|||||||
.catch(err => done(err));
|
.catch(err => done(err));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should be able to submit a single time with an action type (JSON method)', (done: Done) => {
|
||||||
|
fetch(getbaseURL()
|
||||||
|
+ "/api/postVideoSponsorTimes", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
userID: "test",
|
||||||
|
videoID: "dQw4w9WgXcV",
|
||||||
|
segments: [{
|
||||||
|
segment: [0, 10],
|
||||||
|
category: "sponsor",
|
||||||
|
actionType: "mute"
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then(async res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const row = await db.prepare('get', `SELECT "startTime", "endTime", "locked", "category", "actionType" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcV"]);
|
||||||
|
if (row.startTime === 0 && row.endTime === 10 && row.locked === 0 && row.category === "sponsor" && row.actionType === "mute") {
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
done("Submitted times were not saved. Actual submission: " + JSON.stringify(row));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
done("Status code was " + res.status);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => done(err));
|
||||||
|
});
|
||||||
|
|
||||||
it('Should be able to submit a single time with a duration from the YouTube API (JSON method)', (done: Done) => {
|
it('Should be able to submit a single time with a duration from the YouTube API (JSON method)', (done: Done) => {
|
||||||
fetch(getbaseURL()
|
fetch(getbaseURL()
|
||||||
+ "/api/postVideoSponsorTimes", {
|
+ "/api/postVideoSponsorTimes", {
|
||||||
|
|||||||
Reference in New Issue
Block a user