mirror of
https://github.com/captbaritone/webamp.git
synced 2026-01-23 18:25:30 +00:00
170 lines
4.6 KiB
TypeScript
170 lines
4.6 KiB
TypeScript
import { getScreenshotUrl, getSkinUrl } from "./skins";
|
|
import { TweetStatus, SkinRow, ReviewRow } from "../types";
|
|
import UserContext, { ctxWeakMapMemoize } from "./UserContext";
|
|
import TweetModel, { TweetDebugData } from "./TweetModel";
|
|
import IaItemModel, { IaItemDebugData } from "./IaItemModel";
|
|
import FileModel, { FileDebugData } from "./FileModel";
|
|
import { MD5_REGEX } from "../utils";
|
|
import DataLoader from "dataloader";
|
|
import { knex } from "../db";
|
|
|
|
export default class SkinModel {
|
|
constructor(readonly ctx: UserContext, readonly row: SkinRow) {}
|
|
|
|
static async fromMd5(
|
|
ctx: UserContext,
|
|
md5: string
|
|
): Promise<SkinModel | null> {
|
|
const row = await getSkinLoader(ctx).load(md5);
|
|
return row == null ? null : new SkinModel(ctx, row);
|
|
}
|
|
|
|
static async fromAnything(
|
|
ctx: UserContext,
|
|
anything: string
|
|
): Promise<SkinModel | null> {
|
|
const md5Match = anything.match(MD5_REGEX);
|
|
if (md5Match != null) {
|
|
const md5 = md5Match[1];
|
|
const found = await SkinModel.fromMd5(ctx, md5);
|
|
if (found != null) {
|
|
return found;
|
|
}
|
|
}
|
|
const iaItem = await IaItemModel.fromAnything(ctx, anything);
|
|
if (iaItem != null) {
|
|
return iaItem.getSkin();
|
|
}
|
|
const tweet = await TweetModel.fromAnything(ctx, anything);
|
|
if (tweet != null) {
|
|
return tweet.getSkin();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
static async exists(ctx: UserContext, md5: string): Promise<boolean> {
|
|
const row = await getSkinLoader(ctx).load(md5);
|
|
return row != null;
|
|
}
|
|
|
|
async tweeted(): Promise<boolean> {
|
|
return (await this.getTweet()) != null;
|
|
}
|
|
|
|
async getTweet(): Promise<TweetModel | null> {
|
|
const tweets = await this.getTweets();
|
|
return tweets[0] || null;
|
|
}
|
|
|
|
async getTweets(): Promise<TweetModel[]> {
|
|
return TweetModel.fromMd5(this.ctx, this.row.md5);
|
|
}
|
|
|
|
getIaItem(): Promise<IaItemModel | null> {
|
|
return IaItemModel.fromMd5(this.ctx, this.row.md5);
|
|
}
|
|
|
|
getReviews(): Promise<ReviewRow[]> {
|
|
return getReviewsLoader(this.ctx).load(this.row.md5);
|
|
}
|
|
|
|
getFiles(): Promise<FileModel[]> {
|
|
return FileModel.fromMd5(this.ctx, this.row.md5);
|
|
}
|
|
|
|
async getIsNsfw(): Promise<boolean> {
|
|
const reviews = await this.getReviews();
|
|
return reviews.some((review) => review.review === "NSFW");
|
|
}
|
|
|
|
async getTweetStatus(): Promise<TweetStatus> {
|
|
const tweet = await this.getTweet();
|
|
if (tweet != null) {
|
|
"TWEETED";
|
|
}
|
|
const reviewRows = await this.getReviews();
|
|
const reviews = new Set(reviewRows.map((row) => row.review));
|
|
if (reviews.has("NSFW")) {
|
|
return "NSFW";
|
|
}
|
|
if (reviews.has("REJECTED")) {
|
|
return "REJECTED";
|
|
}
|
|
if (reviews.has("APPROVED")) {
|
|
return "APPROVED";
|
|
}
|
|
|
|
return "UNREVIEWED";
|
|
}
|
|
|
|
async getFileName(): Promise<string> {
|
|
const files = await this.getFiles();
|
|
if (files.length === 0) {
|
|
throw new Error(`Could not find file for skin with md5 ${this.getMd5()}`);
|
|
}
|
|
return files[0].getFileName();
|
|
}
|
|
|
|
getMd5(): string {
|
|
return this.row.md5;
|
|
}
|
|
|
|
getEmails(): string[] {
|
|
const { emails } = this.row;
|
|
return emails ? emails.split(" ") : [];
|
|
}
|
|
|
|
getReadme(): string | null {
|
|
return this.row.readme_text || null;
|
|
}
|
|
|
|
getMuseumUrl(): string {
|
|
return `https://skins.webamp.org/skin/${this.row.md5}`;
|
|
}
|
|
getWebampUrl(): string {
|
|
return `https://webamp.org?skinUrl=${this.getSkinUrl()}`;
|
|
}
|
|
getScreenshotUrl(): string {
|
|
return getScreenshotUrl(this.row.md5);
|
|
}
|
|
getSkinUrl(): string {
|
|
return getSkinUrl(this.row.md5);
|
|
}
|
|
|
|
async debug(): Promise<{
|
|
row: SkinRow;
|
|
reviews: ReviewRow[];
|
|
tweets: TweetDebugData[];
|
|
files: FileDebugData[];
|
|
iaItem: IaItemDebugData | null;
|
|
}> {
|
|
const tweets = await this.getTweets();
|
|
const files = await this.getFiles();
|
|
const iaItem = await this.getIaItem();
|
|
return {
|
|
row: this.row,
|
|
reviews: await this.getReviews(),
|
|
tweets: await Promise.all(tweets.map((tweet) => tweet.debug())),
|
|
files: await Promise.all(files.map((file) => file.debug())),
|
|
iaItem: iaItem == null ? null : await iaItem.debug(),
|
|
};
|
|
}
|
|
}
|
|
|
|
const getSkinLoader = ctxWeakMapMemoize<DataLoader<string, SkinRow | null>>(
|
|
() =>
|
|
new DataLoader(async (md5s) => {
|
|
const rows = await knex("skins").whereIn("md5", md5s).select();
|
|
return md5s.map((md5) => rows.find((x) => x.md5 === md5));
|
|
})
|
|
);
|
|
|
|
const getReviewsLoader = ctxWeakMapMemoize<DataLoader<string, ReviewRow[]>>(
|
|
() =>
|
|
new DataLoader(async (md5s) => {
|
|
const rows = await knex("skin_reviews")
|
|
.whereIn("skin_md5", md5s)
|
|
.select();
|
|
return md5s.map((md5) => rows.filter((x) => x.skin_md5 === md5));
|
|
})
|
|
);
|