From d96868931e35c3aa16e4f42f2b4b5446cad40b46 Mon Sep 17 00:00:00 2001 From: DeSqBlocki Date: Sun, 9 Feb 2025 22:36:28 +0100 Subject: [PATCH] Put Offline/Online in their own Events --- commands/discord/channel.js | 4 +- commands/discord/simLive.js | 7 +- events/Twitch/Connected.js | 124 +------------------------ events/Twitch/EventSub.js | 130 +++++++++++++++++++++++++++ events/Twitch/Offline.js | 9 ++ events/Twitch/{Live.js => Online.js} | 23 ++--- functions.js | 4 +- 7 files changed, 159 insertions(+), 142 deletions(-) create mode 100644 events/Twitch/EventSub.js create mode 100644 events/Twitch/Offline.js rename events/Twitch/{Live.js => Online.js} (80%) diff --git a/commands/discord/channel.js b/commands/discord/channel.js index e0a8bf2..6858278 100644 --- a/commands/discord/channel.js +++ b/commands/discord/channel.js @@ -71,7 +71,7 @@ module.exports = { { "name": "When a user left this server", "value": "GuildMemberRemove" }, { "name": "When it's a users birthday", "value": "Discord/Birthday" }, { "name": "When debug logs are sent", "value": "Discord/Logs" }, - { "name": "When stream is live", "value": "Twitch/Live" } + { "name": "When stream is live", "value": "Twitch/Online" } ]) .setRequired(true) ) @@ -96,7 +96,7 @@ module.exports = { { "name": "When a user left this server", "value": "GuildMemberRemove" }, { "name": "When it's a users birthday", "value": "Discord/Birthday" }, { "name": "When debug logs are sent", "value": "Discord/Logs" }, - { "name": "When stream is live", "value": "Twitch/Live" } + { "name": "When stream is live", "value": "Twitch/Online" } ]) .setRequired(true) ) diff --git a/commands/discord/simLive.js b/commands/discord/simLive.js index c12774c..93e62b7 100644 --- a/commands/discord/simLive.js +++ b/commands/discord/simLive.js @@ -12,8 +12,11 @@ module.exports = { }) } - const streamer = 'x__hel__x' - interaction.client.emit('Twitch/Live', streamer) + const stream = { + broadcaster_user_login: 'x__hel__x' + } + + interaction.client.emit('Twitch/Online', stream) await interaction.reply({ content: "Done!", flags: MessageFlags.Ephemeral diff --git a/events/Twitch/Connected.js b/events/Twitch/Connected.js index d2a46a5..0964422 100644 --- a/events/Twitch/Connected.js +++ b/events/Twitch/Connected.js @@ -1,129 +1,11 @@ -// Event triggered by client connected to server +const { dClient } = require("../..") -const ReconnectingWebSocket = require("reconnecting-websocket"); -const { mClient, dClient } = require("../.."); -const { getIDByName } = require("../../functions"); -const { WebSocket, EventEmitter } = require("ws"); -const { default: axios } = require("axios"); -const events = new EventEmitter() -const WebsocketEvents = { - CONNECTED: "connected", - DISCONNECTED: "disconnected" -} +// Event triggered by client connected to server module.exports = { name: 'Twitch/Connected', once: false, async execute(address, port) { console.log(`Connected to ${address}:${port}`) - const endpoint = `wss://eventsub.wss.twitch.tv/ws` - - const db = mClient.db('clients') - const coll = db.collection('credentials') - const credentials = await coll.findOne({ service: 'twitch' }) - - const headers = { - 'Client-Id': credentials.client_id, - 'Authorization': `Bearer ${credentials.token.access_token}`, - 'Content-Type': 'application/json', - }; - - var connection - var transport = {} - var subscribedEvents = {} - - const options = { - debug: true - } - function onConnect(data) { - transport.session_id = data.payload.session.id, - transport.conncted_at = data.payload.session.connected_at, - events.emit(WebsocketEvents.CONNECTED) - } - function onDisconnect(reason){ - console.log(`Disconnecting due to reason`, reason) - } - function connect() { - connection = new ReconnectingWebSocket(endpoint, [], { - WebSocket: WebSocket, - maxRetries: Infinity - }) - - return new Promise((resolve, reject) => { - connection.onclose = ({ reason }) => onDisconnect(reason) - connection.onmessage = ({ data }) => onMessage(data) - }) - } - function onMessage(data){ - const parsed = JSON.parse(data) - - if(options.debug){ - console.log(`[Debug] EvenSub Data:`, parsed) - } - - if (parsed.metadata.message_type === 'session_welcome'){ - return onConnect(parsed) - } - return onEventMessage(parsed) - } - function onEventMessage(data){ - const messageType = data.metadata.message_type - - switch (messageType) { - case 'notification': - const subscriptionType = data.metadata.subscription_type - return subscribedEvents[subscriptionType]?.(data.payload?.event) - default: - return subscribedEvents[messageType]?.(data.payload) - } - } - async function subscribe(type, condition, listener, version = 1){ - const sessionId = transport.session_id - const subscriptionPayload = { - type: type, - version: version, - condition: condition, - transport: { - method: 'websocket', - session_id: sessionId, - }, - }; - const res = await axios.post('https://api.twitch.tv/helix/eventsub/subscriptions', - subscriptionPayload, { - headers: headers - }) - console.log(`Subscribed to ${type}`) - subscribedEvents[type] = listener - return true - } - connect(options) - if (options.debug){ - events.on(WebsocketEvents.CONNECTED, () => { - console.log("Connected to EventSub"); - }) - - events.on(WebsocketEvents.DISCONNECTED, () => { - console.log("Disconnected from EventSub"); - }) - } - - const conditions = [{ - broadcaster_user_id: String(await getIDByName("x__hel__x")) - }] - - subscribe( - "stream.online", - conditions[0], - stream => { -dClient.emit('Twitch/Online', stream) - } - ) - - subscribe( - "stream.offline", - conditions[0], - stream => { -dClient.emit('Twitch/Offline', stream); - } - ) + dClient.emit('Twitch/EventSub') } } \ No newline at end of file diff --git a/events/Twitch/EventSub.js b/events/Twitch/EventSub.js new file mode 100644 index 0000000..96defc7 --- /dev/null +++ b/events/Twitch/EventSub.js @@ -0,0 +1,130 @@ +const ReconnectingWebSocket = require("reconnecting-websocket"); +const { mClient, dClient } = require("../.."); +const { getIDByName } = require("../../functions"); +const { WebSocket, EventEmitter } = require("ws"); +const axios = require("axios") +const events = new EventEmitter() +const WebsocketEvents = { + CONNECTED: "connected", + DISCONNECTED: "disconnected" +} +module.exports = { + name: 'Twitch/EventSub', + once: false, + async execute() { + const endpoint = `wss://eventsub.wss.twitch.tv/ws` + + const db = mClient.db('clients') + const coll = db.collection('credentials') + const credentials = await coll.findOne({ service: 'twitch' }) + + const headers = { + 'Client-Id': credentials.client_id, + 'Authorization': `Bearer ${credentials.token.access_token}`, + 'Content-Type': 'application/json', + }; + + var connection + var transport = {} + var subscribedEvents = {} + + const options = { + debug: true + } + function onConnect(data) { + transport.session_id = data.payload.session.id, + transport.conncted_at = data.payload.session.connected_at, + events.emit(WebsocketEvents.CONNECTED) + } + function onDisconnect(reason) { + console.log(`Disconnecting due to reason`, reason) + } + function connect() { + connection = new ReconnectingWebSocket(endpoint, [], { + WebSocket: WebSocket, + maxRetries: Infinity + }) + + return new Promise((resolve, reject) => { + connection.onclose = ({ reason }) => onDisconnect(reason, reject) + connection.onmessage = ({ data }) => onMessage(data, resolve) + }) + } + function onMessage(data) { + const parsed = JSON.parse(data) + + if (options.debug) { + console.log(`[Debug] EvenSub Data:`, parsed) + } + + if (parsed.metadata.message_type === 'session_welcome') { + return onConnect(parsed) + } + return onEventMessage(parsed) + } + function onEventMessage(data) { + const messageType = data.metadata.message_type + + switch (messageType) { + case 'notification': + const subscriptionType = data.metadata.subscription_type + return subscribedEvents[subscriptionType]?.(data.payload?.event) + default: + return subscribedEvents[messageType]?.(data.payload) + } + } + async function subscribe(type, condition, listener, version = 1) { + const sessionId = transport.session_id + const subscriptionPayload = { + type: type, + version: version, + condition: condition, + transport: { + method: 'websocket', + session_id: sessionId, + }, + }; + const res = await axios.post('https://api.twitch.tv/helix/eventsub/subscriptions', + subscriptionPayload, { + headers: headers + }) + console.log(`Subscribed to ${type}`) + subscribedEvents[type] = listener + return true + } + connect(options) + if (options.debug) { + events.on(WebsocketEvents.CONNECTED, () => { + console.log("Connected to EventSub"); + }) + + events.on(WebsocketEvents.DISCONNECTED, () => { + console.log("Disconnected from EventSub"); + }) + } + + const conditions = [{ + broadcaster_user_id: String(await getIDByName("x__hel__x")) + },{ + broadcaster_user_id: String(await getIDByName("desq_blocki")) + }] + + subscribe( + "stream.online", + conditions[0], + stream => { + dClient.emit('Twitch/Online', stream) + } + ) + + subscribe( + "stream.offline", + conditions[0], + stream => { + dClient.emit('Twitch/Offline', stream); + } + ) + } +} + + diff --git a/events/Twitch/Offline.js b/events/Twitch/Offline.js new file mode 100644 index 0000000..5202a0a --- /dev/null +++ b/events/Twitch/Offline.js @@ -0,0 +1,9 @@ +const { updateChatMode } = require('../../functions') +module.exports = { + name: 'Twitch/Offline', + once: false, + execute(stream) { + console.log(`${stream.broadcaster_user_login} went offline!`) + updateChatMode(stream.broadcaster_user_id, "on") + } +} \ No newline at end of file diff --git a/events/Twitch/Live.js b/events/Twitch/Online.js similarity index 80% rename from events/Twitch/Live.js rename to events/Twitch/Online.js index 46f41c5..f757f4f 100644 --- a/events/Twitch/Live.js +++ b/events/Twitch/Online.js @@ -3,18 +3,19 @@ const { mClient, dClient } = require("../..") const { getStreams } = require('../../functions') module.exports = { - name: 'Twitch/Live', + name: 'Twitch/Online', once: false, - async execute(streamer) { + async execute(stream) { const db = mClient.db('guilds') const res = await db.listCollections().toArray() - + const streamer = stream.broadcaster_user_login + res.forEach(async (guildColl) => { const guildId = guildColl.name const coll = db.collection(guildId) - const res = await coll.findOne({ event: 'Twitch/Live' }) + const res = await coll.findOne({ event: 'Twitch/Online' }) if(!res){ - console.log('No Live Nofitication Channel') + return // ignore if no live channel set } const guild = dClient.guilds.cache.get(guildId) const channel = guild.channels.cache.get(res.channel) @@ -60,18 +61,10 @@ module.exports = { return channel.send({ embeds: [embed], flags: MessageFlags.Ephemeral - }).then(message => setTimeout(() => { - message.deleteReply() - }, 60000)) + }) } } catch (error) { - console.error(error) - return channel.send({ - content: `**[ERROR]:** Could not get stream info for *${escapeMarkdown(channelName)}*!\r\n${error}`, - ephemeral: true - }).then(message => setTimeout(() => { - message.deleteReply() - }, 60000)) + return console.error } }) diff --git a/functions.js b/functions.js index d03c4ea..35f6e35 100644 --- a/functions.js +++ b/functions.js @@ -159,8 +159,8 @@ async function updateChatMode(broadcaster_id, setTo) { } // Get channel information -async function getChannelInformation(streamer) { - const broadcaster_id = await getIDByName(streamer) +async function getChannelInformation(user_login) { + const broadcaster_id = await getIDByName(user_login) return await makeHelixRequest('GET', 'channels', { broadcaster_id }); }