diff options
author | Luca Matei Pintilie <lucafulger@gmail.com> | 2022-07-03 12:49:52 +0000 |
---|---|---|
committer | Luca Matei Pintilie <lucafulger@gmail.com> | 2022-07-03 12:49:52 +0000 |
commit | 439284472ddc7825728159f03b727667f5a21969 (patch) | |
tree | 9e6b7643c9607f1aa6e3f0ee8c6a31341976e8aa | |
parent | 16e6131b2a5ccd183a2ec4037cf38e7f87197647 (diff) | |
download | speedrunbot-slash-439284472ddc7825728159f03b727667f5a21969.tar speedrunbot-slash-439284472ddc7825728159f03b727667f5a21969.tar.gz speedrunbot-slash-439284472ddc7825728159f03b727667f5a21969.tar.bz2 speedrunbot-slash-439284472ddc7825728159f03b727667f5a21969.tar.lz speedrunbot-slash-439284472ddc7825728159f03b727667f5a21969.tar.xz speedrunbot-slash-439284472ddc7825728159f03b727667f5a21969.tar.zst speedrunbot-slash-439284472ddc7825728159f03b727667f5a21969.zip |
Add BROKEN posts command
-rwxr-xr-x | src/srcom/posts.ts | 134 | ||||
-rw-r--r-- | src/srcom/slash_commands.ts | 19 | ||||
-rw-r--r-- | tests/srcom/posts.test.ts | 13 |
3 files changed, 166 insertions, 0 deletions
diff --git a/src/srcom/posts.ts b/src/srcom/posts.ts new file mode 100755 index 0000000..c7aba2f --- /dev/null +++ b/src/srcom/posts.ts @@ -0,0 +1,134 @@ +#!/usr/bin/env -S deno run --allow-net=www.speedrun.com --allow-env=NO_COLOR --no-check +import { Format } from "./fmt.ts"; +import { CommandError, getUser } from "./utils.ts"; +import type { Opts } from "./utils.ts"; + +export const dateFormat = Intl.DateTimeFormat("en-uk", { + day: "numeric", + month: "long", + year: "numeric", + timeZone: "Europe/London", +}).format; + +export interface Posts { + game: number; + site: number; + secret: number; + total: number; +} + +// Strongly copied from +// https://github.com/Mango0x45/speedrunbot-plusplus/blob/38a7231805c966d55b1e23cd7e94a7ddd042088e/src/srcom/posts.sh +export async function posts( + username: string, + { outputType }: { outputType?: "object" }, +): Promise<Posts>; +export async function posts( + username: string, + { outputType }: Opts, +): Promise<string>; +export async function posts( + username: string, + { outputType = "markdown" }: Opts = {}, +): Promise<string | Posts> { + const fmt = new Format(outputType); + const output: string[] = []; + + const user = await getUser(username); + if (!user) throw new CommandError(`No user with the username "${username}"`); + + const userAllPostsRes = await fetch( + `https://www.speedrun.com/${user.names.international}/allposts`, + ); + const userAllPostsText = await userAllPostsRes.text(); + const numberOfPages = parseInt( + // @ts-ignore the regex will only match numbers + // And we check below if it's NaN + userAllPostsText.match(/Page 1 of (\d+)+/)?.[1], + ); + const fetchPageTasks: Promise<string>[] = []; + + if ( + userAllPostsText.includes( + "This user has not posted anything on the forum yet.", + ) + ) { + return "This user has not posted anything on the forum yet."; + } else if (isNaN(numberOfPages)) { + fetchPageTasks.push( + fetch( + `https://www.speedrun.com/${user.names.international}/allposts`, + ).then((res) => res.text()), + ); + } else { + for (let i = 0; i < numberOfPages; i++) { + fetchPageTasks.push( + fetch( + `https://www.speedrun.com/${user.names.international}/allposts/${i}`, + ).then((res) => res.text()), + ); + } + } + + const results = (await Promise.all(fetchPageTasks)).map((page) => { + const match = page.match( + /<\s*a href='\/(.*?)\/forum'[^>]*>(.*?)<\s*\/\s*a>/g, + ); + const sitePattern = + /supporter|news|introductions|speedrunning|streaming_recording_equipment|tournaments_and_races|talk|the_site/; + let game = 0; + let site = 0; + + if (match) { + for (const link of match) { + if (sitePattern.test(link)) site++; + else game++; + } + } + + return { + game, + site, + }; + }); + + const userInfoRes = await fetch( + `https://www.speedrun.com/user/${user.names.international}/info`, + ); + const userInfoText = await userInfoRes.text(); + + // @ts-ignore I don't think this is possible to fail + const total = parseInt(userInfoText.match(/.*Posts:[^0-9]*([0-9]*).*/)?.[1]); + let game = 0; + let site = 0; + + for (const result of results) { + game += result.game; + site += result.site; + } + + const secret = total - site - game; + + if (outputType === "object") { + return { + game, + site, + secret, + total, + }; + } + + output.push(`${fmt.bold("Posts")}: ${user.names.international}`); + output.push(`Site Forums: ${site}`); + output.push(`Game Forums: ${game}`); + if (secret) output.push(`Secret Forums: ${secret}`); + output.push(`Total: ${total}`); + + return output.join("\n"); +} + +export default posts; + +if (import.meta.main) { + console.log(await posts(Deno.args[0], { outputType: "terminal" })); +} diff --git a/src/srcom/slash_commands.ts b/src/srcom/slash_commands.ts index d4ed885..762461c 100644 --- a/src/srcom/slash_commands.ts +++ b/src/srcom/slash_commands.ts @@ -12,6 +12,7 @@ import { } from "../../deps_server.ts"; import { games } from "./games.ts"; +import { posts } from "./posts.ts"; import { examined } from "./examined.ts"; import { examinedLeaderboard } from "./examined_leaderboard.ts"; import { categories } from "./categories.ts"; @@ -77,6 +78,16 @@ export const commands: SlashCommandPartial[] = [ ], }, { + name: "posts", + description: "See how many posts a player has posted on the site.", + options: [ + { + ...srcUser, + required: true, + }, + ], + }, + { name: "mod-count", description: "See how many games and series a user moderates.", options: [ @@ -483,6 +494,14 @@ export class SpeedrunCom extends ApplicationCommandsModule { ); } + @slash() + async posts(i: ApplicationCommandInteraction) { + await sendCommand( + i, + (i) => posts(i.option("username"), { outputType: "markdown" }), + ); + } + @slash("mod-count") async modCount(i: ApplicationCommandInteraction) { await sendCommand( diff --git a/tests/srcom/posts.test.ts b/tests/srcom/posts.test.ts new file mode 100644 index 0000000..b111c17 --- /dev/null +++ b/tests/srcom/posts.test.ts @@ -0,0 +1,13 @@ +import { assertEquals } from "../../deps_testing.ts"; +import { posts } from "../../src/srcom/posts.ts"; + + +Deno.test("Get user posts by username", async () => { + const res = await posts("1", { outputType: "plain" }); + const expected = `Posts: 1 +Site Forums: 606 +Game Forums: 774 +Secret Forums: 1365 +Total: 1365`; + assertEquals(res, expected); +}); |