From 32150e4a1dd55a2dd5478ef27602e07a684d65c0 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 6 Nov 2021 00:54:28 -0400 Subject: [PATCH] Add submitting description for chapters --- ci.json | 1 - databases/_upgrade_sponsorTimes_27.sql | 8 +++ src/config.ts | 3 +- src/routes/postSkipSegments.ts | 19 +++++-- src/types/segments.model.ts | 4 +- test.json | 1 - test/cases/getLockReason.ts | 3 +- test/cases/postSkipSegments.ts | 69 ++++++++++++++++++++++++++ 8 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 databases/_upgrade_sponsorTimes_27.sql diff --git a/ci.json b/ci.json index 32ef176..2f948b7 100644 --- a/ci.json +++ b/ci.json @@ -46,7 +46,6 @@ ] } ], - "categoryList": ["sponsor", "selfpromo", "interaction", "intro", "outro", "preview", "music_offtopic", "poi_highlight"], "maxNumberOfActiveWarnings": 3, "hoursAfterWarningExpires": 24, "rateLimit": { diff --git a/databases/_upgrade_sponsorTimes_27.sql b/databases/_upgrade_sponsorTimes_27.sql new file mode 100644 index 0000000..8887875 --- /dev/null +++ b/databases/_upgrade_sponsorTimes_27.sql @@ -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; \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index d28d2aa..ed6c440 100644 --- a/src/config.ts +++ b/src/config.ts @@ -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, diff --git a/src/routes/postSkipSegments.ts b/src/routes/postSkipSegments.ts index c65e770..09b6c06 100644 --- a/src/routes/postSkipSegments.ts +++ b/src/routes/postSkipSegments.ts @@ -299,7 +299,7 @@ async function checkUserActiveWarning(userID: string): Promise { return CHECK_PASS; } -function checkInvalidFields(videoID: any, userID: any, segments: Array): 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): 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 { { 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(); diff --git a/test/cases/postSkipSegments.ts b/test/cases/postSkipSegments.ts index b4d7f4f..2784d23 100644 --- a/test/cases/postSkipSegments.ts +++ b/test/cases/postSkipSegments.ts @@ -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({