Compare commits
3 Commits
3d76a5ece5
...
96b4cecaec
Author | SHA1 | Date | |
---|---|---|---|
96b4cecaec | |||
94bd14db52 | |||
fb0c60a71e |
@ -34,7 +34,7 @@ function Image({ src }: { src: string }) {
|
||||
<img
|
||||
src={src}
|
||||
alt="Current frame"
|
||||
className="w-full h-full object-cover absolute inset-0"
|
||||
className="w-full h-full object-contain absolute inset-0"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -181,8 +181,6 @@ export default function RewindPage() {
|
||||
const newIndex = Math.min(Math.max(currentIndex - delta, 0), timeline.length - 1);
|
||||
const newFrameId = timeline[newIndex].id;
|
||||
|
||||
console.log(currentFrameId, lastAvaliableFrameId);
|
||||
|
||||
if (newFrameId !== currentFrameId) {
|
||||
setCurrentFrameId(newFrameId);
|
||||
// Preload adjacent images
|
||||
@ -212,9 +210,19 @@ export default function RewindPage() {
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="w-screen h-screen relative dark:text-white overflow-hidden"
|
||||
className="w-screen h-screen relative dark:text-white overflow-hidden bg-black"
|
||||
onWheel={handleScroll}
|
||||
>
|
||||
<img
|
||||
src={currentFrameId
|
||||
? images[currentFrameId] ||
|
||||
(lastAvaliableFrameId.current ? images[lastAvaliableFrameId.current] : "")
|
||||
: ""}
|
||||
alt="background"
|
||||
className="w-full h-full object-cover absolute inset-0 blur-lg"
|
||||
/>
|
||||
|
||||
|
||||
{/* Current image */}
|
||||
<Image
|
||||
src={
|
||||
@ -225,6 +233,8 @@ export default function RewindPage() {
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
{/* Time capsule */}
|
||||
<div
|
||||
className="absolute bottom-8 left-8 bg-zinc-800 text-white bg-opacity-80 backdrop-blur-lg
|
||||
|
@ -19,8 +19,9 @@ export function checkFramesForEncoding() {
|
||||
const stmt = db.prepare(`
|
||||
SELECT id, imgFilename, createdAt
|
||||
FROM frame
|
||||
WHERE encodeStatus = 0 AND imgFilename IS NOT NULL
|
||||
ORDER BY createdAt ASC;
|
||||
WHERE encodeStatus = 0
|
||||
AND imgFilename IS NOT NULL
|
||||
ORDER BY createdAt;
|
||||
`);
|
||||
const frames = stmt.all() as Frame[];
|
||||
|
||||
@ -52,19 +53,23 @@ export function checkFramesForEncoding() {
|
||||
if (chunkConditionSatisfied) {
|
||||
// Create new encoding task
|
||||
const taskStmt = db.prepare(`
|
||||
INSERT INTO encoding_task (status) VALUES (0);
|
||||
INSERT INTO encoding_task (status)
|
||||
VALUES (0);
|
||||
`);
|
||||
const taskId = taskStmt.run().lastInsertRowid;
|
||||
|
||||
// Insert frames into encoding_task_data
|
||||
const insertStmt = db.prepare(`
|
||||
INSERT INTO encoding_task_data (encodingTaskID, frame) VALUES (?, ?);
|
||||
INSERT INTO encoding_task_data (encodingTaskID, frame)
|
||||
VALUES (?, ?);
|
||||
`);
|
||||
for (const frame of buffer) {
|
||||
insertStmt.run(taskId, frame.id);
|
||||
db.prepare(
|
||||
`
|
||||
UPDATE frame SET encodeStatus = 1 WHERE id = ?;
|
||||
UPDATE frame
|
||||
SET encodeStatus = 1
|
||||
WHERE id = ?;
|
||||
`
|
||||
).run(frame.id);
|
||||
}
|
||||
@ -78,14 +83,21 @@ function deleteEncodedScreenshots() {
|
||||
const db = getDatabase();
|
||||
// TODO: double-check that the frame was really encoded into the video
|
||||
const stmt = db.prepare(`
|
||||
SELECT * FROM frame WHERE encodeStatus = 2 AND imgFilename IS NOT NULL;
|
||||
SELECT *
|
||||
FROM frame
|
||||
WHERE encodeStatus = 2
|
||||
AND imgFilename IS NOT NULL;
|
||||
`);
|
||||
const frames = stmt.all() as Frame[];
|
||||
for (const frame of frames) {
|
||||
if (!frame.imgFilename) continue;
|
||||
fs.unlinkSync(path.join(getScreenshotsDir(), frame.imgFilename));
|
||||
const imgPath = path.join(getScreenshotsDir(), frame.imgFilename!);
|
||||
if (fs.existsSync(imgPath)) {
|
||||
fs.unlinkSync(imgPath);
|
||||
}
|
||||
const updateStmt = db.prepare(`
|
||||
UPDATE frame SET imgFilename = NULL WHERE id = ?;
|
||||
UPDATE frame
|
||||
SET imgFilename = NULL
|
||||
WHERE id = ?;
|
||||
`);
|
||||
updateStmt.run(frame.id);
|
||||
}
|
||||
@ -97,7 +109,9 @@ function _deleteNonExistentScreenshots() {
|
||||
const filesInDir = new Set(fs.readdirSync(screenshotDir));
|
||||
|
||||
const dbStmt = db.prepare(`
|
||||
SELECT imgFilename FROM frame WHERE imgFilename IS NOT NULL;
|
||||
SELECT imgFilename
|
||||
FROM frame
|
||||
WHERE imgFilename IS NOT NULL;
|
||||
`);
|
||||
const dbFiles = dbStmt.all() as { imgFilename: string }[];
|
||||
const dbFileSet = new Set(dbFiles.map((f) => f.imgFilename));
|
||||
@ -118,7 +132,9 @@ export async function deleteUnnecessaryScreenshots() {
|
||||
export function deleteFrameFromDB(id: number) {
|
||||
const db = getDatabase();
|
||||
const deleteStmt = db.prepare(`
|
||||
DELETE FROM frame WHERE id = ?;
|
||||
DELETE
|
||||
FROM frame
|
||||
WHERE id = ?;
|
||||
`);
|
||||
deleteStmt.run(id);
|
||||
console.log(`Deleted frame ${id} from database`);
|
||||
@ -148,8 +164,7 @@ export function processEncodingTasks() {
|
||||
const stmt = db.prepare(`
|
||||
SELECT id, status
|
||||
FROM encoding_task
|
||||
WHERE status = 0
|
||||
LIMIT ?
|
||||
WHERE status = 0 LIMIT ?
|
||||
`);
|
||||
|
||||
const tasks = stmt.all(CONCURRENCY - tasksPerforming.length) as EncodingTask[];
|
||||
@ -161,7 +176,9 @@ export function processEncodingTasks() {
|
||||
|
||||
// Update task status as processing (1)
|
||||
const updateStmt = db.prepare(`
|
||||
UPDATE encoding_task SET status = 1 WHERE id = ?
|
||||
UPDATE encoding_task
|
||||
SET status = 1
|
||||
WHERE id = ?
|
||||
`);
|
||||
updateStmt.run(taskId);
|
||||
|
||||
@ -170,7 +187,7 @@ export function processEncodingTasks() {
|
||||
FROM encoding_task_data
|
||||
JOIN frame ON encoding_task_data.frame = frame.id
|
||||
WHERE encoding_task_data.encodingTaskID = ?
|
||||
ORDER BY frame.createdAt ASC
|
||||
ORDER BY frame.createdAt
|
||||
`);
|
||||
const frames = framesStmt.all(taskId) as Frame[];
|
||||
|
||||
@ -191,13 +208,19 @@ export function processEncodingTasks() {
|
||||
console.log(`Video ${videoPath} created successfully`);
|
||||
// Update task status to complete (2)
|
||||
const completeStmt = db.prepare(`
|
||||
UPDATE encoding_task SET status = 2 WHERE id = ?
|
||||
UPDATE encoding_task
|
||||
SET status = 2
|
||||
WHERE id = ?
|
||||
`);
|
||||
completeStmt.run(taskId);
|
||||
for (let frameIndex = 0; frameIndex < frames.length; frameIndex++) {
|
||||
const frame = frames[frameIndex];
|
||||
const updateFrameStmt = db.prepare(`
|
||||
UPDATE frame SET videoPath = ?, videoFrameIndex = ?, encodeStatus = 2 WHERE id = ?
|
||||
UPDATE frame
|
||||
SET videoPath = ?,
|
||||
videoFrameIndex = ?,
|
||||
encodeStatus = 2
|
||||
WHERE id = ?
|
||||
`);
|
||||
updateFrameStmt.run(`${taskId}.mp4`, frameIndex, frame.id);
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ function init(db: Database) {
|
||||
|
||||
export async function initDatabase() {
|
||||
const dbPath = getDatabaseDir();
|
||||
const db = new DB(dbPath, { verbose: console.log });
|
||||
const db = new DB(dbPath);
|
||||
const libSimpleExtensionPath = getLibSimpleExtensionPath();
|
||||
|
||||
db.loadExtension(libSimpleExtensionPath);
|
||||
|
@ -5,7 +5,6 @@ interface Task {
|
||||
id: TaskId;
|
||||
func: TaskFunction;
|
||||
interval?: number;
|
||||
maxInterval?: number;
|
||||
lastRun?: number;
|
||||
nextRun?: number;
|
||||
isPaused: boolean;
|
||||
@ -21,8 +20,6 @@ export interface TaskStatus {
|
||||
export class Scheduler {
|
||||
private tasks: Map<TaskId, Task> = new Map();
|
||||
private timer: NodeJS.Timeout | null = null;
|
||||
private nextTickTime: number | null = null;
|
||||
|
||||
constructor(private readonly minTickInterval: number = 500) {
|
||||
this.start();
|
||||
}
|
||||
@ -76,16 +73,6 @@ export class Scheduler {
|
||||
task.nextRun = now + task.interval!;
|
||||
}
|
||||
|
||||
const isTaskReadyForMaxIntervalRun =
|
||||
task.maxInterval && task.lastRun && now - task.lastRun >= task.maxInterval;
|
||||
if (isTaskReadyForMaxIntervalRun) {
|
||||
task.func();
|
||||
task.lastRun = now;
|
||||
if (task.interval) {
|
||||
task.nextRun = now + task.interval;
|
||||
}
|
||||
}
|
||||
|
||||
const isTaskNextRunEarlierThanNextTick = task.nextRun && task.nextRun < getNextTick();
|
||||
if (isTaskNextRunEarlierThanNextTick) {
|
||||
updateNextTick(task.nextRun!);
|
||||
@ -113,15 +100,12 @@ export class Scheduler {
|
||||
* @param id A unique string identifier for the task.
|
||||
* @param func The function to be executed by the task.
|
||||
* @param interval The interval (in milliseconds) between task executions.
|
||||
* @param maxInterval The maximum time (in milliseconds) that a task can wait before being executed.
|
||||
* If a task has not been executed in this amount of time, it will be executed immediately.
|
||||
*/
|
||||
addTask(id: TaskId, func: TaskFunction, interval?: number, maxInterval?: number): void {
|
||||
addTask(id: TaskId, func: TaskFunction, interval?: number): void {
|
||||
this.tasks.set(id, {
|
||||
id,
|
||||
func,
|
||||
interval,
|
||||
maxInterval,
|
||||
isPaused: false,
|
||||
lastRun: undefined,
|
||||
nextRun: interval ? Date.now() + interval : undefined
|
||||
@ -165,7 +149,7 @@ export class Scheduler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume a paused task, so that it can be executed according to its interval and maxInterval.
|
||||
* Resume a paused task, so that it can be executed according to its interval.
|
||||
*
|
||||
* @param id The unique string identifier for the task.
|
||||
*/
|
||||
|
@ -110,10 +110,10 @@ app.on("ready", () => {
|
||||
});
|
||||
});
|
||||
initDatabase().then((db) => {
|
||||
scheduler.addTask("screenshot", takeScreenshot, 2000, 2000);
|
||||
scheduler.addTask("check-encoding", checkFramesForEncoding, 5000, 10000);
|
||||
scheduler.addTask("process-encoding", processEncodingTasks, 10000, 30000);
|
||||
scheduler.addTask("delete-screenshots", deleteUnnecessaryScreenshots, 20000, 60000);
|
||||
scheduler.addTask("screenshot", takeScreenshot, 2000);
|
||||
scheduler.addTask("check-encoding", checkFramesForEncoding, 5000);
|
||||
scheduler.addTask("process-encoding", processEncodingTasks, 10000);
|
||||
scheduler.addTask("delete-screenshots", deleteUnnecessaryScreenshots, 20000);
|
||||
dbConnection = db;
|
||||
cache.put("server:dbConnection", dbConnection);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user