200 lines
6.0 KiB
JavaScript
200 lines
6.0 KiB
JavaScript
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!`);
|
|
});
|
|
}
|
|
});
|