UNPKG

@twitchfy/chatbot

Version:

A powerful node module to make your own Twitch ChatBot

302 lines (301 loc) 11.1 kB
"use strict"; /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable @typescript-eslint/ban-types */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ChatBot = void 0; const eventsub_1 = require("@twitchfy/eventsub"); const helix_1 = require("@twitchfy/helix"); const path_1 = require("path"); const BaseChannel_1 = require("./BaseChannel"); const Collection_1 = require("./Collection"); const ChatBotUser_1 = require("./ChatBotUser"); const EventHandler_1 = require("./EventHandler"); const CommandHandler_1 = require("./CommandHandler"); const Stream_1 = require("./Stream"); const Clip_1 = require("./Clip"); const ChatRoom_1 = require("./ChatRoom"); const managers_1 = require("./managers"); const managers_2 = require("./managers"); const managers_3 = require("./managers"); const enums_1 = require("../enums"); const util_1 = require("../util"); /** * Represents a chatbot. */ class ChatBot { /** * The client Id of the Twitch's application. */ clientId; /** * The client secret of the Twitch's application. */ clientSecret; /** * A Collection of the profiles of the joined channels. */ profiles; /** * The manager of the chatbot channels. */ channels; /** * The handlers of resources of the chatbot. * @private */ handlers; /** * A Collection of the chatbot commands. */ commands; /** * A Collection of the chatbot events. */ events; /** * The message manager of the chatbot. */ messages; /** * The ban manager of the chatbot. */ bans; /** * The user manager of the chatbot. */ users; /** * The timeout manager of the chatbot. */ timeouts; /** * The warning manager of the chatbot. */ warns; /** * The chatters manager of the chatbot. */ chatters; /** * The Twitch user of the chatbot. */ user; /** * The user Id of the chatbot. */ userId; /** * The operator to separate the options in the command. */ optionOperator; /** * The EventSub connection type used by the chatbot. */ connectionType; /** * The EventSub connection of the chatbot. */ eventsub; /** * The Helix client of the chatbot. */ helixClient; /** * The options of the chatbot. */ options; /** * The prefix callback used to handle command prefixes. * @protected */ __prefix; /** * Creates a new instance of the chatbot. * @param options The options to build up the chatbot. */ constructor(options) { this.options = options; this.clientId = options.clientId; this.clientSecret = options.clientSecret; this.profiles = new Collection_1.Collection(); this.channels = new managers_3.ChannelManager(this); this.messages = new managers_3.ChatBotMessageManager(this); this.bans = new managers_3.ChatBotBanManager(this); this.timeouts = new managers_3.ChatBotTimeoutManager(this); this.users = new managers_3.ChatBotUserManager(this); this.warns = new managers_2.ChatBotWarnsManager(this); this.chatters = new managers_1.ChatBotChatterManager(this); this.handlers = { commands: new CommandHandler_1.CommandHandler((0, path_1.join)(process.cwd(), options.paths.output, options.paths.commands || '.')), events: new EventHandler_1.EventHandler((0, path_1.join)(process.cwd(), options.paths.output, options.paths.events || '.')) }; this.commands = new Collection_1.Collection(); this.events = new Collection_1.Collection(); this.connectionType = options.connectionType; this.optionOperator = options.optionOperator ?? '-'; this.helixClient = new helix_1.HelixClient({ ...options, ...options.helix }); this.__prefix = options.prefix ?? (() => ['!']); this.eventsub = this.createEventSubConnection(options.connectionType, options); const fn = util_1.handleSubscriptionReload.bind(this); // @ts-expect-error this.eventsub.on(eventsub_1.Events.SubscriptionReload, fn); } /** * Creates the EventSub connection of the chatbot. * @param type The type of the EventSub connection. * @param options The options to build up the EventSub connection. * @returns The EventSub connection of the chatbot. * @private */ createEventSubConnection(type, options) { switch (type) { case enums_1.EventSubConnection.WebSocket: { const { clientId, clientSecret, userToken, eventsub } = options; this.helixClient.preferedToken = 'user'; // @ts-expect-error return new eventsub_1.WebSocketConnection({ clientId, clientSecret, userToken, ...eventsub }); } break; case enums_1.EventSubConnection.Webhook: { const { clientId, clientSecret, eventsub } = options; this.helixClient.setAppToken(eventsub.appToken); // @ts-expect-error return new eventsub_1.WebhookConnection({ clientId, clientSecret, ...eventsub }, eventsub.server); } break; case enums_1.EventSubConnection.Conduit: { const { clientId, clientSecret, eventsub } = options; this.helixClient.setAppToken(eventsub.appToken); // @ts-expect-error return new eventsub_1.Conduit({ clientId, clientSecret, ...eventsub }); } } // @ts-expect-error return; } /** * Start the chatbot. * @param options The start options to start the chatbot. * @returns The current instance of the chatbot. When the promise is resolved the chatbot has been completly started. */ async start(options) { if (this.options.paths.commands) { const commands = await this.handlers.commands.load(); for (const commandClass of commands) { const command = new commandClass(); if (!command.name || !command.run) continue; this.commands.set(command.name, command); } } if (this.options.paths.events) { const events = await this.handlers.events.load(); for (const data of events) { if (!data.event || !data.run) continue; this.events.set(data.event, data); } } const listener = util_1.handleEvent.bind(this); // @ts-expect-error this.eventsub.on(eventsub_1.Events.SubscriptionMessage, listener); const tokenInfo = await this.helixClient.getUserToken(false).catch(async (err) => { if (this.helixClient.userToken?.refresh) { //@ts-expect-error const token = await this.helixClient.refreshToken(this.helixClient.userToken).catch(() => { throw err; }); this.helixClient.setUserToken(token); return await this.helixClient.getUserToken(false); } throw err; }); this.userId = tokenInfo.user_id; this.user = new ChatBotUser_1.ChatBotUser(this, await this.helixClient.getUser(this.userId)); // @ts-expect-error await ((this.eventsub instanceof eventsub_1.WebhookConnection || this.eventsub instanceof eventsub_1.Conduit) ? this.eventsub.start(options?.port, options?.callback) : this.eventsub.connect()); const readyEvent = this.events.get('ChatBotReady'); if (readyEvent) readyEvent.run(this, undefined); return this; } /** * Get Twitch streams from the API. * @param options The options to filter the streams. * @param number The number of streams to fetch. This number could vary from the result due to API reasons. * @returns An array containing the streams fetched from the API. If there isn't any stream founded, it will return a nullish value. */ async streams(options, number) { if (typeof options === 'number') { number = options; options = {}; } const streams = await this.helixClient.getStreams(options, { pages: number ? number / 100 : Infinity }); if (!streams.length) return null; return streams.map(stream => new Stream_1.Stream(this, stream)); } /** * Fetches a Twitch stream from the API. * @param options The options for filter the stream. * @returns A stream fetched from the API or null if the stream wasn't founded. */ async stream(options) { const stream = await this.helixClient.getStream(options); return stream ? new Stream_1.Stream(this, stream) : null; } /** * Get Twitch clips from the API. * @param options The options to filter the clips. * @returns An array containing the clips fetched from the API. If there isn't any clip founded, it will return a nullish value. */ async clips(options) { const data = await this.helixClient.getClips(options); if (!data.length) return null; return data.map(clip => new Clip_1.Clip(this, clip)); } /** * Get a specific Twitch clip from the API. * @param options The options to filter the clip. * @returns The clip fetched from the API or null if the clip wasn't founded. */ async clip(options) { const data = await this.helixClient.getClip(options); if (!data) return null; return new Clip_1.Clip(this, data); } /** * Checks whether the chatbot is moderator in a specific channel. * @param channelId The Id of the channel to check. * @returns A boolean indicating whether the chatbot is moderator in the channel. */ async isModerator(channelId) { const data = await this.moderatedChannels(); return data.some((x) => x.id === channelId); } /** * Get the moderated channels of the chatbot. * @returns An array containing the moderated channels of the chatbot. */ async moderatedChannels() { const data = await this.helixClient.getModeratedChannels(this.userId); return data.map((x) => new BaseChannel_1.BaseChannel(this, x, new ChatRoom_1.ChatRoom(this, x))); } /** * The user token of the chatbot Twitch account to make requests. */ get userToken() { return this.helixClient.userToken; } /** * The app token of the Twitch application. The value is null if the chatbot is using a WebSocket EventSub connection. */ get appToken() { return this.helixClient.appToken ?? null; } } exports.ChatBot = ChatBot;