Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions replay-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import cron from 'node-cron';
import { WebClient } from "@slack/web-api";

export type QueueItem = {
md5: string,
playerName: string,
ts: string,
userId: string,
fileName: string
};

export const queue: QueueItem[] = [];
const rendering = new Map<number, QueueItem>();

const client = new WebClient(process.env.BOT_TOKEN);

export const replayRenderTask = cron.createTask('*/5 * * * * *', async (ctx) => {
if (queue.length === 0) {
replayRenderTask.stop();
return;
}

const item = queue.shift();

// This should really never happen, but typescript-language-server is screaming at me because of it.
if (!item) {
replayRenderTask.stop();
return;
}

const render = await ordr.sendRender({
replay: `.replay/${item.md5}.osr`,
skin: 'default',
username: item.playerName,
showDanserLogo: false,
resolution: '1280x720',
introBGDim: 100,
inGameBGDim: 100,
breakBGDim: 100
});

if (render.errorCode !== 0) {
client.reactions.add({
channel: 'C165V7XT9',
name: 'x',
timestamp: item.ts
});

client.chat.postMessage({
channel: 'C165V7XT9',
thread_ts: item.ts,
text: `:warning: *Hey <@${item.userId}>!* o!rdr refused your replay: \`${render.message}\``
});

return;
}

client.reactions.add({
channel: 'C165V7XT9',
name: "thinkspin",
timestamp: item.ts
});

rendering.set(render.renderID!, item)
});

const socket = io('https://apis.issou.best', {
path: '/ordr/ws',
autoConnect: true
});

socket.on('connect', () => {
console.log('[ORDR] Connected to issou.best');
});

socket.on('disconnect', (reason) => {
if (reason === "io server disconnect") {
console.log('[ORDR] issou.best disconnected client, attempting to reconnect');
setTimeout(() => socket.connect(), 5_000);
}

console.log('[ORDR] Disconnected from issou.best:', reason);
});

socket.on('render_done_json', async (render) => {
const item = rendering.get(render.renderID!);

if (!item) return;

client.reactions.remove({
channel: 'C165V7XT9',
name: 'thinkspin',
timestamp: item.ts
});

client.chat.postMessage({
channel: 'C165V7XT9',
thread_ts: item.ts,
reply_broadcast: true,
text: `<${render.videoUrl}|${item.fileName}>`,
unfurl_media: true
})

rendering.delete(render.renderID!)
});

socket.on('render_failed_json', async (render) => {
const item = rendering.get(render.renderID!);

if (!item) return;

client.reactions.remove({
channel: 'C165V7XT9',
name: 'thinkspin',
timestamp: item.ts
});

client.reactions.add({
channel: 'C165V7XT9',
name: 'x',
timestamp: item.ts
});

client.chat.postMessage({
channel: 'C165V7XT9',
thread_ts: item.ts,
text: `:warning: *Hey <@${item.userId}>!* o!rdr couldn't render your replay for some reason: \`${render.errorMessage}\``
});

rendering.delete(render.renderID!)
})
68 changes: 68 additions & 0 deletions src/events/message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { AllMiddlewareArgs, SlackEventMiddlewareArgs, StringIndexed } from "@slack/bolt";
import fs from "node:fs/promises";
import osr from "node-osr";
import { queue } from "../../replay-handler";

// For proper type-checking + intellisense, replace "event_template" with the raw event name
export default async function Message(ctx: SlackEventMiddlewareArgs<"message"> & AllMiddlewareArgs<StringIndexed>) {
if (ctx.event.channel !== "C165V7XT9") return;
if (ctx.event.subtype !== "file_share") return;

const msg = ctx.body.message!;

if (!msg.files) return;
if (msg.files.length === 0) return;

const replay = msg.files.find(file => file.name?.endsWith('.osr'));

if (!replay) return;

const replayData = await fetch(replay.url_private_download!, {
headers: {
'Authorization': `Bearer ${process.env.BOT_TOKEN}`
}
}).then(res => res.arrayBuffer());

const replayBuffer = Buffer.from(replayData);

const _replay = await osr.read(replayBuffer);

if (_replay.gameMode !== 0) {
return ctx.client.chat.postEphemeral({
channel: "C165V7XT9",
user: ctx.body.user_id!,
text: `:warning: *Hey <${ctx.body.user_id}>!* You uploaded a replay file. Unfortunately, o!rdr doesn't support replays other than :osu-standard: osu!standard replays, so I can't render your replay. Sorry!`
});
}

// ensure .replays folder exists
try {
const statRes = await fs.stat('.replay');
if (!statRes.isDirectory()) throw { code: 'IS_A_FILE' }
} catch (err) {
if (err.code == 'ENOENT') {
await fs.mkdir('.replay')
} else {
return ctx.client.chat.postEphemeral({
channel: "C165V7XT9",
user: ctx.body.user_id!,
text: `:warning: *Hey <@${ctx.body.user_id}>!* An unexpected error occured while trying to handle your replay. Contact the bot maintainer. (${err.code})`
});
}
}

const replayFile = fs.createWriteStream(`.replay/${_replay.replayMD5}.osr`);

replayFile.write(replayBuffer);
replayFile.end();

replayFile.on('finish', () => {
queue.push({
md5: '',
playerName: '',
ts: msg.ts,
userId: ctx.body.user_id,
fileName: replay.name.slice(0, -4)
})
})
}