From 02e628f5330403bc578d1e92a54d7d4ab08b54f2 Mon Sep 17 00:00:00 2001
From: Ajay Ramachandran
Date: Sat, 20 Mar 2021 01:08:33 -0400
Subject: [PATCH] Setup csv exports and html status page
---
.gitignore | 1 +
docker/docker-compose.yml | 1 +
src/app.ts | 11 +++++--
src/routes/dumpDatabase.ts | 61 ++++++++++++++++++++++++++++++++++++++
4 files changed, 71 insertions(+), 3 deletions(-)
create mode 100644 src/routes/dumpDatabase.ts
diff --git a/.gitignore b/.gitignore
index 3cff924..dd78e49 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,6 +99,7 @@ test/databases/sponsorTimes.db
test/databases/sponsorTimes.db-shm
test/databases/sponsorTimes.db-wal
test/databases/private.db
+docker/database-export
# Config files
config.json
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index a54a3c0..4ee69ee 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -7,6 +7,7 @@ services:
- database.env
volumes:
- database-data:/var/lib/postgresql/data
+ - ./database-export/:/opt/exports
ports:
- 127.0.0.1:5432:5432
redis:
diff --git a/src/app.ts b/src/app.ts
index 098e5f3..026f74c 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -26,6 +26,7 @@ import {userCounter} from './middleware/userCounter';
import {loggerMiddleware} from './middleware/logger';
import {corsMiddleware} from './middleware/cors';
import {rateLimitMiddleware} from './middleware/requestRateLimit';
+import dumpDatabase from './routes/dumpDatabase';
export function createServer(callback: () => void) {
@@ -127,7 +128,11 @@ function setupRoutes(app: Express) {
//get if user is a vip
app.post('/api/segmentShift', postSegmentShift);
- app.get('/database.db', function (req: Request, res: Response) {
- res.sendFile("./databases/sponsorTimes.db", {root: "./"});
- });
+ if (config.postgres) {
+ app.get('/database', dumpDatabase);
+ } else {
+ app.get('/database.db', function (req: Request, res: Response) {
+ res.sendFile("./databases/sponsorTimes.db", {root: "./"});
+ });
+ }
}
diff --git a/src/routes/dumpDatabase.ts b/src/routes/dumpDatabase.ts
new file mode 100644
index 0000000..fb8363d
--- /dev/null
+++ b/src/routes/dumpDatabase.ts
@@ -0,0 +1,61 @@
+import {db} from '../databases/databases';
+import {Logger} from '../utils/logger';
+import {Request, Response} from 'express';
+import { config } from '../config';
+
+const ONE_MINUTE = 1000 * 60;
+
+const styleHeader = ``
+
+const licenseHeader = `The API and database follow CC BY-NC-SA 4.0 unless you have explicit permission.
+Attribution Template
+If you need to use the database or API in a way that violates this license, contact me with your reason and I may grant you access under a different license.
`;
+
+const tables = [{
+ name: "sponsorTimes",
+ order: "timeSubmitted"
+},
+{
+ name: "userNames"
+},
+{
+ name: "categoryVotes"
+},
+{
+ name: "noSegments",
+},
+{
+ name: "warnings",
+ order: "issueTime"
+},
+{
+ name: "vipUsers"
+}];
+
+const links: string = tables.map((table) => `${table.name}.csv
`)
+ .reduce((acc, url) => acc + url, "");
+
+let lastUpdate = 0;
+
+export default function dumpDatabase(req: Request, res: Response) {
+ if (!config.postgres) {
+ res.status(404).send("Not supported on this instance");
+ return;
+ }
+
+ const now = Date.now();
+ const updateQueued = now - lastUpdate > ONE_MINUTE;
+
+ res.status(200).send(`${styleHeader}
+ SponsorBlock database dumps
${licenseHeader}${links}
+ ${updateQueued ? `Update queued.` : ``} Last updated: ${lastUpdate ? new Date(lastUpdate).toUTCString() : `Unknown`}`);
+
+ if (updateQueued) {
+ lastUpdate = Date.now();
+
+ for (const table of tables) {
+ db.prepare('run', `COPY (SELECT * FROM "${table.name}"${table.order ? ` ORDER BY "${table.order}"` : ``})
+ TO '/opt/exports/${table.name}.csv' WITH (FORMAT CSV, HEADER true);`);
+ }
+ }
+}
\ No newline at end of file