diff --git a/.example.env b/.example.env index cf8aa10..f68137f 100644 --- a/.example.env +++ b/.example.env @@ -6,6 +6,7 @@ CLIENT_SECRET= # Client_secret gotten from the twitch dev console # REDIRECT_URL= # Redirect URL that has been set in the twitch dev console. Defaults to: http://localhost:3456 # REDIRECT_PORT= # Redirect port if the REDIRECT_URL has not been set. Defaults to 3456. This is also the port the bot will listen on to authenticate # COMMAND_PREFIX= # The prefix which will be used to activate commands. Defaults to '!'. When requiring a space between prefix and command, escape the space with a backslash +CHATWIDGET_PORT= # The port that the chat widget will be served on # The Twitch IDs required below can be gotten from this website: https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/ diff --git a/package.json b/package.json index 638e6bd..222da61 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "qweribot", - "module": "bot/index.ts", + "module": "src/index.ts", "devDependencies": { "@types/bun": "latest" }, diff --git a/bot/auth.ts b/src/auth.ts similarity index 100% rename from bot/auth.ts rename to src/auth.ts diff --git a/src/chatwidget/index.ts b/src/chatwidget/index.ts new file mode 100644 index 0000000..c52340b --- /dev/null +++ b/src/chatwidget/index.ts @@ -0,0 +1,72 @@ +import { chatterApi, streamerId } from ".."; +import logger from "../lib/logger"; +import chatWidget from "./www/index.html"; + +type badgeObject = { + [key: string]: { + [key: string]: string; + }; +}; + +const port = Number(process.env.CHATWIDGET_PORT); +if (isNaN(port)) { logger.enverr("CHATWIDGET_PORT"); process.exit(1); }; + +export default Bun.serve({ + port, + fetch(request, server) { + if (server.upgrade(request)) return; + return new Response('oops', { status: 500 }); + }, + routes: { + "/": chatWidget, + "/getBadges": async () => { + const globalBadges = chatterApi.chat.getGlobalBadges(); + const channelBadges = chatterApi.chat.getChannelBadges(streamerId); + const rawBadges = await Promise.all([globalBadges, channelBadges]); + + const newObj: badgeObject = {}; + parseRawBadges(newObj, rawBadges[0]); + parseRawBadges(newObj, rawBadges[1]); + + return Response.json(newObj); + }, + }, + websocket: { + open(ws) { + logger.ok('Opened websocket connection to chatwidget'); + ws.sendText(JSON.stringify({ + function: 'serverNotification', + message: 'Sucessfully opened websocket connection' + })); + }, + message(ws, omessage) { + const message = JSON.parse(omessage.toString()); + if (!message.type) return; + switch (message.type) { + case 'subscribe': + if (!message.target) return; + ws.subscribe(message.target); + ws.send(JSON.stringify({ + function: 'serverNotification', + message: `Successfully subscribed to all ${message.target} events` + })); + break; + }; + }, + close(ws) { + ws.close(); + } + }, + development: true +}); + +import { HelixChatBadgeSet } from "@twurple/api"; + +function parseRawBadges(returnobj: badgeObject, data: HelixChatBadgeSet[]) { + for (const badge of data) { + if (!returnobj[badge.id]) returnobj[badge.id] = {}; + for (const version of badge.versions) { + returnobj[badge.id]![version.id] = version.getImageUrl(4); + }; + }; +}; diff --git a/src/chatwidget/message.ts b/src/chatwidget/message.ts new file mode 100644 index 0000000..2483652 --- /dev/null +++ b/src/chatwidget/message.ts @@ -0,0 +1,21 @@ +import { EventSubChannelChatMessageEvent, EventSubChannelChatMessageDeleteEvent } from "@twurple/eventsub-base"; +import chatwserver from "."; + +export async function addMessageToChatWidget(msg: EventSubChannelChatMessageEvent) { + chatwserver.publish('twitch', JSON.stringify({ + function: 'createMessage', + messageParts: msg.messageParts, + displayName: msg.chatterDisplayName, + chatterId: msg.chatterId, + chatterColor: msg.color, + messageId: msg.messageId, + badgeData: msg.badges + })); +}; + +export async function deleteMessageFromChatWidget(msg: EventSubChannelChatMessageDeleteEvent) { + chatwserver.publish('twitch', JSON.stringify({ + function: 'deleteMessage', + messageId: msg.messageId + })); +}; diff --git a/src/chatwidget/websockettypes.ts b/src/chatwidget/websockettypes.ts new file mode 100644 index 0000000..65ff4ff --- /dev/null +++ b/src/chatwidget/websockettypes.ts @@ -0,0 +1,55 @@ +export type createMessageEvent = { function: 'createMessage', messageParts: EventSubChatMessagePart[], messageId: string, displayName: string, chatterId: string, chatterColor: null | string, badgeData: string[] }; +export type deleteMessageEvent = { function: 'deleteMessage', messageId: string }; +export type serverNotificationEvent = { function: 'serverNotification', message: string }; + +export type eventData = createMessageEvent | deleteMessageEvent | serverNotificationEvent; + +// The types below are taken straight from @twurple/eventsub-base +// I would import this from the package, but that's impossible +export interface EventSubChatMessageTextPart { + type: 'text'; + text: string; +} + +export interface EventSubChatMessageCheermote { + prefix: string; + bits: number; + tier: number; +} + +export interface EventSubChatMessageCheermotePart { + type: 'cheermote'; + text: string; + cheermote: EventSubChatMessageCheermote; +} + +export interface EventSubChatMessageEmote { + id: string; + emote_set_id: string; + owner_id: string; + format: string[]; +} + +export interface EventSubChatMessageEmotePart { + type: 'emote'; + text: string; + emote: EventSubChatMessageEmote; +} + +export interface EventSubChatMessageMention { + user_id: string; + user_name: string; + user_login: string; +} + +export interface EventSubChatMessageMentionPart { + type: 'mention'; + text: string; + mention: EventSubChatMessageMention; +} + +export type EventSubChatMessagePart = + | EventSubChatMessageTextPart + | EventSubChatMessageCheermotePart + | EventSubChatMessageEmotePart + | EventSubChatMessageMentionPart; diff --git a/src/chatwidget/www/index.html b/src/chatwidget/www/index.html new file mode 100644 index 0000000..25b02f3 --- /dev/null +++ b/src/chatwidget/www/index.html @@ -0,0 +1,12 @@ + + + + + + qwerinope's chat widget + + +
+ + + diff --git a/src/chatwidget/www/src/createMessage.ts b/src/chatwidget/www/src/createMessage.ts new file mode 100644 index 0000000..213e3c5 --- /dev/null +++ b/src/chatwidget/www/src/createMessage.ts @@ -0,0 +1,61 @@ +import './style.css'; + +const badges = await fetch(`http://${location.host}/getBadges`).then(data => data.json()); + +import { type createMessageEvent } from '../../websockettypes'; + +export function parseMessage(data: createMessageEvent): HTMLDivElement { + const parentDiv = document.createElement('div'); + parentDiv.className = 'message'; + + // Badge Parsing + const badgeContainer = document.createElement('div'); + badgeContainer.className = 'badgeContainer'; + for (const badge of Object.entries(data.badgeData)) { + const badgeElement = document.createElement('img'); + badgeElement.className = 'badgeElement'; + const currentbadge = badges[badge[0]][badge[1]]; + badgeElement.src = currentbadge; + badgeContainer.appendChild(badgeElement); + }; + parentDiv.appendChild(badgeContainer); + + const chatterName = document.createElement('span'); + chatterName.style = `color: ${data.chatterColor ?? "#00ff00"}`; + chatterName.innerText = data.displayName; + chatterName.className = "chatterName"; + parentDiv.appendChild(chatterName); + + const seperator = document.createElement('span'); + seperator.innerText = ": "; + seperator.className = "chatMessageSeparator"; + parentDiv.appendChild(seperator); + + const textElement = document.createElement('div'); + for (const messagePart of data.messageParts) { + let messageElement; + switch (messagePart.type) { + case 'text': + messageElement = document.createElement('span'); + messageElement.className = "textMessage"; + messageElement.innerText = messagePart.text; + break; + case 'cheermote': + messageElement = document.createElement('img'); + break; + case 'emote': + messageElement = document.createElement('img'); + messageElement.className = "emoteMessage"; + messageElement.src = `https://static-cdn.jtvnw.net/emoticons/v2/${messagePart.emote.id}/default/dark/3.0`; + break; + case 'mention': + messageElement = document.createElement('span'); + messageElement.innerText = `Replying to ${messagePart.text}`; + messageElement.className = "replyMessage"; + break; + }; + textElement.appendChild(messageElement); + }; + parentDiv.appendChild(textElement); + return parentDiv; +}; diff --git a/src/chatwidget/www/src/main.ts b/src/chatwidget/www/src/main.ts new file mode 100644 index 0000000..8b1cf6f --- /dev/null +++ b/src/chatwidget/www/src/main.ts @@ -0,0 +1,33 @@ +import { type eventData } from "../../websockettypes"; + +import { parseMessage } from './createMessage'; + +const socket = new WebSocket(`ws://${location.host}`); + +socket.onopen = () => { + socket.send(JSON.stringify({ + type: 'subscribe', + target: 'twitch' + })); +}; + +socket.onmessage = event => { + const data: eventData = JSON.parse(event.data); + switch (data.function) { + case 'createMessage': + const newMessageElement = parseMessage(data); + newMessageElement.id = data.messageId; + document.querySelector("#message-container")?.appendChild(newMessageElement); + break; + case 'deleteMessage': + document.querySelector(`#${CSS.escape(data.messageId)}`)?.remove(); + break; + case 'serverNotification': + console.log(data.message); + break; + }; +}; + +document.querySelector('#app')!.innerHTML = ` +
+`; diff --git a/src/chatwidget/www/src/style.css b/src/chatwidget/www/src/style.css new file mode 100644 index 0000000..b394652 --- /dev/null +++ b/src/chatwidget/www/src/style.css @@ -0,0 +1,46 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + margin: 0; + display: flex; + min-width: 320px; + min-height: 100vh; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; +} + +.message { + >* { + display: inline; + } + + .replymessage { + color: grey; + font-size: 2px; + } + + padding: 2px; +} + +img { + vertical-align: middle; + width: 18px; + padding: 1px; +} diff --git a/src/chatwidget/www/tsconfig.json b/src/chatwidget/www/tsconfig.json new file mode 100644 index 0000000..c56e058 --- /dev/null +++ b/src/chatwidget/www/tsconfig.json @@ -0,0 +1,105 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "libReplacement": true, /* Enable lib replacement. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Modules */ + "module": "esnext", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/bot/cheers/index.ts b/src/cheers/index.ts similarity index 100% rename from bot/cheers/index.ts rename to src/cheers/index.ts diff --git a/bot/cheers/timeout.ts b/src/cheers/timeout.ts similarity index 100% rename from bot/cheers/timeout.ts rename to src/cheers/timeout.ts diff --git a/bot/commands/addadmin.ts b/src/commands/addadmin.ts similarity index 100% rename from bot/commands/addadmin.ts rename to src/commands/addadmin.ts diff --git a/bot/commands/admindonate.ts b/src/commands/admindonate.ts similarity index 100% rename from bot/commands/admindonate.ts rename to src/commands/admindonate.ts diff --git a/bot/commands/admingive.ts b/src/commands/admingive.ts similarity index 100% rename from bot/commands/admingive.ts rename to src/commands/admingive.ts diff --git a/bot/commands/disablecheer.ts b/src/commands/disablecheer.ts similarity index 100% rename from bot/commands/disablecheer.ts rename to src/commands/disablecheer.ts diff --git a/bot/commands/disablecommand.ts b/src/commands/disablecommand.ts similarity index 100% rename from bot/commands/disablecommand.ts rename to src/commands/disablecommand.ts diff --git a/bot/commands/donateqbucks.ts b/src/commands/donateqbucks.ts similarity index 100% rename from bot/commands/donateqbucks.ts rename to src/commands/donateqbucks.ts diff --git a/bot/commands/enablecheer.ts b/src/commands/enablecheer.ts similarity index 100% rename from bot/commands/enablecheer.ts rename to src/commands/enablecheer.ts diff --git a/bot/commands/enablecommand.ts b/src/commands/enablecommand.ts similarity index 100% rename from bot/commands/enablecommand.ts rename to src/commands/enablecommand.ts diff --git a/bot/commands/getadmins.ts b/src/commands/getadmins.ts similarity index 100% rename from bot/commands/getadmins.ts rename to src/commands/getadmins.ts diff --git a/bot/commands/getbalance.ts b/src/commands/getbalance.ts similarity index 100% rename from bot/commands/getbalance.ts rename to src/commands/getbalance.ts diff --git a/bot/commands/getcheers.ts b/src/commands/getcheers.ts similarity index 100% rename from bot/commands/getcheers.ts rename to src/commands/getcheers.ts diff --git a/bot/commands/getcommands.ts b/src/commands/getcommands.ts similarity index 100% rename from bot/commands/getcommands.ts rename to src/commands/getcommands.ts diff --git a/bot/commands/getinventory.ts b/src/commands/getinventory.ts similarity index 100% rename from bot/commands/getinventory.ts rename to src/commands/getinventory.ts diff --git a/bot/commands/gettimeout.ts b/src/commands/gettimeout.ts similarity index 100% rename from bot/commands/gettimeout.ts rename to src/commands/gettimeout.ts diff --git a/bot/commands/giveitem.ts b/src/commands/giveitem.ts similarity index 100% rename from bot/commands/giveitem.ts rename to src/commands/giveitem.ts diff --git a/bot/commands/index.ts b/src/commands/index.ts similarity index 100% rename from bot/commands/index.ts rename to src/commands/index.ts diff --git a/bot/commands/iteminfo.ts b/src/commands/iteminfo.ts similarity index 100% rename from bot/commands/iteminfo.ts rename to src/commands/iteminfo.ts diff --git a/bot/commands/itemlock.ts b/src/commands/itemlock.ts similarity index 100% rename from bot/commands/itemlock.ts rename to src/commands/itemlock.ts diff --git a/bot/commands/ping.ts b/src/commands/ping.ts similarity index 100% rename from bot/commands/ping.ts rename to src/commands/ping.ts diff --git a/bot/commands/removeadmin.ts b/src/commands/removeadmin.ts similarity index 100% rename from bot/commands/removeadmin.ts rename to src/commands/removeadmin.ts diff --git a/bot/commands/seiso.ts b/src/commands/seiso.ts similarity index 100% rename from bot/commands/seiso.ts rename to src/commands/seiso.ts diff --git a/bot/commands/testcheer.ts b/src/commands/testcheer.ts similarity index 100% rename from bot/commands/testcheer.ts rename to src/commands/testcheer.ts diff --git a/bot/commands/useitem.ts b/src/commands/useitem.ts similarity index 100% rename from bot/commands/useitem.ts rename to src/commands/useitem.ts diff --git a/bot/commands/vulnchatters.ts b/src/commands/vulnchatters.ts similarity index 100% rename from bot/commands/vulnchatters.ts rename to src/commands/vulnchatters.ts diff --git a/bot/commands/yabai.ts b/src/commands/yabai.ts similarity index 100% rename from bot/commands/yabai.ts rename to src/commands/yabai.ts diff --git a/bot/db/connection.ts b/src/db/connection.ts similarity index 100% rename from bot/db/connection.ts rename to src/db/connection.ts diff --git a/bot/db/dbAuth.ts b/src/db/dbAuth.ts similarity index 100% rename from bot/db/dbAuth.ts rename to src/db/dbAuth.ts diff --git a/bot/db/dbTimeouts.ts b/src/db/dbTimeouts.ts similarity index 100% rename from bot/db/dbTimeouts.ts rename to src/db/dbTimeouts.ts diff --git a/bot/db/dbUsedItems.ts b/src/db/dbUsedItems.ts similarity index 100% rename from bot/db/dbUsedItems.ts rename to src/db/dbUsedItems.ts diff --git a/bot/db/dbUser.ts b/src/db/dbUser.ts similarity index 100% rename from bot/db/dbUser.ts rename to src/db/dbUser.ts diff --git a/src/events/deleteMessage.ts b/src/events/deleteMessage.ts new file mode 100644 index 0000000..d98d622 --- /dev/null +++ b/src/events/deleteMessage.ts @@ -0,0 +1,6 @@ +import { eventSub, streamerId } from ".."; +import { deleteMessageFromChatWidget } from "../chatwidget/message"; + +eventSub.onChannelChatMessageDelete(streamerId, streamerId, async msg => { + deleteMessageFromChatWidget(msg); +}); diff --git a/bot/events/index.ts b/src/events/index.ts similarity index 100% rename from bot/events/index.ts rename to src/events/index.ts diff --git a/bot/events/message.ts b/src/events/message.ts similarity index 96% rename from bot/events/message.ts rename to src/events/message.ts index 1414897..4300772 100644 --- a/bot/events/message.ts +++ b/src/events/message.ts @@ -6,12 +6,14 @@ import { redis } from "bun"; import { isAdmin } from "../lib/admins"; import cheers from "../cheers"; import logger from "../lib/logger"; +import { addMessageToChatWidget } from "../chatwidget/message"; logger.info(`Loaded the following commands: ${commands.keys().toArray().join(', ')}`); eventSub.onChannelChatMessage(streamerId, streamerId, parseChatMessage); async function parseChatMessage(msg: EventSubChannelChatMessageEvent) { + addMessageToChatWidget(msg); if (!singleUserMode && msg.chatterId === chatterId) return; // return if double user mode is on and the chatter says something, we don't need them diff --git a/bot/index.ts b/src/index.ts similarity index 98% rename from bot/index.ts rename to src/index.ts index 9970605..b273a5d 100644 --- a/bot/index.ts +++ b/src/index.ts @@ -31,3 +31,5 @@ export const streamerUsers = [chatterId, streamerId]; streamerUsers.forEach(async id => await addAdmin(id)); await import("./events"); + +await import("./chatwidget"); diff --git a/bot/items/blaster.ts b/src/items/blaster.ts similarity index 100% rename from bot/items/blaster.ts rename to src/items/blaster.ts diff --git a/bot/items/grenade.ts b/src/items/grenade.ts similarity index 100% rename from bot/items/grenade.ts rename to src/items/grenade.ts diff --git a/bot/items/index.ts b/src/items/index.ts similarity index 100% rename from bot/items/index.ts rename to src/items/index.ts diff --git a/bot/items/silverbullet.ts b/src/items/silverbullet.ts similarity index 100% rename from bot/items/silverbullet.ts rename to src/items/silverbullet.ts diff --git a/bot/items/tnt.ts b/src/items/tnt.ts similarity index 100% rename from bot/items/tnt.ts rename to src/items/tnt.ts diff --git a/bot/lib/admins.ts b/src/lib/admins.ts similarity index 100% rename from bot/lib/admins.ts rename to src/lib/admins.ts diff --git a/bot/lib/changeBalance.ts b/src/lib/changeBalance.ts similarity index 100% rename from bot/lib/changeBalance.ts rename to src/lib/changeBalance.ts diff --git a/bot/lib/dateManager.ts b/src/lib/dateManager.ts similarity index 100% rename from bot/lib/dateManager.ts rename to src/lib/dateManager.ts diff --git a/bot/lib/logger.ts b/src/lib/logger.ts similarity index 100% rename from bot/lib/logger.ts rename to src/lib/logger.ts diff --git a/bot/lib/parseCommandArgs.ts b/src/lib/parseCommandArgs.ts similarity index 100% rename from bot/lib/parseCommandArgs.ts rename to src/lib/parseCommandArgs.ts diff --git a/bot/lib/timeout.ts b/src/lib/timeout.ts similarity index 100% rename from bot/lib/timeout.ts rename to src/lib/timeout.ts diff --git a/bot/user.ts b/src/user.ts similarity index 100% rename from bot/user.ts rename to src/user.ts