mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-16 16:37:12 +03:00
Merge branch 'master' of https://github.com/ajayyy/SponsorBlockServer into switch-axios
This commit is contained in:
80
src/app.ts
80
src/app.ts
@@ -1,44 +1,44 @@
|
||||
import express, {Request, RequestHandler, Response, Router} from "express";
|
||||
import {config} from "./config";
|
||||
import {oldSubmitSponsorTimes} from "./routes/oldSubmitSponsorTimes";
|
||||
import {oldGetVideoSponsorTimes} from "./routes/oldGetVideoSponsorTimes";
|
||||
import {postSegmentShift} from "./routes/postSegmentShift";
|
||||
import {postWarning} from "./routes/postWarning";
|
||||
import {getIsUserVIP} from "./routes/getIsUserVIP";
|
||||
import {deleteLockCategoriesEndpoint} from "./routes/deleteLockCategories";
|
||||
import {postLockCategories} from "./routes/postLockCategories";
|
||||
import {endpoint as getUserInfo} from "./routes/getUserInfo";
|
||||
import {getDaysSavedFormatted} from "./routes/getDaysSavedFormatted";
|
||||
import {getTotalStats} from "./routes/getTotalStats";
|
||||
import {getTopUsers} from "./routes/getTopUsers";
|
||||
import {getViewsForUser} from "./routes/getViewsForUser";
|
||||
import {getSavedTimeForUser} from "./routes/getSavedTimeForUser";
|
||||
import {addUserAsVIP} from "./routes/addUserAsVIP";
|
||||
import {shadowBanUser} from "./routes/shadowBanUser";
|
||||
import {getUsername} from "./routes/getUsername";
|
||||
import {setUsername} from "./routes/setUsername";
|
||||
import {viewedVideoSponsorTime} from "./routes/viewedVideoSponsorTime";
|
||||
import {voteOnSponsorTime, getUserID as voteGetUserID} from "./routes/voteOnSponsorTime";
|
||||
import {getSkipSegmentsByHash} from "./routes/getSkipSegmentsByHash";
|
||||
import {postSkipSegments} from "./routes/postSkipSegments";
|
||||
import {endpoint as getSkipSegments} from "./routes/getSkipSegments";
|
||||
import {userCounter} from "./middleware/userCounter";
|
||||
import {loggerMiddleware} from "./middleware/logger";
|
||||
import {corsMiddleware} from "./middleware/cors";
|
||||
import {apiCspMiddleware} from "./middleware/apiCsp";
|
||||
import {rateLimitMiddleware} from "./middleware/requestRateLimit";
|
||||
import dumpDatabase, {redirectLink} from "./routes/dumpDatabase";
|
||||
import {endpoint as getSegmentInfo} from "./routes/getSegmentInfo";
|
||||
import {postClearCache} from "./routes/postClearCache";
|
||||
import express, { Request, RequestHandler, Response, Router } from "express";
|
||||
import { config } from "./config";
|
||||
import { oldSubmitSponsorTimes } from "./routes/oldSubmitSponsorTimes";
|
||||
import { oldGetVideoSponsorTimes } from "./routes/oldGetVideoSponsorTimes";
|
||||
import { postSegmentShift } from "./routes/postSegmentShift";
|
||||
import { postWarning } from "./routes/postWarning";
|
||||
import { getIsUserVIP } from "./routes/getIsUserVIP";
|
||||
import { deleteLockCategoriesEndpoint } from "./routes/deleteLockCategories";
|
||||
import { postLockCategories } from "./routes/postLockCategories";
|
||||
import { endpoint as getUserInfo } from "./routes/getUserInfo";
|
||||
import { getDaysSavedFormatted } from "./routes/getDaysSavedFormatted";
|
||||
import { getTotalStats } from "./routes/getTotalStats";
|
||||
import { getTopUsers } from "./routes/getTopUsers";
|
||||
import { getViewsForUser } from "./routes/getViewsForUser";
|
||||
import { getSavedTimeForUser } from "./routes/getSavedTimeForUser";
|
||||
import { addUserAsVIP } from "./routes/addUserAsVIP";
|
||||
import { shadowBanUser } from "./routes/shadowBanUser";
|
||||
import { getUsername } from "./routes/getUsername";
|
||||
import { setUsername } from "./routes/setUsername";
|
||||
import { viewedVideoSponsorTime } from "./routes/viewedVideoSponsorTime";
|
||||
import { voteOnSponsorTime, getUserID as voteGetUserID } from "./routes/voteOnSponsorTime";
|
||||
import { getSkipSegmentsByHash } from "./routes/getSkipSegmentsByHash";
|
||||
import { postSkipSegments } from "./routes/postSkipSegments";
|
||||
import { endpoint as getSkipSegments } from "./routes/getSkipSegments";
|
||||
import { userCounter } from "./middleware/userCounter";
|
||||
import { loggerMiddleware } from "./middleware/logger";
|
||||
import { corsMiddleware } from "./middleware/cors";
|
||||
import { apiCspMiddleware } from "./middleware/apiCsp";
|
||||
import { rateLimitMiddleware } from "./middleware/requestRateLimit";
|
||||
import dumpDatabase, { redirectLink } from "./routes/dumpDatabase";
|
||||
import { endpoint as getSegmentInfo } from "./routes/getSegmentInfo";
|
||||
import { postClearCache } from "./routes/postClearCache";
|
||||
import { addUnlistedVideo } from "./routes/addUnlistedVideo";
|
||||
import {postPurgeAllSegments} from "./routes/postPurgeAllSegments";
|
||||
import {getUserID} from "./routes/getUserID";
|
||||
import {getLockCategories} from "./routes/getLockCategories";
|
||||
import {getLockCategoriesByHash} from "./routes/getLockCategoriesByHash";
|
||||
import {endpoint as getSearchSegments } from "./routes/getSearchSegments";
|
||||
import {getStatus } from "./routes/getStatus";
|
||||
import { postPurgeAllSegments } from "./routes/postPurgeAllSegments";
|
||||
import { getUserID } from "./routes/getUserID";
|
||||
import { getLockCategories } from "./routes/getLockCategories";
|
||||
import { getLockCategoriesByHash } from "./routes/getLockCategoriesByHash";
|
||||
import { endpoint as getSearchSegments } from "./routes/getSearchSegments";
|
||||
import { getStatus } from "./routes/getStatus";
|
||||
import { getLockReason } from "./routes/getLockReason";
|
||||
import {getUserStats} from "./routes/getUserStats";
|
||||
import { getUserStats } from "./routes/getUserStats";
|
||||
import ExpressPromiseRouter from "express-promise-router";
|
||||
import { Server } from "http";
|
||||
import { youtubeApiProxy } from "./routes/youtubeApiProxy";
|
||||
@@ -188,7 +188,7 @@ function setupRoutes(router: Router) {
|
||||
router.get("/database/*", redirectLink);
|
||||
} else {
|
||||
router.get("/database.db", function (req: Request, res: Response) {
|
||||
res.sendFile("./databases/sponsorTimes.db", {root: "./"});
|
||||
res.sendFile("./databases/sponsorTimes.db", { root: "./" });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import fs from "fs";
|
||||
import {SBSConfig} from "./types/config.model";
|
||||
import { SBSConfig } from "./types/config.model";
|
||||
import packageJson from "../package.json";
|
||||
|
||||
const isTestMode = process.env.npm_lifecycle_script === packageJson.scripts.test;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Logger} from "../utils/logger";
|
||||
import {IDatabase, QueryType} from "./IDatabase";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { IDatabase, QueryType } from "./IDatabase";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
import MysqlInterface from "sync-mysql";
|
||||
@@ -10,6 +10,7 @@ export class Mysql implements IDatabase {
|
||||
constructor(private config: unknown) {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
async init(): Promise<void> {
|
||||
this.connection = new MysqlInterface(this.config);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export class Postgres implements IDatabase {
|
||||
Logger.debug(`prepare (postgres): type: ${type}, query: ${query}, params: ${params}`);
|
||||
|
||||
try {
|
||||
const queryResult = await this.pool.query({text: query, values: params});
|
||||
const queryResult = await this.pool.query({ text: query, values: params });
|
||||
|
||||
switch (type) {
|
||||
case "get": {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {IDatabase, QueryType} from "./IDatabase";
|
||||
import Sqlite3, {Database, Database as SQLiteDatabase} from "better-sqlite3";
|
||||
import { IDatabase, QueryType } from "./IDatabase";
|
||||
import Sqlite3, { Database, Database as SQLiteDatabase } from "better-sqlite3";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {Logger} from "../utils/logger";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { Logger } from "../utils/logger";
|
||||
|
||||
export class Sqlite implements IDatabase {
|
||||
private db: SQLiteDatabase;
|
||||
@@ -12,6 +12,7 @@ export class Sqlite implements IDatabase {
|
||||
{
|
||||
}
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
async prepare(type: QueryType, query: string, params: any[] = []): Promise<any[]> {
|
||||
// Logger.debug(`prepare (sqlite): type: ${type}, query: ${query}, params: ${params}`);
|
||||
const preparedQuery = this.db.prepare(query);
|
||||
@@ -30,13 +31,14 @@ export class Sqlite implements IDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
async init(): Promise<void> {
|
||||
// Make dirs if required
|
||||
if (!fs.existsSync(path.join(this.config.dbPath, "../"))) {
|
||||
fs.mkdirSync(path.join(this.config.dbPath, "../"));
|
||||
}
|
||||
|
||||
this.db = new Sqlite3(this.config.dbPath, {readonly: this.config.readOnly, fileMustExist: !this.config.createDbIfNotExists});
|
||||
this.db = new Sqlite3(this.config.dbPath, { readonly: this.config.readOnly, fileMustExist: !this.config.createDbIfNotExists });
|
||||
|
||||
if (this.config.createDbIfNotExists && !this.config.readOnly && fs.existsSync(this.config.dbSchemaFileName)) {
|
||||
this.db.exec(Sqlite.processUpgradeQuery(fs.readFileSync(this.config.dbSchemaFileName).toString()));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {config} from "../config";
|
||||
import {Sqlite} from "./Sqlite";
|
||||
import {Mysql} from "./Mysql";
|
||||
import {Postgres} from "./Postgres";
|
||||
import {IDatabase} from "./IDatabase";
|
||||
import { config } from "../config";
|
||||
import { Sqlite } from "./Sqlite";
|
||||
import { Mysql } from "./Mysql";
|
||||
import { Postgres } from "./Postgres";
|
||||
import { IDatabase } from "./IDatabase";
|
||||
|
||||
|
||||
let db: IDatabase;
|
||||
|
||||
10
src/index.ts
10
src/index.ts
@@ -1,8 +1,8 @@
|
||||
import {config} from "./config";
|
||||
import {initDb} from "./databases/databases";
|
||||
import {createServer} from "./app";
|
||||
import {Logger} from "./utils/logger";
|
||||
import {startAllCrons} from "./cronjob";
|
||||
import { config } from "./config";
|
||||
import { initDb } from "./databases/databases";
|
||||
import { createServer } from "./app";
|
||||
import { Logger } from "./utils/logger";
|
||||
import { startAllCrons } from "./cronjob";
|
||||
import { getCommit } from "./utils/getCommit";
|
||||
|
||||
async function init() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
|
||||
export function apiCspMiddleware(req: Request, res: Response, next: NextFunction): void {
|
||||
res.header("Content-Security-Policy", "script-src 'none'; object-src 'none'");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
|
||||
export function corsMiddleware(req: Request, res: Response, next: NextFunction): void {
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Logger} from "../utils/logger";
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
|
||||
export function loggerMiddleware(req: Request, res: Response, next: NextFunction): void {
|
||||
Logger.info(`Request received: ${req.method} ${req.url}`);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {getIP} from "../utils/getIP";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import { getIP } from "../utils/getIP";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import rateLimit from "express-rate-limit";
|
||||
import {RateLimitConfig} from "../types/config.model";
|
||||
import {Request} from "express";
|
||||
import { RateLimitConfig } from "../types/config.model";
|
||||
import { Request } from "express";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { UserID } from "../types/user.model";
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {Logger} from "../utils/logger";
|
||||
import {config} from "../config";
|
||||
import {getIP} from "../utils/getIP";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import axios from "axios";
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { config } from "../config";
|
||||
import { getIP } from "../utils/getIP";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
|
||||
export function userCounter(req: Request, res: Response, next: NextFunction): void {
|
||||
axios.post(`${config.userCounterURL}/api/v1/addIP?hashedIP=${getHash(getIP(req), 1)}`)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Request, Response} from "express";
|
||||
import { Request, Response } from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { Logger } from "../utils/logger";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {db} from "../databases/databases";
|
||||
import {config} from "../config";
|
||||
import {Request, Response} from "express";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { db } from "../databases/databases";
|
||||
import { config } from "../config";
|
||||
import { Request, Response } from "express";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { HashedUserID } from "../types/user.model";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {Request, Response} from "express";
|
||||
import {isUserVIP} from "../utils/isUserVIP";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {db} from "../databases/databases";
|
||||
import { Request, Response } from "express";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { db } from "../databases/databases";
|
||||
import { Category, VideoID } from "../types/segments.model";
|
||||
import { UserID } from "../types/user.model";
|
||||
|
||||
@@ -35,7 +35,7 @@ export async function deleteLockCategoriesEndpoint(req: Request, res: Response):
|
||||
|
||||
await deleteLockCategories(videoID, categories);
|
||||
|
||||
return res.status(200).json({message: `Removed lock categories entrys for video ${videoID}`});
|
||||
return res.status(200).json({ message: `Removed lock categories entrys for video ${videoID}` });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { Request, Response } from "express";
|
||||
import { config } from "../config";
|
||||
import util from "util";
|
||||
import fs from "fs";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function getDaysSavedFormatted(req: Request, res: Response): Promise<Response> {
|
||||
const row = await db.prepare("get", 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {Logger} from "../utils/logger";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {isUserVIP} from "../utils/isUserVIP";
|
||||
import {Request, Response} from "express";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { Request, Response } from "express";
|
||||
import { HashedUserID, UserID } from "../types/user.model";
|
||||
|
||||
export async function getIsUserVIP(req: Request, res: Response): Promise<Response> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { Request, Response } from "express";
|
||||
import { Category, VideoID } from "../types/segments.model";
|
||||
|
||||
export async function getLockCategories(req: Request, res: Response): Promise<Response> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {Request, Response} from "express";
|
||||
import {hashPrefixTester} from "../utils/hashPrefixTester";
|
||||
import { db } from "../databases/databases";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { Request, Response } from "express";
|
||||
import { hashPrefixTester } from "../utils/hashPrefixTester";
|
||||
import { Category, VideoID, VideoIDHash } from "../types/segments.model";
|
||||
|
||||
interface LockResultByHash {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { Request, Response } from "express";
|
||||
import { Category, VideoID } from "../types/segments.model";
|
||||
import {config} from "../config";
|
||||
import { config } from "../config";
|
||||
|
||||
const possibleCategoryList = config.categoryList;
|
||||
interface lockArray {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Request, Response} from "express";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {config} from "../config";
|
||||
import { db } from "../databases/databases";
|
||||
import { Request, Response } from "express";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "../utils/logger";
|
||||
|
||||
const maxRewardTimePerSegmentInSeconds = config.maxRewardTimePerSegmentInSeconds ?? 86400;
|
||||
|
||||
@@ -10,7 +10,7 @@ type searchSegmentResponse = {
|
||||
segments: DBSegment[]
|
||||
};
|
||||
|
||||
async function getSegmentsFromDBByVideoID(videoID: VideoID, service: Service): Promise<DBSegment[]> {
|
||||
function getSegmentsFromDBByVideoID(videoID: VideoID, service: Service): Promise<DBSegment[]> {
|
||||
return db.prepare(
|
||||
"all",
|
||||
`SELECT "UUID", "timeSubmitted", "startTime", "endTime", "category", "actionType", "votes", "views", "locked", "hidden", "shadowHidden" FROM "sponsorTimes"
|
||||
|
||||
@@ -13,7 +13,7 @@ import { getReputation } from "../utils/reputation";
|
||||
import { getService } from "../utils/getService";
|
||||
|
||||
|
||||
async function prepareCategorySegments(req: Request, videoID: VideoID, category: Category, segments: DBSegment[], cache: SegmentCache = {shadowHiddenSegmentIPs: {}}): Promise<Segment[]> {
|
||||
async function prepareCategorySegments(req: Request, videoID: VideoID, category: Category, segments: DBSegment[], cache: SegmentCache = { shadowHiddenSegmentIPs: {} }): Promise<Segment[]> {
|
||||
const shouldFilter: boolean[] = await Promise.all(segments.map(async (segment) => {
|
||||
if (segment.votes < -1 && !segment.required) {
|
||||
return false; //too untrustworthy, just ignore it
|
||||
@@ -56,7 +56,7 @@ async function prepareCategorySegments(req: Request, videoID: VideoID, category:
|
||||
|
||||
async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories: Category[],
|
||||
actionTypes: ActionType[], requiredSegments: SegmentUUID[], service: Service): Promise<Segment[]> {
|
||||
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
|
||||
const cache: SegmentCache = { shadowHiddenSegmentIPs: {} };
|
||||
const segments: Segment[] = [];
|
||||
|
||||
try {
|
||||
@@ -89,7 +89,7 @@ async function getSegmentsByVideoID(req: Request, videoID: VideoID, categories:
|
||||
|
||||
async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash, categories: Category[],
|
||||
actionTypes: ActionType[], requiredSegments: SegmentUUID[], service: Service): Promise<SBRecord<VideoID, VideoData>> {
|
||||
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
|
||||
const cache: SegmentCache = { shadowHiddenSegmentIPs: {} };
|
||||
const segments: SBRecord<VideoID, VideoData> = {};
|
||||
|
||||
try {
|
||||
@@ -182,7 +182,7 @@ function getWeightedRandomChoice<T extends VotableObject>(choices: T[], amountOf
|
||||
const weight = Math.exp(choice.votes * Math.max(1, choice.reputation + 1) + 3 + boost);
|
||||
totalWeight += Math.max(weight, 0);
|
||||
|
||||
return {...choice, weight};
|
||||
return { ...choice, weight };
|
||||
});
|
||||
|
||||
//iterate and find amountOfChoices choices
|
||||
@@ -220,7 +220,7 @@ async function chooseSegments(segments: DBSegment[], max: number): Promise<DBSeg
|
||||
let cursor = -1; //-1 to make sure that, even if the 1st segment starts at 0, a new group is created
|
||||
for (const segment of segments) {
|
||||
if (segment.startTime >= cursor) {
|
||||
currentGroup = {segments: [], votes: 0, reputation: 0, locked: false, required: false};
|
||||
currentGroup = { segments: [], votes: 0, reputation: 0, locked: false, required: false };
|
||||
overlappingSegmentsGroups.push(currentGroup);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {hashPrefixTester} from "../utils/hashPrefixTester";
|
||||
import {getSegmentsByHash} from "./getSkipSegments";
|
||||
import {Request, Response} from "express";
|
||||
import { ActionType, Category, SegmentUUID, Service, VideoIDHash } from "../types/segments.model";
|
||||
import { hashPrefixTester } from "../utils/hashPrefixTester";
|
||||
import { getSegmentsByHash } from "./getSkipSegments";
|
||||
import { Request, Response } from "express";
|
||||
import { ActionType, Category, SegmentUUID, VideoIDHash, Service } from "../types/segments.model";
|
||||
import { getService } from "../utils/getService";
|
||||
|
||||
export async function getSkipSegmentsByHash(req: Request, res: Response): Promise<Response> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function getStatus(req: Request, res: Response): Promise<Response> {
|
||||
const startTime = Date.now();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {createMemoryCache} from "../utils/createMemoryCache";
|
||||
import {config} from "../config";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { createMemoryCache } from "../utils/createMemoryCache";
|
||||
import { config } from "../config";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
const MILLISECONDS_IN_MINUTE = 60000;
|
||||
const getTopUsersWithCache = createMemoryCache(generateTopUsersStats, config.getTopUsersCacheTimeMinutes * MILLISECONDS_IN_MINUTE);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {config} from "../config";
|
||||
import {Request, Response} from "express";
|
||||
import {Logger} from "../utils/logger";
|
||||
import { db } from "../databases/databases";
|
||||
import { config } from "../config";
|
||||
import { Request, Response } from "express";
|
||||
import axios from "axios";
|
||||
import { Logger } from "../utils/logger";
|
||||
|
||||
// A cache of the number of chrome web store users
|
||||
let chromeUsersCache = 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Request, Response} from "express";
|
||||
import {UserID} from "../types/user.model";
|
||||
import { db } from "../databases/databases";
|
||||
import { Request, Response } from "express";
|
||||
import { UserID } from "../types/user.model";
|
||||
|
||||
function getFuzzyUserID(userName: string): Promise<{userName: string, userID: UserID }[]> {
|
||||
// escape [_ % \] to avoid ReDOS
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {isUserVIP} from "../utils/isUserVIP";
|
||||
import {Request, Response} from "express";
|
||||
import {Logger} from "../utils/logger";
|
||||
import { db } from "../databases/databases";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { Request, Response } from "express";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { HashedUserID, UserID } from "../types/user.model";
|
||||
import { getReputation } from "../utils/reputation";
|
||||
import { SegmentUUID } from "../types/segments.model";
|
||||
import {config} from "../config";
|
||||
import { config } from "../config";
|
||||
const maxRewardTime = config.maxRewardTimePerSegmentInSeconds;
|
||||
|
||||
async function dbGetSubmittedSegmentSummary(userID: HashedUserID): Promise<{ minutesSaved: number, segmentCount: number }> {
|
||||
@@ -116,7 +116,7 @@ const objSwitch = (cases: cases) => (defaultCase: string) => (key: string) =>
|
||||
const functionSwitch = (cases: cases) => (defaultCase: string) => (key: string) =>
|
||||
executeIfFunction(objSwitch(cases)(defaultCase)(key));
|
||||
|
||||
const dbGetValue = async (userID: HashedUserID, property: string): Promise<string|SegmentUUID|number> => {
|
||||
const dbGetValue = (userID: HashedUserID, property: string): Promise<string|SegmentUUID|number> => {
|
||||
return functionSwitch({
|
||||
userID,
|
||||
userName: dbGetUsername(userID),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {Request, Response} from "express";
|
||||
import {HashedUserID, UserID} from "../types/user.model";
|
||||
import {config} from "../config";
|
||||
import { db } from "../databases/databases";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { Request, Response } from "express";
|
||||
import { HashedUserID, UserID } from "../types/user.model";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "../utils/logger";
|
||||
type nestedObj = Record<string, Record<string, number>>;
|
||||
const maxRewardTimePerSegmentInSeconds = config.maxRewardTimePerSegmentInSeconds ?? 86400;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function getUsername(req: Request, res: Response): Promise<Response> {
|
||||
let userID = req.query.userID as string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Request, Response} from "express";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {Logger} from "../utils/logger";
|
||||
import { db } from "../databases/databases";
|
||||
import { Request, Response } from "express";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { Logger } from "../utils/logger";
|
||||
|
||||
export async function getViewsForUser(req: Request, res: Response): Promise<Response> {
|
||||
let userID = req.query.userID as string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {handleGetSegments} from "./getSkipSegments";
|
||||
import {Request, Response} from "express";
|
||||
import { handleGetSegments } from "./getSkipSegments";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function oldGetVideoSponsorTimes(req: Request, res: Response): Promise<Response> {
|
||||
const segments = await handleGetSegments(req, res);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {postSkipSegments} from "./postSkipSegments";
|
||||
import {Request, Response} from "express";
|
||||
import { postSkipSegments } from "./postSkipSegments";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function oldSubmitSponsorTimes(req: Request, res: Response): Promise<Response> {
|
||||
export function oldSubmitSponsorTimes(req: Request, res: Response): Promise<Response> {
|
||||
req.query.category = "sponsor";
|
||||
return postSkipSegments(req, res);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export async function postClearCache(req: Request, res: Response): Promise<Respo
|
||||
// Ensure user is a VIP
|
||||
if (!(await isUserVIP(hashedUserID))){
|
||||
Logger.warn(`Permission violation: User ${hashedUserID} attempted to clear cache for video ${videoID}.`);
|
||||
return res.status(403).json({"message": "Not a VIP"});
|
||||
return res.status(403).json({ "message": "Not a VIP" });
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {Logger} from "../utils/logger";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {isUserVIP} from "../utils/isUserVIP";
|
||||
import {db} from "../databases/databases";
|
||||
import {Request, Response} from "express";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { db } from "../databases/databases";
|
||||
import { Request, Response } from "express";
|
||||
import { VideoIDHash } from "../types/segments.model";
|
||||
|
||||
export async function postLockCategories(req: Request, res: Response): Promise<string[]> {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {Logger} from "../utils/logger";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {isUserVIP} from "../utils/isUserVIP";
|
||||
import {Request, Response} from "express";
|
||||
import {HashedUserID, UserID} from "../types/user.model";
|
||||
import {VideoID} from "../types/segments.model";
|
||||
import {db} from "../databases/databases";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { Request, Response } from "express";
|
||||
import { HashedUserID, UserID } from "../types/user.model";
|
||||
import { VideoID } from "../types/segments.model";
|
||||
import { db } from "../databases/databases";
|
||||
|
||||
export async function postPurgeAllSegments(req: Request, res: Response): Promise<Response> {
|
||||
const userID = req.body.userID as UserID;
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
import {Request, Response} from "express";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {isUserVIP} from "../utils/isUserVIP";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {db} from "../databases/databases";
|
||||
import { Request, Response } from "express";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { db } from "../databases/databases";
|
||||
|
||||
const ACTION_NONE = Symbol("none");
|
||||
const ACTION_UPDATE = Symbol("update");
|
||||
const ACTION_REMOVE = Symbol("remove");
|
||||
|
||||
function shiftSegment(segment: any, shift: { startTime: any; endTime: any }) {
|
||||
if (segment.startTime >= segment.endTime) return {action: ACTION_NONE, segment};
|
||||
if (shift.startTime >= shift.endTime) return {action: ACTION_NONE, segment};
|
||||
if (segment.startTime >= segment.endTime) return { action: ACTION_NONE, segment };
|
||||
if (shift.startTime >= shift.endTime) return { action: ACTION_NONE, segment };
|
||||
const duration = shift.endTime - shift.startTime;
|
||||
if (shift.endTime < segment.startTime) {
|
||||
// Scenario #1 cut before segment
|
||||
segment.startTime -= duration;
|
||||
segment.endTime -= duration;
|
||||
return {action: ACTION_UPDATE, segment};
|
||||
return { action: ACTION_UPDATE, segment };
|
||||
}
|
||||
if (shift.startTime > segment.endTime) {
|
||||
// Scenario #2 cut after segment
|
||||
return {action: ACTION_NONE, segment};
|
||||
return { action: ACTION_NONE, segment };
|
||||
}
|
||||
if (segment.startTime < shift.startTime && segment.endTime > shift.endTime) {
|
||||
// Scenario #3 cut inside segment
|
||||
segment.endTime -= duration;
|
||||
return {action: ACTION_UPDATE, segment};
|
||||
return { action: ACTION_UPDATE, segment };
|
||||
}
|
||||
if (segment.startTime >= shift.startTime && segment.endTime > shift.endTime) {
|
||||
// Scenario #4 cut overlap startTime
|
||||
segment.startTime = shift.startTime;
|
||||
segment.endTime -= duration;
|
||||
return {action: ACTION_UPDATE, segment};
|
||||
return { action: ACTION_UPDATE, segment };
|
||||
}
|
||||
if (segment.startTime < shift.startTime && segment.endTime <= shift.endTime) {
|
||||
// Scenario #5 cut overlap endTime
|
||||
segment.endTime = shift.startTime;
|
||||
return {action: ACTION_UPDATE, segment};
|
||||
return { action: ACTION_UPDATE, segment };
|
||||
}
|
||||
if (segment.startTime >= shift.startTime && segment.endTime <= shift.endTime) {
|
||||
// Scenario #6 cut overlap startTime and endTime
|
||||
return {action: ACTION_REMOVE, segment};
|
||||
return { action: ACTION_REMOVE, segment };
|
||||
}
|
||||
return {action: ACTION_NONE, segment};
|
||||
return { action: ACTION_NONE, segment };
|
||||
}
|
||||
|
||||
export async function postSegmentShift(req: Request, res: Response): Promise<Response> {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {config} from "../config";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {db, privateDB} from "../databases/databases";
|
||||
import {getMaxResThumbnail, YouTubeAPI} from "../utils/youtubeApi";
|
||||
import {getSubmissionUUID} from "../utils/getSubmissionUUID";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {getIP} from "../utils/getIP";
|
||||
import {getFormattedTime} from "../utils/getFormattedTime";
|
||||
import {isUserTrustworthy} from "../utils/isUserTrustworthy";
|
||||
import {dispatchEvent} from "../utils/webhookUtils";
|
||||
import {Request, Response} from "express";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { db, privateDB } from "../databases/databases";
|
||||
import { getMaxResThumbnail, YouTubeAPI } from "../utils/youtubeApi";
|
||||
import { getSubmissionUUID } from "../utils/getSubmissionUUID";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { getIP } from "../utils/getIP";
|
||||
import { getFormattedTime } from "../utils/getFormattedTime";
|
||||
import { isUserTrustworthy } from "../utils/isUserTrustworthy";
|
||||
import { dispatchEvent } from "../utils/webhookUtils";
|
||||
import { Request, Response } from "express";
|
||||
import { ActionType, Category, CategoryActionType, IncomingSegment, SegmentUUID, Service, VideoDuration, VideoID } from "../types/segments.model";
|
||||
import { deleteLockCategories } from "./deleteLockCategories";
|
||||
import { getCategoryActionType } from "../utils/categoryInfo";
|
||||
@@ -33,7 +33,7 @@ const CHECK_PASS: CheckResult = {
|
||||
errorCode: 0
|
||||
};
|
||||
|
||||
async function sendWebhookNotification(userID: string, videoID: string, UUID: string, submissionCount: number, youtubeData: APIVideoData, {submissionStart, submissionEnd}: { submissionStart: number; submissionEnd: number; }, segmentInfo: any) {
|
||||
async function sendWebhookNotification(userID: string, videoID: string, UUID: string, submissionCount: number, youtubeData: APIVideoData, { submissionStart, submissionEnd }: { submissionStart: number; submissionEnd: number; }, segmentInfo: any) {
|
||||
const row = await db.prepare("get", `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
|
||||
const userName = row !== undefined ? row.userName : null;
|
||||
|
||||
@@ -66,7 +66,7 @@ async function sendWebhooks(apiVideoInfo: APIVideoInfo, userID: string, videoID:
|
||||
if (apiVideoInfo && service == Service.YouTube) {
|
||||
const userSubmissionCountRow = await db.prepare("get", `SELECT count(*) as "submissionCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
|
||||
|
||||
const {data, err} = apiVideoInfo;
|
||||
const { data, err } = apiVideoInfo;
|
||||
if (err) return;
|
||||
|
||||
const startTime = parseFloat(segmentInfo.segment[0]);
|
||||
@@ -170,7 +170,7 @@ async function sendWebhooksNB(userID: string, videoID: string, UUID: string, sta
|
||||
async function autoModerateSubmission(apiVideoInfo: APIVideoInfo,
|
||||
submission: { videoID: VideoID; userID: UserID; segments: IncomingSegment[] }) {
|
||||
if (apiVideoInfo) {
|
||||
const {err, data} = apiVideoInfo;
|
||||
const { err, data } = apiVideoInfo;
|
||||
if (err) return false;
|
||||
|
||||
const duration = apiVideoInfo?.data?.lengthSeconds;
|
||||
@@ -225,7 +225,7 @@ async function autoModerateSubmission(apiVideoInfo: APIVideoInfo,
|
||||
const neuralBlockURL = config.neuralBlockURL;
|
||||
if (!neuralBlockURL) return false;
|
||||
const response = await axios.get(`${neuralBlockURL}/api/checkSponsorSegments?vid=${submission.videoID}
|
||||
&segments=${nbString.substring(0, nbString.length - 1)}`, { validateStatus: () => true});
|
||||
&segments=${nbString.substring(0, nbString.length - 1)}`, { validateStatus: () => true });
|
||||
if (response.status !== 200) return false;
|
||||
|
||||
const nbPredictions = response.data;
|
||||
@@ -262,7 +262,7 @@ async function autoModerateSubmission(apiVideoInfo: APIVideoInfo,
|
||||
}
|
||||
}
|
||||
|
||||
async function getYouTubeVideoInfo(videoID: VideoID, ignoreCache = false): Promise<APIVideoInfo> {
|
||||
function getYouTubeVideoInfo(videoID: VideoID, ignoreCache = false): Promise<APIVideoInfo> {
|
||||
if (config.newLeafURLs !== null) {
|
||||
return YouTubeAPI.listVideos(videoID, ignoreCache);
|
||||
} else {
|
||||
@@ -343,11 +343,11 @@ async function checkEachSegmentValid(userID: string, videoID: VideoID,
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
if (segments[i] === undefined || segments[i].segment === undefined || segments[i].category === undefined) {
|
||||
//invalid request
|
||||
return { pass: false, errorMessage: "One of your segments are invalid", errorCode: 400};
|
||||
return { pass: false, errorMessage: "One of your segments are invalid", errorCode: 400 };
|
||||
}
|
||||
|
||||
if (!config.categoryList.includes(segments[i].category)) {
|
||||
return { pass: false, errorMessage: "Category doesn't exist.", errorCode: 400};
|
||||
return { pass: false, errorMessage: "Category doesn't exist.", errorCode: 400 };
|
||||
}
|
||||
|
||||
// Reject segment if it's in the locked categories list
|
||||
@@ -380,24 +380,24 @@ async function checkEachSegmentValid(userID: string, videoID: VideoID,
|
||||
|| (getCategoryActionType(segments[i].category) === CategoryActionType.Skippable && startTime === endTime)
|
||||
|| (getCategoryActionType(segments[i].category) === CategoryActionType.POI && startTime !== endTime)) {
|
||||
//invalid request
|
||||
return { pass: false, errorMessage: "One of your segments times are invalid (too short, startTime before endTime, etc.)", errorCode: 400};
|
||||
return { pass: false, errorMessage: "One of your segments times are invalid (too short, startTime before endTime, etc.)", errorCode: 400 };
|
||||
}
|
||||
|
||||
// Check for POI segments before some seconds
|
||||
if (!isVIP && getCategoryActionType(segments[i].category) === CategoryActionType.POI && startTime < config.poiMinimumStartTime) {
|
||||
return { pass: false, errorMessage: `POI cannot be that early`, errorCode: 400};
|
||||
return { pass: false, errorMessage: `POI cannot be that early`, errorCode: 400 };
|
||||
}
|
||||
|
||||
if (!isVIP && segments[i].category === "sponsor" && Math.abs(startTime - endTime) < 1) {
|
||||
// Too short
|
||||
return { pass: false, errorMessage: "Sponsors must be longer than 1 second long", errorCode: 400};
|
||||
return { pass: false, errorMessage: "Sponsors must be longer than 1 second long", errorCode: 400 };
|
||||
}
|
||||
|
||||
//check if this info has already been submitted before
|
||||
const duplicateCheck2Row = await db.prepare("get", `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "startTime" = ?
|
||||
and "endTime" = ? and "category" = ? and "actionType" = ? and "videoID" = ? and "service" = ?`, [startTime, endTime, segments[i].category, segments[i].actionType, videoID, service]);
|
||||
if (duplicateCheck2Row.count > 0) {
|
||||
return { pass: false, errorMessage: "Sponsors has already been submitted before.", errorCode: 409};
|
||||
return { pass: false, errorMessage: "Sponsors has already been submitted before.", errorCode: 409 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ async function checkEachSegmentValid(userID: string, videoID: VideoID,
|
||||
async function checkByAutoModerator(videoID: any, userID: any, segments: Array<any>, isVIP: boolean, service:string, apiVideoInfo: APIVideoInfo, decreaseVotes: number): Promise<CheckResult & { decreaseVotes: number; } > {
|
||||
// Auto moderator check
|
||||
if (!isVIP && service == Service.YouTube) {
|
||||
const autoModerateResult = await autoModerateSubmission(apiVideoInfo, {userID, videoID, segments});//startTime, endTime, category: segments[i].category});
|
||||
const autoModerateResult = await autoModerateSubmission(apiVideoInfo, { userID, videoID, segments });//startTime, endTime, category: segments[i].category});
|
||||
if (autoModerateResult == "Rejected based on NeuralBlock predictions.") {
|
||||
// If NB automod rejects, the submission will start with -2 votes.
|
||||
// Note, if one submission is bad all submissions will be affected.
|
||||
@@ -520,7 +520,7 @@ async function checkRateLimit(userID:string, videoID: VideoID, timeSubmitted: nu
|
||||
|
||||
function proxySubmission(req: Request) {
|
||||
axios.post(`${config.proxySubmission}/api/skipSegments?userID=${req.query.userID}&videoID=${req.query.videoID}`, req.body)
|
||||
.then(async res => {
|
||||
.then(res => {
|
||||
Logger.debug(`Proxy Submission: ${res.status} (${res.data})`);
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -555,7 +555,7 @@ function preprocessInput(req: Request) {
|
||||
|
||||
const userAgent = req.query.userAgent ?? req.body.userAgent ?? parseUserAgent(req.get("user-agent")) ?? "";
|
||||
|
||||
return {videoID, userID, service, videoDuration, videoDurationParam, segments, userAgent};
|
||||
return { videoID, userID, service, videoDuration, videoDurationParam, segments, userAgent };
|
||||
}
|
||||
|
||||
export async function postSkipSegments(req: Request, res: Response): Promise<Response> {
|
||||
@@ -564,7 +564,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let {videoID, userID, service, videoDuration, videoDurationParam, segments, userAgent} = preprocessInput(req);
|
||||
let { videoID, userID, service, videoDuration, videoDurationParam, segments, userAgent } = preprocessInput(req);
|
||||
|
||||
const invalidCheckResult = checkInvalidFields(videoID, userID, segments);
|
||||
if (!invalidCheckResult.pass) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {Request, Response} from "express";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {db} from "../databases/databases";
|
||||
import {isUserVIP} from "../utils/isUserVIP";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import { Request, Response } from "express";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { db } from "../databases/databases";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { HashedUserID, UserID } from "../types/user.model";
|
||||
import { config } from "../config";
|
||||
|
||||
@@ -23,7 +23,7 @@ function checkExpiredWarning(warning: warningEntry): boolean {
|
||||
|
||||
export async function postWarning(req: Request, res: Response): Promise<Response> {
|
||||
// exit early if no body passed in
|
||||
if (!req.body.userID && !req.body.issuerUserID) return res.status(400).json({"message": "Missing parameters"});
|
||||
if (!req.body.userID && !req.body.issuerUserID) return res.status(400).json({ "message": "Missing parameters" });
|
||||
// Collect user input data
|
||||
const issuerUserID: HashedUserID = getHash(<UserID> req.body.issuerUserID);
|
||||
const userID: UserID = req.body.userID;
|
||||
@@ -34,7 +34,7 @@ export async function postWarning(req: Request, res: Response): Promise<Response
|
||||
// Ensure user is a VIP
|
||||
if (!await isUserVIP(issuerUserID)) {
|
||||
Logger.warn(`Permission violation: User ${issuerUserID} attempted to warn user ${userID}.`);
|
||||
return res.status(403).json({"message": "Not a VIP"});
|
||||
return res.status(403).json({ "message": "Not a VIP" });
|
||||
}
|
||||
|
||||
let resultStatus = "";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {config} from "../config";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {db, privateDB} from "../databases/databases";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {Request, Response} from "express";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { db, privateDB } from "../databases/databases";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
async function logUserNameChange(userID: string, newUserName: string, oldUserName: string, updatedByAdmin: boolean): Promise<Response> {
|
||||
function logUserNameChange(userID: string, newUserName: string, oldUserName: string, updatedByAdmin: boolean): Promise<Response> {
|
||||
return privateDB.prepare("run",
|
||||
`INSERT INTO "userNameLogs"("userID", "newUserName", "oldUserName", "updatedByAdmin", "updatedAt") VALUES(?, ?, ?, ?, ?)`,
|
||||
[userID, newUserName, oldUserName, + updatedByAdmin, new Date().getTime()]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { Request, Response } from "express";
|
||||
import { config } from "../config";
|
||||
import { Category, Service, VideoID, VideoIDHash } from "../types/segments.model";
|
||||
import { UserID } from "../types/user.model";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {db} from "../databases/databases";
|
||||
import {Request, Response} from "express";
|
||||
import { db } from "../databases/databases";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function viewedVideoSponsorTime(req: Request, res: Response): Promise<Response> {
|
||||
const UUID = req.query.UUID;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {Request, Response} from "express";
|
||||
import {Logger} from "../utils/logger";
|
||||
import {isUserVIP} from "../utils/isUserVIP";
|
||||
import {getMaxResThumbnail, YouTubeAPI} from "../utils/youtubeApi";
|
||||
import {db, privateDB} from "../databases/databases";
|
||||
import {dispatchEvent, getVoteAuthor, getVoteAuthorRaw} from "../utils/webhookUtils";
|
||||
import {getFormattedTime} from "../utils/getFormattedTime";
|
||||
import {getIP} from "../utils/getIP";
|
||||
import {getHash} from "../utils/getHash";
|
||||
import {config} from "../config";
|
||||
import { Request, Response } from "express";
|
||||
import { Logger } from "../utils/logger";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { getMaxResThumbnail, YouTubeAPI } from "../utils/youtubeApi";
|
||||
import { db, privateDB } from "../databases/databases";
|
||||
import { dispatchEvent, getVoteAuthor, getVoteAuthorRaw } from "../utils/webhookUtils";
|
||||
import { getFormattedTime } from "../utils/getFormattedTime";
|
||||
import { getIP } from "../utils/getIP";
|
||||
import { getHash } from "../utils/getHash";
|
||||
import { config } from "../config";
|
||||
import { UserID } from "../types/user.model";
|
||||
import { Category, CategoryActionType, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash, Visibility } from "../types/segments.model";
|
||||
import { getCategoryActionType } from "../utils/categoryInfo";
|
||||
@@ -135,7 +135,7 @@ async function sendWebhooks(voteData: VoteData) {
|
||||
},
|
||||
}],
|
||||
})
|
||||
.then(async res => {
|
||||
.then(res => {
|
||||
if (res.status >= 400) {
|
||||
Logger.error("Error sending reported submission Discord hook");
|
||||
Logger.error(JSON.stringify((res.data)));
|
||||
@@ -453,6 +453,6 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
|
||||
return res.status(finalResponse.finalStatus).send(finalResponse.finalMessage ?? undefined);
|
||||
} catch (err) {
|
||||
Logger.error(err as string);
|
||||
return res.status(500).json({error: "Internal error creating segment vote"});
|
||||
return res.status(500).json({ error: "Internal error creating segment vote" });
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import {config} from "../config";
|
||||
import {Request} from "express";
|
||||
import { config } from "../config";
|
||||
import { Request } from "express";
|
||||
import { IPAddress } from "../types/segments.model";
|
||||
|
||||
export function getIP(req: Request): IPAddress {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {getHash} from "./getHash";
|
||||
import { getHash } from "./getHash";
|
||||
import { HashedValue } from "../types/hash.model";
|
||||
import { ActionType, VideoID } from "../types/segments.model";
|
||||
import { UserID } from "../types/user.model";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {config} from "../config";
|
||||
import { config } from "../config";
|
||||
|
||||
const minimumPrefix = config.minimumPrefix || "3";
|
||||
const maximumPrefix = config.maximumPrefix || "32"; // Half the hash.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {db} from "../databases/databases";
|
||||
import { db } from "../databases/databases";
|
||||
|
||||
/**
|
||||
* Returns true if the user is considered trustworthy. This happens after a user has made 5 submissions and has less than 60% downvoted submissions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {db} from "../databases/databases";
|
||||
import { db } from "../databases/databases";
|
||||
import { HashedUserID } from "../types/user.model";
|
||||
|
||||
export async function isUserVIP(userID: HashedUserID): Promise<boolean> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {config} from "../config";
|
||||
import { config } from "../config";
|
||||
|
||||
const enum LogLevel {
|
||||
ERROR = "ERROR",
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Service, VideoID, VideoIDHash } from "../types/segments.model";
|
||||
import { UserID } from "../types/user.model";
|
||||
|
||||
async function get<T>(fetchFromDB: () => Promise<T>, key: string): Promise<T> {
|
||||
const {err, reply} = await redis.getAsync(key);
|
||||
const { err, reply } = await redis.getAsync(key);
|
||||
|
||||
if (!err && reply) {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {config} from "../config";
|
||||
import {Logger} from "./logger";
|
||||
import redis, {Callback} from "redis";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "./logger";
|
||||
import redis, { Callback } from "redis";
|
||||
|
||||
interface RedisSB {
|
||||
get(key: string, callback?: Callback<string | null>): void;
|
||||
@@ -13,10 +13,10 @@ interface RedisSB {
|
||||
let exportObject: RedisSB = {
|
||||
get: (key, callback?) => callback(null, undefined),
|
||||
getAsync: () =>
|
||||
new Promise((resolve) => resolve({err: null, reply: undefined})),
|
||||
new Promise((resolve) => resolve({ err: null, reply: undefined })),
|
||||
set: (key, value, callback) => callback(null, undefined),
|
||||
setAsync: () =>
|
||||
new Promise((resolve) => resolve({err: null, reply: undefined})),
|
||||
new Promise((resolve) => resolve({ err: null, reply: undefined })),
|
||||
delAsync: () =>
|
||||
new Promise((resolve) => resolve(null)),
|
||||
};
|
||||
@@ -26,8 +26,8 @@ if (config.redis) {
|
||||
const client = redis.createClient(config.redis);
|
||||
exportObject = client;
|
||||
|
||||
exportObject.getAsync = (key) => new Promise((resolve) => client.get(key, (err, reply) => resolve({err, reply})));
|
||||
exportObject.setAsync = (key, value) => new Promise((resolve) => client.set(key, value, (err, reply) => resolve({err, reply})));
|
||||
exportObject.getAsync = (key) => new Promise((resolve) => client.get(key, (err, reply) => resolve({ err, reply })));
|
||||
exportObject.setAsync = (key, value) => new Promise((resolve) => client.set(key, value, (err, reply) => resolve({ err, reply })));
|
||||
exportObject.delAsync = (...keys) => new Promise((resolve) => client.del(keys, (err) => resolve(err)));
|
||||
|
||||
client.on("error", function(error) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {config} from "../config";
|
||||
import {Logger} from "../utils/logger";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "../utils/logger";
|
||||
import axios from "axios";
|
||||
|
||||
function getVoteAuthorRaw(submissionCount: number, isVIP: boolean, isOwnSubmission: boolean): string {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {config} from "../config";
|
||||
import {Logger} from "./logger";
|
||||
import { config } from "../config";
|
||||
import { Logger } from "./logger";
|
||||
import { APIVideoData, APIVideoInfo } from "../types/youtubeApi.model";
|
||||
import DiskCache from "./diskCache";
|
||||
import axios from "axios";
|
||||
@@ -24,7 +24,7 @@ export class YouTubeAPI {
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.newLeafURLs || config.newLeafURLs.length <= 0) return {err: "NewLeaf URL not found", data: null};
|
||||
if (!config.newLeafURLs || config.newLeafURLs.length <= 0) return { err: "NewLeaf URL not found", data: null };
|
||||
|
||||
try {
|
||||
const result = await axios.get(`${config.newLeafURLs[Math.floor(Math.random() * config.newLeafURLs.length)]}/api/v1/videos/${videoID}`);
|
||||
@@ -45,7 +45,7 @@ export class YouTubeAPI {
|
||||
return { err: result.statusText, data: null };
|
||||
}
|
||||
} catch (err) {
|
||||
return {err: err as string | boolean, data: null};
|
||||
return { err: err as string | boolean, data: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user