Skip to content

Instantly share code, notes, and snippets.

@luke10x
Created June 16, 2025 01:55
Show Gist options
  • Save luke10x/a0e2a2e478ac2f4b5ff9e35783d7b57e to your computer and use it in GitHub Desktop.
Save luke10x/a0e2a2e478ac2f4b5ff9e35783d7b57e to your computer and use it in GitHub Desktop.
Twitch bot
import tmi from 'tmi.js';
import { exec, execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
// Define your Twitch credentials
const opts = {
identity: {
username: 'your_twitch_username', // same as your nick in Go
password: process.env.TWITCH_KEY // same OAuth token
},
channels: [
'#10x_developer' // same as your Go channel
],
connection: {
secure: true, // use TLS
reconnect: true // auto-reconnect if disconnected
}
};
// Create a client with the options
const client = new tmi.Client(opts);
let lastPingTime = 0;
client.on('connected', (addr, port) => {
console.log(`Connected to ${addr}:${port}`);
});
client.on('ping', ping => {
console.log('Received ping event;');
sendPingMessageIfTimeElapsed(30_000);
});
// Message received
client.on('message', (channel, tags, message, self) => {
// if (self) return; // Ignore messages from the bot itself
try {
console.log ({message})
const regex = /^!sr\s+https:\/\/www\.youtube\.com\/watch\?v=([^\s]+)$/;
const match = message.match(regex);
if (match) {
const url = `https://www.youtube.com/watch?v=${match[1]}`;
lastPingTime = Date.now();
downloadVideo(url).then(dlResults => {
const vlcCmd = `ffplay -autoexit -nodisp -volume 25 "${dlResults.filename.replace(/'/g, "\'")}"`;
console.log('Executing ', {vlcCmd});
try {
execSync(vlcCmd);
} catch(Err) {
console.error('failed to execture', { vlcCmd, Err });
}
lastPingTime = Date.now();
});
} else {
const regex = /^!tts\s+(.+)$/;
const match = message.match(regex);
if (match) {
const ttsCmd = `say -v rishi "${match[1]}"`;
console.log('Executing ', {ttsCmd});
execSync(ttsCmd)
} else {
console.log('N');
}
}
} catch (error) {
console.log("Error while processing people message:", error);
const ttsCmd = `say -v rishi "Error while processing people message"`;
console.log('Executing ', {ttsCmd});
execSync(ttsCmd).toString().trim();
}
});
client.connect().catch(console.error);
async function downloadVideo(videoUrl) {
const outputDirectory = '/Users/lape/Music/yt/%(id)s-%(title)s.%(ext)s';
const downloadCommand = `yt-dlp -j --no-simulate -o '${outputDirectory}' ${videoUrl}`;
console.log(`Executing download command: ${downloadCommand}`);
try {
const output = execSync(downloadCommand).toString().trim();
const { filename, title } = JSON.parse(output);
return { filename, title };
} catch (err) {
console.error(`Error downloading video: ${err}`);
}
}
function sendPingMessageIfTimeElapsed(timeThresholdMs) {
const currentTime = Date.now();
const timeElapsed = currentTime - lastPingTime;
if (timeElapsed > timeThresholdMs) {
console.log('Ellapsed time is enough to play song', {timeElapsed, lastPingTime, timeThresholdMs})
lastPingTime = currentTime // reset timing
getRandomSongId('/Users/lape/Music/yt/').then(randomSongId => {
const url = `https://www.youtube.com/watch?v=${randomSongId}`;
client.say('#10x_developer', '!sr ' + url)
.catch((error) => {
console.error('Failed to send message:', error);
});
});
} else {
console.log('not yet', {timeElapsed})
}
}
// Function to get file names from a directory and filter based on the prefix criteria
async function getRandomSongId(directoryPath) {
try {
const files = [];
const entries = await fs.promises.readdir(directoryPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(directoryPath, entry.name);
if (entry.isDirectory()) {
} else {
// Add the file path
files.push(entry.name);
}
}
// Function to extract prefix before the first '-' and check for valid characters
const getPrefix = (filePath) => {
// const prefix = filePath.split('-')[0];
const isValidPrefix = /^[a-zA-Z0-9]+$/.test(prefix);
return prefix;
};
// Filter the files based on the prefix criteria
const matchingFiles = files
.filter(f => f.length > 11)
.map(filePath => filePath.slice(0,11));
const randomIndex = Math.floor(Math.random() * matchingFiles.length);
const randomId = matchingFiles[randomIndex];
return randomId;
} catch (error) {
console.error('Error reading files:', error);
return [];
}
}
// const videoUrl = 'https://www.youtube.com/watch?v=cbB3iGRHtqA';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment