75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import { findClosestSnapshot, getLatestSnapshot, hasAtLeast2Snapshots } from "db/snapshotSchedule";
|
|
import { truncate } from "utils/truncate";
|
|
import { closetMilestone } from "./exec/snapshotTick";
|
|
import { HOUR, MINUTE } from "@core/lib";
|
|
import type { Psql } from "@core/db/psql.d";
|
|
import { updateETA } from "db/eta";
|
|
|
|
const log = (value: number, base: number = 10) => Math.log(value) / Math.log(base);
|
|
|
|
const getFactor = (x: number) => {
|
|
const a = 1.054;
|
|
const b = 4.5;
|
|
const c = 100;
|
|
const u = 0.601;
|
|
const g = 455;
|
|
if (x > g) {
|
|
return log(b / log(x + 1), a);
|
|
} else {
|
|
return log(b / log(x + c), a) + u;
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Returns the minimum ETA in hours for the next snapshot
|
|
* @param client - Postgres client
|
|
* @param aid - aid of the video
|
|
* @returns ETA in hours
|
|
*/
|
|
export const getAdjustedShortTermETA = async (sql: Psql, aid: number) => {
|
|
const latestSnapshot = await getLatestSnapshot(sql, aid);
|
|
// Immediately dispatch a snapshot if there is no snapshot yet
|
|
if (!latestSnapshot) return 0;
|
|
const snapshotsEnough = await hasAtLeast2Snapshots(sql, aid);
|
|
if (!snapshotsEnough) return 0;
|
|
|
|
const currentTimestamp = new Date().getTime();
|
|
const timeIntervals = [3 * MINUTE, 20 * MINUTE, HOUR, 3 * HOUR, 6 * HOUR, 72 * HOUR];
|
|
const originalWeight = [3, 5, 3, 2, 2, 3];
|
|
const weight = originalWeight.map((x) => x / originalWeight.reduce((a, b) => a + b, 0));
|
|
const DELTA = 0.00001;
|
|
let minETAHours = Infinity;
|
|
let avgSpeed = 0;
|
|
|
|
const target = closetMilestone(latestSnapshot.views);
|
|
const viewsToIncrease = target - latestSnapshot.views;
|
|
const factor = truncate(getFactor(viewsToIncrease), 4.5, 100);
|
|
|
|
for (const timeInterval of timeIntervals) {
|
|
const date = new Date(currentTimestamp - timeInterval);
|
|
const snapshot = await findClosestSnapshot(sql, aid, date);
|
|
if (!snapshot) continue;
|
|
const hoursDiff = (latestSnapshot.created_at - snapshot.created_at) / HOUR;
|
|
const viewsDiff = latestSnapshot.views - snapshot.views;
|
|
if (viewsDiff <= 0) continue;
|
|
const speed = viewsDiff / (hoursDiff + DELTA);
|
|
avgSpeed += speed * weight[timeIntervals.indexOf(timeInterval)];
|
|
const eta = viewsToIncrease / (speed + DELTA);
|
|
const adjustedETA = eta / factor;
|
|
if (adjustedETA < minETAHours) {
|
|
minETAHours = adjustedETA;
|
|
}
|
|
}
|
|
|
|
if (isNaN(minETAHours)) {
|
|
minETAHours = Infinity;
|
|
}
|
|
|
|
const remaining = closetMilestone(latestSnapshot.views, true) - latestSnapshot.views;
|
|
const avgETAHours = remaining / (avgSpeed + DELTA);
|
|
|
|
await updateETA(sql, aid, avgETAHours, avgSpeed, latestSnapshot.views);
|
|
|
|
return minETAHours;
|
|
};
|