Real time updating slideshow with webcam photos

I recently hosted a Halloween party and I thought it would be a cool idea to have my Raspberry Pi set up to take photos every few seconds and display them in some sort of slideshow. After a few hours of tinkering with my Raspberry Pi and Camera Module (technically the Pi Noir module), I ended up breaking the camera by sticking it too violently to a mount with Blu-tac. Oops. Not to worry though – I fished out a decent USB webcam and hooked it up to my laptop instead. I didn’t get to use my Raspberry Pi in a nerdy way, but this still did the job.

On the laptop I ran standard webcam software (Cheese) which saved the photos into a specified directory (/home/sean/Pictures/Webcam/). I then ran a cron job every five minutes to synchronise these photos with my web server. In the crontab, I specified a line:

# m h  dom mon dow   command
*/5 * * * * /home/sean/scripts/sync-photos.sh

And in /home/sean/scripts/sync-photos.sh I made an executable script with the following contents:

#!/bin/bash

cd /home/sean/Pictures/Webcam/
rsync *.jpg user@example.com:/path/to/web/directory/halloween/

I had already setup my laptop user account with an SSH key for the server, meaning the rsync command would not ask for a password. This can be done quickly on Ubuntu by doing something like this (but you should Google for a proper guide if you’re unsure):

~$ cd ~/.ssh
~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa): <filename here>
Enter passphrase (empty for no passphrase): <password here - this can be blank>
Enter same passphrase again: <password again, or blank>
The key fingerprint is:
a1:a3:32:ff:24:dc:ff:21:10:44:0e:ed:95:c2:ac:e3 user@hostname
The key's randomart image is:
+--[ RSA 2048]----+
<random art>
+-----------------+
~$ ssh-add -i <filename here>

So now, anyone taking a photo with the webcam would have their photo uploaded to my server. So far, so good. I still needed some way of displaying the photos. It turns out that there don’t seem to be very many decent, free and open source slideshow scripts which work in a browser and update their slideshow images periodically. Since the server would potentially receive a bunch of new photos every five minutes, I couldn’t be hitting refresh all night.

I ended up using a nice, simple slideshow script called slides.js. It uses jQuery, a really awesome Javascript library which makes Javascript a bearable programming language. I then crafted a bit of AJAX to grab the directory index page. By default, Apache web server will list all files in a directory if there doesn’t exist a file called index.html, index.php or similar. Index pages are predictable structure – they use simple HTML lists to display a link to each file – so it’s easy to grab out the relevant data with jQuery.

Finally, I had to find a way to update the slideshow periodically. This was not done with Javascript, but rather a rudimentary piece of HTML in the page’s header which tells the user’s browser to refresh every X seconds. I set this to fifteen minutes.

Here is the full slideshow script, which sits in the same web-accessible directory as the images on the server. I also added a piece of code to shuffle the images found in the directory, just to mix things up a bit!

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="refresh" content="900">
    <script src="jquery.js"></script>
    <script src="jquery.slides.min.js"></script>
    <style>
      #slides {
      /* Prevents slides from flashing */
	display:none;
      /* Sets width of photos to fit the screen (in my case, 1750px) */
	width: 1750px;
      }
    </style>
    <script>
      function shuffleArray(array) {
	for (var i = array.length - 1; i > 0; i--) {
	  var j = Math.floor(Math.random() * (i + 1));
	  var temp = array[i];
	  array[i] = array[j];
	  array[j] = temp;
	}
	
	return array;
      }

      function getImages() {
	var images = [];

	$.ajax({
	  url: "http://example.com/path/to/images/",
	  success: function(data){
	    $(data).find("td > a").each(function(){
		var name = $(this).attr("href");

		if (name.slice(-4) == '.jpg') {
	            images.push(name);
		}
	    });

	    // randomise
	    images = shuffleArray(images);

	    var imgstr = "";

	    for (var i = 0; i < images.length; i++) {
	      imgstr += "<img src=\"" + images[i] + "\">";
	    }

	    $('#slides').html(imgstr);

	    $(function(){
	      $("#slides").slidesjs({
		//width: 200,
		//height: 200,
		play: {
		  active: true,
		  effect: "slide",
		  interval: 5000,
		  auto: true,
		  swap: true,
		  pauseOnHover: false,
		  restartDelay: 2500
		}
	      });
	    });

	  }
	});
      }
    </script>
  </head>
  <body>
    <div id="slides"></div>
    <script>
      getImages();
    </script>
  </body>
</html>

The above script cannot be saved as index.html, otherwise it won’t be able to get an index page list of the files in the directory! There are ways around this, e.g. with PHP or similar, but as this was just a hack I renamed the file to slideshow.html.

With all of this set up properly, I opened a browser on my TV, pointed it to this script and entered into full screen mode. It displayed a nice slideshow of photos people took of themselves on my laptop, and updated throughout the night with the latest photos. Awesome!