mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2024-11-10 01:02:30 +01:00
Add submitting description for chapters
This commit is contained in:
parent
0c16448065
commit
32150e4a1d
8 changed files with 98 additions and 10 deletions
1
ci.json
1
ci.json
|
@ -46,7 +46,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"categoryList": ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "poi_highlight"],
|
||||
"maxNumberOfActiveWarnings": 3,
|
||||
"hoursAfterWarningExpires": 24,
|
||||
"rateLimit": {
|
||||
|
|
8
databases/_upgrade_sponsorTimes_27.sql
Normal file
8
databases/_upgrade_sponsorTimes_27.sql
Normal file
|
@ -0,0 +1,8 @@
|
|||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE "sponsorTimes" ADD "description" TEXT NOT NULL default '';
|
||||
ALTER TABLE "archivedSponsorTimes" ADD "description" TEXT NOT NULL default '';
|
||||
|
||||
UPDATE "config" SET value = 27 WHERE key = 'version';
|
||||
|
||||
COMMIT;
|
|
@ -19,7 +19,7 @@ addDefaults(config, {
|
|||
privateDBSchema: "./databases/_private.db.sql",
|
||||
readOnly: false,
|
||||
webhooks: [],
|
||||
categoryList: ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "poi_highlight"],
|
||||
categoryList: ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "poi_highlight", "chapter"],
|
||||
categorySupport: {
|
||||
sponsor: ["skip", "mute"],
|
||||
selfpromo: ["skip", "mute"],
|
||||
|
@ -29,6 +29,7 @@ addDefaults(config, {
|
|||
preview: ["skip"],
|
||||
music_offtopic: ["skip"],
|
||||
poi_highlight: ["skip"],
|
||||
chapter: ["chapter"]
|
||||
},
|
||||
maxNumberOfActiveWarnings: 1,
|
||||
hoursAfterWarningExpires: 24,
|
||||
|
|
|
@ -299,7 +299,7 @@ async function checkUserActiveWarning(userID: string): Promise<CheckResult> {
|
|||
return CHECK_PASS;
|
||||
}
|
||||
|
||||
function checkInvalidFields(videoID: any, userID: any, segments: Array<any>): CheckResult {
|
||||
function checkInvalidFields(videoID: VideoID, userID: UserID, segments: IncomingSegment[]): CheckResult {
|
||||
const invalidFields = [];
|
||||
const errors = [];
|
||||
if (typeof videoID !== "string") {
|
||||
|
@ -320,6 +320,12 @@ function checkInvalidFields(videoID: any, userID: any, segments: Array<any>): Ch
|
|||
(typeof endTime === "string" && endTime.includes(":"))) {
|
||||
invalidFields.push("segment time");
|
||||
}
|
||||
|
||||
if (typeof segmentPair.description !== "string"
|
||||
|| (segmentPair.description.length > 60 && segmentPair.actionType === ActionType.Chapter)
|
||||
|| (segmentPair.description.length !== 0 && segmentPair.actionType !== ActionType.Chapter)) {
|
||||
invalidFields.push("segment description");
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidFields.length !== 0) {
|
||||
|
@ -541,7 +547,8 @@ function preprocessInput(req: Request) {
|
|||
segments = [{
|
||||
segment: [req.query.startTime as string, req.query.endTime as string],
|
||||
category: req.query.category as Category,
|
||||
actionType: (req.query.actionType as ActionType) ?? ActionType.Skip
|
||||
actionType: (req.query.actionType as ActionType) ?? ActionType.Skip,
|
||||
description: req.query.description as string || "",
|
||||
}];
|
||||
}
|
||||
// Add default action type
|
||||
|
@ -550,6 +557,7 @@ function preprocessInput(req: Request) {
|
|||
segment.actionType = ActionType.Skip;
|
||||
}
|
||||
|
||||
segment.description ??= "";
|
||||
segment.segment = segment.segment.map((time) => typeof segment.segment[0] === "string" ? time?.replace(",", ".") : time);
|
||||
});
|
||||
|
||||
|
@ -633,9 +641,10 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||
const startingLocked = isVIP ? 1 : 0;
|
||||
try {
|
||||
await db.prepare("run", `INSERT INTO "sponsorTimes"
|
||||
("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "reputation", "shadowHidden", "hashedVideoID", "userAgent")
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
||||
videoID, segmentInfo.segment[0], segmentInfo.segment[1], startingVotes, startingLocked, UUID, userID, timeSubmitted, 0, segmentInfo.category, segmentInfo.actionType, service, videoDuration, reputation, shadowBanRow.userCount, hashedVideoID, userAgent
|
||||
("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "reputation", "shadowHidden", "hashedVideoID", "userAgent", "description")
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
||||
videoID, segmentInfo.segment[0], segmentInfo.segment[1], startingVotes, startingLocked, UUID, userID, timeSubmitted, 0
|
||||
, segmentInfo.category, segmentInfo.actionType, service, videoDuration, reputation, shadowBanRow.userCount, hashedVideoID, userAgent, segmentInfo.description
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import { UserID } from "./user.model";
|
|||
export type SegmentUUID = string & { __segmentUUIDBrand: unknown };
|
||||
export type VideoID = string & { __videoIDBrand: unknown };
|
||||
export type VideoDuration = number & { __videoDurationBrand: unknown };
|
||||
export type Category = ("sponsor" | "selfpromo" | "interaction" | "intro" | "outro" | "preview" | "music_offtopic" | "poi_highlight") & { __categoryBrand: unknown };
|
||||
export type Category = ("sponsor" | "selfpromo" | "interaction" | "intro" | "outro" | "preview" | "music_offtopic" | "poi_highlight" | "chapter") & { __categoryBrand: unknown };
|
||||
export type VideoIDHash = VideoID & HashedValue;
|
||||
export type IPAddress = string & { __ipAddressBrand: unknown };
|
||||
export type HashedIP = IPAddress & HashedValue;
|
||||
|
@ -13,6 +13,7 @@ export type HashedIP = IPAddress & HashedValue;
|
|||
export enum ActionType {
|
||||
Skip = "skip",
|
||||
Mute = "mute",
|
||||
Chapter = "chapter"
|
||||
}
|
||||
|
||||
// Uncomment as needed
|
||||
|
@ -30,6 +31,7 @@ export interface IncomingSegment {
|
|||
category: Category;
|
||||
actionType: ActionType;
|
||||
segment: string[];
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface Segment {
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"categoryList": ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "poi_highlight"],
|
||||
"maxNumberOfActiveWarnings": 3,
|
||||
"hoursAfterWarningExpires": 24,
|
||||
"rateLimit": {
|
||||
|
|
|
@ -108,7 +108,8 @@ describe("getLockReason", () => {
|
|||
{ category: "outro", locked: 1, reason: "outro-reason", userID: vipUserID2, userName: vipUserName2 },
|
||||
{ category: "preview", locked: 1, reason: "preview-reason", userID: vipUserID1, userName: vipUserName1 },
|
||||
{ category: "music_offtopic", locked: 1, reason: "nonmusic-reason", userID: vipUserID1, userName: vipUserName1 },
|
||||
{ category: "poi_highlight", locked: 0, reason: "", userID: "", userName: "" }
|
||||
{ category: "poi_highlight", locked: 0, reason: "", userID: "", userName: "" },
|
||||
{ category: "chapter", locked: 0, reason: "", userID: "", userName: "" }
|
||||
];
|
||||
assert.deepStrictEqual(res.data, expected);
|
||||
done();
|
||||
|
|
|
@ -37,6 +37,7 @@ describe("postSkipSegments", () => {
|
|||
|
||||
const queryDatabase = (videoID: string) => db.prepare("get", `SELECT "startTime", "endTime", "locked", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoID]);
|
||||
const queryDatabaseActionType = (videoID: string) => db.prepare("get", `SELECT "startTime", "endTime", "locked", "category", "actionType" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoID]);
|
||||
const queryDatabaseChapter = (videoID: string) => db.prepare("get", `SELECT "startTime", "endTime", "locked", "category", "actionType", "description" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoID]);
|
||||
const queryDatabaseDuration = (videoID: string) => db.prepare("get", `SELECT "startTime", "endTime", "locked", "category", "videoDuration" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoID]);
|
||||
const queryDatabaseVideoInfo = (videoID: string) => db.prepare("get", `SELECT * FROM "videoInfo" WHERE "videoID" = ?`, [videoID]);
|
||||
|
||||
|
@ -181,6 +182,34 @@ describe("postSkipSegments", () => {
|
|||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it("Should be able to submit a single chapter (JSON method)", (done) => {
|
||||
const videoID = "postSkipChapter1";
|
||||
postSkipSegmentJSON({
|
||||
userID: submitUserOne,
|
||||
videoID,
|
||||
segments: [{
|
||||
segment: [0, 10],
|
||||
category: "chapter",
|
||||
actionType: "chapter",
|
||||
description: "This is a chapter"
|
||||
}],
|
||||
})
|
||||
.then(async res => {
|
||||
assert.strictEqual(res.status, 200);
|
||||
const row = await queryDatabaseChapter(videoID);
|
||||
const expected = {
|
||||
startTime: 0,
|
||||
endTime: 10,
|
||||
category: "chapter",
|
||||
actionType: "chapter",
|
||||
description: "This is a chapter"
|
||||
};
|
||||
assert.ok(partialDeepEquals(row, expected));
|
||||
done();
|
||||
})
|
||||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it("Should not be able to submit an intro with mute action type (JSON method)", (done) => {
|
||||
const videoID = "postSkip4";
|
||||
postSkipSegmentJSON({
|
||||
|
@ -201,6 +230,46 @@ describe("postSkipSegments", () => {
|
|||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it("Should not be able to submit a chapter with skip action type (JSON method)", (done) => {
|
||||
const videoID = "postSkipChapter2";
|
||||
postSkipSegmentJSON({
|
||||
userID: submitUserOne,
|
||||
videoID,
|
||||
segments: [{
|
||||
segment: [0, 10],
|
||||
category: "chapter",
|
||||
actionType: "skip"
|
||||
}],
|
||||
})
|
||||
.then(async res => {
|
||||
assert.strictEqual(res.status, 400);
|
||||
const row = await queryDatabaseActionType(videoID);
|
||||
assert.strictEqual(row, undefined);
|
||||
done();
|
||||
})
|
||||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it("Should not be able to submit a sponsor with a description (JSON method)", (done) => {
|
||||
const videoID = "postSkipChapter3";
|
||||
postSkipSegmentJSON({
|
||||
userID: submitUserOne,
|
||||
videoID,
|
||||
segments: [{
|
||||
segment: [0, 10],
|
||||
category: "sponsor",
|
||||
description: "This is a sponsor"
|
||||
}],
|
||||
})
|
||||
.then(async res => {
|
||||
assert.strictEqual(res.status, 400);
|
||||
const row = await queryDatabaseActionType(videoID);
|
||||
assert.strictEqual(row, undefined);
|
||||
done();
|
||||
})
|
||||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it("Should be able to submit a single time with a duration from the YouTube API (JSON method)", (done) => {
|
||||
const videoID = "postSkip5";
|
||||
postSkipSegmentJSON({
|
||||
|
|
Loading…
Reference in a new issue