This commit is contained in:
Ajay 2024-08-11 13:49:48 -04:00
commit d2df5cef98
5 changed files with 78 additions and 22 deletions

View file

@ -64,7 +64,7 @@ jobs:
env: env:
PG_USER: ci_db_user PG_USER: ci_db_user
PG_PASS: ci_db_pass PG_PASS: ci_db_pass
run: docker-compose -f docker/docker-compose-ci.yml up -d run: docker compose -f docker/docker-compose-ci.yml up -d
- name: Check running containers - name: Check running containers
run: docker ps run: docker ps
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3

View file

@ -241,7 +241,7 @@
| title | TEXT | not null | | title | TEXT | not null |
| original | INTEGER | default 0 | | original | INTEGER | default 0 |
| userID | TEXT | not null | userID | TEXT | not null
| service | TEXT not null | | service | TEXT | not null |
| hashedVideoID | TEXT | not null | | hashedVideoID | TEXT | not null |
| timeSubmitted | INTEGER | not null | | timeSubmitted | INTEGER | not null |
| UUID | TEXT | not null, primary key | UUID | TEXT | not null, primary key
@ -277,7 +277,6 @@
| Name | Type | | | Name | Type | |
| -- | :--: | -- | | -- | :--: | -- |
| UUID | TEXT | not null |
| original | INTEGER | default 0 | | original | INTEGER | default 0 |
| userID | TEXT | not null | | userID | TEXT | not null |
| service | TEXT | not null | | service | TEXT | not null |
@ -305,8 +304,8 @@
### thumbnailVotes ### thumbnailVotes
| index | field | | Name | Type | |
| -- | :--: | | -- | :--: | -- |
| UUID | TEXT | not null, primary key | | UUID | TEXT | not null, primary key |
| votes | INTEGER | not null, default 0 | | votes | INTEGER | not null, default 0 |
| locked | INTEGER |not null, default 0 | | locked | INTEGER |not null, default 0 |

View file

@ -27,10 +27,11 @@ export async function getChapterNames(req: Request, res: Response): Promise<Resp
FROM "videoInfo" FROM "videoInfo"
WHERE "channelID" = ? WHERE "channelID" = ?
) AND "description" != '' ) AND "description" != ''
AND similarity("description", ?) >= 0.1
GROUP BY "description" GROUP BY "description"
ORDER BY SUM("votes"), similarity("description", ?) DESC ORDER BY SUM("votes"), similarity("description", ?) DESC
LIMIT 5;` LIMIT 5;`
, [channelID, description]) as { description: string }[]; , [channelID, description, description]) as { description: string }[];
if (descriptions?.length > 0) { if (descriptions?.length > 0) {
return res.status(200).json(descriptions.map(d => ({ return res.status(200).json(descriptions.map(d => ({

View file

@ -85,6 +85,7 @@ export async function postBranding(req: Request, res: Response) {
const existingIsLocked = !!existingUUID && (await db.prepare("get", `SELECT "locked" from "titleVotes" where "UUID" = ?`, [existingUUID]))?.locked; const existingIsLocked = !!existingUUID && (await db.prepare("get", `SELECT "locked" from "titleVotes" where "UUID" = ?`, [existingUUID]))?.locked;
if (existingUUID != undefined && isBanned) return; // ignore votes on existing details from banned users if (existingUUID != undefined && isBanned) return; // ignore votes on existing details from banned users
if (downvote && existingIsLocked && !isVip) { if (downvote && existingIsLocked && !isVip) {
sendWebhooks(videoID, existingUUID, voteType).catch((e) => Logger.error(e));
errorCode = 403; errorCode = 403;
return; return;
} }
@ -113,7 +114,7 @@ export async function postBranding(req: Request, res: Response) {
await db.prepare("run", `UPDATE "titleVotes" as tv SET "locked" = 0 FROM "titles" t WHERE tv."UUID" = t."UUID" AND tv."UUID" != ? AND t."videoID" = ?`, [UUID, videoID]); await db.prepare("run", `UPDATE "titleVotes" as tv SET "locked" = 0 FROM "titles" t WHERE tv."UUID" = t."UUID" AND tv."UUID" != ? AND t."videoID" = ?`, [UUID, videoID]);
} }
sendWebhooks(videoID, UUID).catch((e) => Logger.error(e)); sendWebhooks(videoID, UUID, voteType).catch((e) => Logger.error(e));
} }
})(), (async () => { })(), (async () => {
if (thumbnail) { if (thumbnail) {
@ -290,14 +291,34 @@ export async function verifyOldSubmissions(hashedUserID: HashedUserID, verificat
} }
} }
async function sendWebhooks(videoID: VideoID, UUID: BrandingUUID) { async function sendWebhooks(videoID: VideoID, UUID: BrandingUUID, voteType: BrandingVoteType) {
const lockedSubmission = await db.prepare("get", `SELECT "titleVotes"."votes", "titles"."title", "titles"."userID" FROM "titles" JOIN "titleVotes" ON "titles"."UUID" = "titleVotes"."UUID" WHERE "titles"."videoID" = ? AND "titles"."UUID" != ? AND "titleVotes"."locked" = 1`, [videoID, UUID]); const currentSubmission = await db.prepare(
"get",
`SELECT
"titles"."title",
"titleVotes"."locked",
"titles"."userID",
"titleVotes"."votes"-"titleVotes"."downvotes"+"titleVotes"."verification" AS "score"
FROM "titles" JOIN "titleVotes" ON "titles"."UUID" = "titleVotes"."UUID"
WHERE "titles"."UUID" = ?`,
[UUID]);
if (lockedSubmission) { // Unlocked title getting more upvotes than the locked one
const currentSubmission = await db.prepare("get", `SELECT "titleVotes"."votes", "titles"."title" FROM "titles" JOIN "titleVotes" ON "titles"."UUID" = "titleVotes"."UUID" WHERE "titles"."UUID" = ?`, [UUID]); if (voteType === BrandingVoteType.Upvote) {
const lockedSubmission = await db.prepare(
"get",
`SELECT
"titles"."title",
"titles"."userID",
"titleVotes"."votes"-"titleVotes"."downvotes"+"titleVotes"."verification" AS "score"
FROM "titles" JOIN "titleVotes" ON "titles"."UUID" = "titleVotes"."UUID"
WHERE "titles"."videoID" = ?
AND "titles"."UUID" != ?
AND "titleVotes"."locked" = 1`,
[videoID, UUID]);
// Time to warn that there may be an issue // Time to warn that there may be an issue
if (currentSubmission.votes - lockedSubmission.votes > 2) { if (lockedSubmission && currentSubmission.score - lockedSubmission.score > 2) {
const usernameRow = await db.prepare("get", `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [lockedSubmission.userID]); const usernameRow = await db.prepare("get", `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [lockedSubmission.userID]);
const data = await getVideoDetails(videoID); const data = await getVideoDetails(videoID);
@ -305,7 +326,7 @@ async function sendWebhooks(videoID: VideoID, UUID: BrandingUUID) {
"embeds": [{ "embeds": [{
"title": data?.title, "title": data?.title,
"url": `https://www.youtube.com/watch?v=${videoID}`, "url": `https://www.youtube.com/watch?v=${videoID}`,
"description": `**${lockedSubmission.votes}** Votes vs **${currentSubmission.votes}**\ "description": `**${lockedSubmission.score}** score vs **${currentSubmission.score}**\
\n\n**Locked title:** ${lockedSubmission.title}\ \n\n**Locked title:** ${lockedSubmission.title}\
\n**New title:** ${currentSubmission.title}\ \n**New title:** ${currentSubmission.title}\
\n\n**Submitted by:** ${usernameRow?.userName ?? ""}\n${lockedSubmission.userID}`, \n\n**Submitted by:** ${usernameRow?.userName ?? ""}\n${lockedSubmission.userID}`,
@ -329,6 +350,38 @@ async function sendWebhooks(videoID: VideoID, UUID: BrandingUUID) {
}); });
} }
} }
// Downvotes on locked title
if (voteType === BrandingVoteType.Downvote && currentSubmission.locked === 1) {
const usernameRow = await db.prepare("get", `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [currentSubmission.userID]);
const data = await getVideoDetails(videoID);
axios.post(config.discordDeArrowLockedWebhookURL, {
"embeds": [{
"title": data?.title,
"url": `https://www.youtube.com/watch?v=${videoID}`,
"description": `Locked title with **${currentSubmission.score}** score received a downvote\
\n\n**Locked title:** ${currentSubmission.title}\
\n**Submitted by:** ${usernameRow?.userName ?? ""}\n${currentSubmission.userID}`,
"color": 10813440,
"thumbnail": {
"url": getMaxResThumbnail(videoID),
},
}],
})
.then(res => {
if (res.status >= 400) {
Logger.error("Error sending reported submission Discord hook");
Logger.error(JSON.stringify((res.data)));
Logger.error("\n");
}
})
.catch(err => {
Logger.error("Failed to send reported submission Discord hook.");
Logger.error(JSON.stringify(err));
Logger.error("\n");
});
}
} }
async function checkForWrongVideoDuration(videoID: VideoID, duration: number): Promise<boolean> { async function checkForWrongVideoDuration(videoID: VideoID, duration: number): Promise<boolean> {

View file

@ -16,17 +16,18 @@ describe("getChapterNames", function () {
"Weird name", "Weird name",
"A different one", "A different one",
"Something else", "Something else",
"Weirder name",
]; ];
const nameSearch = (query: string, expected: string): Promise<void> => { const nameSearch = (query: string, expected: string | null, expectedResults: number): Promise<void> => {
const expectedData = [{ const expectedData = [{
description: expected description: expected
}]; }];
return client.get(`${endpoint}?description=${query}&channelID=${chapterChannelID}`) return client.get(`${endpoint}?description=${query}&channelID=${chapterChannelID}`)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, expectedResults == 0 ? 404 : 200);
assert.strictEqual(res.data.length, chapterNames.length); assert.strictEqual(res.data.length, expectedResults);
assert.ok(partialDeepEquals(res.data, expectedData)); if (expected != null) assert.ok(partialDeepEquals(res.data, expectedData));
}); });
}; };
@ -35,11 +36,13 @@ describe("getChapterNames", function () {
await insertChapter(db, chapterNames[0], { videoID: chapterNamesVid1, startTime: 60, endTime: 80 }); await insertChapter(db, chapterNames[0], { videoID: chapterNamesVid1, startTime: 60, endTime: 80 });
await insertChapter(db, chapterNames[1], { videoID: chapterNamesVid1, startTime: 70, endTime: 75 }); await insertChapter(db, chapterNames[1], { videoID: chapterNamesVid1, startTime: 70, endTime: 75 });
await insertChapter(db, chapterNames[2], { videoID: chapterNamesVid1, startTime: 71, endTime: 76 }); await insertChapter(db, chapterNames[2], { videoID: chapterNamesVid1, startTime: 71, endTime: 76 });
await insertChapter(db, chapterNames[3], { videoID: chapterNamesVid1, startTime: 72, endTime: 77 });
await insertVideoInfo(db, chapterNamesVid1, chapterChannelID); await insertVideoInfo(db, chapterNamesVid1, chapterChannelID);
}); });
it("Search for 'weird'", () => nameSearch("weird", chapterNames[0])); it("Search for 'weird' (2 results)", () => nameSearch("weird", chapterNames[0], 2));
it("Search for 'different'", () => nameSearch("different", chapterNames[1])); it("Search for 'different' (1 result)", () => nameSearch("different", chapterNames[1], 1));
it("Search for 'something'", () => nameSearch("something", chapterNames[2])); it("Search for 'something' (1 result)", () => nameSearch("something", chapterNames[2], 1));
it("Search for 'unrelated' (0 result)", () => nameSearch("unrelated", null, 0));
}); });