Make Your Own Instavision

Recently I built the backend for the Instavision TV and wanted to give a quick tutorial on how to build one yourself. Brian Fouhy, George Tong, Jesse Weaver and Pedro Sorrentino actually made this TV a reality.

Materials

  • Retro looking TV
  • VGA to Coaxial adapter
  • Old Laptop
  • Instagram account
  • Instagram API Client ID, Client Secret and an Access Token
  • Node.js
  • Shell access to your server

Getting Started…

The first step is to get the backend working. Register a new client on the Instagram API, just register for the url you’ll be using to setup your feed.

Next you need to store an access token to use later on in our node.js file. Once you have your Client registered with Instagram, simply input the following into your browser’s url (replacing with your newly registered client ID and your specific redirect URI):

https://instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=token

Once you visit this page, simply login with your instagram account credentials and you should be redirected. You don’t necessarily need to have your redirect URI do anything when you land on it, what your interested in is the access token.

Copy this access token and save it for later, we’ll use it to gain access to Instagram and pull information for our TV to display.

Coding…

Lets get our code up and running. The basic idea is to have a client side page calling our server about every 5 seconds to get an update on the most recent photo. We’ll then also need something on our server to go out and get the most recent photos from Instagram, this script will also run about every 5 seconds. It would be hard to do this with PHP, sleep() and a chron job…so we’ll turn to node.js. Copy the following script and put it in the root of your public_html folder (make sure you replace your access token with the access token you got in the previous step also, you’ll need to make sure and replace all paths and urls with your own custom paths and domains).

/*
	INSTRUCTIONS

	shell: cd /home/instavis/public_html/
	shell: node instavision.js
	shell: kill ##### (process number)

	call the url: http://instavision.tv:8080/feed.html

	Needs:
			find out rate limit with instagram = 5000 requests per hour
*/
var sys = require("sys"),
    http = require("http"),
    https = require("https"),
    url = require("url"),
    path = require("path"),
    fs = require("fs"),
    util = require("util"),
    events = require("events");  

function load_static_file(uri, response) {
    var filename = path.join(process.cwd(), uri);
    path.exists(filename, function(exists) {
        if(!exists) {
            response.writeHead(404, {"Content-Type": "text/plain"});
            response.write("404 Not Foundn" + " filename: " + filename);
            response.end();
            return;
        }  

        fs.readFile(filename, "binary", function(err, file) {
            if(err) {
                response.writeHead(500, {"Content-Type": "text/plain"});
                response.write(err + "n");
                response.end();
                return;
            }  

            response.writeHead(200);
            response.write(file, "binary");
            response.end();
        });
    });
}

//var twitter_client = http.createClient(80, "api.instagram.com");  

var tweet_emitter = new events.EventEmitter();  

function get_tweets() {
    //var request = twitter_client.request("GET", "/v1/tags/bdwinstavision/media/recent?access_token=3036112.f59def8.4708bbe9fe9e43639c8d9fe93c5c41df", {"host": "api.instagram.com"}); 

    var options = {
    // public search - unauthenticated
	//host: 'api.instagram.com',
	//path: '/v1/tags/bdwinstavision/media/recent?access_token=3036112.f59def8.4708bbe9fe9e43639c8d9fe93c5c41df',

	// authenticated feed - https://api.instagram.com/v1/users/self/feed?access_token=3036112.c90c34d.411d18988857490c9032a2bac30e6943

	// instavisionTV access token
	// access_token = 3036112.c90c34d.411d18988857490c9032a2bac30e6943

	// instavision access token
	// access_token = 3060511.0b03a1e.fff65e339b694cf0844306131ab82b97
	host: 'api.instagram.com',
	path: '/v1/users/self/feed?access_token=3060511.0b03a1e.fff65e339b694cf0844306131ab82b97',
    } 

    https.get(options, function (res) {
		var raw = "";
		res.on('data', function (chunk) {
		    raw += chunk;
		});
		res.on('end', function () {
		    var response = JSON.parse(raw);

		   //sys.puts(response); 

		    if(raw.length > 0) {
	/*         	sys.puts("tweets:" + response);  */
	            tweet_emitter.emit("tweets", response);
	        }
	        //res.removeListener('connection', callback);
		});
    }).on('error', function(e) {
	  //console.error(e);
	  sys.puts(e);
	});

    /*request.addListener("response", function(response) {
        var body = "";
        response.addListener("data", function(data) {
            body += data;
            sys.puts("tweets:" + data);
        });  

        response.addListener("end", function() {
            var tweets = JSON.parse(body);
            sys.puts(body);
            if(tweets.length > 0) {
            	//sys.puts("tweets:" + tweets);
                tweet_emitter.emit("tweets", tweets);
            }
        });
    }); */ 

    //request.end();
}

setInterval(get_tweets, 5000);

http.createServer(function(request, response) {
    var uri = url.parse(request.url).pathname;
    //var uri = request.url;

    var callback = function(stream) {
	  sys.puts('listener removed!');
	};

    if(uri === "/stream") {  

        //var listener = tweet_emitter.addListener("tweets", function(tweets) {
        var listener = tweet_emitter.on("tweets", function(tweets) {
            response.writeHead(200, { "Content-Type" : "text/plain" });

            response.write(JSON.stringify(tweets));

            //sys.puts("stringify tweets:" + JSON.stringify(tweets));

            response.end();

            //var listenersForTeets = tweet_emitter.listeners(listener);

        	//sys.puts(util.inspect(listener));

        	//tweet_emitter.removeListener(tweets);
        	//tweet_emitter.removeListener(tweet_emitter);
        	//tweet_emitter.removeListener(listener);
        	//tweet_emitter.removeListener("tweets");
  			//tweet_emitter.removeListener("listener");
  			//tweet_emitter.removeListener("tweet_emitter");

  			listener.removeAllListeners("tweets");

            clearTimeout(timeout);  

        });

        //tweet_emitter.removeListener(tweets);

        //sys.puts(util.inspect(tweet_emitter.listeners(listener), true, null));

        var timeout = setTimeout(function() {
            response.writeHead(200, { "Content-Type" : "text/plain" });
            response.write(JSON.stringify([])); 

            response.end();  

            tweet_emitter.removeListener(listener);
        }, 10000); 

    }
    else {
        load_static_file(uri, response);
    }
}).listen(8080);  

sys.puts("Server running at http://instavision.com:8080/");

Note: I am pulling a user feed in this case, you can also do a search for specific photos and other users’ feeds if you call different urls. For more information read the Instagram API.

Once you have this copied and named instavision.js in your root, you need to make an html page with a special script to call instavision.js and get the most recent photos. Copy the following and save this into a file named feed.html, also in the root of your public_html folder:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link href="css/styleDark.css" rel="stylesheet" type="text/css">
<title>Instavision TV</title>
</head>

<body style="">
    <div id="wrap">

    	<div id="tweets"></div>
    </div>

	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
	<script type="text/javascript">
	    var tweet_list = $("#tweets");
	    var tweet_caption = $("#caption"); 

	    function load_tweets() {
	        $.getJSON("/stream", function(tweets) {
	            var imageurl = tweets.data[0].images.standard_resolution.url;
	            var imageUser = tweets.data[0].user.username;
	            var imageCaption = '';
	            if (tweets.data[0].caption != null){
	            var imageCaption = tweets.data[0].caption.text;
	            }

	            console.log(imageUser);
	            console.log(imageCaption);
	            imageurl = "<img id='tweet' src='"+imageurl+"' /><br/>";
	            imageCaption = "<div id='caption'><img id='captionImage' src='/images/ColorBars.png' height='18px' width='29px'/><h1>"+imageUser+"</h1><h3>"+imageCaption+"</h3></div>";
	            console.log(imageurl);
	            $(tweet_list).html(imageurl + imageCaption);
	            load_tweets();
	        });
	    }  

	    setTimeout(load_tweets, 5000); 

	    $(document).ready(function() {
	    	load_tweets();
	    });
	</script>

</body>
</html>

Once you have feed.html saved, you can try it out! You have to run the instavision.js script as a process on your server, simply run these commands to get it running:

cd /home/instavis/public_html
node instavision.js&

Make sure you have node installed. If you find that you want this process to stop, look at its process ID and kill it by:

kill 76234

Once you have the process running, visit the feed.html page at port 8080 (place the url with your custom url):

http://your-custom-domain.com:8080/feed.html

If it worked, then you’re good to go! If it didn’t, leave a comment below and I’ll try to help out!

Once you have it up and running, its simply a matter of plugging the TV in and formatting the image, which is totally a case by case situation and thus beyond the scope of this tutorial.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.