Skip to content

How come you get access tokens? I don't understand. #140

@Benzitczo

Description

@Benzitczo
require('dotenv').config();
const cloudscraper = require('cloudscraper');
const { KickClient } = require('@botk4cp3r/kick.js');
const initDatabase = require('./database');
const fs = require('fs');
const path = require('path');

// Bloqueo para evitar ejecución múltiple
const lockFile = path.join(__dirname, 'bot.lock');
try {
    if (fs.existsSync(lockFile)) {
        const lockContent = fs.readFileSync(lockFile, 'utf8');
        console.log(`Script ya está ejecutándose (PID: ${lockContent}), saliendo...`);
        process.exit(0);
    }
    fs.writeFileSync(lockFile, process.pid.toString());
} catch (error) {
    console.error('Error al manejar lock file:', error.message);
    process.exit(1);
}

// Limpiar lock file al salir
process.on('exit', () => {
    try {
        if (fs.existsSync(lockFile)) {
            fs.unlinkSync(lockFile);
            console.log('Lock file eliminado');
        }
    } catch (error) {
        console.error('Error al eliminar lock file:', error.message);
    }
});
process.on('SIGINT', () => process.exit(0));
process.on('SIGTERM', () => process.exit(0));

let giveawayActive = false;
let participants = [];
let endTime = null;

(async () => {
    // Conectar a la base de datos
    let db;
    try {
        db = await initDatabase();
        console.log('Conectado a la base de datos');
    } catch (error) {
        console.error('Error al conectar a la base de datos:', error.message);
        return;
    }

    // Verificar variables de entorno
    const requiredEnvVars = ['KICK_CHANNEL', 'CLIENT_ID', 'CLIENT_SECRET', 'BROADCASTER_USER_ID'];
    for (const envVar of requiredEnvVars) {
        if (!process.env[envVar]) {
            console.error(`Error: ${envVar} no está definido en .env`);
            return;
        }
    }

    // Obtener access_token con cloudscraper
    let accessToken;
    try {
        const response = await cloudscraper({
            method: 'POST',
            url: 'https://id.kick.com/oauth/token',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: new URLSearchParams({
                grant_type: 'client_credentials',
                client_id: process.env.CLIENT_ID,
                client_secret: process.env.CLIENT_SECRET
            }).toString(),
            cloudflareMaxTimeout: 30000,
            challengesToSolve: 3
        });
        const data = JSON.parse(response);
        if (!data.access_token) {
            throw new Error('No se recibió access_token');
        }
        accessToken = data.access_token;
        console.log('Access token obtenido correctamente');
    } catch (error) {
        console.error('Error al obtener access_token:', error.message);
        return;
    }

    // Obtener broadcaster_user_id
    let broadcasterUserId = process.env.BROADCASTER_USER_ID;
    const broadcasterUserIdNum = parseInt(broadcasterUserId, 10);
    if (isNaN(broadcasterUserIdNum) || broadcasterUserIdNum <= 0) {
        console.error('Error: BROADCASTER_USER_ID debe ser un número válido');
        return;
    }
    console.log('Usando BROADCASTER_USER_ID de .env:', broadcasterUserIdNum);

    // Crear instancia del cliente
    const clientOptions = {
        token: accessToken,
        channel: process.env.KICK_CHANNEL,
        broadcaster_user_id: broadcasterUserIdNum,
        broadcaster_id: broadcasterUserId // Prueba ambos formatos
    };
    console.log('Inicializando KickClient con:', {
        channel: clientOptions.channel,
        broadcaster_user_id: clientOptions.broadcaster_user_id,
        broadcaster_id: clientOptions.broadcaster_id
    });
    let client;
    try {
        client = new KickClient(clientOptions);
        console.log('KickClient creado correctamente');
    } catch (error) {
        console.error('Error al crear KickClient:', error.message);
        console.error('Parámetros enviados:', clientOptions);
        return;
    }

    // Intentar inicializar el cliente para eventos de chat
    try {
        await client.subscribeToEvents(['chat.message.sent']);
        console.log('Conectado al chat de Kick');
    } catch (error) {
        console.error('Error al inicializar el cliente:', error.message);
        console.error('Parámetros enviados a KickClient:', clientOptions);
        return;
    }

    // Escuchar mensajes del chat
    client.on('chatMessage', async (message) => {
        try {
            const sender = message.sender.username;
            const content = message.content;
            const args = content.split(' ');

            if (content.startsWith('!giveaway')) {
                const subcommand = args[1]?.toLowerCase();

                if (subcommand === 'start' && args[2]) {
                    if (!giveawayActive) {
                        const minutes = parseInt(args[2]);
                        if (isNaN(minutes) || minutes <= 0) {
                            await client.sendChatMessage({ content: 'Por favor, indica un número válido de minutos.' });
                            return;
                        }
                        giveawayActive = true;
                        participants = [];
                        endTime = new Date(Date.now() + minutes * 60 * 1000);

                        await db.query('INSERT INTO giveaways (active, end_time, participants) VALUES (?, ?, ?)', [
                            true,
                            endTime,
                            JSON.stringify(participants)
                        ]);

                        await client.sendChatMessage({ content: `¡Sorteo iniciado! Dura ${minutes} minutos. Usa !giveaway join para participar.` });
                        setTimeout(async () => {
                            if (giveawayActive) {
                                await endGiveaway(db, client);
                            }
                        }, minutes * 60 * 1000);
                    } else {
                        await client.sendChatMessage({ content: 'Ya hay un sorteo activo.' });
                    }
                }

                if (subcommand === 'join') {
                    if (giveawayActive) {
                        if (!participants.includes(sender)) {
                            participants.push(sender);
                            await db.query('UPDATE giveaways SET participants = ? WHERE active = TRUE', [
                                JSON.stringify(participants)
                            ]);
                            await client.sendChatMessage({ content: `${sender} ha entrado al sorteo.` });
                        } else {
                            await client.sendChatMessage({ content: `${sender}, ya estás en el sorteo.` });
                        }
                    } else {
                        await client.sendChatMessage({ content: 'No hay un sorteo activo.' });
                    }
                }

                if (subcommand === 'participants') {
                    if (giveawayActive) {
                        await client.sendChatMessage({ content: `Participantes: ${participants.join(', ') || 'Ninguno'}` });
                    } else {
                        await client.sendChatMessage({ content: 'No hay un sorteo activo.' });
                    }
                }

                if (subcommand === 'end') {
                    if (giveawayActive) {
                        await endGiveaway(db, client);
                    } else {
                        await client.sendChatMessage({ content: 'No hay un sorteo activo.' });
                    }
                }

                if (subcommand === 'enable') {
                    giveawayActive = true;
                    await db.query('UPDATE giveaways SET active = TRUE WHERE id = (SELECT MAX(id) FROM giveaways)');
                    await client.sendChatMessage({ content: 'Sorteos habilitados.' });
                }

                if (subcommand === 'disable') {
                    giveawayActive = false;
                    await db.query('UPDATE giveaways SET active = FALSE WHERE id = (SELECT MAX(id) FROM giveaways)');
                    await client.sendChatMessage({ content: 'Sorteos deshabilitados.' });
                }
            }
        } catch (error) {
            console.error('Error al procesar mensaje:', error.message);
        }
    });

    // Manejar errores del cliente
    client.on('error', (error) => {
        console.error('Error en el cliente:', error.message);
    });

    // Manejar desconexión
    client.on('close', async () => {
        console.log('Desconectado del chat, intentando reconectar...');
        try {
            const tokenResponse = await cloudscraper({
                method: 'POST',
                url: 'https://id.kick.com/oauth/token',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: new URLSearchParams({
                    grant_type: 'client_credentials',
                    client_id: process.env.CLIENT_ID,
                    client_secret: process.env.CLIENT_SECRET
                }).toString(),
                cloudflareMaxTimeout: 30000,
                challengesToSolve: 3
            });
            const tokenData = JSON.parse(tokenResponse);
            if (!tokenData.access_token) {
                throw new Error('No se recibió access_token');
            }
            accessToken = tokenData.access_token;
            client.token = accessToken;
            await client.subscribeToEvents(['chat.message.sent']);
            console.log('Reconectado al chat de Kick');
        } catch (error) {
            console.error('Error al reconectar:', error.message);
        }
    });

    async function endGiveaway(db, client) {
        if (participants.length > 0) {
            const winner = participants[Math.floor(Math.random() * participants.length)];
            await client.sendChatMessage({ content: `¡El sorteo ha terminado! El ganador es: ${winner}` });
        } else {
            await client.sendChatMessage({ content: 'El sorteo ha terminado, pero no hubo participantes.' });
        }
        giveawayActive = false;
        participants = [];
        endTime = null;
        await db.query('UPDATE giveaways SET active = FALSE, participants = ? WHERE active = TRUE', [
            JSON.stringify([])
        ]);
    }
})();

===

KICK_CHANNEL=benzitczo
CLIENT_ID=
CLIENT_SECRET=
ACCESS_TOKEN=
BROADCASTER_USER_ID=


Oh sorry, that's bot hosting, this Pterodacty, for if I can, right? and how explain where is acces tokens?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions