Files
bot_Laytho/app.js
2023-05-11 01:39:20 +02:00

208 lines
8.4 KiB
JavaScript

// PACKAGES
const WebSocketClient = require('websocket').client
const express = require('express')
require('dotenv').config()
require('require-all')(__dirname + '/utils/')
// VARIABLES
let client_id = process.env.TWITCH_APP_ID
let client_secret = process.env.TWITCH_APP_SECRET
let user_name = process.env.TWITCH_USER_USERNAME
let channel_name = process.env.TWITCH_CHANNEL_USERNAME
let channel_reward_name = process.env.TWITCH_CHANNEL_REWARD_NAME
const user_scope = ['chat:read', 'chat:edit', 'channel:moderate']
const channel_scope = ['channel:manage:redemptions']
const uri = 'https://angels-dev.fr/twitch/'
const redirect_uri = uri + 'oauth/login/'
const chatBeginMsg = `PRIVMSG #${channel_name}`
// EXPRESS
const port = 3000
const app = express()
app.use(express.json())
app.use(express.static('public'))
// Twitch OAuth
app.get('/twitch/oauth/:type', async (req, res) => {
let type = req.params.type
let url = await oauthGen(client_id, redirect_uri + type, type === 'user' ? user_scope : type === 'channel' ? channel_scope : [])
return res.redirect(url)
})
app.get('/twitch/oauth/login/:type', async (req, res) => {
let type = req.params.type
if (type === 'user') {
[ user_access_token, user_refresh_token ] = await getUserAccessToken(client_id, client_secret, req.query.code, redirect_uri + type)
writeEnv('TWITCH_USER_ACCESS_TOKEN', user_access_token)
writeEnv('TWITCH_USER_REFRESH_TOKEN', user_refresh_token)
user_name = await getUserInfo(client_id, user_access_token).login
writeEnv('TWITCH_USER_USERNAME', user_name)
clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
}
else if (type === 'channel') {
[ channel_access_token, channel_refresh_token ] = await getUserAccessToken(client_id, client_secret, req.query.code, redirect_uri + type)
writeEnv('TWITCH_CHANNEL_ACCESS_TOKEN', channel_access_token)
writeEnv('TWITCH_CHANNEL_REFRESH_TOKEN', channel_refresh_token)
channel_name = await getUserInfo(client_id, channel_access_token).login
writeEnv('TWITCH_CHANNEL_USERNAME', channel_name)
clientEventSub.connect('wss://eventsub.wss.twitch.tv/ws')
}
return res.send('Login successful !')
})
// Twitch Panel
app.get('/twitch/panel/:file', async (req, res) => {
let file = req.params.file
if (file === 'data') {
//let { panel_user_id } = req.query
let panel_user_id = '44322889'
//let event_user_id = '55833896'
//let event_user_name = 'angelskimi'
//await rewardRedemption(event_user_id, event_user_name)
let panel_data = await getRewardData()
let response = { scoreboard: panel_data, user: panel_data.find(entry => entry.user_id === panel_user_id) }
return res.json(response)
}
else return res.sendFile(__dirname + '/public/panel/' + file)
})
app.listen(port, () => { console.log(`Express listening at port ${port} !`) })
// CHATBOT
const clientChatBot = new WebSocketClient()
let connectionChatBot
clientChatBot.on('connect', async connection => {
connectionChatBot = connection
console.log('Twitch ChatBot WebSocket Connected !')
// Check if the user access token is still valid
let [user_access_token, user_name] = await checkUser(process.env.TWITCH_USER_ACCESS_TOKEN)
if (user_access_token === 'no_refresh') return console.log("Can't refresh user access token: ", user_name)
// Authenticate to Twitch IRC and join channel
connection.sendUTF('CAP REQ :twitch.tv/commands twitch.tv/membership twitch.tv/tags')
connection.sendUTF(`PASS oauth:${user_access_token}`)
connection.sendUTF(`NICK ${user_name}`)
connection.sendUTF(`JOIN #${channel_name}`)
connection.sendUTF(`PRIVMSG #${channel_name} :Salut tout le monde !`)
connection.on('message', async message => {
if (message.type === 'utf8') {
try {
let data = parseMessage(message.utf8Data)
// Handle incoming messages
if (data.command.command === 'PRIVMSG') {
let message = data.parameters.split('\r\n')[0]
console.log(`${data.source.nick}: ${message}`)
if (message.includes('@Bot_Laytho')) {
connection.sendUTF(`@reply-parent-msg-id=${data.tags.id} ${chatBeginMsg} :Kestuveu @${data.tags['display-name']} ?`)
connection.sendUTF(`${chatBeginMsg} :/timeout ${data.tags['display-name']} 60 T'as pas à me parler comme ça !`)
}
else if (message.toLowerCase().includes('quoi')) {
connection.sendUTF(`@reply-parent-msg-id=${data.tags.id} ${chatBeginMsg} :@${data.tags['display-name']} Coubeh !`)
connection.sendUTF(`${chatBeginMsg} :/timeout ${data.tags['display-name']} 60 T'as pas à me parler comme ça !`)
}
else if (message === '!ping') {
connection.sendUTF(`@reply-parent-msg-id=${data.tags.id} ${chatBeginMsg} :Pong !`)
}
} else if (data.command.command === 'NOTICE') {
if (data.parameters.includes('Login authentication failed')) {
console.log('Erreur de connexion ChatBot, veuillez vous reconnecter !\nhttps://angels-dev.fr/twitch/oauth/user')
}
}
} catch (error) { } // catch (error) { console.error(error) }
} })
.on('error', error => { console.error(error) })
.on('close', () => { console.log('Twitch ChatBot Connection Closed !') })
}).on('connectFailed', error => { console.error(error) })
clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
// EVENTSUB
const clientEventSub = new WebSocketClient().on('connect', async connection => {
console.log('Twitch EventSub WebSocket Connected !')
// Check if the channel access token is still valid
let [channel_access_token, channel_name] = await checkChannel(process.env.TWITCH_CHANNEL_ACCESS_TOKEN)
if (channel_access_token === 'no_refresh') return console.log("Can't refresh channel access token: ", channel_name)
connection.on('message', async message => {
if (message.type === 'utf8') {
try {
let data = JSON.parse(message.utf8Data)
// Check when Twitch asks to login
if (data.metadata.message_type === 'session_welcome') {
// Get broadcaster user id and reward id
let broadcaster_user_id = await getUserInfo(client_id, channel_access_token).id
writeEnv('TWITCH_CHANNEL_BROADCASTER_ID', broadcaster_user_id)
let reward_id = await getRewardID(client_id, channel_access_token, broadcaster_user_id, channel_reward_name)
writeEnv('TWITCH_CHANNEL_REWARD_ID', reward_id)
let topics = {
'channel.channel_points_custom_reward_redemption.add': { version: '1', condition: { broadcaster_user_id, reward_id } },
'stream.online': { version: '1', condition: { broadcaster_user_id } }
}
// Subscribe to all events required
for (let type in topics) {
console.log(`Creating ${type}...`)
let { version, condition } = topics[type]
let status = await subscribeToEvents(client_id, channel_access_token, data.payload.session.id, type, version, condition)
if (!status) return console.error(`Failed to create ${type}`)
else if (status.error) {
console.error(status)
console.log('Erreur de connexion EventSub, veuillez vous reconnecter !\nhttps://angels-dev.fr/twitch/oauth/channel')
return connection.sendUTF(`${chatBeginMsg} :@${channel_name} Erreur de connexion EventSub, veuillez vous reconnecter !\nhttps://angels-dev.fr/twitch/oauth/channel`)
} else console.log(`Successfully created ${type}`)
}
}
// Handle notification messages for reward redemption
else if (data.metadata.message_type === 'notification') {
let { subscription, event } = data.payload
if (subscription.type === 'channel.channel_points_custom_reward_redemption.add') {
console.log(`User ${{ user_name } = event} claimed reward ${event.reward.title} !`)
await rewardRedemption({ user_id, user_name } = event)
}
else if (subscription.type === 'stream.online') {
console.log(`Stream from ${event.broadcaster_user_name} is now online, connecting to chat...`)
clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
}
}
// Don't log ping/pong messages
else if (data.metadata.message_type === 'session_keepalive') return
// Log unknown messages
else console.log(data)
} catch (error) { console.error(error) }
} })
.on('error', error => { console.error(error) })
.on('close', () => { console.log('Twitch EventSub Connection Closed !') })
}).on('connectFailed', error => { console.error(error) })
clientEventSub.connect('wss://eventsub.wss.twitch.tv/ws')