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.