Merge pull request #581 from mini-bomba/videoduration-inconsistency

Make returned video duration in getBranding.ts consistent
This commit is contained in:
Ajay Ramachandran 2024-05-05 01:28:22 -04:00 committed by GitHub
commit 622c3f27d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 36 additions and 9 deletions

View file

@ -45,7 +45,8 @@ export async function getVideoBranding(res: Response, videoID: VideoID, service:
const getSegments = () => db.prepare( const getSegments = () => db.prepare(
"all", "all",
`SELECT "startTime", "endTime", "category", "videoDuration" FROM "sponsorTimes" `SELECT "startTime", "endTime", "category", "videoDuration" FROM "sponsorTimes"
WHERE "votes" > -2 AND "shadowHidden" = 0 AND "hidden" = 0 AND "actionType" = 'skip' AND "videoID" = ? AND "service" = ?`, WHERE "votes" > -2 AND "shadowHidden" = 0 AND "hidden" = 0 AND "actionType" = 'skip' AND "videoID" = ? AND "service" = ?
ORDER BY "timeSubmitted" ASC`,
[videoID, service], [videoID, service],
{ useReplica: true } { useReplica: true }
) as Promise<BrandingSegmentDBResult[]>; ) as Promise<BrandingSegmentDBResult[]>;
@ -110,7 +111,8 @@ export async function getVideoBrandingByHash(videoHashPrefix: VideoIDHash, servi
const getSegments = () => db.prepare( const getSegments = () => db.prepare(
"all", "all",
`SELECT "videoID", "startTime", "endTime", "category", "videoDuration" FROM "sponsorTimes" `SELECT "videoID", "startTime", "endTime", "category", "videoDuration" FROM "sponsorTimes"
WHERE "votes" > -2 AND "shadowHidden" = 0 AND "hidden" = 0 AND "actionType" = 'skip' AND "hashedVideoID" LIKE ? AND "service" = ?`, WHERE "votes" > -2 AND "shadowHidden" = 0 AND "hidden" = 0 AND "actionType" = 'skip' AND "hashedVideoID" LIKE ? AND "service" = ?
ORDER BY "timeSubmitted" ASC`,
[`${videoHashPrefix}%`, service], [`${videoHashPrefix}%`, service],
{ useReplica: true } { useReplica: true }
) as Promise<BrandingSegmentHashDBResult[]>; ) as Promise<BrandingSegmentHashDBResult[]>;
@ -200,11 +202,13 @@ async function filterAndSortBranding(videoID: VideoID, returnUserID: boolean, fe
})) }))
.filter((a) => fetchAll || a.votes >= 0 || a.locked) as ThumbnailResult[]; .filter((a) => fetchAll || a.votes >= 0 || a.locked) as ThumbnailResult[];
const videoDuration = dbSegments.filter(s => s.videoDuration !== 0)[0]?.videoDuration ?? null;
return { return {
titles, titles,
thumbnails, thumbnails,
randomTime: findRandomTime(videoID, dbSegments), randomTime: findRandomTime(videoID, dbSegments, videoDuration),
videoDuration: dbSegments[0]?.videoDuration ?? null videoDuration: videoDuration,
}; };
} }
@ -233,7 +237,7 @@ async function shouldKeepSubmission(submissions: BrandingDBSubmission[], type: B
return (_, index) => shouldKeep[index]; return (_, index) => shouldKeep[index];
} }
export function findRandomTime(videoID: VideoID, segments: BrandingSegmentDBResult[]): number { export function findRandomTime(videoID: VideoID, segments: BrandingSegmentDBResult[], videoDuration: number): number {
let randomTime = SeedRandom.alea(videoID)(); let randomTime = SeedRandom.alea(videoID)();
// Don't allow random times past 90% of the video if no endcard // Don't allow random times past 90% of the video if no endcard
@ -243,7 +247,7 @@ export function findRandomTime(videoID: VideoID, segments: BrandingSegmentDBResu
if (segments.length === 0) return randomTime; if (segments.length === 0) return randomTime;
const videoDuration = segments[0].videoDuration || Math.max(...segments.map((s) => s.endTime)); videoDuration ||= Math.max(...segments.map((s) => s.endTime)); // use highest end time as a fallback here
// There are segments, treat this as a relative time in the chopped up video // There are segments, treat this as a relative time in the chopped up video
const sorted = segments.sort((a, b) => a.startTime - b.startTime); const sorted = segments.sort((a, b) => a.startTime - b.startTime);

View file

@ -13,6 +13,7 @@ describe("getBranding", () => {
const videoIDEmpty = "videoID4"; const videoIDEmpty = "videoID4";
const videoIDRandomTime = "videoID5"; const videoIDRandomTime = "videoID5";
const videoIDUnverified = "videoID6"; const videoIDUnverified = "videoID6";
const videoIDvidDuration = "videoID7";
const videoID1Hash = getHash(videoID1, 1).slice(0, 4); const videoID1Hash = getHash(videoID1, 1).slice(0, 4);
const videoID2LockedHash = getHash(videoID2Locked, 1).slice(0, 4); const videoID2LockedHash = getHash(videoID2Locked, 1).slice(0, 4);
@ -20,6 +21,7 @@ describe("getBranding", () => {
const videoIDEmptyHash = "aaaa"; const videoIDEmptyHash = "aaaa";
const videoIDRandomTimeHash = getHash(videoIDRandomTime, 1).slice(0, 4); const videoIDRandomTimeHash = getHash(videoIDRandomTime, 1).slice(0, 4);
const videoIDUnverifiedHash = getHash(videoIDUnverified, 1).slice(0, 4); const videoIDUnverifiedHash = getHash(videoIDUnverified, 1).slice(0, 4);
const videoIDvidDurationHash = getHash(videoIDUnverified, 1).slice(0, 4);
const endpoint = "/api/branding"; const endpoint = "/api/branding";
const getBranding = (params: Record<string, any>) => client({ const getBranding = (params: Record<string, any>) => client({
@ -40,6 +42,7 @@ describe("getBranding", () => {
const thumbnailQuery = `INSERT INTO "thumbnails" ("videoID", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?)`; const thumbnailQuery = `INSERT INTO "thumbnails" ("videoID", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?)`;
const thumbnailTimestampsQuery = `INSERT INTO "thumbnailTimestamps" ("UUID", "timestamp") VALUES (?, ?)`; const thumbnailTimestampsQuery = `INSERT INTO "thumbnailTimestamps" ("UUID", "timestamp") VALUES (?, ?)`;
const thumbnailVotesQuery = `INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden", "downvotes", "removed") VALUES (?, ?, ?, ?, ?, ?)`; const thumbnailVotesQuery = `INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden", "downvotes", "removed") VALUES (?, ?, ?, ?, ?, ?)`;
const segmentQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "description", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
await Promise.all([ await Promise.all([
db.prepare("run", titleQuery, [videoID1, "title1", 0, "userID1", Service.YouTube, videoID1Hash, 1, "UUID1"]), db.prepare("run", titleQuery, [videoID1, "title1", 0, "userID1", Service.YouTube, videoID1Hash, 1, "UUID1"]),
@ -107,9 +110,8 @@ describe("getBranding", () => {
db.prepare("run", thumbnailVotesQuery, ["UUID32T", 1, 0, 1, 0, 0]) db.prepare("run", thumbnailVotesQuery, ["UUID32T", 1, 0, 1, 0, 0])
]); ]);
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "description", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; await db.prepare("run", segmentQuery, [videoIDRandomTime, 1, 11, 1, 0, "uuidbranding1", "testman", 0, 50, "sponsor", "skip", "YouTube", 100, 0, 0, "", videoIDRandomTimeHash]);
await db.prepare("run", query, [videoIDRandomTime, 1, 11, 1, 0, "uuidbranding1", "testman", 0, 50, "sponsor", "skip", "YouTube", 100, 0, 0, "", videoIDRandomTimeHash]); await db.prepare("run", segmentQuery, [videoIDRandomTime, 20, 33, 2, 0, "uuidbranding2", "testman", 0, 50, "intro", "skip", "YouTube", 100, 0, 0, "", videoIDRandomTimeHash]);
await db.prepare("run", query, [videoIDRandomTime, 20, 33, 2, 0, "uuidbranding2", "testman", 0, 50, "intro", "skip", "YouTube", 100, 0, 0, "", videoIDRandomTimeHash]);
await Promise.all([ await Promise.all([
db.prepare("run", titleQuery, [videoIDUnverified, "title1", 0, "userID1", Service.YouTube, videoIDUnverifiedHash, 1, "UUID-uv-1"]), db.prepare("run", titleQuery, [videoIDUnverified, "title1", 0, "userID1", Service.YouTube, videoIDUnverifiedHash, 1, "UUID-uv-1"]),
@ -130,6 +132,17 @@ describe("getBranding", () => {
db.prepare("run", thumbnailVotesQuery, ["UUID-uv-2T", 2, 0, 0, 0, 0]), db.prepare("run", thumbnailVotesQuery, ["UUID-uv-2T", 2, 0, 0, 0, 0]),
db.prepare("run", thumbnailVotesQuery, ["UUID-uv-3T", 1, 0, 0, 0, 0]) db.prepare("run", thumbnailVotesQuery, ["UUID-uv-3T", 1, 0, 0, 0, 0])
]); ]);
// Video duration test segments
await Promise.all([
db.prepare("run", segmentQuery, [videoIDvidDuration, 0, 1, 0, 0, "uuidvd1", "testman", 10, 0, "sponsor", "skip", "YouTube", 0, 0, 0, "", videoIDvidDurationHash]), // visible, no vid duration
db.prepare("run", segmentQuery, [videoIDvidDuration, 0, 2, -2, 0, "uuidvd2", "testman", 11, 0, "sponsor", "skip", "YouTube", 10, 0, 0, "", videoIDvidDurationHash]), // downvoted
db.prepare("run", segmentQuery, [videoIDvidDuration, 0, 3, 0, 0, "uuidvd3", "testman", 12, 0, "sponsor", "skip", "YouTube", 10.1, 1, 0, "", videoIDvidDurationHash]), // hidden
db.prepare("run", segmentQuery, [videoIDvidDuration, 0, 4, 0, 0, "uuidvd4", "testman", 13, 0, "sponsor", "skip", "YouTube", 20.1, 0, 1, "", videoIDvidDurationHash]), // shadowhidden
db.prepare("run", segmentQuery, [videoIDvidDuration, 0, 5, 0, 0, "uuidvd5", "testman", 14, 0, "sponsor", "skip", "YouTube", 21.3, 0, 0, "", videoIDvidDurationHash]), // oldest visible w/ duration, should be picked
db.prepare("run", segmentQuery, [videoIDvidDuration, 0, 6, 0, 0, "uuidvd6", "testman", 15, 0, "sponsor", "skip", "YouTube", 21.37, 0, 0, "", videoIDvidDurationHash]), // not the oldest visible
db.prepare("run", segmentQuery, [videoIDvidDuration, 0, 7, -2, 0, "uuidvd7", "testman", 16, 0, "sponsor", "skip", "YouTube", 21.38, 0, 0, "", videoIDvidDurationHash]), // downvoted, not the oldest
]);
}); });
it("should get top titles and thumbnails", async () => { it("should get top titles and thumbnails", async () => {
@ -312,6 +325,16 @@ describe("getBranding", () => {
}); });
}); });
it("should get the correct video duration", async () => {
const correctDuration = 21.3;
const result1 = await getBranding({ videoID: videoIDvidDuration, fetchAll: true });
const result2 = await getBrandingByHash(videoIDvidDurationHash, { fetchAll: true });
assert.strictEqual(result1.data.videoDuration, correctDuration);
assert.strictEqual(result2.data[videoIDvidDuration].videoDuration, correctDuration);
});
async function checkVideo(videoID: string, videoIDHash: string, fetchAll: boolean, expected: { async function checkVideo(videoID: string, videoIDHash: string, fetchAll: boolean, expected: {
titles: TitleResult[], titles: TitleResult[],
thumbnails: ThumbnailResult[] thumbnails: ThumbnailResult[]