Add files via upload

This commit is contained in:
Noah Pombas
2025-02-12 09:20:14 +01:00
committed by GitHub
parent 0d1957f618
commit fb094cc159
4 changed files with 308 additions and 0 deletions

26
.env Normal file
View File

@@ -0,0 +1,26 @@
# https://dev.twitch.tv/console
TWITCH_CLIENT_ID=
TWITCH_CLIENT_SECRET=
# You can generate an OAuth token by using this Twitch authentication link in your browser:
# https://id.twitch.tv/oauth2/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost&response_type=token&scope=chat:read+chat:edit
# After authorizing your Twitch account, you'll get a token in the URL.
# Alternatively, use https://twitchtokengenerator.com/ to generate an OAuth token easily.
TWITCH_OAUTH=oauth:
TWITCH_ACCESS_TOKEN=
# This is simply your Twitch username.
# example: noahpombass
TWITCH_USERNAME=
# Type your twitch username and copy the Twitch ID: output
# https://www.streamweasels.com/tools/convert-twitch-username-%20to-user-id/
TWITCH_CHANNEL=
DB_HOST=
DB_USER=
DB_NAME=
DB_PASSWORD=

75
db.sql Normal file
View File

@@ -0,0 +1,75 @@
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `twitchapi`
--
CREATE DATABASE IF NOT EXISTS `twitchapi` DEFAULT CHARACTER SET utf8mb4;
USE `twitchapi`;
-- --------------------------------------------------------
--
-- Table structure for table `blacklist_users`
--
CREATE TABLE `blacklist_users` (
`id` int NOT NULL,
`username` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- --------------------------------------------------------
--
-- Table structure for table `watch_time`
--
CREATE TABLE `watch_time` (
`id` int NOT NULL,
`username` varchar(255) NOT NULL,
`session_start` datetime DEFAULT CURRENT_TIMESTAMP,
`total_watch_time` int DEFAULT '0',
`points` int DEFAULT '0',
`last_seen` datetime DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `blacklist_users`
--
ALTER TABLE `blacklist_users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `username` (`username`);
--
-- Indexes for table `watch_time`
--
ALTER TABLE `watch_time`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `username` (`username`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `blacklist_users`
--
ALTER TABLE `blacklist_users`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
--
-- AUTO_INCREMENT for table `watch_time`
--
ALTER TABLE `watch_time`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=13;

199
index.js Normal file
View File

@@ -0,0 +1,199 @@
require("dotenv").config();
const tmi = require("tmi.js");
const mysql = require("mysql2");
const axios = require("axios"); // Used to call the Twitch API
/**
* Database Connection - MySQL
*/
const db = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
});
db.connect((err) => {
if (err) {
console.error("❌ Error connecting to MySQL:", err);
return;
}
console.log("✅ Connected to MySQL!");
});
/**
* Twitch Bot Connection
*/
const client = new tmi.Client({
identity: {
username: process.env.TWITCH_USERNAME,
password: process.env.TWITCH_OAUTH,
},
channels: [process.env.TWITCH_CHANNEL],
});
client
.connect()
.then(() => console.log(`✅ Bot connected to channel: ${process.env.TWITCH_CHANNEL}`))
.catch((err) => console.error("❌ Error connecting to Twitch chat:", err));
let viewers = new Set(); // Store active viewers
/**
* Tracks viewers' watch time in MySQL database
*/
client.on("chat", (channel, user) => {
const username = user.username;
db.query("SELECT * FROM watch_time WHERE username = ?", [username], (err, results) => {
if (err) {
console.error("❌ Error fetching user:", err);
return;
}
if (results.length > 0) {
db.query("UPDATE watch_time SET last_seen = NOW() WHERE username = ?", [username]);
} else {
db.query("INSERT INTO watch_time (username, session_start, last_seen, total_watch_time, points) VALUES (?, NOW(), NOW(), 0, 0)", [username]);
}
});
viewers.add(username);
});
/**
* Checks if the stream is currently live
*/
async function isStreamLive() {
try {
const response = await axios.get(`https://api.twitch.tv/helix/streams?user_login=${process.env.TWITCH_CHANNEL}`, {
headers: {
"Client-ID": process.env.TWITCH_CLIENT_ID,
Authorization: `Bearer ${process.env.TWITCH_ACCESS_TOKEN}`,
},
});
if (response.data.data.length > 0) {
console.log("✅ Stream is live!");
return true;
} else {
console.log("🚫 Stream is offline.");
return false;
}
} catch (error) {
console.error("❌ Error fetching Twitch API:", error.response?.data || error.message);
return false;
}
}
/**
* Checks if a user is blacklisted
*/
async function isUserBlacklisted(username) {
return new Promise((resolve, reject) => {
db.query("SELECT * FROM blacklist_users WHERE username = ?", [username], (err, results) => {
if (err) {
console.error("❌ Error fetching blacklist:", err);
reject(err);
} else {
resolve(results.length > 0);
}
});
});
}
/**
* Periodically update watch time every 5 minutes if stream is live
*/
let wasLive = false;
setInterval(async () => {
const live = await isStreamLive();
if (live) {
if (!wasLive) console.log("🎥 Stream started! Updating watch time...");
wasLive = true;
for (const username of viewers) {
try {
const blacklisted = await isUserBlacklisted(username);
if (blacklisted) {
console.log(`🚫 ${username} is blacklisted. No time counted.`);
continue;
}
db.query("SELECT TIMESTAMPDIFF(SECOND, session_start, last_seen) AS time_watched FROM watch_time WHERE username = ?", [username], (err, results) => {
if (err) {
console.error("❌ Error fetching user watch time:", err);
return;
}
if (results.length > 0) {
const timeWatched = results[0].time_watched;
if (timeWatched >= 60) {
db.query("UPDATE watch_time SET total_watch_time = total_watch_time + 60, points = points + 1 WHERE username = ?", [username]);
} else {
console.log(`🚫 ${username} watched less than a minute. No time counted.`);
}
}
});
} catch (error) {
console.error(`❌ Error checking blacklist for ${username}:`, error);
}
}
console.log(`✅ Updated watch time for ${viewers.size} viewers!`);
viewers.clear();
} else {
if (wasLive) console.log("🚫 Stream ended. Stopping watch time counting.");
wasLive = false;
}
}, 300000);
/**
* Chat commands for watch time and blacklist management
*/
client.on("chat", (channel, user, message, self) => {
if (self) return;
const args = message.split(" ");
const command = args[0].toLowerCase();
const targetUser = args[1]?.toLowerCase();
if (command === "!watchtime") {
db.query("SELECT total_watch_time FROM watch_time WHERE username = ?", [user.username], (err, results) => {
if (err) {
console.error("❌ Error fetching watch time:", err);
return;
}
if (results.length > 0) {
let watchTimeSec = results[0].total_watch_time;
let watchTimeFormatted = new Date(watchTimeSec * 1000).toISOString().substr(11, 8);
client.say(channel, `@${user.username}, you've watched for ${watchTimeFormatted} while the stream was online! ⏳`);
} else {
client.say(channel, `@${user.username}, you have no recorded watch time.`);
}
});
}
if (command === "!addblacklist" && targetUser) {
db.query("INSERT INTO blacklist_users (username) VALUES (?) ON DUPLICATE KEY UPDATE username = username", [targetUser], (err) => {
if (err) {
console.error("❌ Error adding user to blacklist:", err);
return;
}
client.say(channel, `🚫 ${targetUser} has been added to the blacklist!`);
});
}
if (command === "!removeblacklist" && targetUser) {
db.query("DELETE FROM blacklist_users WHERE username = ?", [targetUser], (err) => {
if (err) {
console.error("❌ Error removing user from blacklist:", err);
return;
}
client.say(channel, `${targetUser} has been removed from the blacklist!`);
});
}
});

8
package.json Normal file
View File

@@ -0,0 +1,8 @@
{
"dependencies": {
"axios": "^1.7.9",
"dotenv": "^16.4.7",
"mysql2": "^3.12.0",
"tmi.js": "^1.8.5"
}
}