Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Chatbot] Add integration with Twitch #140

Open
2 tasks
yuripourre opened this issue May 10, 2022 · 1 comment
Open
2 tasks

[Chatbot] Add integration with Twitch #140

yuripourre opened this issue May 10, 2022 · 1 comment
Labels
external project It should be done in another repository

Comments

@yuripourre
Copy link
Member

yuripourre commented May 10, 2022

https://github.com/twitch4j/twitch4j

Example: https://github.com/twitch4j/twitch4j-chatbot/blob/master/src/main/java/com/github/twitch4j/chatbot/Bot.java

Authentication: https://twitch4j.github.io/credentialmanager
Send Message: https://twitch4j.github.io/chat/send-message
Receive Message: https://twitch4j.github.io/events/channel-message-event

BareMetal

Client: https://dev.twitch.tv/docs/irc/example-bot
Parser: https://dev.twitch.tv/docs/irc/example-parser/

Seems that Twitch uses websocket for connections.
All the commands are compatible with IRC protocol.

  • Add client
  • Add parser
@yuripourre yuripourre changed the title Add support to twitch [Chatbot] Add integration with twitch Jul 5, 2022
@yuripourre yuripourre changed the title [Chatbot] Add integration with twitch [Chatbot] Add integration with Twitch Aug 21, 2023
@yuripourre
Copy link
Member Author

#!/usr/bin/env node
const WebSocketClient = require('websocket').client;

const client = new WebSocketClient();
const channel = '#<channel>';  // Replace with your channel.
const account = '<account>';   // Replace with the account the bot runs as
const password = 'oauth:<your access token goes here>';

const moveMessage = 'Get up and move, your body will thank you!';
const defaultMoveInterval = 1000 * 60 * 1; // Set to 1 minute for testing.
let moveInterval = defaultMoveInterval;

client.on('connectFailed', function(error) {
    console.log('Connect Error: ' + error.toString());
});

client.on('connect', function(connection) {
    console.log('WebSocket Client Connected');

    // This is a simple bot that doesn't need the additional
    // Twitch IRC capabilities.

    // connection.sendUTF('CAP REQ :twitch.tv/commands twitch.tv/membership twitch.tv/tags');
    
    // Authenticate with the Twitch IRC server and then join the channel.
    // If the authentication fails, the server drops the connection.

    connection.sendUTF(`PASS ${password}`); 
    connection.sendUTF(`NICK ${account}`);

    // Set a timer to post future 'move' messages. This timer can be
    // reset if the user passes, !move [minutes], in chat.
    let intervalObj = setInterval(() => {
        connection.sendUTF(`PRIVMSG ${channel} :${moveMessage}`);
    }, moveInterval);
    
    connection.on('error', function(error) {
        console.log("Connection Error: " + error.toString());
    });

    connection.on('close', function() {
        console.log('Connection Closed');
        console.log(`close description: ${connection.closeDescription}`);
        console.log(`close reason code: ${connection.closeReasonCode}`);

        clearInterval(intervalObj);
    });

    // Process the Twitch IRC message.

    connection.on('message', function(ircMessage) {
        if (ircMessage.type === 'utf8') {
            let rawIrcMessage = ircMessage.utf8Data.trimEnd();
            console.log(`Message received (${new Date().toISOString()}): '${rawIrcMessage}'\n`);

            let messages = rawIrcMessage.split('\r\n');  // The IRC message may contain one or more messages.
            messages.forEach(message => {
                let parsedMessage = parseMessage(message);
            
                if (parsedMessage) {
                    // console.log(`Message command: ${parsedMessage.command.command}`);
                    // console.log(`\n${JSON.stringify(parsedMessage, null, 3)}`)

                    switch (parsedMessage.command.command) {
                        case 'PRIVMSG':
                            // Ignore all messages except the '!move' bot
                            // command. A user can post a !move command to change the 
                            // interval for when the bot posts its move message.

                            if ('move' === parsedMessage.command.botCommand) {
                                
                                // Assumes the command's parameter is well formed (e.g., !move 15).

                                let updateInterval = (parsedMessage.command.botCommandParams) ?
                                    parseInt(parsedMessage.command.botCommandParams) * 1000 * 60 : defaultMoveInterval;

                                if (moveInterval != updateInterval) {
                                    // Valid range: 1 minute to 60 minutes
                                    if (updateInterval >= 60000 && updateInterval <= 3600000) {  
                                        moveInterval = updateInterval;

                                        // Reset the timer.
                                        clearInterval(intervalObj);
                                        intervalObj = null;
                                        intervalObj = setInterval(() => {
                                            connection.sendUTF(`PRIVMSG ${channel} :${moveMessage}`);
                                        }, moveInterval);
                                    }
                                }
                            }
                            else if ('moveoff' === parsedMessage.command.botCommand) {
                                clearInterval(intervalObj);
                                connection.sendUTF(`PART ${channel}`);
                                connection.close();
                            }
                            
                            break;
                        case 'PING':
                            connection.sendUTF('PONG ' + parsedMessage.parameters);
                            break;
                        case '001':
                            // Successfully logged in, so join the channel.
                            connection.sendUTF(`JOIN ${channel}`); 
                            break; 
                        case 'JOIN':
                            // Send the initial move message. All other move messages are
                            // sent by the timer.
                            connection.sendUTF(`PRIVMSG ${channel} :${moveMessage}`);
                            break;
                        case 'PART':
                            console.log('The channel must have banned (/ban) the bot.');
                            connection.close();
                            break;
                        case 'NOTICE': 
                            // If the authentication failed, leave the channel.
                            // The server will close the connection.
                            if ('Login authentication failed' === parsedMessage.parameters) {
                                console.log(`Authentication failed; left ${channel}`);
                                connection.sendUTF(`PART ${channel}`);
                            }
                            else if ('You don’t have permission to perform that action' === parsedMessage.parameters) {
                                console.log(`No permission. Check if the access token is still valid. Left ${channel}`);
                                connection.sendUTF(`PART ${channel}`);
                            }
                            break;
                        default:
                            ; // Ignore all other IRC messages.
                    }
                }
            });
        }
    });
    
});

client.connect('ws://irc-ws.chat.twitch.tv:80');


// Parses an IRC message and returns a JSON object with the message's 
// component parts (tags, source (nick and host), command, parameters). 
// Expects the caller to pass a single message. (Remember, the Twitch 
// IRC server may send one or more IRC messages in a single message.)

function parseMessage(message) {
    // Replace with the code from the Example Message Parser topic.
}

@yuripourre yuripourre added the external project It should be done in another repository label Aug 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external project It should be done in another repository
Projects
None yet
Development

No branches or pull requests

1 participant