diff --git a/README.MD b/README.MD index e2a2b6c..2511ea2 100644 --- a/README.MD +++ b/README.MD @@ -8,7 +8,7 @@ This is the server backend for it This is a simple Sqlite database that will hold all the timing data. -To make sure that this project doesn't die, I have made the database publicly downloadable at https://api.sponsor.ajay.app/database.db (formerly https://sponsor.ajay.app/database.db). You can download a backup or get archive.org to take a backup if you do desire. The database is under [this license](https://creativecommons.org/licenses/by-nc-sa/4.0/) unless you get explicit permission from me. +To make sure that this project doesn't die, I have made the database publicly downloadable at https://sponsor.ajay.app/database.db. You can download a backup or get archive.org to take a backup if you do desire. The database is under [this license](https://creativecommons.org/licenses/by-nc-sa/4.0/) unless you get explicit permission from me. Hopefully this project can be combined with projects like [this](https://github.com/Sponsoff/sponsorship_remover) and use this data to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea. diff --git a/src/app.js b/src/app.js index 3c7ec8a..9561dc1 100644 --- a/src/app.js +++ b/src/app.js @@ -26,7 +26,6 @@ var getDaysSavedFormatted = require('./routes/getDaysSavedFormatted.js'); var oldGetVideoSponsorTimes = require('./routes/oldGetVideoSponsorTimes.js'); var oldSubmitSponsorTimes = require('./routes/oldSubmitSponsorTimes.js'); - //setup CORS correctly app.use(corsMiddleware); app.use(loggerMiddleware); @@ -35,6 +34,9 @@ app.use(express.json()) // Setup pretty JSON if (config.mode === "development") app.set('json spaces', 2); +// Set production mode +app.set('env', config.mode || 'production'); + //add the get function app.get('/api/getVideoSponsorTimes', oldGetVideoSponsorTimes); @@ -82,10 +84,10 @@ app.get('/api/getTopUsers', getTopUsers); app.get('/api/getTotalStats', getTotalStats); //send out a formatted time saved total -app.get('/api/getdayssavedformatted', getDaysSavedFormatted); +app.get('/api/getDaysSavedFormatted', getDaysSavedFormatted); app.get('/database.db', function (req, res) { - res.sendfile("./databases/sponsortimes.db", { root: __dirname }); + res.sendFile("./databases/sponsorTimes.db", { root: "./" }); }); // Create an HTTP service. diff --git a/src/routes/getDaysSavedFormatted.js b/src/routes/getDaysSavedFormatted.js index 7fece0c..45f13d8 100644 --- a/src/routes/getDaysSavedFormatted.js +++ b/src/routes/getDaysSavedFormatted.js @@ -1,12 +1,12 @@ -var db = require('../databases/databases.js'); +var db = require('../databases/databases.js').db; module.exports = function getDaysSavedFormatted (req, res) { - let row = db.prepare("select sum((endtime - starttime) / 60 / 60 / 24 * views) as dayssaved from sponsortimes where shadowhidden != 1").get(); + let row = db.prepare("SELECT SUM((endTime - startTime) / 60 / 60 / 24 * views) as daysSaved from sponsorTimes where shadowHidden != 1").get(); if (row !== undefined) { //send this result res.send({ - dayssaved: row.dayssaved.tofixed(2) + daysSaved: row.daysSaved.toFixed(2) }); } -} \ No newline at end of file +} diff --git a/src/routes/postSkipSegments.js b/src/routes/postSkipSegments.js index a41bebd..5882529 100644 --- a/src/routes/postSkipSegments.js +++ b/src/routes/postSkipSegments.js @@ -102,13 +102,16 @@ async function autoModerateSubmission(submission, callback) { } else { // Check to see if video exists if (data.pageInfo.totalResults === 0) { - callback("No video exists with id " + submission.videoID); + return "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) { + if (duration == 0) { + // Allow submission if the duration is 0 (bug in youtube api) + return false; + } else if ((submission.endTime - submission.startTime) > (duration / 100) * 80) { + // Reject submission if over 80% of the video return "Sponsor segment is over 80% of the video."; } else { let overlap = false; diff --git a/src/routes/voteOnSponsorTime.js b/src/routes/voteOnSponsorTime.js index bc9a326..dda73ac 100644 --- a/src/routes/voteOnSponsorTime.js +++ b/src/routes/voteOnSponsorTime.js @@ -86,7 +86,11 @@ module.exports = async function voteOnSponsorTime(req, res) { // Send discord message if (type != 1) { // Get video ID - let submissionInfoRow = db.prepare("SELECT videoID, userID, startTime, endTime FROM sponsorTimes WHERE UUID = ?").get(UUID); + let submissionInfoRow = db.prepare("SELECT s.videoID, s.userID, s.startTime, s.endTime, u.userName, "+ + "(select count(1) from sponsorTimes where userID = s.userID) count, "+ + "(select count(1) from sponsorTimes where userID = s.userID and votes <= -2) disregarded "+ + "FROM sponsorTimes s inner join userNames u on s.userID = u.userID where s.UUID=?" + ).get(UUID); let userSubmissionCountRow = db.prepare("SELECT count(*) as submissionCount FROM sponsorTimes WHERE userID = ?").get(nonAnonUserID); @@ -104,11 +108,14 @@ module.exports = async function voteOnSponsorTime(req, res) { json: { "embeds": [{ "title": data.items[0].snippet.title, - "url": "https://www.youtube.com/watch?v=" + submissionInfoRow.videoID + - "&t=" + (submissionInfoRow.startTime.toFixed(0) - 2), - "description": "**" + row.votes + " Votes Prior | " + (row.votes + incrementAmount - oldIncrementAmount) + " Votes Now | " + row.views + - " Views**\n\nSubmission ID: " + UUID + - "\n\nSubmitted by: " + submissionInfoRow.userID + "\n\nTimestamp: " + + "url": "https://www.youtube.com/watch?v=" + submissionInfoRow.videoID + + "&t=" + (submissionInfoRow.startTime.toFixed(0) - 2), + "description": "**" + row.votes + " Votes Prior | " + (row.votes + incrementAmount - oldIncrementAmount) + " Votes Now | " + row.views + + " Views**\n\n**Submission ID:** " + UUID + + "\n\n**Submitted by:** "+submissionInfoRow.userName+"\n " + submissionInfoRow.userID + + "\n\n**Total User Submissions:** "+submissionInfoRow.count + + "\n**Ignored User Submissions:** "+submissionInfoRow.disregarded + +"\n\n**Timestamp:** " + getFormattedTime(submissionInfoRow.startTime) + " to " + getFormattedTime(submissionInfoRow.endTime), "color": 10813440, "author": { @@ -167,5 +174,6 @@ module.exports = async function voteOnSponsorTime(req, res) { res.sendStatus(200); } catch (err) { console.error(err); + res.status(500).json({error: 'Internal error creating segment vote'}); } } \ No newline at end of file diff --git a/test.js b/test.js index 3a13418..45ace90 100644 --- a/test.js +++ b/test.js @@ -34,7 +34,7 @@ var mockServer = createMockServer(() => { mocha.run(function(failures) { mockServer.close(); server.close(); - process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures + process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures }); }); }); diff --git a/test/cases/postSkipSegments.js b/test/cases/postSkipSegments.js index c6b7eec..b5fae77 100644 --- a/test/cases/postSkipSegments.js +++ b/test/cases/postSkipSegments.js @@ -130,6 +130,16 @@ describe('postSkipSegments', () => { }); }).timeout(5000); + it('Should be allowed if youtube thinks duration is 0', (done) => { + request.get(utils.getbaseURL() + + "/api/postVideoSponsorTimes?videoID=noDuration&startTime=30&endTime=10000&userID=testing", null, + (err, res, body) => { + if (err) done("Couldn't call endpoint"); + else if (res.statusCode === 200) done(); // pass + else done("non 200 status code: " + res.statusCode + " ("+body+")"); + }); + }).timeout(5000); + it('Should be rejected if not a valid videoID', (done) => { request.get(utils.getbaseURL() + "/api/postVideoSponsorTimes?videoID=knownWrongID&startTime=30&endTime=1000000&userID=testing", null, diff --git a/test/mocks.js b/test/mocks.js index a124646..49060af 100644 --- a/test/mocks.js +++ b/test/mocks.js @@ -4,11 +4,11 @@ var app = express(); var config = require('../src/config.js'); app.post('/ReportChannelWebhook', (req, res) => { - res.status(200); + res.sendStatus(200); }); app.post('/FirstTimeSubmissionsWebhook', (req, res) => { - res.status(200); + res.sendStatus(200); }); module.exports = function createMockServer(callback) { diff --git a/test/youtubeMock.js b/test/youtubeMock.js index 0a9998d..dd64898 100644 --- a/test/youtubeMock.js +++ b/test/youtubeMock.js @@ -10,14 +10,35 @@ YouTubeAPI.videos.list({ const YouTubeAPI = { videos: { list: (obj, callback) => { - if (obj.videoID === "knownWrongID") { + if (obj.id === "knownWrongID") { callback(undefined, { pageInfo: { totalResults: 0 }, items: [] }); - } else { + } if (obj.id === "noDuration") { + callback(undefined, { + pageInfo: { + totalResults: 1 + }, + items: [ + { + contentDetails: { + duration: "PT0S" + }, + snippet: { + title: "Example Title", + thumbnails: { + maxres: { + url: "https://sponsor.ajay.app/LogoSponsorBlockSimple256px.png" + } + } + } + } + ] + }); + } else { callback(undefined, { pageInfo: { totalResults: 1