add: endpoint /timeline & /frame/:id in backend server
improve: simplify the migration code
This commit is contained in:
parent
fb70acab00
commit
f53616f345
@ -12,26 +12,23 @@ function migrateTo(version: number, db: Database) {
|
||||
}
|
||||
}
|
||||
|
||||
function getVersion(db: Database): number {
|
||||
const stmt = db.prepare(`SELECT value FROM config WHERE key = 'version';`);
|
||||
const data = stmt.get() as { value: string };
|
||||
const version = data.value;
|
||||
return parseInt(version);
|
||||
}
|
||||
|
||||
export function migrate(db: Database) {
|
||||
const configTableExists =
|
||||
db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='config';`).get()
|
||||
!== undefined;
|
||||
db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='config';`).get() !==
|
||||
undefined;
|
||||
if (!configTableExists) {
|
||||
migrateToV2(db);
|
||||
}
|
||||
let databaseVersion = parseInt(
|
||||
(
|
||||
db.prepare(`SELECT value FROM config WHERE key = 'version';`).get() as
|
||||
{ value: any }
|
||||
).value
|
||||
);
|
||||
let databaseVersion = getVersion(db);
|
||||
while (databaseVersion < CURRENT_VERSION) {
|
||||
migrateTo(databaseVersion, db);
|
||||
databaseVersion = parseInt(
|
||||
(
|
||||
db.prepare(`SELECT value FROM config WHERE key = 'version';`).get() as
|
||||
{ value: any }
|
||||
).value
|
||||
);
|
||||
databaseVersion = getVersion(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ app.on("ready", () => {
|
||||
setInterval(processEncodingTasks, 10000, db);
|
||||
setInterval(deleteEncodedScreenshots, 5000, db);
|
||||
dbConnection = db;
|
||||
cache.put("server:dbConnection", dbConnection);
|
||||
});
|
||||
mainWindow = createMainWindow(port, () => (mainWindow = null));
|
||||
settingsWindow = createSettingsWindow(port, () => (settingsWindow = null));
|
||||
@ -107,6 +108,8 @@ app.on("ready", () => {
|
||||
|
||||
app.on("will-quit", () => {
|
||||
dbConnection?.close();
|
||||
if (screenshotInterval)
|
||||
clearInterval(screenshotInterval);
|
||||
});
|
||||
|
||||
// app.on("window-all-closed", () => {
|
||||
|
@ -1,17 +1,75 @@
|
||||
import { Hono } from 'hono'
|
||||
import { Hono } from "hono";
|
||||
import cache from "memory-cache";
|
||||
import { join } from "path";
|
||||
import fs from "fs";
|
||||
import { Database } from "better-sqlite3";
|
||||
import type { Frame } from "../backend/schema";
|
||||
import { getScreenshotsDir } from "../utils/backend.js";
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
app.use(async (c, next) => {
|
||||
const key = cache.get("server:APIKey");
|
||||
if (key && c.req.header("x-api-key") !== key) {
|
||||
c.res = undefined
|
||||
c.res = undefined;
|
||||
c.res = c.json({ error: "Invalid API key" }, 401);
|
||||
}
|
||||
await next();
|
||||
})
|
||||
});
|
||||
|
||||
app.get('/ping', (c) => c.text('pong'))
|
||||
app.get("/ping", (c) => c.text("pong"));
|
||||
|
||||
export default app;
|
||||
app.get("/timeline", async (c) => {
|
||||
const { offset = 0, limit = 50 } = c.req.query();
|
||||
const db = cache.get("server:dbConnection");
|
||||
|
||||
const frames = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT id, createdAt, imgFilename, videoPath, videoFrameIndex
|
||||
FROM frame
|
||||
ORDER BY createdAt DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`
|
||||
)
|
||||
.all(limit, offset);
|
||||
|
||||
return c.json(frames);
|
||||
});
|
||||
|
||||
app.get("/frame/:id", async (c) => {
|
||||
const { id } = c.req.param();
|
||||
const db: Database = cache.get("server:dbConnection");
|
||||
|
||||
const frame = db
|
||||
.prepare(
|
||||
`
|
||||
SELECT imgFilename, videoPath, videoFrameIndex
|
||||
FROM frame
|
||||
WHERE id = ?
|
||||
`
|
||||
)
|
||||
.get(id) as Frame;
|
||||
|
||||
if (!frame) {
|
||||
return c.json({ error: "Frame not found" }, 404);
|
||||
}
|
||||
|
||||
// If frame is from video, decode and return frame
|
||||
if (frame.videoPath) {
|
||||
// TODO: Implement video frame extraction
|
||||
return c.json({ error: "Video frame extraction not implemented" }, 501);
|
||||
}
|
||||
|
||||
// Return image file
|
||||
const imagePath = join(getScreenshotsDir(), frame.imgFilename);
|
||||
const imageBuffer = fs.readFileSync(imagePath);
|
||||
return new Response(imageBuffer, {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "image/png"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default app;
|
||||
|
Loading…
Reference in New Issue
Block a user