mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-12 06:27:10 +03:00
Add initial version of querying by hash prefix
This commit is contained in:
26
databases/_upgrade_sponsorTimes_2.sql
Normal file
26
databases/_upgrade_sponsorTimes_2.sql
Normal file
@@ -0,0 +1,26 @@
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
/* Add hash field */
|
||||
CREATE TABLE "sqlb_temp_table_1" (
|
||||
"videoID" TEXT NOT NULL,
|
||||
"startTime" REAL NOT NULL,
|
||||
"endTime" REAL NOT NULL,
|
||||
"votes" INTEGER NOT NULL,
|
||||
"incorrectVotes" INTEGER NOT NULL default '1',
|
||||
"UUID" TEXT NOT NULL UNIQUE,
|
||||
"userID" TEXT NOT NULL,
|
||||
"timeSubmitted" INTEGER NOT NULL,
|
||||
"views" INTEGER NOT NULL,
|
||||
"category" TEXT NOT NULL DEFAULT "sponsor",
|
||||
"shadowHidden" INTEGER NOT NULL,
|
||||
"hashedVideoID" TEXT NOT NULL
|
||||
);
|
||||
INSERT INTO sqlb_temp_table_1 SELECT *, sha256(videoID) FROM sponsorTimes;
|
||||
|
||||
DROP TABLE sponsorTimes;
|
||||
ALTER TABLE sqlb_temp_table_1 RENAME TO "sponsorTimes";
|
||||
|
||||
/* Bump version in config */
|
||||
UPDATE config SET value = 2 WHERE key = "version";
|
||||
|
||||
COMMIT;
|
||||
@@ -10,6 +10,7 @@ var loggerMiddleware = require('./middleware/logger.js');
|
||||
// Routes
|
||||
var getSkipSegments = require('./routes/getSkipSegments.js').endpoint;
|
||||
var postSkipSegments = require('./routes/postSkipSegments.js');
|
||||
var getSkipSegmentsByHash = require('./routes/getSkipSegmentsByHash.js');
|
||||
var voteOnSponsorTime = require('./routes/voteOnSponsorTime.js');
|
||||
var viewedVideoSponsorTime = require('./routes/viewedVideoSponsorTime.js');
|
||||
var setUsername = require('./routes/setUsername.js');
|
||||
@@ -48,6 +49,9 @@ app.post('/api/postVideoSponsorTimes', oldSubmitSponsorTimes);
|
||||
app.get('/api/skipSegments', getSkipSegments);
|
||||
app.post('/api/skipSegments', postSkipSegments);
|
||||
|
||||
// add the privacy protecting skip segments functions
|
||||
app.get('/api/skipSegments/:prefix', getSkipSegmentsByHash);
|
||||
|
||||
//voting endpoint
|
||||
app.get('/api/voteOnSponsorTime', voteOnSponsorTime);
|
||||
app.post('/api/voteOnSponsorTime', voteOnSponsorTime);
|
||||
|
||||
@@ -26,6 +26,10 @@ if (config.createDatabaseIfNotExist && !config.readOnly) {
|
||||
|
||||
// Upgrade database if required
|
||||
if (!config.readOnly) {
|
||||
// Register hashing function needed for running database upgrade
|
||||
db.function("sha256", function (string) {
|
||||
return require('crypto').createHash("sha256").update(string).digest("hex");
|
||||
});
|
||||
ugradeDB(db, "sponsorTimes");
|
||||
ugradeDB(privateDB, "private")
|
||||
}
|
||||
|
||||
69
src/routes/getSkipSegmentsByHash.js
Normal file
69
src/routes/getSkipSegmentsByHash.js
Normal file
@@ -0,0 +1,69 @@
|
||||
const config = require('../config.js');
|
||||
const { db, privateDB } = require('../databases/databases.js');
|
||||
|
||||
const getHash = require('../utils/getHash.js');
|
||||
const getIP = require('../utils/getIP.js');
|
||||
|
||||
/**
|
||||
* @typedef {Object} Segment
|
||||
* @property {string} videoID YouTube video ID the segment is meant for
|
||||
* @property {number[]} segment Tuple of start and end times in seconds
|
||||
* @property {string} category Category of content to skip
|
||||
* @property {string} UUID Unique identifier for the specific segment
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} prefix Lowercased hexadecimal hash prefix
|
||||
* @param {string} hashedIP Custom hash of the visitor’s IP address
|
||||
* @returns {Segment[]}
|
||||
*/
|
||||
function getSkipSegmentsByHash(prefix, hashedIP) {
|
||||
/**
|
||||
* @constant
|
||||
* @type {Segment[]}
|
||||
* @default
|
||||
*/
|
||||
const segments = [];
|
||||
|
||||
const rows = db.prepare('SELECT videoID, startTime, endTime, UUID, category, shadowHidden FROM sponsorTimes WHERE votes >= -1 AND hashedVideoID LIKE ? ORDER BY startTime')
|
||||
.all(prefix + '%');
|
||||
|
||||
const onlyForCurrentUser = privateDB.prepare('SELECT videoID FROM sponsorTimes WHERE hashedIP = ?').all(hashedIP).map(row => row.videoID);
|
||||
|
||||
for (const row of rows) {
|
||||
/** @TODO check if this logic does what is expected. */
|
||||
if (row.shadowHidden === 1 && onlyForCurrentUser.indexOf(row.videoID) === -1) {
|
||||
// The current visitor’s IP did not submit for the current video.
|
||||
// Do not send shadowHidden segments to them.
|
||||
continue;
|
||||
}
|
||||
|
||||
segments.push({
|
||||
videoID: row.videoID,
|
||||
segment: [row.startTime, row.endTime],
|
||||
category: row.category,
|
||||
UUID: row.UUID
|
||||
});
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
const minimumPrefix = config.minimumPrefix || '3';
|
||||
const maximumPrefix = config.maximumPrefix || '32'; // Half the hash.
|
||||
const prefixChecker = new RegExp('^[\\dA-F]{' + minimumPrefix + ',' + maximumPrefix + '}$', 'i');
|
||||
|
||||
module.exports = async function (req, res) {
|
||||
if (!prefixChecker.test(req.params.prefix)) {
|
||||
res.sendStatus(400).end(); // Exit early on faulty prefix
|
||||
}
|
||||
|
||||
const segments = getSkipSegmentsByHash(
|
||||
req.params.prefix.toLowerCase(),
|
||||
getHash(getIP(req) + config.globalSalt)
|
||||
);
|
||||
|
||||
if (segments) {
|
||||
res.send(segments)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user