Screenshot Streamer

Post screeshots via API and have them neatly appear in all clients without reloading

This is a streaming app that pushes uploaded images to all connected clients. The server is built with Sinatra and sends push notifications to all connected clients once it receives a proper POST request.

To test the front-end code Jasmine and Grunt are used and the testsuite runs headless, started via grunt jasmine.

While the app works, it could use some more work: There are no tests for the Sinatra app and the jQuery plugin could use some refactoring as well.

Code snippets

get '/' do
  @images = images
  erb :index

post '/screenshot/:filename' do

  notification = params.merge( {'timestamp' => timestamp}).to_json

  connections.each { |out| out << "data: #{notification}\n\n"}
  "wrote to #{params[:filename]}\n"

get '/connect', provides: 'text/event-stream' do
  stream :keep_open do |out|
    connections << out
    out.callback { connections.delete(out) }

The routes of the Sinatra app.

(function ( $ ) {
  $.fn.moveImages = function(options) {
    var settings = $.extend({
      filename: "#",
      limitThumbnails: 6
    }, options );

    img_copy = $('#newest_image').clone();

    // only add thumbnail if newest image has a source
    if($("#thumbnails ul li").size() == 0 && $('#newest_image').attr("href")) {
      $("#thumbnails ul").prepend("<li></li>");
      $("#thumbnails li").first().html(img_copy);
    else if($("#thumbnails ul li").size() == 1) {
      oldFirstLi = $("#thumbnails li").first();
      newFirstLi = oldFirstLi.clone().prependTo(oldFirstLi.parent());
      newFirstLi.attr("class", "first");
      oldFirstLi.attr("class", "last");
    else {
      oldFirstLi = $("#thumbnails ul li").first();
      //Remove the class attr of the first element

      // Remove the last list element if the limit is reached
      if($('#thumbnails ul li').size() >= settings.limitThumbnails) {
        $("#thumbnails ul li").last().remove();
        // Set the class of the new last element to "last"
        $("#thumbnails li").last().attr("class", "last");

      //Copy the big image to the thumbnails
      newFirstLi = oldFirstLi.clone().prependTo(oldFirstLi.parent());
      newFirstLi.attr("class", "first");

    $('#newest_image').attr("href", "/screenshots/" + settings.filename);
    $('#newest_image img').attr("src", "/screenshots/" + settings.filename);
}( jQuery ));

The jQuery plugin to move around the images.

describe("adding the first image", function() {
  var fixture;

  beforeEach(function() {
    fixture = $('#test');
    fixture.moveImages({filename: "whatever.png"});

  afterEach(function() {

  it('should add the correct link to the empty a href', function() {
    expect('a#newest_image').toHaveAttr('href', '/screenshots/whatever.png');

  it('should add the correct link to the empty img src', function() {
    expect('a#newest_image img').toHaveAttr('src', '/screenshots/whatever.png');

  it('should add nothing to the thumbnail list', function() {
    expect($('#thumbnails ul')).not.toContainElement('li');

Jasmine tests for the jQuery plugin.


No download available.

Screenshot Streamer on GitHub/GitLab

Download the latest source or clone/fork the project from source control.