116 lines
3.8 KiB
TypeScript
116 lines
3.8 KiB
TypeScript
#!/usr/bin/env ts-node
|
|
import path from 'path';
|
|
import fs from 'fs/promises';
|
|
import { gameDB } from "../routes/games/store";
|
|
|
|
async function main() {
|
|
const gamesDir = path.resolve(__dirname, "../../db/games");
|
|
let files: string[] = [];
|
|
try {
|
|
files = await fs.readdir(gamesDir);
|
|
} catch (e) {
|
|
console.error("Failed to read games dir", gamesDir, e);
|
|
process.exit(2);
|
|
}
|
|
|
|
if (!gameDB.db) {
|
|
await gameDB.init();
|
|
}
|
|
|
|
let db = gameDB.db;
|
|
|
|
if (!db.sequelize) {
|
|
console.error("DB did not expose sequelize; cannot proceed.");
|
|
process.exit(4);
|
|
}
|
|
|
|
for (const f of files) {
|
|
// ignore dotfiles and .bk backup files (we don't want to import backups)
|
|
if (f.startsWith(".") || f.endsWith(".bk")) continue;
|
|
const full = path.join(gamesDir, f);
|
|
try {
|
|
const stat = await fs.stat(full);
|
|
if (!stat.isFile()) continue;
|
|
const raw = await fs.readFile(full, "utf8");
|
|
const game = JSON.parse(raw);
|
|
// Derive id from filename (strip .json if present)
|
|
const idStr = f.endsWith(".json") ? f.slice(0, -5) : f;
|
|
const id = isNaN(Number(idStr)) ? idStr : Number(idStr);
|
|
|
|
// derive a friendly name from the saved game when present
|
|
const nameCandidate = game && (game.name || game.id) ? String(game.name || game.id) : undefined;
|
|
|
|
try {
|
|
if (typeof id === "number") {
|
|
// numeric filename: use the typed helper
|
|
await db.saveGame(game);
|
|
console.log(`Saved game id=${id}`);
|
|
if (nameCandidate) {
|
|
try {
|
|
await db.sequelize.query("UPDATE games SET name=:name WHERE id=:id", {
|
|
replacements: { id, name: nameCandidate },
|
|
});
|
|
} catch (_) {
|
|
// ignore name update failure
|
|
}
|
|
}
|
|
} else {
|
|
// string filename: try to find an existing row by path and save via id;
|
|
// otherwise insert a new row with path and the JSON game.
|
|
let found: any[] = [];
|
|
try {
|
|
found = await db.sequelize.query("SELECT id FROM games WHERE path=:path", {
|
|
replacements: { path: idStr },
|
|
type: db.Sequelize.QueryTypes.SELECT,
|
|
});
|
|
} catch (qe) {
|
|
found = [];
|
|
}
|
|
|
|
if (found && found.length) {
|
|
const foundId = found[0].id;
|
|
await db.saveGame(game);
|
|
console.log(`Saved game path=${idStr} -> id=${foundId}`);
|
|
if (nameCandidate) {
|
|
try {
|
|
await db.sequelize.query("UPDATE games SET name=:name WHERE id=:id", {
|
|
replacements: { id: foundId, name: nameCandidate },
|
|
});
|
|
} catch (_) {
|
|
// ignore
|
|
}
|
|
}
|
|
} else {
|
|
// ensure state column exists before inserting a new row
|
|
try {
|
|
await db.sequelize.query("ALTER TABLE games ADD COLUMN state TEXT");
|
|
} catch (_) {
|
|
// ignore
|
|
}
|
|
const payload = JSON.stringify(game);
|
|
if (nameCandidate) {
|
|
await db.sequelize.query("INSERT INTO games (path, state, name) VALUES(:path, :state, :name)", {
|
|
replacements: { path: idStr, state: payload, name: nameCandidate },
|
|
});
|
|
} else {
|
|
await db.sequelize.query("INSERT INTO games (path, state) VALUES(:path, :state)", {
|
|
replacements: { path: idStr, state: payload },
|
|
});
|
|
}
|
|
console.log(`Inserted game path=${idStr}`);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error("Failed to save game", idStr, e);
|
|
}
|
|
} catch (e) {
|
|
console.error("Failed to read/parse", full, e);
|
|
}
|
|
}
|
|
|
|
console.log("Import complete");
|
|
process.exit(0);
|
|
}
|
|
|
|
main();
|