mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-06 11:36:58 +03:00
Add support for spotify service
This commit is contained in:
@@ -1,16 +1,18 @@
|
|||||||
import { db } from "../databases/databases";
|
import { db } from "../databases/databases";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
import { getService } from "../utils/getService";
|
||||||
|
|
||||||
export async function getSegmentID(req: Request, res: Response): Promise<Response> {
|
export async function getSegmentID(req: Request, res: Response): Promise<Response> {
|
||||||
const partialUUID = req.query?.UUID;
|
const partialUUID = req.query?.UUID;
|
||||||
const videoID = req.query?.videoID;
|
const videoID = req.query?.videoID;
|
||||||
|
const service = getService(req.query?.service as string);
|
||||||
|
|
||||||
if (!partialUUID || !videoID) {
|
if (!partialUUID || !videoID) {
|
||||||
//invalid request
|
//invalid request
|
||||||
return res.sendStatus(400);
|
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) {
|
if (data) {
|
||||||
return res.status(200).send(data.UUID);
|
return res.status(200).send(data.UUID);
|
||||||
|
|||||||
@@ -141,8 +141,8 @@ async function autoModerateSubmission(apiVideoDetails: videoDetails,
|
|||||||
.map(segment => [parseFloat(segment.segment[0]), parseFloat(segment.segment[1])]);
|
.map(segment => [parseFloat(segment.segment[0]), parseFloat(segment.segment[1])]);
|
||||||
|
|
||||||
// add previous submissions by this user
|
// 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`
|
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]) as { startTime: string, endTime: string }[];
|
, [submission.userID, submission.videoID, submission.service]) as { startTime: string, endTime: string }[];
|
||||||
|
|
||||||
if (allSubmittedByUser) {
|
if (allSubmittedByUser) {
|
||||||
//add segments the user has previously submitted
|
//add segments the user has previously submitted
|
||||||
@@ -195,13 +195,18 @@ async function checkInvalidFields(videoID: VideoID, userID: UserID, hashedUserID
|
|||||||
if (typeof videoID !== "string" || videoID?.length == 0) {
|
if (typeof videoID !== "string" || videoID?.length == 0) {
|
||||||
invalidFields.push("videoID");
|
invalidFields.push("videoID");
|
||||||
}
|
}
|
||||||
if (service === Service.YouTube && config.mode !== "test") {
|
if (service === Service.YouTube) {
|
||||||
|
if (config.mode !== "test") {
|
||||||
const sanitizedVideoID = youtubeID.validate(videoID) ? videoID : youtubeID.sanitize(videoID);
|
const sanitizedVideoID = youtubeID.validate(videoID) ? videoID : youtubeID.sanitize(videoID);
|
||||||
if (!youtubeID.validate(sanitizedVideoID)) {
|
if (!youtubeID.validate(sanitizedVideoID)) {
|
||||||
invalidFields.push("videoID");
|
invalidFields.push("videoID");
|
||||||
errors.push("YouTube videoID could not be extracted");
|
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;
|
const minLength = config.minUserIDLength;
|
||||||
if (typeof userID !== "string" || userID?.length < minLength) {
|
if (typeof userID !== "string" || userID?.length < minLength) {
|
||||||
invalidFields.push("userID");
|
invalidFields.push("userID");
|
||||||
@@ -360,6 +365,15 @@ async function checkByAutoModerator(videoID: VideoID, userID: HashedUserID, segm
|
|||||||
async function updateDataIfVideoDurationChange(videoID: VideoID, service: Service, videoDuration: VideoDuration, videoDurationParam: VideoDuration) {
|
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]);
|
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",
|
const previousSubmissions = await db.prepare("all",
|
||||||
`SELECT "videoDuration", "UUID"
|
`SELECT "videoDuration", "UUID"
|
||||||
FROM "sponsorTimes"
|
FROM "sponsorTimes"
|
||||||
@@ -617,10 +631,12 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
//add to private db as well
|
//add to private db as well
|
||||||
await privateDB.prepare("run", `INSERT INTO "sponsorTimes" VALUES(?, ?, ?, ?)`, [videoID, hashedIP, timeSubmitted, service]);
|
await privateDB.prepare("run", `INSERT INTO "sponsorTimes" VALUES(?, ?, ?, ?)`, [videoID, hashedIP, timeSubmitted, service]);
|
||||||
|
|
||||||
|
if (service === Service.YouTube) {
|
||||||
await db.prepare("run", `INSERT INTO "videoInfo" ("videoID", "channelID", "title", "published")
|
await db.prepare("run", `INSERT INTO "videoInfo" ("videoID", "channelID", "title", "published")
|
||||||
SELECT ?, ?, ?, ?
|
SELECT ?, ?, ?, ?
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM "videoInfo" WHERE "videoID" = ?)`, [
|
WHERE NOT EXISTS (SELECT 1 FROM "videoInfo" WHERE "videoID" = ?)`, [
|
||||||
videoID, apiVideoDetails?.authorId || "", apiVideoDetails?.title || "", apiVideoDetails?.published || 0, videoID]);
|
videoID, apiVideoDetails?.authorId || "", apiVideoDetails?.title || "", apiVideoDetails?.published || 0, videoID]);
|
||||||
|
}
|
||||||
|
|
||||||
// Clear redis cache for this video
|
// Clear redis cache for this video
|
||||||
QueryCacher.clearSegmentCache({
|
QueryCacher.clearSegmentCache({
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ export enum ActionType {
|
|||||||
// Uncomment as needed
|
// Uncomment as needed
|
||||||
export enum Service {
|
export enum Service {
|
||||||
YouTube = "YouTube",
|
YouTube = "YouTube",
|
||||||
PeerTube = "PeerTube",
|
Spotify = "Spotify",
|
||||||
|
PeerTube = "PeerTube"
|
||||||
// Twitch = 'Twitch',
|
// Twitch = 'Twitch',
|
||||||
// Nebula = 'Nebula',
|
// Nebula = 'Nebula',
|
||||||
// RSS = 'RSS',
|
// RSS = 'RSS',
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ describe("postSkipSegments", () => {
|
|||||||
|
|
||||||
const submitVIPuser = `VIPPostSkipUser${".".repeat(16)}`;
|
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 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) => db.prepare("get", `SELECT "startTime", "endTime", "locked", "category", "actionType" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoID]);
|
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]);
|
const queryDatabaseVideoInfo = (videoID: string) => db.prepare("get", `SELECT * FROM "videoInfo" WHERE "videoID" = ?`, [videoID]);
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@@ -142,33 +142,6 @@ describe("postSkipSegments", () => {
|
|||||||
.catch(err => done(err));
|
.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) => {
|
it("VIP submission should start locked", (done) => {
|
||||||
const videoID = "vipuserIDSubmission";
|
const videoID = "vipuserIDSubmission";
|
||||||
postSkipSegmentJSON({
|
postSkipSegmentJSON({
|
||||||
@@ -374,4 +347,55 @@ describe("postSkipSegments", () => {
|
|||||||
})
|
})
|
||||||
.catch(err => done(err));
|
.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));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user