twitchtwitch-api

How to get Twitch watchtime (like streamelements)


I am currently on developing a little twitch.tv chatbot. I know, there are like a thousand of them but I would like to create my own, just to have a project - so this is not the point.

I was wondering, how the watchtime of a user could be calculated. Just as streamelements.com does it with their !watchtime chat command. I did not find any API endpoint to get the users, which are currently viewing the stream. The only thing found is the current viewcount in https://dev.twitch.tv/docs/api/reference#get-streams but there is no way to link to a specific user.

Anyone has any idea?


Solution

  • There's not an API endpoint to do it directly. However, I've recently done a similar thing with PHP, without the need for Twitch API credentials. The channel I work for uses NightBot, so I'll try to explain briefly how it works with it, so you can implement it however you want. Disclaimer: I'm new to PHP, so it probably can be improved; also, using commands from the Twitch API can probably polish the code.

    The file is named 'watchtime.php'. On an update request, it fetches the chatters and adds the time difference between the updates to the watch time of each user. On a get request, it takes the watch time saved and parses it in days, hours, minutes and seconds.

    To update the database for a channel, you have to use a scheduler or a loop that requests https://path/to/watchtime.php?action=update&channel=target, where 'target' is the channel name. The requests have to be less than 10 mins apart. However, make sure to do the request if only the channel is streaming. Every loop cycle, the script requests the Twitch TMI to fetch the chatters (ex. for Ludwig https://tmi.twitch.tv/group/user/ludwig/chatters) and then it adds to each chatter the time difference between the updates. I store the values in a JSON; for your chatbot, I suggest implementing a real database. If there are no errors in the update, the response text will be "OK".

    To get the watch time from NightBot, I used the command $(urlfetch https://path/to/watchtime.php?action=get&channel=$(channel)&user=$(user)&time=$(time)), where $(urlfetch url) returns the output of an url, $(channel) is the channel name, $(user) is the user name, and $(time) is the current time (it's useless for the PHP, but it's used to bypass the query caching in NightBot). However, I calculate the watch times only for viewers and VIPs; for a mod, it will return an error (it can be changed).

    Here's the PHP code:

    <?php
    if (!array_key_exists('channel', $_REQUEST)) {
        echo 'Empty channel';
        return;
    }
    if (!array_key_exists('action', $_REQUEST)) {
        echo 'Empty action (get/update)';
        return;
    }
    
    $channel = $_REQUEST['channel'];   // Channel username
    $file = "{$channel}.watchtime.json";    // File with watchtime
    
    // Open json and collect data
    if (file_exists($file)) {
        $data = json_decode(file_get_contents($file), true);
    } else {
        $data = [];
    }
     if ($_REQUEST['action'] == 'update') {
        // Update watchtime (watchtime.php?channel=streamer&action=update)
        // Do an update only when the target is streaming!
        // You can also insert here a API call to verify it.
    
        $now = time();  // Epoch time
        if (array_key_exists('$', $data) && $now - $data['$'] < 600) {
            // Increment if only the last update has been made in less than 10 min.
            // This prevents increments when the stream is first loaded.
    
            // Fetch chatters
            $url = "http://tmi.twitch.tv/group/user/{$channel}/chatters";  // Don't use https here
            $users = json_decode(file_get_contents($url), true)['chatters'];
    
            // Lazy way to find if the stream is off
            if (empty($users['broadcaster'])) {
                echo 'Empty broadcaster';
                return;
            }
    
            // This script selects only vips ans viewers, mods watchtimes are not counted.
            $chatters = array_merge($users['vips'], $users['viewers']);
            // Increment watchtime
            $passed = $now - $data['$'];  // Time passed since last update
            foreach ($chatters as $viewer) {
                if (!array_key_exists($viewer, $data))
                    $data[$viewer] = 0;
                $data[$viewer] += $passed;
            }
        }
        $data['$'] = $now;  // Store the epoch time of the update
        file_put_contents($file, json_encode($data));    // Save data
        echo "OK";
    
    } elseif ($_REQUEST['action'] == 'get') {
        // Get watchtime of an user (watchtime.php?channel=streamer&action=get&user=username)
    
        if (empty($data)) {
            echo 'Empty watchtime, update it first!';
            return;
        }
        if (!array_key_exists('user', $_REQUEST)) {
            echo 'Empty username';
            return;
        }
        define("username", $_REQUEST['user']);
        if (array_key_exists(username, $data)) {
            $passed = time() - $data['$'];
            if ($passed > 600)
                $passed  = 0;
            // Both $data[username] and $passed are integers
            $s = $data[username] + $passed;
    
            // Parsing seconds to days, hours, mins, secs
            $m = intdiv($s, 60);
            $s -= $m * 60;
            $h = intdiv($m, 60);
            $m -= $h * 60;
            $d = intdiv($h, 24);
            $h -= $d * 24;
    
            // Show times if only they are greater than zeros
            $args = [];
            if ($d > 0) array_push($args, "{$d} days");
            if ($h > 0) array_push($args, "{$h} hours");
            if ($m > 0) array_push($args, "{$m} minutes");
            if ($s > 0) array_push($args, "{$s} seconds");
    
            echo username . ' watched  the stream for ' . implode(', ', $args) . '!';
        } else echo 'Invalid username "' . username . '": moderator, too new or nonexistent';
    }