diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 64d9db08662989cdce019aa13801783018cd2297..5ac96414271d44a899abca06475a421a2b6c51dd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,7 +2,7 @@ image: docker:20.10.9
 
 variables:
   DOCKER_TLS_CERTDIR: "/certs"
-  IMAGE_VER: 2.0.2
+  IMAGE_VER: 2.1.0
 
 services:
   - docker:20.10.9-dind
diff --git a/lib/PiTube.pm b/lib/PiTube.pm
index 190a70e703c372a987b61b9beb576031015caa70..4517d6bb101f786479e9e947319bf8a46aef5227 100644
--- a/lib/PiTube.pm
+++ b/lib/PiTube.pm
@@ -77,7 +77,6 @@ sub startup {
     $r->get('/streams')->to(cb => sub { shift->render('streams'); });
     $r->get('/api/streams')->to('Stream#list');
     $r->get('/streams/:id')->to('Stream#info');
-    $r->put('/streams/:id/recording')->to('Stream#recording');
 
     $r->get('/calendar')->to(cb => sub { shift->render('calendar'); });
     $r->get('/api/calendar')->to('Calendar#list');
diff --git a/lib/PiTube/Controller/Nginx.pm b/lib/PiTube/Controller/Nginx.pm
index 5cc008c00375466123c6437c01cdb553ec835e3c..28f791d3030d175398db030545e6542d1b8d778c 100644
--- a/lib/PiTube/Controller/Nginx.pm
+++ b/lib/PiTube/Controller/Nginx.pm
@@ -43,11 +43,6 @@ sub callback_rtmp($c) {
             is_live          => ( $c->param('call') =~ /done/ ) ? 'f':'t',
         });
 
-        # pri zahajeni a ukonceni vysulani smazat priznak nahravani
-        if ( $event ne 'update' ) {
-            $stream->update({ recording => 'f'});
-        }
-
         $pubsub->json('streams')->notify( streams => {
             call      => $c->param('call'),
             stream_id => $stream->id,
@@ -67,29 +62,6 @@ sub callback_recorder($c) {
     });
     $c->render( status => 404, text => '' ), return if ! $stream;
 
-    # aktualizace stavu streamu
-#    $stream->update({
-#        recording     => 'f',
-#    });
-#
-#    my $record = $stream->records(
-#        {
-#            end  => undef,
-#            path => undef,
-#        },
-#        {
-#            order_by => {'-desc' => 'begin'}
-#        }
-#    )->first;
-#
-#    if ( $record ) {
-#        $record->update({
-#            path     => $c->param('path'),
-#            recorder => $c->param('recorder'),
-#            end      => \'now()',
-#        });
-#    }
-
     $stream->add_to_records({
         publish_user_id => $stream->publish_user_id,
         path     => $c->param('path'),
@@ -108,8 +80,8 @@ sub callback_hls($c) {
 
     if ($c->req->headers->header('X-Original-URI') =~ HLS ) {
 
-$c->app->log->error('>>>>>>>>>>>>'. $1
-);
+$c->app->log->error('>>>>>>>>>>>>'. $1);
+
         if ( $c->session->{user} ) {
             $code = 204 if $c->session->{user}{acl}{ $1 } & 4;
         }
@@ -124,8 +96,7 @@ $c->app->log->error('>>>>>>>>>>>>'. $1
     $c->render( status => $code, text => '');
 }
 
-sub callback_record {
-    my $c = shift;
+sub callback_record($c  ) {
 
     $c->app->log->debug($c->req->headers->header('X-Original-URI'));
 
diff --git a/lib/PiTube/Controller/Stream.pm b/lib/PiTube/Controller/Stream.pm
index 7fea7295c8d68b039f15574ddfbea468f87ccf45..556622f54e1daa9968a01ac6d5494089edd16a76 100644
--- a/lib/PiTube/Controller/Stream.pm
+++ b/lib/PiTube/Controller/Stream.pm
@@ -127,61 +127,6 @@ sub info {
     $c->render();
 }
 
-sub recording {
-    my $c = shift;
-
-    # akce
-    if ( ! $c->param('action') || $c->param('action') !~ /(stop|start)/) {
-        $c->render( status => 400, text => '');
-        return;
-    }
-
-    # stream
-    my $stream = $c->schema->resultset('Stream')->find({
-        id => $c->stash->{id}
-    });
-
-    if ( ! $stream ) {
-        $c->render( status => 404, text => '');
-        return;
-    }
-
-    if ( $stream->publish_user_id != $c->session->{user}{id}) {
-        $c->render( status => 403, text => '');
-        return;
-    }
-
-    my $ua = Mojo::UserAgent->new;
-
-    my $res = $ua->get(sprintf(CONTROL_URL,
-        $c->config->{nginx}{base_url},
-        $c->param('action'),
-        $stream->key,
-        'all'
-    ))->result;
-
-    my $recording = ( $c->param('action') eq 'start' ) ? 1 : 0;
-
-    if ($res->is_success) {
-
-        my $guard = $c->schema->txn_scope_guard;
-
-        $stream->update({
-            recording => $recording
-        });
-
-        if ( $recording ) {
-            $stream->add_to_records({
-                publish_user_id => $stream->publish_user_id,
-                path            => $res->body,
-            });
-        }
-        $guard->commit;
-    }
-
-    $c->render( json => { recording => $stream->recording  } );
-}
-
 
 1;
 
diff --git a/lib/PiTube/Controller/Websockets.pm b/lib/PiTube/Controller/Websockets.pm
index 702ed8594ed0a4dc96f1b060ba0a134f17074d0a..0dbc90763c17576673efd4e08aabb72e31852735 100644
--- a/lib/PiTube/Controller/Websockets.pm
+++ b/lib/PiTube/Controller/Websockets.pm
@@ -10,6 +10,8 @@ use constant SOCKET_INACTIVITY_TIMEOUT => 300;
 
 sub main {
     my $c = shift;
+    my $ip  = $c->tx->remote_address;
+    my $key = $c->req->headers->header('Sec-WebSocket-Key');
 
     $c->inactivity_timeout(SOCKET_INACTIVITY_TIMEOUT);
 
@@ -25,7 +27,13 @@ sub main {
     });
 
     $c->on(json => sub( $c, $message ) {
-        if ( $message->{event} eq 'KEEPALIVE' ) {
+        if ( $message->{stream} ) {
+            $c->redis->set(
+                join (':', ('live', $message->{stream}, $key)),
+                'live', 'EX', 16
+            );
+            my $count = $c->redis->keys( 'live:' . $message->{stream} . ':*' );
+            $c->send({json => { watchers => $count }});
         }
     });
 
diff --git a/nginx.conf b/nginx.conf
index fa8f8b612590d2281cc5b4935f1c5cb00784b446..f6c3cb803e67a48e0b158895537b6aa6a20883f7 100644
--- a/nginx.conf
+++ b/nginx.conf
@@ -30,14 +30,6 @@ rtmp {
             record_unique on;
             record_max_size 8000m;
 
-            recorder all {
-                record all manual;
-                record_suffix -%Y%m%d-%H%M%S.flv;
-                record_path /records;
-                record_unique on;
-                record_max_size 4000m;
-            }
-
             recorder audio {
                 record audio manual;
                 record_suffix -%Y%m%d-%H%M%S.audio.flv;
diff --git a/templates/stream/player.html.ep b/templates/stream/player.html.ep
index efd64f6942988c9270bf7ec6bba2b1d3a0b1452e..8c278b5f3b30988174529825a0bdbdbea13a29ea 100644
--- a/templates/stream/player.html.ep
+++ b/templates/stream/player.html.ep
@@ -1,3 +1,40 @@
 % layout 'default';
 % title $c->stash->{stream}{name};
 %= include 'includes/player', src => $url, live => 1;
+
+<script>
+
+function connect() {
+  var ws = new WebSocket('<%= $c->config->{ws_url} %>');
+
+  ws.onmessage = function (event) {
+    var data = JSON.parse(event.data)
+
+     if ( typeof data.watchers !== 'undefined' ) {
+        console.log(data);
+     }
+     else {
+        ws.send(JSON.stringify({
+            event: "watch",
+            stream: "<%= $c->stash->{stream}{id} %>"
+        }));
+     }
+
+  };
+
+  ws.onclose = function(e) {
+    console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
+    setTimeout(function() {
+      connect();
+    }, 1000);
+  };
+
+  ws.onerror = function(err) {
+    console.error('Socket encountered error: ', err.message, 'Closing socket');
+    ws.close();
+  };
+}
+
+connect();
+
+</script>
diff --git a/templates/streams.html.ep b/templates/streams.html.ep
index 4a1de05b609b9ed607fa34a6b443ac07cd1f8bee..640bd4cd53bf58ba6483062b482bd012579d4a93 100644
--- a/templates/streams.html.ep
+++ b/templates/streams.html.ep
@@ -59,7 +59,6 @@ function formatterStatus(value, row) {
 
 var ws = new WebSocket('<%= $c->config->{ws_url} %>');
 
-
 ws.onmessage = function (event) {
   console.log(event.data);
   $('#Streams').bootstrapTable('refresh', {silent: true})