fix: wrong field type in migrateToV3.ts
improve: use single threaded ffmpeg to reduce peak CPU utilization update: database-changelog.md & database-structure.md
This commit is contained in:
parent
1cd6d7b639
commit
8cf17838f4
@ -1,11 +1,107 @@
|
||||
# Database Schema Documentation
|
||||
# Database Schema Changelog
|
||||
|
||||
This document outlines the changes made across different versions of
|
||||
database structure used in the OpenRewind, including tables and fields.
|
||||
|
||||
## Version 2 Schema Changes
|
||||
## Version 3 Schema Changes
|
||||
|
||||
Cooresponding version: Since 0.4.0
|
||||
Corresponding version: Since 0.5.0
|
||||
|
||||
### Update `encoding_task` Table
|
||||
|
||||
#### Change `createAt` to `createdAt`
|
||||
|
||||
The column `createAt` was renamed to `createdAt` for consistency.
|
||||
|
||||
```sql
|
||||
ALTER TABLE encoding_task RENAME COLUMN createAt TO createdAt;
|
||||
```
|
||||
|
||||
#### Convert `createdAt` to Unix Timestamp
|
||||
|
||||
The `createdAt` column was updated to store Unix timestamps instead of formatted timestamps.
|
||||
|
||||
```typescript
|
||||
const rows = db.prepare(`SELECT id, createdAt FROM encoding_task`).all() as { [x: string]: unknown; id: unknown; }[];
|
||||
const updateStmt = db.prepare(`UPDATE encoding_task SET createdAt_new = ? WHERE id = ?`);
|
||||
rows.forEach((row) => {
|
||||
const unixTimestamp = convertTimestampToUnix(row.createdAt as string);
|
||||
updateStmt.run(unixTimestamp, row.id);
|
||||
});
|
||||
```
|
||||
|
||||
### Update `frame` Table
|
||||
|
||||
#### Change `createAt` to `createdAt`
|
||||
|
||||
The column `createAt` was renamed to `createdAt` for consistency.
|
||||
|
||||
```sql
|
||||
ALTER TABLE frame RENAME COLUMN createAt TO createdAt;
|
||||
```
|
||||
|
||||
#### Convert `createdAt` to Unix Timestamp
|
||||
|
||||
The `createdAt` column was updated to store Unix timestamps instead of formatted timestamps.
|
||||
|
||||
```typescript
|
||||
const rows = db.prepare(`SELECT id, createdAt FROM frame`).all() as { [x: string]: unknown; id: unknown; }[];
|
||||
const updateStmt = db.prepare(`UPDATE frame SET createdAt_new = ? WHERE id = ?`);
|
||||
rows.forEach((row) => {
|
||||
const unixTimestamp = convertTimestampToUnix(row.createdAt as string);
|
||||
updateStmt.run(unixTimestamp, row.id);
|
||||
});
|
||||
```
|
||||
|
||||
### Update `segments` Table
|
||||
|
||||
#### Rename Columns for Consistency
|
||||
|
||||
The columns `startAt` and `endAt` were renamed to `startedAt` and `endedAt` respectively.
|
||||
|
||||
```sql
|
||||
ALTER TABLE segments RENAME COLUMN startAt TO startedAt;
|
||||
ALTER TABLE segments RENAME COLUMN endAt TO endedAt;
|
||||
```
|
||||
|
||||
#### Convert `startedAt` and `endedAt` to Unix Timestamps
|
||||
|
||||
The `startedAt` and `endedAt` columns were updated to store Unix timestamps instead of formatted timestamps.
|
||||
|
||||
```typescript
|
||||
const rows = db.prepare(`SELECT id, startedAt, endedAt FROM segments`).all() as { [x: string]: unknown; id: unknown; }[];
|
||||
const updateStart = db.prepare(`UPDATE segments SET startedAt_new = ? WHERE id = ?`);
|
||||
const updateEnd = db.prepare(`UPDATE segments SET endedAt_new = ? WHERE id = ?`);
|
||||
rows.forEach((row) => {
|
||||
updateStart.run(convertTimestampToUnix(row.startedAt as string), row.id);
|
||||
updateEnd.run(convertTimestampToUnix(row.endedAt as string), row.id);
|
||||
});
|
||||
```
|
||||
|
||||
### Drop Deprecated `encoded` Column
|
||||
|
||||
The deprecated `encoded` column was removed from the `frame` table.
|
||||
|
||||
```sql
|
||||
ALTER TABLE frame DROP COLUMN encoded;
|
||||
```
|
||||
|
||||
### Summary of Changes
|
||||
|
||||
- **Update `encoding_task` Table:**
|
||||
- Renamed `createAt` to `createdAt`.
|
||||
- Converted `createdAt` to store Unix timestamps.
|
||||
- **Update `frame` Table:**
|
||||
- Renamed `createAt` to `createdAt`.
|
||||
- Converted `createdAt` to store Unix timestamps.
|
||||
- Dropped the deprecated `encoded` column.
|
||||
- **Update `segments` Table:**
|
||||
- Renamed `startAt` and `endAt` to `startedAt` and `endedAt` respectively.
|
||||
- Converted `startedAt` and `endedAt` to store Unix timestamps.
|
||||
|
||||
## Version 2 Schema
|
||||
|
||||
Corresponding version: 0.4.0
|
||||
|
||||
### New Table: `config`
|
||||
|
||||
@ -105,7 +201,7 @@ UPDATE frame SET encodeStatus = CASE WHEN encoded THEN 2 ELSE 0 END;
|
||||
|
||||
## Version 1 Schema
|
||||
|
||||
Cooresponding version: 0.3.x
|
||||
Corresponding version: 0.3.x
|
||||
|
||||
### Table: `frame`
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
# Database Schema Documentation (Version 2)
|
||||
# Database Schema Documentation (Version 3)
|
||||
|
||||
This document outlines the current structure of the database schema used in the application.
|
||||
It includes tables, fields, and their descriptions.
|
||||
This document outlines the current structure of the database schema used in the application. It includes tables, fields, and their descriptions.
|
||||
|
||||
## Table: `config`
|
||||
|
||||
@ -14,9 +13,7 @@ Stores configuration data.
|
||||
|
||||
### Key: version
|
||||
|
||||
The current database schema version, represented as a integer.
|
||||
Since the `config` table does not exist in V1, the version must be at least 2.
|
||||
|
||||
The current database schema version, represented as an integer. Since the `config` table does not exist in V1, the version must be at least 2.
|
||||
|
||||
## Table: `frame`
|
||||
|
||||
@ -25,14 +22,13 @@ Stores information about individual frames.
|
||||
| Column Name | Data Type | Constraints/Default | Description |
|
||||
|-------------------|-----------|---------------------------------|-----------------------------------------------------------|
|
||||
| `id` | INTEGER | PRIMARY KEY, AUTOINCREMENT | Unique identifier for each frame. |
|
||||
| `createAt` | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Timestamp when the frame was created. |
|
||||
| `createdAt` | REAL | | Timestamp when the frame was created. |
|
||||
| `imgFilename` | TEXT | | Filename of the image associated with the frame. |
|
||||
| `segmentID` | INTEGER | NULL, FOREIGN KEY (segments.id) | ID of the segment to which the frame belongs. |
|
||||
| `videoPath` | TEXT | NULL | Relative path to the video file if the frame was encoded. |
|
||||
| `videoFrameIndex` | INTEGER | NULL | Index of the frame within the encoded video. |
|
||||
| `collectionID` | INTEGER | NULL | ID of the collection to which the frame belongs. |
|
||||
| `encodeStatus` | INTEGER | 0 | Indicates the encoding status of the frame. |
|
||||
|
||||
| `encodeStatus` | INTEGER | DEFAULT 0 | Indicates the encoding status of the frame. |
|
||||
|
||||
### Status Description
|
||||
|
||||
@ -53,15 +49,13 @@ Stores recognition data associated with frames.
|
||||
|
||||
## Table: `segments`
|
||||
|
||||
A segment is a period of time when a user uses a particular application.
|
||||
While capturing the screen, OpenRewind detects the currently active window.
|
||||
When it finds that the currently active window has changed to another application, a new segment will start.
|
||||
A segment is a period of time when a user uses a particular application. While capturing the screen, OpenRewind detects the currently active window. When it finds that the currently active window has changed to another application, a new segment will start.
|
||||
|
||||
| Column Name | Data Type | Constraints/Default | Description |
|
||||
|---------------|-----------|----------------------------|------------------------------------------------------|
|
||||
| `id` | INTEGER | PRIMARY KEY, AUTOINCREMENT | Unique identifier for each segment. |
|
||||
| `startAt` | TIMESTAMP | | Timestamp when the segment starts. |
|
||||
| `endAt` | TIMESTAMP | | Timestamp when the segment ends. |
|
||||
| `startedAt` | REAL | | Timestamp when the segment starts. |
|
||||
| `endedAt` | REAL | | Timestamp when the segment ends. |
|
||||
| `title` | TEXT | | Title of the segment. |
|
||||
| `appName` | TEXT | | Name of the application associated with the segment. |
|
||||
| `appPath` | TEXT | | Path to the application. |
|
||||
@ -77,7 +71,7 @@ Stores encoding tasks that are queued for processing.
|
||||
| Column Name | Data Type | Constraints/Default | Description |
|
||||
|-------------|-----------|----------------------------|--------------------------------------|
|
||||
| `id` | INTEGER | PRIMARY KEY, AUTOINCREMENT | Unique ID for the task. |
|
||||
| `createAt` | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Timestamp when the task was created. |
|
||||
| `createdAt` | REAL | | Timestamp when the task was created. |
|
||||
| `status` | INTEGER | DEFAULT 0 | Indicates the status of the task. |
|
||||
|
||||
### Task status Description
|
||||
@ -85,17 +79,16 @@ Stores encoding tasks that are queued for processing.
|
||||
- `0`: Pending
|
||||
- `1`: In Progress
|
||||
- `2`: Completed
|
||||
- Once the task was set to this status, it will be imminently deleted by a trigger mentioned below.
|
||||
- Once the task was set to this status, it will be imminently deleted by a trigger mentioned below.
|
||||
|
||||
## Table: `encoding_task_data`
|
||||
|
||||
Stores the frames that need to be encoded for the encoding task
|
||||
Stores the frames that need to be encoded for the encoding task.
|
||||
|
||||
| Column Name | Data Type | Constraints/Default | Description |
|
||||
|------------------|-----------|-------------------------------------|------------------------------------------------------|
|
||||
| `encodingTaskID` | INTEGER | FOREIGN KEY (encoding_task.id) | ID for the encoding task associated with this frame. |
|
||||
| `frame` | INTEGER | PRIMARY KEY, FOREIGN KEY (frame.id) | ID for the frame associated with the encoding task. |
|
||||
| `encodingTaskID` | TIMESTAMP | FOREIGN KEY (encoding_task.id) | ID for the encoding task associated with this frame. |
|
||||
|
||||
|
||||
## Virtual Table: `text_search`
|
||||
|
||||
@ -112,8 +105,7 @@ Used for full-text search on recognition data.
|
||||
|
||||
### `recognition_data_after_insert`
|
||||
|
||||
Triggered after inserting a new row into `recognition_data`.
|
||||
Inserts a new row into `text_search` with the same data.
|
||||
Triggered after inserting a new row into `recognition_data`. Inserts a new row into `text_search` with the same data.
|
||||
|
||||
```sql
|
||||
CREATE TRIGGER IF NOT EXISTS recognition_data_after_insert AFTER INSERT ON recognition_data
|
||||
@ -125,8 +117,7 @@ END;
|
||||
|
||||
### `recognition_data_after_update`
|
||||
|
||||
Triggered after updating a row in `recognition_data`.
|
||||
Updates the associated `text_search` row.
|
||||
Triggered after updating a row in `recognition_data`. Updates the associated `text_search` row.
|
||||
|
||||
```sql
|
||||
CREATE TRIGGER IF NOT EXISTS recognition_data_after_update AFTER UPDATE ON recognition_data
|
||||
@ -139,8 +130,7 @@ END;
|
||||
|
||||
### `recognition_data_after_delete`
|
||||
|
||||
Triggered after deleting a row from `recognition_data`.
|
||||
Deletes the associated `text_search` row.
|
||||
Triggered after deleting a row from `recognition_data`. Deletes the associated `text_search` row.
|
||||
|
||||
```sql
|
||||
CREATE TRIGGER IF NOT EXISTS recognition_data_after_delete AFTER DELETE ON recognition_data
|
||||
@ -151,11 +141,10 @@ END;
|
||||
|
||||
### `delete_encoding_task`
|
||||
|
||||
Triggered after updating the `status` of an encoding task to `2` (Completed).
|
||||
Deletes the associated `encoding_task_data` and `encoding_task` rows.
|
||||
Triggered after updating the `status` of an encoding task to `2` (Completed). Deletes the associated `encoding_task_data` and `encoding_task` rows.
|
||||
|
||||
```sql
|
||||
CREATE TRIGGER delete_encoding_task
|
||||
CREATE TRIGGER IF NOT EXISTS delete_encoding_task
|
||||
AFTER UPDATE OF status
|
||||
ON encoding_task
|
||||
BEGIN
|
||||
@ -165,5 +154,4 @@ BEGIN
|
||||
DELETE FROM encoding_task
|
||||
WHERE id = OLD.id AND NEW.status = 2;
|
||||
END;
|
||||
|
||||
```
|
||||
```
|
@ -1,5 +1,5 @@
|
||||
import { Database } from "better-sqlite3";
|
||||
import { exec, spawnSync } from "child_process";
|
||||
import { exec } from "child_process";
|
||||
import fs from "fs";
|
||||
import path, { join } from "path";
|
||||
import type { EncodingTask, Frame } from "./schema";
|
||||
@ -7,10 +7,10 @@ import sizeOf from "image-size";
|
||||
import { getEncodingTempDir, getRecordingsDir, getScreenshotsDir } from "../utils/backend.js";
|
||||
import cache from "memory-cache";
|
||||
|
||||
const ENCODING_INTERVAL = 10000; // 10 sec
|
||||
const CHECK_TASK_INTERVAL = 5000; // 5 sec
|
||||
const MIN_FRAMES_TO_ENCODE = 60; // At least 10 mins (0.5fps)
|
||||
const CONCURRENCY = 1; // Number of concurrent encoding tasks
|
||||
const FRAME_RATE = 0.5;
|
||||
const THREE_MINUTES = 180;
|
||||
const MIN_FRAMES_TO_ENCODE = THREE_MINUTES * FRAME_RATE;
|
||||
const CONCURRENCY = 1;
|
||||
|
||||
// Detect and insert encoding tasks
|
||||
export function checkFramesForEncoding(db: Database) {
|
||||
@ -114,9 +114,9 @@ export function processEncodingTasks(db: Database) {
|
||||
cache.put("tasksPerforming", [...tasksPerforming, taskId.toString()]);
|
||||
|
||||
const videoPath = path.join(getRecordingsDir(), `${taskId}.mp4`);
|
||||
const ffmpegCommand = `ffmpeg -f concat -safe 0 -i "${metaFilePath}" -c:v libx264 -r 30 "${videoPath}"`;
|
||||
const ffmpegCommand = `ffmpeg -f concat -safe 0 -i "${metaFilePath}" -c:v libx264 -r 30 -threads 1 "${videoPath}"`;
|
||||
console.log("FFMPEG", ffmpegCommand);
|
||||
exec(ffmpegCommand, (error, stdout, stderr) => {
|
||||
exec(ffmpegCommand, (error, _stdout, _stderr) => {
|
||||
if (error) {
|
||||
console.error(`FFmpeg error: ${error.message}`);
|
||||
// Roll back transaction
|
||||
|
@ -12,7 +12,7 @@ function transformEncodingTask(db: Database) {
|
||||
const createTableSql = `
|
||||
CREATE TABLE IF NOT EXISTS encoding_task_new (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
createdAt REAL,
|
||||
status INT DEFAULT 0
|
||||
);
|
||||
|
||||
@ -41,7 +41,7 @@ function transformFrame(db: Database) {
|
||||
const createTableSql = `
|
||||
CREATE TABLE frame_new(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
createdAt REAL,
|
||||
imgFilename TEXT,
|
||||
segmentID INTEGER NULL,
|
||||
videoPath TEXT NULL,
|
||||
|
Loading…
Reference in New Issue
Block a user