mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2024-11-10 01:02:30 +01:00
added checks using the youtube api on segment submission
This commit is contained in:
parent
98d754f605
commit
e5cd72657e
7 changed files with 161 additions and 48 deletions
|
@ -6,6 +6,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test.js",
|
"test": "node test.js",
|
||||||
"dev": "nodemon -x \"(npm test || echo test failed) && npm start\"",
|
"dev": "nodemon -x \"(npm test || echo test failed) && npm start\"",
|
||||||
|
"dev:bash": "nodemon -x 'npm test ; npm start'",
|
||||||
"start": "node index.js"
|
"start": "node index.js"
|
||||||
},
|
},
|
||||||
"author": "Ajay Ramachandran",
|
"author": "Ajay Ramachandran",
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
"better-sqlite3": "^5.4.3",
|
"better-sqlite3": "^5.4.3",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"http": "0.0.0",
|
"http": "0.0.0",
|
||||||
|
"iso8601-duration": "^1.2.0",
|
||||||
"uuid": "^3.3.2",
|
"uuid": "^3.3.2",
|
||||||
"youtube-api": "^2.0.10"
|
"youtube-api": "^2.0.10"
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,8 @@ var databases = require('../databases/databases.js');
|
||||||
var db = databases.db;
|
var db = databases.db;
|
||||||
var privateDB = databases.privateDB;
|
var privateDB = databases.privateDB;
|
||||||
var YouTubeAPI = require('../utils/youtubeAPI.js');
|
var YouTubeAPI = require('../utils/youtubeAPI.js');
|
||||||
|
var request = require('request');
|
||||||
|
var isoDurations = require('iso8601-duration');
|
||||||
|
|
||||||
var getHash = require('../utils/getHash.js');
|
var getHash = require('../utils/getHash.js');
|
||||||
var getIP = require('../utils/getIP.js');
|
var getIP = require('../utils/getIP.js');
|
||||||
|
@ -116,32 +118,77 @@ module.exports = async function submitSponsorTimes(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duplicateCheck2Row == null) {
|
if (duplicateCheck2Row == null) {
|
||||||
//not a duplicate, execute query
|
//not a duplicate
|
||||||
|
|
||||||
|
autoModerateSubmission({videoID, startTime, endTime}, (reject) => {
|
||||||
|
if (!reject) {
|
||||||
try {
|
try {
|
||||||
db.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)").run(videoID, startTime, endTime, startingVotes, UUID, userID, timeSubmitted, 0, shadowBanned);
|
db.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)").run(videoID, startTime, endTime, startingVotes, UUID, userID, timeSubmitted, 0, shadowBanned);
|
||||||
|
|
||||||
//add to private db as well
|
//add to private db as well
|
||||||
privateDB.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?)").run(videoID, hashedIP, timeSubmitted);
|
privateDB.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?)").run(videoID, hashedIP, timeSubmitted);
|
||||||
|
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
//a DB change probably occurred
|
//a DB change probably occurred
|
||||||
res.sendStatus(502);
|
|
||||||
console.log("Error when putting sponsorTime in the DB: " + videoID + ", " + startTime + ", " + "endTime" + ", " + userID);
|
console.log("Error when putting sponsorTime in the DB: " + videoID + ", " + startTime + ", " + "endTime" + ", " + userID);
|
||||||
|
res.sendStatus(502);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
res.status(403).send("Request rejected by auto moderator: " + reject);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
res.sendStatus(409);
|
res.sendStatus(409);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.send(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// submission: {videoID, startTime, endTime}
|
||||||
|
// callback: function(reject: "String containing reason the submission was rejected")
|
||||||
|
const autoModerateSubmission = (submission, callback) => {
|
||||||
|
// Get the video information from the youtube API
|
||||||
|
if (config.youtubeAPI !== null) {
|
||||||
|
YouTubeAPI.videos.list({
|
||||||
|
part: "contentDetails",
|
||||||
|
id: submission.videoID
|
||||||
|
}, (err, data) => {
|
||||||
|
if (err) callback("Couldn't get video information.");
|
||||||
|
else {
|
||||||
|
// Check to see if video exists
|
||||||
|
if (data.pageInfo.totalResults === 0) {
|
||||||
|
callback("No video exists with id " + submission.videoID);
|
||||||
|
} else {
|
||||||
|
let duration = data.items[0].contentDetails.duration;
|
||||||
|
duration = isoDurations.toSeconds(isoDurations.parse(duration));
|
||||||
|
|
||||||
|
// Reject submission if over 80% of the video
|
||||||
|
if ((submission.endTime - submission.startTime) > (duration/100)*80) {
|
||||||
|
callback ("Sponsor segment is over 80% of the video.");
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("skip youtube api");
|
||||||
|
// Can't moderate the submission without calling the youtube API
|
||||||
|
// so allow by default.
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
//check if they are a first time user
|
//check if they are a first time user
|
||||||
//if so, send a notification to discord
|
//if so, send a notification to discord
|
||||||
if (config.youtubeAPIKey !== null && config.discordFirstTimeSubmissionsWebhookURL !== null && duplicateCheck2Row == null) {
|
if (config.youtubeAPIKey !== null && config.discordFirstTimeSubmissionsWebhookURL !== null && duplicateCheck2Row == null) {
|
||||||
let userSubmissionCountRow = db.prepare("SELECT count(*) as submissionCount FROM sponsorTimes WHERE userID = ?").get(userID);
|
let userSubmissionCountRow = db.prepare("SELECT count(*) as submissionCount FROM sponsorTimes WHERE userID = ?").get(userID);
|
||||||
|
|
||||||
// If it is a first time submission
|
// If it is a first time submission
|
||||||
if (userSubmissionCountRow.submissionCount === 0) {
|
if (userSubmissionCountRow.submissionCount <= 1) {
|
||||||
YouTubeAPI.videos.list({
|
YouTubeAPI.videos.list({
|
||||||
part: "snippet",
|
part: "snippet",
|
||||||
id: videoID
|
id: videoID
|
||||||
|
@ -151,6 +198,8 @@ module.exports = async function submitSponsorTimes(req, res) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify(data));
|
||||||
|
|
||||||
request.post(config.discordFirstTimeSubmissionsWebhookURL, {
|
request.post(config.discordFirstTimeSubmissionsWebhookURL, {
|
||||||
json: {
|
json: {
|
||||||
"embeds": [{
|
"embeds": [{
|
||||||
|
@ -181,12 +230,4 @@ module.exports = async function submitSponsorTimes(req, res) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
|
|
||||||
res.send(500);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,8 +2,18 @@ var config = require('../config.js');
|
||||||
|
|
||||||
// YouTube API
|
// YouTube API
|
||||||
const YouTubeAPI = require("youtube-api");
|
const YouTubeAPI = require("youtube-api");
|
||||||
YouTubeAPI.authenticate({
|
|
||||||
|
var exportObject;
|
||||||
|
// If in test mode, return a mocked youtube object
|
||||||
|
// otherwise return an authenticated youtube api
|
||||||
|
if (config.mode === "test") {
|
||||||
|
exportObject = require("../../test/youtubeMock.js");
|
||||||
|
} else {
|
||||||
|
YouTubeAPI.authenticate({
|
||||||
type: "key",
|
type: "key",
|
||||||
key: config.youtubeAPIKey
|
key: config.youtubeAPIKey
|
||||||
});
|
});
|
||||||
module.exports = YouTubeAPI;
|
exportObject = YouTubeAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exportObject;
|
|
@ -12,9 +12,9 @@ describe('getSavedTimeForUser', () => {
|
||||||
request.get(utils.getbaseURL()
|
request.get(utils.getbaseURL()
|
||||||
+ "/api/getSavedTimeForUser?userID=testman", null,
|
+ "/api/getSavedTimeForUser?userID=testman", null,
|
||||||
(err, res, body) => {
|
(err, res, body) => {
|
||||||
if (err) done(false);
|
if (err) done("couldn't call endpoint");
|
||||||
else if (res.statusCode !== 200) done("non 200");
|
else if (res.statusCode !== 200) done("non 200");
|
||||||
else done();
|
else done(); // pass
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -27,9 +27,9 @@ describe('getVideoSponsorTime', () => {
|
||||||
request.get(utils.getbaseURL()
|
request.get(utils.getbaseURL()
|
||||||
+ "/api/getVideoSponsorTimes?videoID=testtesttest", null,
|
+ "/api/getVideoSponsorTimes?videoID=testtesttest", null,
|
||||||
(err, res, body) => {
|
(err, res, body) => {
|
||||||
if (err) done(false);
|
if (err) done("Couldn't call endpoint");
|
||||||
else if (res.statusCode !== 200) done("non 200");
|
else if (res.statusCode !== 200) done("non 200");
|
||||||
else done();
|
else done(); // pass
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -37,9 +37,9 @@ describe('getVideoSponsorTime', () => {
|
||||||
request.get(utils.getbaseURL()
|
request.get(utils.getbaseURL()
|
||||||
+ "/api/getVideoSponsorTimes?videoID=notarealvideo", null,
|
+ "/api/getVideoSponsorTimes?videoID=notarealvideo", null,
|
||||||
(err, res, body) => {
|
(err, res, body) => {
|
||||||
if (err) done(false);
|
if (err) done("couldn't call endpoint");
|
||||||
else if (res.statusCode !== 404) done("non 404 respone code: " + res.statusCode);
|
else if (res.statusCode !== 404) done("non 404 respone code: " + res.statusCode);
|
||||||
else done();
|
else done(); // pass
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -48,9 +48,9 @@ describe('getVideoSponsorTime', () => {
|
||||||
request.get(utils.getbaseURL()
|
request.get(utils.getbaseURL()
|
||||||
+ "/api/getVideoSponsorTimes?videoID=testtesttest&fakeparam=hello", null,
|
+ "/api/getVideoSponsorTimes?videoID=testtesttest&fakeparam=hello", null,
|
||||||
(err, res, body) => {
|
(err, res, body) => {
|
||||||
if (err) done(false);
|
if (err) done("couldn't callendpoint");
|
||||||
else if (res.statusCode !== 200) done("non 200");
|
else if (res.statusCode !== 200) done("non 200");
|
||||||
else done();
|
else done(); // pass
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -58,9 +58,10 @@ describe('getVideoSponsorTime', () => {
|
||||||
request.get(utils.getbaseURL()
|
request.get(utils.getbaseURL()
|
||||||
+ "/api/getVideoSponsorTimes?videoID=testtesttest,test", null,
|
+ "/api/getVideoSponsorTimes?videoID=testtesttest,test", null,
|
||||||
(err, res, body) => {
|
(err, res, body) => {
|
||||||
if (err) done(false);
|
if (err) done("couln't call endpoint");
|
||||||
else if (res.statusCode !== 200) done("non 200 response: " + res.statusCode);
|
else if (res.statusCode !== 200) done("non 200 response: " + res.statusCode);
|
||||||
else (JSON.parse(body).UUIDs[0] === 'uuid-1') && done();
|
else if (JSON.parse(body).UUIDs[0] === 'uuid-1') done(); // pass
|
||||||
|
else done("couldn't parse response");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -68,14 +69,14 @@ describe('getVideoSponsorTime', () => {
|
||||||
request.get(utils.getbaseURL()
|
request.get(utils.getbaseURL()
|
||||||
+ "/api/getVideoSponsorTimes?videoID=testtesttest", null,
|
+ "/api/getVideoSponsorTimes?videoID=testtesttest", null,
|
||||||
(err, res, body) => {
|
(err, res, body) => {
|
||||||
if (err) done(false);
|
if (err) done("couldn't call endpoint");
|
||||||
else if (res.statusCode !== 200) done("non 200");
|
else if (res.statusCode !== 200) done("non 200");
|
||||||
else {
|
else {
|
||||||
let parsedBody = JSON.parse(body);
|
let parsedBody = JSON.parse(body);
|
||||||
if (parsedBody.sponsorTimes[0][0] === 1
|
if (parsedBody.sponsorTimes[0][0] === 1
|
||||||
&& parsedBody.sponsorTimes[0][1] === 11
|
&& parsedBody.sponsorTimes[0][1] === 11
|
||||||
&& parsedBody.UUIDs[0] === 'uuid-0') {
|
&& parsedBody.UUIDs[0] === 'uuid-0') {
|
||||||
done();
|
done(); // pass
|
||||||
} else {
|
} else {
|
||||||
done("Wrong data was returned + " + parsedBody);
|
done("Wrong data was returned + " + parsedBody);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ var utils = require('../utils.js');
|
||||||
describe('postVideoSponsorTime', () => {
|
describe('postVideoSponsorTime', () => {
|
||||||
it('Should be able to create a time', (done) => {
|
it('Should be able to create a time', (done) => {
|
||||||
request.get(utils.getbaseURL()
|
request.get(utils.getbaseURL()
|
||||||
+ "/api/postVideoSponsorTimes?videoID=djgofQKWmXc&startTime=1&endTime=10&userID=test", null,
|
+ "/api/postVideoSponsorTimes?videoID=fWvKvOViM3g&startTime=1&endTime=10&userID=test", null,
|
||||||
(err, res, body) => {
|
(err, res, body) => {
|
||||||
if (err) done(false);
|
if (err) done("Couldn't call endpoint");
|
||||||
else if (res.statusCode === 200) done();
|
else if (res.statusCode === 200) done();
|
||||||
else done(false);
|
else done("non 200 status code: " + res.statusCode + " ("+body+")");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -18,9 +18,30 @@ describe('postVideoSponsorTime', () => {
|
||||||
request.get(utils.getbaseURL()
|
request.get(utils.getbaseURL()
|
||||||
+ "/api/postVideoSponsorTimes?startTime=1&endTime=10&userID=test", null,
|
+ "/api/postVideoSponsorTimes?startTime=1&endTime=10&userID=test", null,
|
||||||
(err, res, body) => {
|
(err, res, body) => {
|
||||||
if (err) done(false);
|
if (err) done("Couldn't call endpoint");
|
||||||
if (res.statusCode === 400) done();
|
else if (res.statusCode === 400) done(); // pass
|
||||||
else done(false);
|
else done("non 400 status code: " + res.statusCode + " ("+body+")");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('Should be rejected if over 80% of the video', (done) => {
|
||||||
|
request.get(utils.getbaseURL()
|
||||||
|
+ "/api/postVideoSponsorTimes?videoID=qqwerty&startTime=1&endTime=1000000&userID=test", null,
|
||||||
|
(err, res, body) => {
|
||||||
|
if (err) done("Couldn't call endpoint");
|
||||||
|
else if (res.statusCode === 403) done(); // pass
|
||||||
|
else done("non 403 status code: " + res.statusCode + " ("+body+")");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be rejected if not a valid videoID', (done) => {
|
||||||
|
request.get(utils.getbaseURL()
|
||||||
|
+ "/api/postVideoSponsorTimes?videoID=knownWrongID&startTime=1&endTime=1000000&userID=test", null,
|
||||||
|
(err, res, body) => {
|
||||||
|
if (err) done("Couldn't call endpoint");
|
||||||
|
else if (res.statusCode === 403) done(); // pass
|
||||||
|
else done("non 403 status code: " + res.statusCode + " ("+body+")");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
38
test/youtubeMock.js
Normal file
38
test/youtubeMock.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
YouTubeAPI.videos.list({
|
||||||
|
part: "snippet",
|
||||||
|
id: videoID
|
||||||
|
}, function (err, data) {});
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://developers.google.com/youtube/v3/docs/videos
|
||||||
|
|
||||||
|
const YouTubeAPI = {
|
||||||
|
videos: {
|
||||||
|
list: (obj, callback) => {
|
||||||
|
if (obj.videoID === "knownWrongID") {
|
||||||
|
callback(undefined, {
|
||||||
|
pageInfo: {
|
||||||
|
totalResults: 0
|
||||||
|
},
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback(undefined, {
|
||||||
|
pageInfo: {
|
||||||
|
totalResults: 1
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
contentDetails: {
|
||||||
|
duration: "PT1H23M30S"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = YouTubeAPI;
|
Loading…
Reference in a new issue