From 041238687012083de18673b54c8c3ba43286619d Mon Sep 17 00:00:00 2001 From: Ajay Date: Tue, 14 Oct 2025 03:34:02 -0400 Subject: [PATCH] Add support for spotify service --- src/routes/getSegmentID.ts | 4 +- src/routes/postSkipSegments.ts | 38 +++++++++++----- src/types/segments.model.ts | 3 +- test/cases/postSkipSegments.ts | 82 ++++++++++++++++++++++------------ 4 files changed, 85 insertions(+), 42 deletions(-) diff --git a/src/routes/getSegmentID.ts b/src/routes/getSegmentID.ts index b65800e..97fd3c2 100644 --- a/src/routes/getSegmentID.ts +++ b/src/routes/getSegmentID.ts @@ -1,16 +1,18 @@ import { db } from "../databases/databases"; import { Request, Response } from "express"; +import { getService } from "../utils/getService"; export async function getSegmentID(req: Request, res: Response): Promise { const partialUUID = req.query?.UUID; const videoID = req.query?.videoID; + const service = getService(req.query?.service as string); if (!partialUUID || !videoID) { //invalid request return res.sendStatus(400); } - const data = await db.prepare("get", `SELECT "UUID" from "sponsorTimes" WHERE "UUID" LIKE ? AND "videoID" = ?`, [`${partialUUID}%`, videoID]); + const data = await db.prepare("get", `SELECT "UUID" from "sponsorTimes" WHERE "UUID" LIKE ? AND "videoID" = ? AND "service" = ?`, [`${partialUUID}%`, videoID, service]); if (data) { return res.status(200).send(data.UUID); diff --git a/src/routes/postSkipSegments.ts b/src/routes/postSkipSegments.ts index 32e5e81..43fea40 100644 --- a/src/routes/postSkipSegments.ts +++ b/src/routes/postSkipSegments.ts @@ -141,8 +141,8 @@ async function autoModerateSubmission(apiVideoDetails: videoDetails, .map(segment => [parseFloat(segment.segment[0]), parseFloat(segment.segment[1])]); // add previous submissions by this user - const allSubmittedByUser = await db.prepare("all", `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "userID" = ? AND "videoID" = ? AND "votes" > -1 AND "actionType" != 'chapter' AND "hidden" = 0` - , [submission.userID, submission.videoID]) as { startTime: string, endTime: string }[]; + const allSubmittedByUser = await db.prepare("all", `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "userID" = ? AND "videoID" = ? AND "service" = ? AND "votes" > -1 AND "actionType" != 'chapter' AND "hidden" = 0` + , [submission.userID, submission.videoID, submission.service]) as { startTime: string, endTime: string }[]; if (allSubmittedByUser) { //add segments the user has previously submitted @@ -195,12 +195,17 @@ async function checkInvalidFields(videoID: VideoID, userID: UserID, hashedUserID if (typeof videoID !== "string" || videoID?.length == 0) { invalidFields.push("videoID"); } - if (service === Service.YouTube && config.mode !== "test") { - const sanitizedVideoID = youtubeID.validate(videoID) ? videoID : youtubeID.sanitize(videoID); - if (!youtubeID.validate(sanitizedVideoID)) { - invalidFields.push("videoID"); - errors.push("YouTube videoID could not be extracted"); + if (service === Service.YouTube) { + if (config.mode !== "test") { + const sanitizedVideoID = youtubeID.validate(videoID) ? videoID : youtubeID.sanitize(videoID); + if (!youtubeID.validate(sanitizedVideoID)) { + invalidFields.push("videoID"); + errors.push("YouTube videoID could not be extracted"); + } } + } else if (service !== Service.Spotify) { + invalidFields.push("service"); + errors.push("Service is not supported"); } const minLength = config.minUserIDLength; if (typeof userID !== "string" || userID?.length < minLength) { @@ -360,6 +365,15 @@ async function checkByAutoModerator(videoID: VideoID, userID: HashedUserID, segm async function updateDataIfVideoDurationChange(videoID: VideoID, service: Service, videoDuration: VideoDuration, videoDurationParam: VideoDuration) { let lockedCategoryList = await db.prepare("all", 'SELECT category, "actionType", reason from "lockCategories" where "videoID" = ? AND "service" = ?', [videoID, service]); + if (service === Service.Spotify) { + // Don't handle changed durations + return { + videoDuration, + apiVideoDetails: null, + lockedCategoryList + }; + } + const previousSubmissions = await db.prepare("all", `SELECT "videoDuration", "UUID" FROM "sponsorTimes" @@ -617,10 +631,12 @@ export async function postSkipSegments(req: Request, res: Response): Promise { const submitVIPuser = `VIPPostSkipUser${".".repeat(16)}`; - const queryDatabase = (videoID: string) => db.prepare("get", `SELECT "startTime", "endTime", "votes", "userID", "locked", "category", "actionType" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoID]); - const queryDatabaseActionType = (videoID: string) => db.prepare("get", `SELECT "startTime", "endTime", "locked", "category", "actionType" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoID]); + const queryDatabase = (videoID: string, service = "YouTube") => db.prepare("get", `SELECT "startTime", "endTime", "votes", "userID", "locked", "category", "actionType" FROM "sponsorTimes" WHERE "videoID" = ? AND "service" = ?`, [videoID, service]); + const queryDatabaseActionType = (videoID: string, service = "YouTube") => db.prepare("get", `SELECT "startTime", "endTime", "locked", "category", "actionType" FROM "sponsorTimes" WHERE "videoID" = ? AND "service" = ?`, [videoID, service]); const queryDatabaseVideoInfo = (videoID: string) => db.prepare("get", `SELECT * FROM "videoInfo" WHERE "videoID" = ?`, [videoID]); before(async () => { @@ -142,33 +142,6 @@ describe("postSkipSegments", () => { .catch(err => done(err)); }); - it("Should be able to submit a single time under a different service (JSON method)", (done) => { - const videoID = "postSkip7"; - postSkipSegmentJSON({ - userID: submitUserOne, - videoID, - service: "PeerTube", - segments: [{ - segment: [0, 10], - category: "sponsor", - }], - }) - .then(async res => { - assert.strictEqual(res.status, 200); - const row = await db.prepare("get", `SELECT "startTime", "endTime", "locked", "category", "service" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoID]); - const expected = { - startTime: 0, - endTime: 10, - locked: 0, - category: "sponsor", - service: "PeerTube", - }; - assert.ok(partialDeepEquals(row, expected)); - done(); - }) - .catch(err => done(err)); - }); - it("VIP submission should start locked", (done) => { const videoID = "vipuserIDSubmission"; postSkipSegmentJSON({ @@ -374,4 +347,55 @@ describe("postSkipSegments", () => { }) .catch(err => done(err)); }); + + it("Should be able to submit for spotify service", (done) => { + const videoID = "postSkipParamSingle"; + postSkipSegmentParam({ + videoID, + startTime: 23, + endTime: 105, + userID: submitUserOne, + category: "sponsor", + service: "Spotify" + }) + .then(async res => { + assert.strictEqual(res.status, 200); + const row = await queryDatabase(videoID, "Spotify"); + const expected = { + startTime: 23, + endTime: 105, + category: "sponsor", + }; + assert.ok(partialDeepEquals(row, expected)); + + done(); + }) + .catch(err => done(err)); + }); + + it("Should be able to submit a time for spotify service (JSON method)", (done) => { + const videoID = "postSkipJSONSingle"; + postSkipSegmentJSON({ + userID: submitUserOne, + videoID, + segments: [{ + segment: [22, 103], + category: "sponsor", + }], + service: "Spotify" + }) + .then(async res => { + assert.strictEqual(res.status, 200); + const row = await queryDatabase(videoID, "Spotify"); + const expected = { + startTime: 22, + endTime: 103, + locked: 0, + category: "sponsor", + }; + assert.ok(partialDeepEquals(row, expected)); + done(); + }) + .catch(err => done(err)); + }); });