webamp/packages/skin-database/cli.ts
2021-01-18 13:37:39 -05:00

185 lines
5.6 KiB
JavaScript
Executable file

#!/usr/bin/env node
import fs from "fs";
import { knex } from "./db";
import { argv } from "yargs";
import logger from "./logger";
import DiscordWinstonTransport from "./DiscordWinstonTransport";
import * as Skins from "./data/skins";
import Discord from "discord.js";
import { tweet } from "./tasks/tweet";
import { addSkinFromBuffer } from "./addSkin";
import * as SkinHash from "./skinHash";
import * as Analyser from "./analyser";
import { searchIndex } from "./algolia";
import { scrapeLikeData } from "./tasks/scrapeLikes";
import { screenshot } from "./tasks/screenshotSkin";
import Shooter from "./shooter";
import UserContext from "./data/UserContext";
import { integrityCheck } from "./tasks/integrityCheck";
import { ensureWebampLinks, syncWithArchive } from "./tasks/syncWithArchive";
import { syncFromArchive } from "./tasks/syncFromArchive";
import { processUserUploads } from "./api/processUserUploads";
import DiscordEventHandler from "./api/DiscordEventHandler";
async function main() {
const client = new Discord.Client();
// The Winston transport logs in the client.
await DiscordWinstonTransport.addToLogger(client, logger);
try {
switch (argv._[0]) {
case "ensure-webamp-links":
await ensureWebampLinks();
break;
case "sync-from-ia":
await syncFromArchive();
break;
case "sync-ia":
await syncWithArchive();
break;
case "integity-check":
await integrityCheck();
break;
case "reject": {
const md5 = argv._[1];
if (md5 == null) {
return;
}
await Skins.reject(new UserContext("CLI"), md5);
break;
}
case "screenshots": {
const stdinBuffer = fs.readFileSync(0); // STDIN_FILENO = 0
let md5s = stdinBuffer.toString().trim().split("\n");
if (md5s.length === 0) {
md5s = await Skins.getSkinsToShoot(1000);
}
await Shooter.withShooter(async (shooter: Shooter) => {
for (const md5 of md5s) {
await screenshot(md5, shooter);
}
});
break;
}
case "readme": {
const rows = await knex.raw(
'SELECT md5 FROM files LEFT JOIN skins on skins.md5 = files.skin_md5 WHERE source_attribution = "Web API" AND readme_text IS NULL;'
);
const hashes = rows.map(({ md5 }) => md5);
for (const hash of hashes) {
console.log(`Setting readme for ${hash}`);
await Analyser.setReadmeForSkin(hash);
}
break;
}
case "content-hash": {
const rows = await knex("skins")
.leftJoin("archive_files", "archive_files.skin_md5", "=", "skins.md5")
.whereNot("skin_md5", null)
.where("content_hash", null)
// This is just because our URL schema sucks
.where("skin_type", Skins.SKIN_TYPE.CLASSIC)
.groupBy("md5")
.select("md5");
console.log(`Found ${rows.length} rows`);
for (const { md5 } of rows) {
const hash = await Skins.setContentHash(md5);
console.log(hash);
}
break;
}
case "hash": {
const rows = await knex("skins")
.leftJoin("archive_files", "archive_files.skin_md5", "=", "skins.md5")
.where("skin_md5", null)
// This is just because our URL schema sucks
.where("skin_type", Skins.SKIN_TYPE.CLASSIC)
.select("md5");
for (const { md5 } of rows) {
console.log(md5);
try {
await SkinHash.setHashesForSkin(md5);
await Skins.setContentHash(md5);
} catch (e) {
console.error(e);
}
}
break;
}
case "tweet": {
console.log("tweet");
await tweet(client, null);
break;
}
case "stats": {
console.log(await Skins.getStats());
break;
}
case "add": {
const filePath = argv._[1];
const buffer = fs.readFileSync(filePath);
console.log(await addSkinFromBuffer(buffer, filePath, "cli-user"));
break;
}
case "delete": {
const md5 = argv._[1];
await Skins.deleteSkin(md5);
break;
}
case "index": {
console.log(await Skins.updateSearchIndex(argv._[1]));
break;
}
case "process": {
const handler = new DiscordEventHandler();
await processUserUploads((event) => handler.handle(event));
handler.dispose();
break;
}
case "add-missing-indexes": {
// eslint-disable-next-line no-inner-declarations
async function indexPage(pageNumber: number): Promise<void> {
const page = await Skins.getMuseumPage({
offset: pageNumber * 500,
first: 500,
});
const toCheck = page.map(({ md5 }) => md5);
const found = await searchIndex.getObjects(toCheck, {
attributesToRetrieve: ["objectId"],
});
// console.log({ toCheck, found });
const missing = toCheck.filter((_md5, i) => {
return found.results[i] == null;
});
console.log(
`Found ${missing.length} missing skins on page ${pageNumber}`
);
console.log(await Skins.updateSearchIndexs(missing));
}
for (let i = 0; i < 140; i++) {
await indexPage(i);
}
break;
}
case "tweet-data": {
await scrapeLikeData();
break;
}
default:
console.log(`Unknown command ${argv._[0]}`);
}
} finally {
knex.destroy();
logger.close();
client.destroy();
}
}
main();