diff --git a/experiments/skin-database/addSkin.ts b/experiments/skin-database/addSkin.ts index 94516b03..151edea0 100644 --- a/experiments/skin-database/addSkin.ts +++ b/experiments/skin-database/addSkin.ts @@ -1,10 +1,10 @@ import * as Skins from "./data/skins"; import fs from "fs"; import md5Buffer from "md5"; -import S3 from "./s3"; +import * as S3 from "./s3"; import Shooter from "./shooter"; import _temp from "temp"; -import Analyser from "./analyser"; +import * as Analyser from "./analyser"; const temp = _temp.track(); diff --git a/experiments/skin-database/analyser.js b/experiments/skin-database/analyser.ts similarity index 72% rename from experiments/skin-database/analyser.js rename to experiments/skin-database/analyser.ts index c1529ad9..7e5ef440 100644 --- a/experiments/skin-database/analyser.js +++ b/experiments/skin-database/analyser.ts @@ -1,9 +1,9 @@ // Functions for deriving information from skins -const exec = require("child_process").exec; -const shellescape = require("shell-escape"); +import { exec } from "child_process"; +import shellescape from "shell-escape"; -function getColor(imgPath) { +export function getColor(imgPath: string): Promise { return new Promise((resolve, reject) => { const excapedImgPath = shellescape([imgPath]); const command = `convert ${excapedImgPath} -scale 1x1\! -format '%[pixel:u]' info:-`; @@ -16,5 +16,3 @@ function getColor(imgPath) { }); }); } - -module.exports = { getColor }; diff --git a/experiments/skin-database/data/skins.ts b/experiments/skin-database/data/skins.ts index 5c9b58d0..da3809e7 100644 --- a/experiments/skin-database/data/skins.ts +++ b/experiments/skin-database/data/skins.ts @@ -1,44 +1,11 @@ import db from "../db"; import path from "path"; -import S3 from "../s3"; +import * as S3 from "../s3"; import logger from "../logger"; +import { DBSkinRecord, SkinRecord, DBIARecord, TweetStatus } from "../types"; const skins = db.get("skins"); const iaItems = db.get("internetArchiveItems"); -type TweetStatus = "APPROVED" | "REJECTED" | "TWEETED" | "UNREVIEWED"; - -type DBSkinRecord = { - md5: string; - averageColor?: string; - emails?: string[]; - tweetUrl?: string; - twitterLikes?: number; - readmeText?: string; - filePaths: string[]; - imageHash?: string; - uploader?: string; -}; - -type DBIARecord = { - identifier: string; -}; - -type SkinRecord = { - md5: string; - averageColor?: string; - emails?: string[]; - tweetUrl?: string; - twitterLikes?: number; - readmeText?: string; - fileNames: string[]; - imageHash?: string; - uploader?: string; - screenshotUrl: string; - skinUrl: string; - canonicalFilename: string | null; - webampUrl: string; -}; - const TWEETABLE_QUERY = { tweeted: { $ne: true }, approved: true, @@ -240,7 +207,10 @@ async function getSkinToReview(): Promise<{ return { filename: canonicalFilename, md5 }; } -async function getSkinToTweet() { +async function getSkinToTweet(): Promise<{ + filename: string | null; + md5: string; +} | null> { const tweetables = await skins.aggregate([ { $match: TWEETABLE_QUERY }, { $sample: { size: 1 } }, @@ -289,6 +259,7 @@ async function setImageHash(md5: string, imageHash: string): Promise { await skins.findOneAndUpdate({ md5 }, { $set: { imageHash } }); } +// Deprecated. Use module exports module.exports = { addSkin, getMd5sMatchingImageHash, diff --git a/experiments/skin-database/discord-bot/commands/approve.js b/experiments/skin-database/discord-bot/commands/approve.ts similarity index 71% rename from experiments/skin-database/discord-bot/commands/approve.js rename to experiments/skin-database/discord-bot/commands/approve.ts index 2ab7fc83..595ed735 100644 --- a/experiments/skin-database/discord-bot/commands/approve.js +++ b/experiments/skin-database/discord-bot/commands/approve.ts @@ -1,8 +1,9 @@ +import { Message } from "discord.js"; const { approve, getStatus } = require("../../data/skins"); const Utils = require("../utils"); const { TWEET_BOT_CHANNEL_ID } = require("../../config"); -async function handler(message, args) { +async function handler(message: Message, args: [string]) { const [md5] = args; const status = await getStatus(md5); if (status !== "UNREVIEWED") { @@ -11,6 +12,9 @@ async function handler(message, args) { } await approve(md5); const tweetBotChannel = message.client.channels.get(TWEET_BOT_CHANNEL_ID); + if (tweetBotChannel == null) { + throw new Error("Could not find tweet-bot channel"); + } let filename = null; await Utils.postSkin({ md5, @@ -21,6 +25,10 @@ async function handler(message, args) { }, dest: tweetBotChannel, }); + if (tweetBotChannel.type !== "text") { + throw new Error("User tried to approve a skin from a non-text channel"); + } + // TODO: Upgrade and see if types improve await tweetBotChannel.send( `${filename} was approved by ${message.author.username}` ); diff --git a/experiments/skin-database/discord-bot/commands/archive.js b/experiments/skin-database/discord-bot/commands/archive.ts similarity index 92% rename from experiments/skin-database/discord-bot/commands/archive.js rename to experiments/skin-database/discord-bot/commands/archive.ts index f425b373..fbecdd5d 100644 --- a/experiments/skin-database/discord-bot/commands/archive.js +++ b/experiments/skin-database/discord-bot/commands/archive.ts @@ -1,10 +1,11 @@ +import { Message } from "discord.js"; const fetch = require("node-fetch"); const Utils = require("../utils"); const { addSkinFromBuffer } = require("../../addSkin"); -async function handler(message) { +async function handler(message: Message) { const { attachments } = message; - if (attachments.length < 1) { + if (attachments.array().length < 1) { await message.channel.send("Could not archive. No attachment found."); return; } diff --git a/experiments/skin-database/s3.js b/experiments/skin-database/s3.ts similarity index 84% rename from experiments/skin-database/s3.js rename to experiments/skin-database/s3.ts index 1be78a2e..0df04956 100644 --- a/experiments/skin-database/s3.js +++ b/experiments/skin-database/s3.ts @@ -1,9 +1,10 @@ -const AWS = require("aws-sdk"); +import AWS from "aws-sdk"; + AWS.config.update({ region: "us-west-2" }); const s3 = new AWS.S3(); -function getFile(key) { +function getFile(key: string): Promise { return new Promise((resolve, rejectPromise) => { const bucketName = "winamp2-js-skins"; s3.getObject({ Bucket: bucketName, Key: key }, (err, data) => { @@ -11,13 +12,17 @@ function getFile(key) { rejectPromise(err); return; } - const body = Buffer.from(data.Body).toString("utf8"); + + const body = Buffer.from( + // @ts-ignore + data.Body + ).toString("utf8"); resolve(body); }); }); } -function putFile(key, body) { +function putFile(key: string, body: string): Promise { return new Promise((resolve, rejectPromise) => { const bucketName = "winamp2-js-skins"; s3.putObject({ Bucket: bucketName, Key: key, Body: body }, (err) => { @@ -30,13 +35,13 @@ function putFile(key, body) { }); } -function putSkin(md5, buffer) { +export function putSkin(md5: string, buffer: Buffer): Promise { return new Promise((resolve, rejectPromise) => { const bucketName = "webamp-uploaded-skins"; const key = `skins/${md5}.wsz`; s3.putObject( { Bucket: bucketName, Key: key, Body: buffer, ACL: "public-read" }, - err => { + (err) => { if (err) { rejectPromise(err); return; @@ -48,13 +53,13 @@ function putSkin(md5, buffer) { }); } -function putScreenshot(md5, buffer) { +export function putScreenshot(md5: string, buffer: Buffer): Promise { return new Promise((resolve, rejectPromise) => { const bucketName = "webamp-uploaded-skins"; const key = `screenshots/${md5}.png`; s3.putObject( { Bucket: bucketName, Key: key, Body: buffer, ACL: "public-read" }, - err => { + (err) => { if (err) { rejectPromise(err); return; @@ -66,22 +71,22 @@ function putScreenshot(md5, buffer) { }); } -function getLines(body) { +function getLines(body: string): string[] { return body .trim() .split("\n") .map((line) => line.trim()); } -async function getAllApproved() { +export async function getAllApproved(): Promise { return getLines(await getFile("approved.txt")); } -async function getAllRejected() { +export async function getAllRejected(): Promise { return getLines(await getFile("rejected.txt")); } -async function getAllTweeted() { +export async function getAllTweeted(): Promise { return getLines(await getFile("tweeted.txt")); } @@ -178,15 +183,15 @@ async function appendLine(key, line) { return putFile(key, newContent); } -async function approve(md5) { +export async function approve(md5: string): Promise { return appendLine("approved.txt", md5); } -async function reject(md5) { +export async function reject(md5: string): Promise { return appendLine("rejected.txt", md5); } -async function markAsTweeted(md5) { +export async function markAsTweeted(md5: string): Promise { return appendLine("tweeted.txt", md5); } diff --git a/experiments/skin-database/types.ts b/experiments/skin-database/types.ts new file mode 100644 index 00000000..82049ea2 --- /dev/null +++ b/experiments/skin-database/types.ts @@ -0,0 +1,33 @@ +export type TweetStatus = "APPROVED" | "REJECTED" | "TWEETED" | "UNREVIEWED"; + +export type DBSkinRecord = { + md5: string; + averageColor?: string; + emails?: string[]; + tweetUrl?: string; + twitterLikes?: number; + readmeText?: string; + filePaths: string[]; + imageHash?: string; + uploader?: string; +}; + +export type DBIARecord = { + identifier: string; +}; + +export type SkinRecord = { + md5: string; + averageColor?: string; + emails?: string[]; + tweetUrl?: string; + twitterLikes?: number; + readmeText?: string; + fileNames: string[]; + imageHash?: string; + uploader?: string; + screenshotUrl: string; + skinUrl: string; + canonicalFilename: string | null; + webampUrl: string; +};