Files
cockinator/lib/avatarRotation.js
Kira 5b24cf324f
All checks were successful
Build and Push Docker Image / build (push) Successful in 48s
actually get profile picture rotation
discord.js was outdated and it was making the client token reset every time i set a pfp,
so this was taking forever to figure out because i dont understand packages
2026-03-11 23:27:36 -04:00

97 lines
3.4 KiB
JavaScript

// this entire file is Opus 4.6 sorry
const fs = require('fs');
const path = require('path');
const IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.webp'];
const DEFAULT_INTERVAL = '24h';
const DEFAULT_DIR = './avatars';
/** Parse an interval string like "24h" or "30m" into milliseconds */
function parseInterval(str) {
const match = String(str).match(/^(\d+)\s*(h|m)$/i);
if (!match) {
console.warn(`Avatars: Invalid interval "${str}", falling back to ${DEFAULT_INTERVAL}`);
return parseInterval(DEFAULT_INTERVAL);
}
const value = parseInt(match[1], 10);
const unit = match[2].toLowerCase();
return unit === 'h' ? value * 60 * 60 * 1000 : value * 60 * 1000;
}
/** Scan the directory and return an array of image file paths */
function scanAvatars(dir) {
try {
return fs.readdirSync(dir)
.filter(f => IMAGE_EXTENSIONS.includes(path.extname(f).toLowerCase()))
.map(f => path.join(dir, f));
} catch (err) {
console.warn(`Avatars: Could not read directory "${dir}": ${err.message}`);
return [];
}
}
/** Pick a random avatar and set it on the client */
async function setRandomAvatar(client, avatars) {
if (!avatars.length) {
console.warn('Avatars: No images found, skipping avatar change');
return;
}
const pick = avatars[Math.floor(Math.random() * avatars.length)];
try {
await client.user.setAvatar(pick);
console.log(`Avatars: Changed to ${path.basename(pick)}`);
} catch (err) {
console.error(`Avatars: Failed to set avatar: ${err.message}`);
}
}
/**
* Start the avatar rotation system.
* @param {import('discord.js').Client} client - The Discord client (must be ready)
* @param {object} config - Bot config object
*/
function start(client, config = {}) {
const avatarDir = path.resolve(config.avatarDir || DEFAULT_DIR);
const intervalMs = parseInterval(config.avatarInterval || DEFAULT_INTERVAL);
// ensure the directory exists
if (!fs.existsSync(avatarDir)) {
console.warn(`Avatars: Directory "${avatarDir}" does not exist, avatar rotation disabled`);
return;
}
let avatars = scanAvatars(avatarDir);
console.log(`Avatars: Found ${avatars.length} image(s) in ${avatarDir}`);
console.log(`Avatars: Rotation interval set to ${config.avatarInterval || DEFAULT_INTERVAL}`);
// set one immediately on boot
setRandomAvatar(client, avatars);
// rotate on the configured interval
setInterval(() => {
avatars = scanAvatars(avatarDir); // re-scan in case watcher missed something
setRandomAvatar(client, avatars);
}, intervalMs);
// live-watch the folder for changes
let debounceTimer = null;
try {
fs.watch(avatarDir, (eventType, filename) => {
if (debounceTimer) clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
const updated = scanAvatars(avatarDir);
if (updated.length !== avatars.length) {
console.log(`Avatars: Folder changed, now ${updated.length} image(s)`);
}
avatars = updated;
}, 500); // 500ms debounce
});
console.log(`Avatars: Watching "${avatarDir}" for changes`);
} catch (err) {
console.warn(`Avatars: Could not watch directory: ${err.message}`);
}
}
module.exports = { start };