"Tonight we are all collectively watching Robin Williams"

On the 11th, we learned the terrible news of Robin Williams's death. And during the outpouring of grief that followed on Twitter, I saw this tweet:

And it got me thinking (and gave my mind something to do): just how much of an increase in viewings would there be? Is it significant or just a blip? Spoiler: Significant.

I collected data from trakt1 using their activity search API call2. I limited the activities to "scrobble" and "checkin". A scrobble is when a significant portion of the film has been watched; trakt recommends 85%. This is usually automatically done by a media center plugin. A checkin is when a user initiates the action. This is usually done via a mobile phone app or with the website for events such as when a user is "watching live tv, at a friend's house, or watching a movie in theaters".3 Data was collected from midnight EDT August 4th to 23:59 EDT August 17th.

Here's what that data looks like:

And here's a map of the locations of people4 who watched Aladdin from August 12th through the 17th.

When someone dies, we reflect and take time to recall what it was about them that made us love them, from telling stories of our loved ones at funerals or wakes to rewatching the films they made. And based on the data from trakt, it's obvious that we rewatched Robin Williams's movies and remembered exactly what it was that made him so beloved.

RIP you beautiful man.


  1. About trakt: "trakt is a platform that does many things, but primarily keeps track of TV shows and movies you watch. It integrates with your media center or home theater PC to enable scrobbling, so everything is automatic. Some people like to check in from their phone, so we enable that too."

  2. activity/movies

  3. Scrobbles vs Checkins

  4. user/profile

Redbox PHP Class

Like all good things in life, the API has been shutdown. Well, I could say it was good while it lasted. But, let's be honest: it was a major pain. And even in the end you couldn't actually book anything; you had to finish the transaction manually. But whatever. Sweet sleep, Redbox API. Sweet sleep.

I got access to the Redbox API the other day, and I'm currently working on integrating it into a semi-automatic movie rental program. But, while no one can fault it for being in-complete, it seems that it's not developer-friendly. For example, it takes three, three, API calls to lookup a DVD and find where it is. So before I start heavy development on it, I decided to write a helper class. Now, instead of having ~70 lines of code, I can have four.

Here's the class:

<?php

$redbox = new Redbox("abc123");
$redbox->SetFilmName("The Butler");
$redbox->SetLocation("31.3299504", "-89.3364833");
$storeData = $redbox->DoLookup();

class Redbox
{
    private $apikey;
    private $filmName;
    private $latlong;

    private $productID;
    private $productName;
    private $storesHoldingProduct = null;

    public function __construct($apikey)
    {
        $this->apikey = $apikey;
    }

    public function SetFilmName($filmName)
    {
        $this->filmName = $filmName;

        $opts = array("http"=>array("header"=>"Accept: application/json\r\n"));
        $context = stream_context_create($opts);
        $json = json_decode(file_get_contents("https://api.redbox.com/v3/products?apiKey=".$this->apikey."&q=".urlencode($filmName), false, $context));

        $this->productID = $json->Products->Movie[0]->{'@productId'};
        $this->productName = $json->Products->Movie[0]->Title;
    }

    public function SetLocation($lat, $long)
    {
        $this->latlong = "$lat,$long";
    }

    public function DoLookup()
    {
        $opts = array("http"=>array("header"=>"Accept: application/json\r\n"));
        $context = stream_context_create($opts);
        $json = json_decode(file_get_contents("https://api.redbox.com/v3/inventory/stores/latlong/".$this->latlong."?apiKey=".$this->apikey."&products=".$this->productID, false, $context));

        if (property_exists($json->Inventory, "StoreInventory"))
        {
            foreach ($json->Inventory->StoreInventory as $store)
            {
                if ($store->ProductInventory->{'@inventoryStatus'} == "InStock")
                    $goodStores[] = $store->{'@storeId'};
            }
            if (!empty($goodStores))
            {
                $json = json_decode(file_get_contents("https://api.redbox.com/v3/stores?apiKey=".$this->apikey."&storeList=".implode(",", $goodStores), false, $context));

                if (count($json->StoreBulkList->Store) > 1)
                    foreach ($json->StoreBulkList->Store as $store)
                        $stores[$store->{'@storeId'}] = $store;
                else
                    $stores[$json->StoreBulkList->Store->{'@storeId'}] = $json->StoreBulkList->Store;

                $this->storesHoldingProduct = $stores;
            }
        }

        $return = new stdClass();
        $return->ProductName = $this->productName;
        $return->Location = $this->latlong;
        $return->Stores = $this->StoreData();

        return $return;
    }

    private function StoreData()
    {
        if (!$this->storesHoldingProduct)
            return null;
        foreach ($this->storesHoldingProduct as $storeID => $store)
        {
            $redbox = new stdClass();
            $redbox->StoreName = $store->Retailer;
            if (property_exists($store, "Label"))
                $redbox->WhereAtStore = $store->Channel." - Kiosk ".$store->Label;
            else
                $redbox->WhereAtStore = $store->Channel;
            $redbox->Location = $store->Location;
            $redbox->Url = $store->WebUrl;
            $redbox->ReserveUrl = "http://www.redbox.com/externalcart?titleID=".strtolower($this->productID)."&StoreGUID=".strtolower($storeID);

            $redboxes[] = $redbox;
        }

        return $redboxes;
    }
}

And it gives you data like:

stdClass Object
(
    [ProductName] => Lee Daniels' The Butler
    [Location] => 31.3299504,-89.3364833
    [Stores] => Array
        (
            [0] => stdClass Object
                (
                    [StoreName] => Corner Market
                    [WhereAtStore] => Outdoor
                    [Location] => stdClass Object
                        (
                            [@lat] => 31.324853
                            [@long] => -89.343855
                            [@locationId] => 5014313
                            [Address] => 3706 Hardy St
                            [City] => Hattiesburg
                            [State] => MS
                            [Zipcode] => 39402-1537
                        )

                    [Url] => http://www.redbox.com/locations/MS/Hattiesburg/39402/54436
                    [ReserveURL] => http://www.redbox.com/externalcart?titleID=d68ee589-dc33-4d14-ba1e-5b4f9b066e07&StoreGUID=12492966-1ec0-4eb8-9a5b-48c8822a9b1a
                )

            [1] => stdClass Object
                (
                    [StoreName] => CVS/Pharmacy
                    [WhereAtStore] => Outdoor - Kiosk B
                    [Location] => stdClass Object
                        (
                            [@lat] => 31.324903
                            [@long] => -89.34672
                            [@locationId] => 5022204
                            [Address] => 3910 Hardy St
                            [City] => Hattiesburg
                            [State] => MS
                            [Zipcode] => 39402-1500
                        )

                    [Url] => http://www.redbox.com/locations/MS/Hattiesburg/39402/56565
                    [ReserveURL] => http://www.redbox.com/externalcart?titleID=d68ee589-dc33-4d14-ba1e-5b4f9b066e07&StoreGUID=d5516458-aff9-4eb7-81f6-0f7ca53e3c16
                )

        )

)

Which makes Redbox's API much, much easier to work with.