mirror of
https://github.com/captbaritone/webamp.git
synced 2026-01-23 18:25:30 +00:00
121 lines
3 KiB
TypeScript
121 lines
3 KiB
TypeScript
import UserContext from "../data/UserContext";
|
|
import SkinModel from "../data/SkinModel";
|
|
import { knex } from "../db";
|
|
import { setHashesForSkin } from "../skinHash";
|
|
import Shooter from "../shooter";
|
|
import { screenshot } from "./screenshotSkin";
|
|
import * as Skins from "../data/skins";
|
|
import { SkinType } from "../types";
|
|
import { getSkinType } from "../addSkin";
|
|
|
|
// TODO Move this into the function so that we clean up on each run?
|
|
|
|
async function getExtractionError(skin: SkinModel): Promise<string | null> {
|
|
try {
|
|
await skin.getZip();
|
|
} catch (e) {
|
|
return e.message;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// A task to download a skin and refresh all the data we scrape from it
|
|
|
|
export async function getSkinsToRefresh(
|
|
ctx: UserContext,
|
|
n: number,
|
|
neverDone = false
|
|
): Promise<SkinModel[]> {
|
|
let query = knex("skins")
|
|
.leftJoin("refreshes", "skins.md5", "refreshes.skin_md5")
|
|
.where("skin_type", 1)
|
|
.orderBy("refreshes.timestamp", "asc")
|
|
.limit(n);
|
|
|
|
if (neverDone) {
|
|
query = query.where("refreshes.skin_md5", null);
|
|
}
|
|
const skins = await query.select();
|
|
|
|
return skins.map((row) => new SkinModel(ctx, row));
|
|
}
|
|
|
|
export async function refreshSkins(
|
|
skins: SkinModel[],
|
|
options: { noScreenshot: boolean }
|
|
): Promise<void> {
|
|
if (options.noScreenshot) {
|
|
while (skins.length > 0) {
|
|
const skin = skins.pop();
|
|
// @ts-ignore
|
|
await refresh(skin, null);
|
|
}
|
|
return;
|
|
}
|
|
const shooterLogger = () => {
|
|
// Don't log
|
|
};
|
|
await Shooter.withShooter(async (shooter: Shooter) => {
|
|
for (const [i, skin] of skins.entries()) {
|
|
await refresh(skin, shooter);
|
|
// We end up caching a lot of stuff (the whole skin/zip) on the model, so we can't just leave these around for the whole process.
|
|
delete skins[i];
|
|
}
|
|
}, shooterLogger);
|
|
}
|
|
|
|
export async function _refresh(
|
|
skin: SkinModel,
|
|
shooter: Shooter | null
|
|
): Promise<void> {
|
|
const extractionError = await getExtractionError(skin);
|
|
if (extractionError != null) {
|
|
throw new Error(extractionError);
|
|
}
|
|
await setHashesForSkin(skin);
|
|
await Skins.setContentHash(skin.getMd5());
|
|
|
|
let skinType: SkinType;
|
|
try {
|
|
skinType = await getSkinType(await skin.getZip());
|
|
} catch (_e) {
|
|
throw new Error("Not a skin (no main.bmp/skin.xml)");
|
|
}
|
|
if (skinType !== "CLASSIC") {
|
|
// TODO:
|
|
// Reviews are invalid
|
|
// Delete from algolia
|
|
// Delete screenshot
|
|
// Tweets are invalid
|
|
throw new Error("Skin type mismatch");
|
|
}
|
|
|
|
// Retake screenshot
|
|
if (shooter != null) {
|
|
await screenshot(skin, shooter);
|
|
}
|
|
|
|
await knex("refreshes").insert({
|
|
skin_md5: skin.getMd5(),
|
|
});
|
|
}
|
|
|
|
export async function refresh(
|
|
skin: SkinModel,
|
|
shooter: Shooter | null
|
|
): Promise<void> {
|
|
if (skin.getSkinType() !== "CLASSIC") {
|
|
throw new Error("Can't refresh non-classic skins");
|
|
}
|
|
try {
|
|
await _refresh(skin, shooter);
|
|
} catch (e) {
|
|
console.error(e);
|
|
await knex("refreshes").insert({
|
|
skin_md5: skin.getMd5(),
|
|
error: e.message,
|
|
});
|
|
return;
|
|
}
|
|
}
|