diff --git a/app.js b/app.js
index 17d74cc..a26e8c1 100644
--- a/app.js
+++ b/app.js
@@ -5,12 +5,12 @@ require('dotenv').config()
// UTILS
+const checkUser = require('./utils/checkUser')
+const checkChannel = require('./utils/checkChannel')
const getRewardData = require('./utils/getRewardData')
const getRewardID = require('./utils/getRewardID')
const getUserAccessToken = require('./utils/getUserAccessToken')
-const getUserID = require('./utils/getUserID')
const getUserInfo = require('./utils/getUserInfo')
-const getUserName = require('./utils/getUserName')
const oauthGen = require('./utils/oauthGen')
const parseMessage = require('./utils/parseMessage')
const rewardRedemption = require('./utils/rewardRedemption')
@@ -54,19 +54,21 @@ app.get('/twitch/oauth/login/:type', async (req, res) => {
let type = req.params.type
if (type === 'user') {
- user_access_token = await getUserAccessToken(client_id, client_secret, req.query.code, redirect_uri + type)
+ [ 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 getUserName(client_id, user_access_token).login
+ 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 = await getUserAccessToken(client_id, client_secret, req.query.code, redirect_uri + type)
+ [ 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 getUserName(client_id, channel_access_token).login
+ channel_name = await getUserInfo(client_id, channel_access_token).login
writeEnv('TWITCH_CHANNEL_USERNAME', channel_name)
clientEventSub.connect('wss://eventsub.wss.twitch.tv/ws')
@@ -102,9 +104,13 @@ const clientChatBot = new WebSocketClient()
let connectionChatBot
clientChatBot.on('connect', async connection => {
- console.log('Twitch ChatBot WebSocket Connected !')
connectionChatBot = connection
+ console.log('Twitch ChatBot WebSocket Connected !')
+
+ // Check if the user access token is still valid
+ //[user_access_token, user_name] = await checkUser(user_access_token)
+
// 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}`)
@@ -151,6 +157,9 @@ clientChatBot.connect('wss://irc-ws.chat.twitch.tv:443')
const clientEventSub = new WebSocketClient().on('connect', async connection => {
console.log('Twitch EventSub WebSocket Connected !')
+ // Check if the channel access token is still valid
+ //[channel_access_token, channel_name] = await checkChannel(channel_access_token)
+
connection.on('message', async message => {
if (message.type === 'utf8') {
try {
@@ -160,7 +169,7 @@ const clientEventSub = new WebSocketClient().on('connect', async connection => {
if (data.metadata.message_type === 'session_welcome') {
// Get broadcaster user id and reward id
- let broadcaster_user_id = await getUserID(client_id, channel_access_token)
+ 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)
diff --git a/public/panel/arrow.svg b/public/panel/arrow.svg
new file mode 100644
index 0000000..c06756a
--- /dev/null
+++ b/public/panel/arrow.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/panel/background.png b/public/panel/background.png
new file mode 100644
index 0000000..a277494
Binary files /dev/null and b/public/panel/background.png differ
diff --git a/public/panel/panel.css b/public/panel/panel.css
index ce59694..bbe85d9 100644
--- a/public/panel/panel.css
+++ b/public/panel/panel.css
@@ -1,16 +1,113 @@
-p {
- color: white;
- text-align: center;
+@import url('https://fonts.googleapis.com/css2?family=Annie+Use+Your+Telescope&display=swap');
+@import url('https://fonts.googleapis.com/css2?family=Advent+Pro&display=swap');
+
+body {
+ /* background-color: #B9F1FD; */
+ background: url(https://angels-dev.fr/twitch/panel/background.png);
+ background-repeat: no-repeat;
+ /* border: 2px solid black; */
+ font-family: 'Advent Pro', sans-serif;
+ font-weight: 400;
+ color: black;
}
+
+.div__title {
+ width: 205px;
+ height: 34px;
+ border-radius: 15px;
+ border-bottom: 1px solid #205E8B;
+ background-color: #5FB5F4;
+ justify-content: center;
+ margin: auto;
+ margin-bottom: 15px;
+}
+
+.title {
+ color: black;
+ text-align: center;
+ font-family: 'Annie Use Your Telescope', cursive;
+ font-size: 24px;
+ font-weight: 600;
+}
+
+.table {
+ margin: auto;
+ border-collapse : separate;
+ border-spacing: 4px;
+}
+
+.table__body {
+ overflow-y: scroll;
+ scrollbar-width: thin; /* "auto" or "thin" */
+ scrollbar-color: #24AEEA #7A7979; /* scroll thumb and track */
+}
+
+.table__rank {
+ background-color: #5FB6F4;
+ width: 30px;
+ height: 20px;
+ border-radius: 5px;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.table__pseudos {
+ background-color: #5FB6F4;
+ width: 200px;
+ height: 20px;
+ border-radius: 5px;
+ text-align: left;
+ padding-left: 5px;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.table__arrows {
+ background-color: #5FB6F4;
+ width: 54px;
+ height: 20px;
+ border-radius: 5px;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.row__rank {
+ background-color: #99CFEE;
+ width: 30px;
+ height: 20px;
+ border-radius: 5px;
+ font-size: 12px;
+ font-weight: 800;
+}
+
+.row__pseudos {
+ background-color: #99CFEE;
+ width: 200px;
+ height: 20px;
+ border-radius: 5px;
+ text-align: left;
+ padding-left: 5px;
+ font-size: 16px;
+ font-weight: 400;
+}
+
+.row__arrows {
+ background-color: #99CFEE;
+ width: 54px;
+ height: 20px;
+ border-radius: 5px;
+ font-size: 14px;
+ font-weight: 400;
+}
+
+.row__arrows::after {
+ content: url(https://angels-dev.fr/twitch/panel/arrow.svg);
+ margin-left: 7.5px;
+}
+
th {
- color: white;
text-align: center;
}
td {
- color: white;
text-align: center;
}
-table .center {
- margin-left: auto;
- margin-right: auto;
-}
\ No newline at end of file
diff --git a/public/panel/panel.html b/public/panel/panel.html
index 9c6fe81..1a53276 100644
--- a/public/panel/panel.html
+++ b/public/panel/panel.html
@@ -1,16 +1,25 @@
-
-
-
+
+
+
+
+
+
-Panel Laytho
-Classement des Daily Arrows
-
-
-
- | Pseudo |
- Daily Arrows |
-
-
-
-
\ No newline at end of file
+ Laytho Panel
+
+
+
+
Stand de tir à l'arc
+
+
+
+
+ | Rank |
+ Pseudo |
+ Carquois |
+
+
+
+
+
\ No newline at end of file
diff --git a/public/panel/script.js b/public/panel/script.js
index def9cbf..cdfe5b0 100644
--- a/public/panel/script.js
+++ b/public/panel/script.js
@@ -8,10 +8,20 @@ xhr.onload = () => {
let tbodyRef = document.getElementById('table').getElementsByTagName('tbody')[0]
- for (let entry of data.scoreboard) {
+ for (entry of data.scoreboard) {
let row = tbodyRef.insertRow()
+
+ row.insertCell().appendChild(document.createTextNode(data.scoreboard.indexOf(entry) + 1))
row.insertCell().appendChild(document.createTextNode(entry.user_name))
row.insertCell().appendChild(document.createTextNode(entry.count))
+
+ let i = 0
+ for (cell of row.cells) {
+ i++
+ if (i === 1) cell.className = "row__rank"
+ if (i === 2) cell.className = "row__pseudos"
+ if (i === 3) cell.className = "row__arrows"
+ }
}
} else console.error('Error:', xhr.statusText)
}
diff --git a/utils/checkChannel.js b/utils/checkChannel.js
new file mode 100644
index 0000000..f0eaeae
--- /dev/null
+++ b/utils/checkChannel.js
@@ -0,0 +1,25 @@
+require('dotenv').config()
+
+const validateToken = require('./validateToken')
+const refreshToken = require('./refreshToken')
+const writeEnv = require('./writeEnv')
+
+let client_id = process.env.TWITCH_APP_ID
+let client_secret = process.env.TWITCH_APP_SECRET
+
+module.exports = async function (channel_access_token) {
+ let channel_refresh_token = ''
+
+ // Check if channel_access_token is valid
+ if (!await validateToken(channel_access_token)) {
+
+ // If not, refresh it
+ [channel_access_token, channel_refresh_token] = await refreshToken(client_id, client_secret, channel_access_token)
+ writeEnv('TWITCH_CHANNEL_ACCESS_TOKEN', channel_access_token)
+ writeEnv('TWITCH_CHANNEL_REFRESH_TOKEN', channel_refresh_token)
+
+ let channel_name = await getUserInfo(client_id, channel_access_token).login
+ writeEnv('TWITCH_CHANNEL_USERNAME', channel_name)
+ }
+ return [channel_access_token, channel_name]
+}
\ No newline at end of file
diff --git a/utils/checkUser.js b/utils/checkUser.js
new file mode 100644
index 0000000..8eaeb34
--- /dev/null
+++ b/utils/checkUser.js
@@ -0,0 +1,25 @@
+require('dotenv').config()
+
+const validateToken = require('./validateToken')
+const refreshToken = require('./refreshToken')
+const writeEnv = require('./writeEnv')
+
+let client_id = process.env.TWITCH_APP_ID
+let client_secret = process.env.TWITCH_APP_SECRET
+
+module.exports = async function (user_access_token) {
+ let user_refresh_token = ''
+
+ // Check if user_access_token is valid
+ if (!await validateToken(user_access_token)) {
+
+ // If not, refresh it
+ [user_access_token, user_refresh_token ] = await refreshToken(client_id, client_secret, user_access_token)
+ writeEnv('TWITCH_USER_ACCESS_TOKEN', user_access_token)
+ writeEnv('TWITCH_USER_REFRESH_TOKEN', user_refresh_token)
+
+ let user_name = await getUserInfo(client_id, user_access_token).login
+ writeEnv('TWITCH_USER_USERNAME', user_name)
+ }
+ return [user_access_token, user_name]
+}
\ No newline at end of file
diff --git a/utils/getRewardData.js b/utils/getRewardData.js
index 9d70f7e..2eb9dd3 100644
--- a/utils/getRewardData.js
+++ b/utils/getRewardData.js
@@ -1,4 +1,5 @@
const mysql = require('mysql2/promise')
+require('dotenv').config()
module.exports = async function () {
// Create a connection to the MySQL database
diff --git a/utils/getRewardID.js b/utils/getRewardID.js
index 10bb1fa..bc14613 100644
--- a/utils/getRewardID.js
+++ b/utils/getRewardID.js
@@ -7,6 +7,7 @@ module.exports = async function (client_id, access_token, broadcaster_id, reward
'Client-Id': client_id
}
}).then(response => {
+ //console.log(response.data)
let reward = response.data.data.find(reward => reward.title === reward_name)
return reward.id
}).catch(error => { console.log(error.response.data) })
diff --git a/utils/getUserAccessToken.js b/utils/getUserAccessToken.js
index 203247b..cc19003 100644
--- a/utils/getUserAccessToken.js
+++ b/utils/getUserAccessToken.js
@@ -8,7 +8,7 @@ module.exports = async function (client_id, client_secret, code, redirect_uri) {
redirect_uri,
grant_type: 'authorization_code'
}).then(response => {
- console.log(response.data)
- if (response.data.token_type === 'bearer') return response.data.access_token
+ //console.log(response.data)
+ if (response.data.token_type === 'bearer') return [response.data.access_token, response.data.refresh_token]
}).catch(error => { console.log(error.response.data) })
}
\ No newline at end of file
diff --git a/utils/getUserID.js b/utils/getUserID.js
deleted file mode 100644
index 2d37d81..0000000
--- a/utils/getUserID.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const axios = require('axios')
-
-module.exports = async function (client_id, access_token) {
- return await axios.get(`https://api.twitch.tv/helix/users`, {
- 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) })
-}
\ No newline at end of file
diff --git a/utils/getUserName.js b/utils/getUserName.js
deleted file mode 100644
index 83e5e2f..0000000
--- a/utils/getUserName.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const axios = require('axios')
-
-module.exports = async function (client_id, access_token) {
- return await axios.get(`https://api.twitch.tv/helix/users`, {
- headers: {
- 'Authorization': `Bearer ${access_token}`,
- 'Client-Id': client_id
- }
- }).then(response => {
- //console.log(response.data)
- return response.data.data[0].login
- }).catch(error => { console.log(error.response.data) })
-}
\ No newline at end of file
diff --git a/utils/oauthGen.js b/utils/oauthGen.js
index b5dba34..515cfae 100644
--- a/utils/oauthGen.js
+++ b/utils/oauthGen.js
@@ -1,7 +1,7 @@
module.exports = async function (client_id, redirect_uri, scope) {
console.log(scope)
let queries = {
- response_type: 'code',
+ response_type: 'code',
client_id,
redirect_uri,
scope: scope.join('+')
diff --git a/utils/refreshToken.js b/utils/refreshToken.js
new file mode 100644
index 0000000..3305da4
--- /dev/null
+++ b/utils/refreshToken.js
@@ -0,0 +1,13 @@
+const axios = require('axios')
+
+module.exports = async function (client_id, client_secret, refresh_token) {
+ return await axios.post('https://id.twitch.tv/oauth2/token', {
+ client_id,
+ client_secret,
+ refresh_token,
+ grant_type: 'refresh_token'
+ }).then(response => {
+ //console.log(response.data)
+ if (response.data.token_type === 'bearer') return [response.data.access_token, response.data.refresh_token]
+ }).catch(error => { console.log(error.response.data) })
+}
\ No newline at end of file
diff --git a/utils/subscribeToEvents.js b/utils/subscribeToEvents.js
index 96c8c8b..1bac78e 100644
--- a/utils/subscribeToEvents.js
+++ b/utils/subscribeToEvents.js
@@ -16,6 +16,7 @@ module.exports = async function (client_id, access_token, session_id, type, vers
'Content-Type': 'application/json'
}
}).then(response => {
+ //console.log(response.data)
return response.data.data[0].status
}).catch(error => { return error.response.data })
}
\ No newline at end of file
diff --git a/utils/validateToken.js b/utils/validateToken.js
new file mode 100644
index 0000000..cd9ae37
--- /dev/null
+++ b/utils/validateToken.js
@@ -0,0 +1,13 @@
+const axios = require('axios')
+
+module.exports = async function (access_token) {
+ return await axios.get('https://id.twitch.tv/oauth2/validate', {
+ headers: {
+ 'Authorization': `OAuth ${access_token}`,
+ }
+ }).then(response => {
+ //console.log(response.data)
+ if (response.data.status === '401') return false
+ else return true
+ }).catch(error => { console.log(error.response.data) })
+}
\ No newline at end of file
diff --git a/utils/writeEnv.js b/utils/writeEnv.js
index f56bdb0..bf256ab 100644
--- a/utils/writeEnv.js
+++ b/utils/writeEnv.js
@@ -1,7 +1,7 @@
const fs = require('fs')
module.exports = function (variable, value) {
- let parsedFile = fs.readFileSync('./.env', 'utf8')
- parsedFile = parsedFile.replace(new RegExp(`${variable}=.*`, 'g'), `${variable}=${value}`)
- fs.writeFileSync('./.env', parsedFile)
+ let parsedFile = fs.readFileSync('./.env', 'utf8')
+ parsedFile = parsedFile.replace(new RegExp(`${variable}=.*`, 'g'), `${variable}=${value}`)
+ fs.writeFileSync('./.env', parsedFile)
}
\ No newline at end of file