Traitement commandes et ajout J/arrow + Fix login
This commit is contained in:
256
app.js
256
app.js
@@ -1,6 +1,7 @@
|
|||||||
// PACKAGES
|
// PACKAGES
|
||||||
const WebSocketClient = require('websocket').client
|
const WebSocketClient = require('websocket').client
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
|
const getUserID = require('./utils/getUserID')
|
||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
require('require-all')(__dirname + '/utils/')
|
require('require-all')(__dirname + '/utils/')
|
||||||
|
|
||||||
@@ -9,16 +10,20 @@ require('require-all')(__dirname + '/utils/')
|
|||||||
let client_id = process.env.TWITCH_APP_ID
|
let client_id = process.env.TWITCH_APP_ID
|
||||||
let client_secret = process.env.TWITCH_APP_SECRET
|
let client_secret = process.env.TWITCH_APP_SECRET
|
||||||
|
|
||||||
let user_name = process.env.TWITCH_USER_USERNAME
|
let user_name = process.env.TWITCH_USER_NAME
|
||||||
let channel_name = process.env.TWITCH_CHANNEL_USERNAME
|
let channel_name = process.env.TWITCH_CHANNEL_NAME
|
||||||
let channel_reward_name = process.env.TWITCH_CHANNEL_REWARD_NAME
|
let channel_reward_name = process.env.TWITCH_CHANNEL_REWARD_NAME
|
||||||
|
|
||||||
|
let bot_prefix = process.env.TWITCH_BOT_PREFIX
|
||||||
|
let bot_coubeh = process.env.TWITCH_BOT_COUBEH
|
||||||
|
let bot_mention = process.env.TWITCH_BOT_MENTION
|
||||||
|
|
||||||
const user_scope = ['chat:read', 'chat:edit', 'channel:moderate']
|
const user_scope = ['chat:read', 'chat:edit', 'channel:moderate']
|
||||||
const channel_scope = ['channel:manage:redemptions']
|
const channel_scope = ['channel:manage:redemptions']
|
||||||
|
|
||||||
const uri = 'https://angels-dev.fr/twitch/'
|
const redirect_uri = 'https://angels-dev.fr/twitch/oauth/login/'
|
||||||
const redirect_uri = uri + 'oauth/login/'
|
const chatBeginMsg = `PRIVMSG #${channel_name} :`
|
||||||
const chatBeginMsg = `PRIVMSG #${channel_name}`
|
const chatReplyMsg = (id) => `@reply-parent-msg-id=${id} ${chatBeginMsg}`
|
||||||
|
|
||||||
|
|
||||||
// EXPRESS
|
// EXPRESS
|
||||||
@@ -29,31 +34,34 @@ app.use(express.static('public'))
|
|||||||
|
|
||||||
// Twitch OAuth
|
// Twitch OAuth
|
||||||
app.get('/twitch/oauth/:type', async (req, res) => {
|
app.get('/twitch/oauth/:type', async (req, res) => {
|
||||||
|
console.log(`${new Date().toLocaleString()} - ${req.method} ${req._parsedUrl.pathname} from ${req.socket.remoteAddress}`)
|
||||||
let type = req.params.type
|
let type = req.params.type
|
||||||
|
|
||||||
let url = await oauthGen(client_id, redirect_uri + type, type === 'user' ? user_scope : type === 'channel' ? channel_scope : [])
|
let url = await oauthGen(client_id, redirect_uri + type, type === 'user' ? user_scope : type === 'channel' ? channel_scope : [])
|
||||||
return res.redirect(url)
|
return res.redirect(url)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/twitch/oauth/login/:type', async (req, res) => {
|
app.get('/twitch/oauth/login/:type', async (req, res) => {
|
||||||
|
console.log(`${new Date().toLocaleString()} - ${req.method} ${req._parsedUrl.pathname} from ${req.socket.remoteAddress}`)
|
||||||
let type = req.params.type
|
let type = req.params.type
|
||||||
|
|
||||||
if (type === 'user') {
|
if (type === 'user') {
|
||||||
[ user_access_token, user_refresh_token ] = await getUserAccessToken(client_id, client_secret, req.query.code, redirect_uri + type)
|
let [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_ACCESS_TOKEN', user_access_token)
|
||||||
writeEnv('TWITCH_USER_REFRESH_TOKEN', user_refresh_token)
|
writeEnv('TWITCH_USER_REFRESH_TOKEN', user_refresh_token)
|
||||||
|
|
||||||
user_name = await getUserInfo(client_id, user_access_token).login
|
user_name = await getUserInfo(client_id, user_access_token, 'login')
|
||||||
writeEnv('TWITCH_USER_USERNAME', user_name)
|
writeEnv('TWITCH_USER_NAME', user_name)
|
||||||
|
|
||||||
clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
|
clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
|
||||||
}
|
}
|
||||||
else if (type === 'channel') {
|
else if (type === 'channel') {
|
||||||
[ channel_access_token, channel_refresh_token ] = await getUserAccessToken(client_id, client_secret, req.query.code, redirect_uri + type)
|
let [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_ACCESS_TOKEN', channel_access_token)
|
||||||
writeEnv('TWITCH_CHANNEL_REFRESH_TOKEN', channel_refresh_token)
|
writeEnv('TWITCH_CHANNEL_REFRESH_TOKEN', channel_refresh_token)
|
||||||
|
|
||||||
channel_name = await getUserInfo(client_id, channel_access_token).login
|
channel_name = await getUserInfo(client_id, channel_access_token, 'login')
|
||||||
writeEnv('TWITCH_CHANNEL_USERNAME', channel_name)
|
writeEnv('TWITCH_CHANNEL_NAME', channel_name)
|
||||||
|
|
||||||
clientEventSub.connect('wss://eventsub.wss.twitch.tv/ws')
|
clientEventSub.connect('wss://eventsub.wss.twitch.tv/ws')
|
||||||
}
|
}
|
||||||
@@ -62,25 +70,21 @@ app.get('/twitch/oauth/login/:type', async (req, res) => {
|
|||||||
|
|
||||||
// Twitch Panel
|
// Twitch Panel
|
||||||
app.get('/twitch/panel/:file', async (req, res) => {
|
app.get('/twitch/panel/:file', async (req, res) => {
|
||||||
|
console.log(req.socket)
|
||||||
|
console.log(`${new Date().toLocaleString()} - ${req.method} ${req._parsedUrl.pathname} from ${req.socket.remoteAddress}`)
|
||||||
let file = req.params.file
|
let file = req.params.file
|
||||||
|
|
||||||
if (file === 'data') {
|
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 panel_data = await getRewardData()
|
||||||
let response = { scoreboard: panel_data, user: panel_data.find(entry => entry.user_id === panel_user_id) }
|
//let response = { scoreboard: panel_data, viewer: panel_data.find(entry => entry.viewer_id === panel_viewer_id) }
|
||||||
|
let response = { scoreboard: panel_data }
|
||||||
|
|
||||||
return res.json(response)
|
return res.json(response)
|
||||||
}
|
}
|
||||||
else return res.sendFile(__dirname + '/public/panel/' + file)
|
else return res.sendFile(__dirname + '/public/panel/' + file)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.listen(port, () => { console.log(`Express listening at port ${port} !`) })
|
app.listen(port, () => { console.log(`[SYS] Express listening at port ${port} !`) })
|
||||||
|
|
||||||
|
|
||||||
// CHATBOT
|
// CHATBOT
|
||||||
@@ -89,8 +93,7 @@ let connectionChatBot
|
|||||||
|
|
||||||
clientChatBot.on('connect', async connection => {
|
clientChatBot.on('connect', async connection => {
|
||||||
connectionChatBot = connection
|
connectionChatBot = connection
|
||||||
|
console.log('[SYS] Twitch ChatBot WebSocket Connected !')
|
||||||
console.log('Twitch ChatBot WebSocket Connected !')
|
|
||||||
|
|
||||||
// Check if the user access token is still valid
|
// Check if the user access token is still valid
|
||||||
let [user_access_token, user_name] = await checkUser(process.env.TWITCH_USER_ACCESS_TOKEN)
|
let [user_access_token, user_name] = await checkUser(process.env.TWITCH_USER_ACCESS_TOKEN)
|
||||||
@@ -101,108 +104,159 @@ clientChatBot.on('connect', async connection => {
|
|||||||
connection.sendUTF(`PASS oauth:${user_access_token}`)
|
connection.sendUTF(`PASS oauth:${user_access_token}`)
|
||||||
connection.sendUTF(`NICK ${user_name}`)
|
connection.sendUTF(`NICK ${user_name}`)
|
||||||
connection.sendUTF(`JOIN #${channel_name}`)
|
connection.sendUTF(`JOIN #${channel_name}`)
|
||||||
connection.sendUTF(`PRIVMSG #${channel_name} :Salut tout le monde !`)
|
connection.sendUTF(`${chatBeginMsg} Salut tout le monde !`)
|
||||||
|
|
||||||
connection.on('message', async message => {
|
connection.on('message', async message => { if (message.type === 'utf8') { try {
|
||||||
if (message.type === 'utf8') {
|
let data = parseMessage(message.utf8Data)
|
||||||
try {
|
//console.log(data)
|
||||||
let data = parseMessage(message.utf8Data)
|
|
||||||
|
|
||||||
// Handle incoming messages
|
// Handle incoming messages
|
||||||
if (data.command.command === 'PRIVMSG') {
|
if (data.command.command === 'PRIVMSG') {
|
||||||
let message = data.parameters.split('\r\n')[0]
|
let message = data.parameters.split('\r\n')[0]
|
||||||
console.log(`${data.source.nick}: ${message}`)
|
console.log(`${data.source.nick}: ${message}`)
|
||||||
|
|
||||||
if (message.includes('@Bot_Laytho')) {
|
if (message.slice(0, 2) === bot_prefix) {
|
||||||
connection.sendUTF(`@reply-parent-msg-id=${data.tags.id} ${chatBeginMsg} :Kestuveu @${data.tags['display-name']} ?`)
|
if (data.tags.badges.moderator !== '1') return connection.sendUTF(`${chatReplyMsg(data.tags.id)} Oh lache ça, t'es fou toi !`)
|
||||||
connection.sendUTF(`${chatBeginMsg} :/timeout ${data.tags['display-name']} 60 T'as pas à me parler comme ça !`)
|
|
||||||
}
|
let command = message.split(bot_prefix)[1].split(' ')[0]
|
||||||
else if (message.toLowerCase().includes('quoi')) {
|
let args = message.split(' ').slice(1)
|
||||||
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 !`)
|
if (command === 'ping') connection.sendUTF(`${chatReplyMsg(data.tags.id)} Pong !`)
|
||||||
}
|
else if (command === 'coubeh') {
|
||||||
else if (message === '!ping') {
|
if (bot_coubeh === 'true') { bot_coubeh = 'false'
|
||||||
connection.sendUTF(`@reply-parent-msg-id=${data.tags.id} ${chatBeginMsg} :Pong !`)
|
connection.sendUTF(`${chatReplyMsg(data.tags.id)} Ok j'arrête de flop les viewers...`) }
|
||||||
}
|
else { bot_coubeh = 'true'
|
||||||
} else if (data.command.command === 'NOTICE') {
|
connection.sendUTF(`${chatReplyMsg(data.tags.id)} Aller c'est parti pour faire flop du monde :)))`) }
|
||||||
if (data.parameters.includes('Login authentication failed')) {
|
writeEnv('BOT_COUBEH', bot_coubeh)
|
||||||
console.log('Erreur de connexion ChatBot, veuillez vous reconnecter !\nhttps://angels-dev.fr/twitch/oauth/user')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) { } // catch (error) { console.error(error) }
|
else if (command === 'mention') {
|
||||||
} })
|
if (bot_mention === 'true') { bot_mention = 'false'
|
||||||
|
connection.sendUTF(`${chatReplyMsg(data.tags.id)} Ah tu veux plus que je te répondes ? Ok dac`) }
|
||||||
|
else { bot_mention = 'true'
|
||||||
|
connection.sendUTF(`${chatReplyMsg(data.tags.id)} Maintenant vous allez arrêter de me parler :(((`) }
|
||||||
|
writeEnv('BOT_MENTION', bot_mention)
|
||||||
|
}
|
||||||
|
else if (command === 'arrow') {
|
||||||
|
if ((args.length < 2 || args.length > 4)
|
||||||
|
|| !args[1].split('@')[1]
|
||||||
|
|| (args.length === 2 && args[0] !== 'get')
|
||||||
|
|| (args.length >= 3 && (
|
||||||
|
(args[0] !== 'add' && args[0] !== 'remove' && args[0] !== 'set')
|
||||||
|
|| !parseInt(args[2])
|
||||||
|
))
|
||||||
|
|| (args.length === 4 && (args[3] !== 'current' && args[3] !== 'permanent'))
|
||||||
|
) return connection.sendUTF(`${chatReplyMsg(data.tags.id)} Syntaxe: J/arrow <get> <@viewer> | <add|remove|set> <@viewer> <quantity> [current|permanent]`)
|
||||||
|
|
||||||
|
let action = args[0]
|
||||||
|
let viewer_login = args[1].split('@')[1].toLowerCase()
|
||||||
|
let viewer_id = await getUserID(client_id, user_access_token, viewer_login)
|
||||||
|
let quantity = parseInt(args[2])
|
||||||
|
let type = args[3]
|
||||||
|
if (quantity < 0) return connection.sendUTF(`${chatReplyMsg(data.tags.id)} Tu veux spawn un trou noir dans le stand ou quoi ?!`)
|
||||||
|
|
||||||
|
let result = await modifyReward(viewer_id, viewer_login, action, quantity, type)
|
||||||
|
if (result.status === 'get_entry') connection.sendUTF(`${chatReplyMsg(data.tags.id)} ${args[1]} a ${result.count} flèche(s) dans son carquois et ${result.current_count} flèche(s) permanente(s) !`)
|
||||||
|
else if (result.status === 'insert_entry') connection.sendUTF(`${chatReplyMsg(data.tags.id)} ${args[1]} a été ajouté au stand avec ${quantity} flèche(s) !`)
|
||||||
|
else if (result.status === 'update_entry') connection.sendUTF(`${chatReplyMsg(data.tags.id)} ${quantity} flèche(s) ajoutée(s) à ${args[1]} !`)
|
||||||
|
else if (result.status === 'no_get_entry') connection.sendUTF(`${chatReplyMsg(data.tags.id)} ${args[1]} ne dispose d'aucune flèche, il n'est même pas dans le stand !`)
|
||||||
|
else if (result.status === 'no_delete_entry') connection.sendUTF(`${chatReplyMsg(data.tags.id)} Impossble de retirer des flèches à ${args[1]}, il n'en a aucune !`)
|
||||||
|
else if (result.status === 'not_enough_count') connection.sendUTF(`${chatReplyMsg(data.tags.id)} ${args[1]} n'a pas assez de flèches permanentes pour lui en enlever ${quantity} !`)
|
||||||
|
else if (result.status === 'not_enough_current_count') connection.sendUTF(`${chatReplyMsg(data.tags.id)} ${args[1]} n'a pas assez de flèches dans son carquois pour lui en enlever ${quantity} !`)
|
||||||
|
}
|
||||||
|
else connection.sendUTF(`${chatReplyMsg(data.tags.id)} Commande inconnue !`)
|
||||||
|
}
|
||||||
|
else if (message.includes('@Bot_Laytho') && bot_mention === 'true') {
|
||||||
|
connection.sendUTF(`${chatReplyMsg(data.tags.id)} 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') && bot_coubeh === 'true') {
|
||||||
|
connection.sendUTF(`${chatReplyMsg(data.tags.id)} @${data.tags['display-name']} Coubeh !`)
|
||||||
|
//connection.sendUTF(`${chatBeginMsg} /timeout ${data.tags['display-name']} 60 T'as pas à me parler comme ça !`)
|
||||||
|
}
|
||||||
|
} else if (data.command.command === 'NOTICE' && data.parameters.includes('Login authentication failed')) {
|
||||||
|
console.log('[SYS] Erreur de connexion ChatBot, veuillez vous reconnecter !\nhttps://angels-dev.fr/twitch/oauth/user')
|
||||||
|
}
|
||||||
|
} catch (error) { } } })
|
||||||
.on('error', error => { console.error(error) })
|
.on('error', error => { console.error(error) })
|
||||||
.on('close', () => { console.log('Twitch ChatBot Connection Closed !') })
|
.on('close', () => {
|
||||||
|
console.log('[SYS] Twitch ChatBot Connection Closed !')
|
||||||
|
if (connectionEventSub.state === 'open') clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
|
||||||
|
})
|
||||||
}).on('connectFailed', error => { console.error(error) })
|
}).on('connectFailed', error => { console.error(error) })
|
||||||
|
|
||||||
clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
|
clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
|
||||||
|
|
||||||
|
|
||||||
// EVENTSUB
|
// EVENTSUB
|
||||||
const clientEventSub = new WebSocketClient().on('connect', async connection => {
|
const clientEventSub = new WebSocketClient()
|
||||||
console.log('Twitch EventSub WebSocket Connected !')
|
let connectionEventSub
|
||||||
|
|
||||||
// Check if the channel access token is still valid
|
clientEventSub.on('connect', async connection => {
|
||||||
let [channel_access_token, channel_name] = await checkChannel(process.env.TWITCH_CHANNEL_ACCESS_TOKEN)
|
connectionEventSub = connection
|
||||||
if (channel_access_token === 'no_refresh') return console.log("Can't refresh channel access token: ", channel_name)
|
console.log('[SYS] Twitch EventSub WebSocket Connected !')
|
||||||
|
|
||||||
connection.on('message', async message => {
|
connection.on('message', async message => { if (message.type === 'utf8') { try {
|
||||||
if (message.type === 'utf8') {
|
let data = JSON.parse(message.utf8Data)
|
||||||
try {
|
|
||||||
let data = JSON.parse(message.utf8Data)
|
|
||||||
|
|
||||||
// Check when Twitch asks to login
|
// Check when Twitch asks to login
|
||||||
if (data.metadata.message_type === 'session_welcome') {
|
if (data.metadata.message_type === 'session_welcome') {
|
||||||
|
|
||||||
// Get broadcaster user id and reward id
|
// Check if the channel access token is still valid before connecting
|
||||||
let broadcaster_user_id = await getUserInfo(client_id, channel_access_token).id
|
let [channel_access_token, channel_name] = await checkChannel(process.env.TWITCH_CHANNEL_ACCESS_TOKEN)
|
||||||
writeEnv('TWITCH_CHANNEL_BROADCASTER_ID', broadcaster_user_id)
|
if (channel_access_token === 'no_refresh') return console.log("[SYS] Can't refresh channel access token: ", channel_name)
|
||||||
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
|
// Get broadcaster user id and reward id
|
||||||
for (let type in topics) {
|
let broadcaster_user_id = await getUserInfo(client_id, channel_access_token, 'id')
|
||||||
console.log(`Creating ${type}...`)
|
writeEnv('TWITCH_CHANNEL_BROADCASTER_ID', broadcaster_user_id)
|
||||||
let { version, condition } = topics[type]
|
let reward_id = await getRewardID(client_id, channel_access_token, broadcaster_user_id, channel_reward_name)
|
||||||
|
writeEnv('TWITCH_CHANNEL_REWARD_ID', reward_id)
|
||||||
|
|
||||||
let status = await subscribeToEvents(client_id, channel_access_token, data.payload.session.id, type, version, condition)
|
let topics = {
|
||||||
if (!status) return console.error(`Failed to create ${type}`)
|
'channel.channel_points_custom_reward_redemption.add': { version: '1', condition: { broadcaster_user_id, reward_id } },
|
||||||
|
'stream.online': { version: '1', condition: { broadcaster_user_id } }
|
||||||
|
}
|
||||||
|
|
||||||
else if (status.error) {
|
// Subscribe to all events required
|
||||||
console.error(status)
|
for (let type in topics) {
|
||||||
console.log('Erreur de connexion EventSub, veuillez vous reconnecter !\nhttps://angels-dev.fr/twitch/oauth/channel')
|
console.log(`[SYS] Creating ${type}...`)
|
||||||
return connection.sendUTF(`${chatBeginMsg} :@${channel_name} Erreur de connexion EventSub, veuillez vous reconnecter !\nhttps://angels-dev.fr/twitch/oauth/channel`)
|
let { version, condition } = topics[type]
|
||||||
} else console.log(`Successfully created ${type}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle notification messages for reward redemption
|
let status = await subscribeToEvents(client_id, channel_access_token, data.payload.session.id, type, version, condition)
|
||||||
else if (data.metadata.message_type === 'notification') {
|
if (!status) return console.error(`[SYS] Failed to create ${type}`)
|
||||||
let { subscription, event } = data.payload
|
else if (status.error) return console.log('[SYS] Erreur de connexion EventSub, veuillez vous reconnecter !')
|
||||||
|
else console.log(`[SYS] Successfully created ${type}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (subscription.type === 'channel.channel_points_custom_reward_redemption.add') {
|
// Handle notification messages for reward redemption
|
||||||
console.log(`User ${{ user_name } = event} claimed reward ${event.reward.title} !`)
|
else if (data.metadata.message_type === 'notification') {
|
||||||
await rewardRedemption({ user_id, user_name } = event)
|
let { subscription, event } = data.payload
|
||||||
}
|
|
||||||
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
|
if (subscription.type === 'channel.channel_points_custom_reward_redemption.add') {
|
||||||
else if (data.metadata.message_type === 'session_keepalive') return
|
let viewer_id = event.user_id
|
||||||
|
let viewer_name = event.user_name
|
||||||
|
console.log(`[SYS] Viewer ${viewer_name} claimed reward ${event.reward.title} !`)
|
||||||
|
|
||||||
// Log unknown messages
|
let result = await rewardRedemption(viewer_id, viewer_name)
|
||||||
else console.log(data)
|
|
||||||
} catch (error) { console.error(error) }
|
if (result.status === 'insert_entry') connectionChatBot.sendUTF(`${chatReplyMsg(viewer_id)} a récupéré sa première ${event.reward.title}, GG !`)
|
||||||
} })
|
else if (result.status === 'update_entry') connectionChatBot.sendUTF(`${chatReplyMsg(viewer_id)} a récupéré sa ${event.reward.title}, t'en as ${result.current_count} dans ton carquois et récupéré ${result.count} depuis le début !`)
|
||||||
|
}
|
||||||
|
else if (subscription.type === 'stream.online') {
|
||||||
|
console.log(`[SYS] 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('error', error => { console.error(error) })
|
||||||
.on('close', () => { console.log('Twitch EventSub Connection Closed !') })
|
.on('close', () => { console.log('[SYS] Twitch EventSub Connection Closed !') })
|
||||||
}).on('connectFailed', error => { console.error(error) })
|
}).on('connectFailed', error => { console.error(error) })
|
||||||
|
|
||||||
clientEventSub.connect('wss://eventsub.wss.twitch.tv/ws')
|
clientEventSub.connect('wss://eventsub.wss.twitch.tv/ws')
|
||||||
14
public/panel/config.html
Normal file
14
public/panel/config.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<script src="https://extension-files.twitch.tv/helper/v1/twitch-ext.min.js"></script>
|
||||||
|
<script src="https://angels-dev.fr/twitch/panel/script.js"></script>
|
||||||
|
|
||||||
|
<title>Panel Laytho Config</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="div__title">
|
||||||
|
<h2 class="title">Configuration</h2>
|
||||||
|
</div>
|
||||||
|
<p>Work in Progress !</p>
|
||||||
|
</html>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
<link rel="stylesheet" href="https://angels-dev.fr/twitch/panel/panel.css">
|
<link rel="stylesheet" href="https://angels-dev.fr/twitch/panel/panel.css">
|
||||||
<link rel="image/svg" href="https://angels-dev.fr/twitch/panel/arrow.svg">
|
<link rel="image/svg" href="https://angels-dev.fr/twitch/panel/arrow.svg">
|
||||||
|
|
||||||
<title>Laytho Panel</title>
|
<title>Panel Laytho</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="div__title">
|
<div class="div__title">
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const xhr = new XMLHttpRequest()
|
const xhr = new XMLHttpRequest()
|
||||||
const url = 'https://angels-dev.fr/twitch/panel/data'
|
|
||||||
|
|
||||||
xhr.open('GET', url, true)
|
xhr.open('GET', 'https://angels-dev.fr/twitch/panel/data', true)
|
||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
let data = JSON.parse(xhr.responseText)
|
let data = JSON.parse(xhr.responseText)
|
||||||
@@ -12,7 +11,7 @@ xhr.onload = () => {
|
|||||||
let row = tbodyRef.insertRow()
|
let row = tbodyRef.insertRow()
|
||||||
|
|
||||||
row.insertCell().appendChild(document.createTextNode(data.scoreboard.indexOf(entry) + 1))
|
row.insertCell().appendChild(document.createTextNode(data.scoreboard.indexOf(entry) + 1))
|
||||||
row.insertCell().appendChild(document.createTextNode(entry.user_name))
|
row.insertCell().appendChild(document.createTextNode(entry.viewer_name))
|
||||||
row.insertCell().appendChild(document.createTextNode(entry.count))
|
row.insertCell().appendChild(document.createTextNode(entry.count))
|
||||||
|
|
||||||
let i = 0
|
let i = 0
|
||||||
|
|||||||
@@ -7,21 +7,26 @@ const writeEnv = require('./writeEnv')
|
|||||||
let client_id = process.env.TWITCH_APP_ID
|
let client_id = process.env.TWITCH_APP_ID
|
||||||
let client_secret = process.env.TWITCH_APP_SECRET
|
let client_secret = process.env.TWITCH_APP_SECRET
|
||||||
|
|
||||||
module.exports = checkChannel = (async (access_token) => {
|
module.exports = checkChannel = (async (channel_access_token) => {
|
||||||
|
let result = [channel_access_token, '']
|
||||||
|
|
||||||
// Check if channel_access_token is valid
|
// Check if channel_access_token is valid
|
||||||
if (!await validateToken(access_token)) {
|
if (!await validateToken(channel_access_token)) {
|
||||||
|
result = await refreshToken(client_id, client_secret, process.env.TWITCH_CHANNEL_REFRESH_TOKEN)
|
||||||
|
|
||||||
// If not, refresh it
|
|
||||||
let result = await refreshToken(client_id, client_secret, process.env.TWITCH_CHANNEL_REFRESH_TOKEN)
|
|
||||||
if (result.status) return result = ['no_refresh', result.message]
|
if (result.status) return result = ['no_refresh', result.message]
|
||||||
|
else {
|
||||||
|
let [channel_access_token, channel_refresh_token] = result
|
||||||
|
writeEnv('TWITCH_CHANNEL_ACCESS_TOKEN', channel_access_token)
|
||||||
|
writeEnv('TWITCH_CHANNEL_REFRESH_TOKEN', channel_refresh_token)
|
||||||
|
|
||||||
let [channel_access_token, channel_refresh_token] = result
|
let channel_name = await getUserInfo(client_id, channel_access_token, 'login')
|
||||||
writeEnv('TWITCH_CHANNEL_ACCESS_TOKEN', channel_access_token)
|
writeEnv('TWITCH_CHANNEL_NAME', channel_name)
|
||||||
writeEnv('TWITCH_CHANNEL_REFRESH_TOKEN', channel_refresh_token)
|
}
|
||||||
|
} else {
|
||||||
let channel_name = await getUserInfo(client_id, channel_access_token).login
|
let channel_name = await getUserInfo(client_id, channel_access_token, 'login')
|
||||||
writeEnv('TWITCH_CHANNEL_USERNAME', channel_name)
|
result = [channel_access_token, channel_name]
|
||||||
|
writeEnv('TWITCH_CHANNEL_NAME', channel_name)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
@@ -7,21 +7,26 @@ const writeEnv = require('./writeEnv')
|
|||||||
let client_id = process.env.TWITCH_APP_ID
|
let client_id = process.env.TWITCH_APP_ID
|
||||||
let client_secret = process.env.TWITCH_APP_SECRET
|
let client_secret = process.env.TWITCH_APP_SECRET
|
||||||
|
|
||||||
module.exports = checkUser = (async (access_token) => {
|
module.exports = checkUser = (async (user_access_token) => {
|
||||||
|
let result = [user_access_token, '']
|
||||||
|
|
||||||
// Check if user_access_token is valid
|
// Check if user_access_token is valid
|
||||||
if (!await validateToken(access_token)) {
|
if (!await validateToken(user_access_token)) {
|
||||||
|
result = await refreshToken(client_id, client_secret, process.env.TWITCH_USER_REFRESH_TOKEN)
|
||||||
|
|
||||||
// If not, refresh it
|
|
||||||
let result = await refreshToken(client_id, client_secret, process.env.TWITCH_USER_REFRESH_TOKEN)
|
|
||||||
if (result.status) return result = ['no_refresh', result.message]
|
if (result.status) return result = ['no_refresh', result.message]
|
||||||
|
else {
|
||||||
|
let [user_access_token, user_refresh_token] = result
|
||||||
|
writeEnv('TWITCH_USER_ACCESS_TOKEN', user_access_token)
|
||||||
|
writeEnv('TWITCH_USER_REFRESH_TOKEN', user_refresh_token)
|
||||||
|
|
||||||
let [user_access_token, user_refresh_token] = result
|
let user_name = await getUserInfo(client_id, user_access_token, 'login')
|
||||||
writeEnv('TWITCH_USER_ACCESS_TOKEN', user_access_token)
|
writeEnv('TWITCH_USER_NAME', user_name)
|
||||||
writeEnv('TWITCH_USER_REFRESH_TOKEN', user_refresh_token)
|
}
|
||||||
|
} else {
|
||||||
let user_name = await getUserInfo(client_id, user_access_token).login
|
let user_name = await getUserInfo(client_id, user_access_token, 'login')
|
||||||
writeEnv('TWITCH_USER_USERNAME', user_name)
|
result = [user_access_token, user_name]
|
||||||
|
writeEnv('TWITCH_USER_NAME', user_name)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
@@ -11,7 +11,7 @@ module.exports = getRewardData = (async () => {
|
|||||||
database: process.env.MYSQL_DATABASE
|
database: process.env.MYSQL_DATABASE
|
||||||
})
|
})
|
||||||
|
|
||||||
// Retrieve the count of rewards claimed by each user, sorted by count
|
// Retrieve the count of rewards claimed by each viewer, sorted by count
|
||||||
let results = await connection.execute('SELECT * FROM rewards ORDER BY count DESC')
|
let results = await connection.execute('SELECT * FROM rewards ORDER BY count DESC')
|
||||||
.then(async ([rows, fields]) => { return rows })
|
.then(async ([rows, fields]) => { return rows })
|
||||||
.catch(error => { console.error(error) })
|
.catch(error => { console.error(error) })
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module.exports = getUserAccessToken = (async (client_id, client_secret, code, re
|
|||||||
redirect_uri,
|
redirect_uri,
|
||||||
grant_type: 'authorization_code'
|
grant_type: 'authorization_code'
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
//console.log(response.data)
|
console.log(response.data)
|
||||||
if (response.data.token_type === 'bearer') return [response.data.access_token, response.data.refresh_token]
|
if (response.data.token_type === 'bearer') return [response.data.access_token, response.data.refresh_token]
|
||||||
}).catch(error => { console.log(error.response.data) })
|
}).catch(error => { console.log(error.response.data) })
|
||||||
})
|
})
|
||||||
13
utils/getUserID.js
Normal file
13
utils/getUserID.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const axios = require('axios')
|
||||||
|
|
||||||
|
module.exports = getUserID = (async (client_id, access_token, login) => {
|
||||||
|
return await axios.get(`https://api.twitch.tv/helix/users?login=${login}`, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${access_token}`,
|
||||||
|
'Client-Id': client_id
|
||||||
|
}
|
||||||
|
}).then(response => {
|
||||||
|
//console.log(response.data)
|
||||||
|
return response.data.data[0].id
|
||||||
|
}).catch(error => { console.log(error.response.data) })
|
||||||
|
})
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
|
|
||||||
module.exports = getUserInfo = (async (client_id, access_token) => {
|
module.exports = getUserInfo = (async (client_id, access_token, type) => {
|
||||||
return await axios.get(`https://api.twitch.tv/helix/users`, {
|
return await axios.get('https://api.twitch.tv/helix/users', {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${access_token}`,
|
'Authorization': `Bearer ${access_token}`,
|
||||||
'Client-Id': client_id
|
'Client-Id': client_id
|
||||||
}
|
}
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
//console.log(response.data)
|
//console.log(response.data)
|
||||||
return response.data.data[0]
|
if (type === 'login') return response.data.data[0].login
|
||||||
|
if (type === 'id') return response.data.data[0].id
|
||||||
}).catch(error => { console.log(error.response.data) })
|
}).catch(error => { console.log(error.response.data) })
|
||||||
})
|
})
|
||||||
72
utils/modifyReward.js
Normal file
72
utils/modifyReward.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
const mysql = require('mysql2/promise')
|
||||||
|
require('dotenv').config()
|
||||||
|
|
||||||
|
module.exports = modifyReward = (async (viewer_id, viewer_name, action, quantity, type) => {
|
||||||
|
// Create a connection to the MySQL database
|
||||||
|
const connection = await mysql.createConnection({
|
||||||
|
host: process.env.MYSQL_HOST,
|
||||||
|
port: process.env.MYSQL_PORT,
|
||||||
|
user: process.env.MYSQL_USER,
|
||||||
|
password: process.env.MYSQL_PASSWORD,
|
||||||
|
database: process.env.MYSQL_DATABASE
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = {}
|
||||||
|
let sql_data = {}
|
||||||
|
|
||||||
|
// Check if the viewer already exists in the rewards table
|
||||||
|
await connection.query('SELECT * FROM rewards WHERE viewer_id = ?', [viewer_id])
|
||||||
|
.then(async ([rows, fields]) => {
|
||||||
|
console.log(rows)
|
||||||
|
|
||||||
|
if (rows.length === 0) {
|
||||||
|
// Viewer doesn't exist, insert a new row
|
||||||
|
sql_data = { viewer_id, viewer_name }
|
||||||
|
|
||||||
|
if (action === 'add' || action === 'set') { // Add or set the viewer with the quantity
|
||||||
|
if (type === 'permanent') sql_data.count = quantity
|
||||||
|
else if (type === 'current') sql_data.current_count = quantity
|
||||||
|
else { sql_data.count = quantity; sql_data.current_count = quantity }
|
||||||
|
|
||||||
|
await connection.query('INSERT INTO rewards SET ?', sql_data) .catch(error => { console.error(error) })
|
||||||
|
return result.status = 'insert_entry'
|
||||||
|
}
|
||||||
|
else if (action === 'get') return result.status = 'no_get_entry' // Can't get a viewer that doesn't exist
|
||||||
|
else if (action === 'remove') return result.status = 'no_delete_entry' // Can't remove a viewer that doesn't exist
|
||||||
|
} else {
|
||||||
|
// Viewer exists, update the count
|
||||||
|
result.count = rows[0].count
|
||||||
|
result.current_count = rows[0].current_count
|
||||||
|
|
||||||
|
if (action === 'get') return result.status = 'get_entry'
|
||||||
|
|
||||||
|
else if (action === 'add') { // Add the quantity
|
||||||
|
if (type === 'permanent') sql_data.count = rows[0].count + quantity
|
||||||
|
else if (type === 'current') sql_data.current_count = rows[0].current_count + quantity
|
||||||
|
else { sql_data.count = rows[0].count + quantity; sql_data.current_count = rows[0].current_count + quantity }
|
||||||
|
}
|
||||||
|
else if (action === 'remove') { // Remove the quantity
|
||||||
|
if (type === 'permanent') sql_data.count = rows[0].count - quantity
|
||||||
|
else if (type === 'current') sql_data.current_count = rows[0].current_count - quantity
|
||||||
|
else { sql_data.count = rows[0].count - quantity; sql_data.current_count = rows[0].current_count - quantity }
|
||||||
|
|
||||||
|
if (sql_data.count < 0) return result.status = 'not_enough_count' // Can't delete more than the count
|
||||||
|
if (sql_data.current_count < 0) return result.status = 'not_enough_current_count' // Can't delete more than the current_count
|
||||||
|
}
|
||||||
|
else if (action === 'set') { // Set the quantity
|
||||||
|
if (type === 'permanent') sql_data.count = quantity
|
||||||
|
else if (type === 'current') sql_data.current_count = quantity
|
||||||
|
else { sql_data.count = quantity; sql_data.current_count = quantity }
|
||||||
|
}
|
||||||
|
|
||||||
|
await connection.query('UPDATE rewards SET ? WHERE viewer_id = ?', [sql_data, viewer_id]).catch(error => { console.error(error) })
|
||||||
|
return result.status = 'update_entry'
|
||||||
|
}
|
||||||
|
}).catch(error => { console.error(error) })
|
||||||
|
|
||||||
|
// Terminate the connection to the database
|
||||||
|
await connection.end()
|
||||||
|
|
||||||
|
result.sql_data = sql_data
|
||||||
|
return result
|
||||||
|
})
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
const mysql = require('mysql2/promise')
|
const mysql = require('mysql2/promise')
|
||||||
|
require('dotenv').config()
|
||||||
|
|
||||||
module.exports = rewardRedemption = (async (user_id, user_name) => {
|
module.exports = rewardRedemption = (async (viewer_id, viewer_name) => {
|
||||||
// Create a connection to the MySQL database
|
// Create a connection to the MySQL database
|
||||||
const connection = await mysql.createConnection({
|
const connection = await mysql.createConnection({
|
||||||
host: process.env.MYSQL_HOST,
|
host: process.env.MYSQL_HOST,
|
||||||
@@ -10,21 +11,33 @@ module.exports = rewardRedemption = (async (user_id, user_name) => {
|
|||||||
database: process.env.MYSQL_DATABASE
|
database: process.env.MYSQL_DATABASE
|
||||||
})
|
})
|
||||||
|
|
||||||
// Check if the user already exists in the rewards table
|
const result = {}
|
||||||
await connection.query('SELECT * FROM rewards WHERE user_id = ?', [user_id])
|
|
||||||
|
// Check if the viewer already exists in the rewards table
|
||||||
|
await connection.query('SELECT * FROM rewards WHERE viewer_id = ?', [viewer_id])
|
||||||
.then(async ([rows, fields]) => {
|
.then(async ([rows, fields]) => {
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
// User doesn't exist, insert a new row
|
// Viewer doesn't exist, insert a new row
|
||||||
await connection.query('INSERT INTO rewards SET ?', { user_id, user_name, count: 1, current_count: 1 })
|
|
||||||
.catch(error => { console.error(error) })
|
let sql_data = { viewer_id, viewer_name, count: 1, current_count: 1 }
|
||||||
|
|
||||||
|
await connection.query('INSERT INTO rewards SET ?', sql_data).catch(error => { console.error(error) })
|
||||||
|
return result.status = 'insert_entry'
|
||||||
} else {
|
} else {
|
||||||
// User exists, update the count
|
// Viewer exists, update the count
|
||||||
const newRow = { count: rows[0].count + 1, current_count: rows[0].current_count + 1 }
|
result.count = rows[0].count + 1
|
||||||
await connection.query('UPDATE rewards SET ? WHERE user_id = ?', [newRow, user_id])
|
result.current_count = rows[0].current_count + 1
|
||||||
.catch(error => { console.error(error) })
|
|
||||||
|
let sql_data = { count: result.count, current_count: result.current_count }
|
||||||
|
|
||||||
|
await connection.query('UPDATE rewards SET ? WHERE viewer_id = ?', [sql_data, viewer_id]).catch(error => { console.error(error) })
|
||||||
|
return result.status = 'update_entry'
|
||||||
}
|
}
|
||||||
}).catch(error => { console.error(error) })
|
}).catch(error => { console.error(error) })
|
||||||
|
|
||||||
// Terminate the connection to the database
|
// Terminate the connection to the database
|
||||||
await connection.end()
|
await connection.end()
|
||||||
|
|
||||||
|
//return [newRow.current_count, newRow.count]
|
||||||
|
return result
|
||||||
})
|
})
|
||||||
@@ -7,7 +7,6 @@ module.exports = validateToken = (async (access_token) => {
|
|||||||
}
|
}
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
//console.log(response.data)
|
//console.log(response.data)
|
||||||
if (response.data.status === '401') return false
|
return true
|
||||||
else return true
|
|
||||||
}).catch(error => { console.log(error.response.data) })
|
}).catch(error => { console.log(error.response.data) })
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user