diff --git a/server/index.html b/server/index.html deleted file mode 100644 index 6dc181330cf5d38b75f991e5cb404eabc9ab9b68..0000000000000000000000000000000000000000 --- a/server/index.html +++ /dev/null @@ -1,62 +0,0 @@ -<!DOCTYPE html> - -<html lang="en"> -<head> - <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" - integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" /> - <meta charset="utf-8"/> - <script type="text/javascript" src="reconnecting-websocket.js"></script> - <script type="text/javascript" src="index.js"></script> -</head> -<body onload="init()"> - <div class="container"> - <div class="row align-items-center"> - <div class="col-xl-12 my-2"> - <div class="custom-file"> - <input type="file" class="custom-file-input" id="fileSelector" name="fileSelector" - accept="video/*" /> - <label for="fileSelector" class="custom-file-label"> - Select a video - </label> - </div> - </div> - </div> - <div class="row justify-content-md-center"> - <div class="col-xl-12"> - <div align="center" class="embed-responsive embed-responsive-16by9 my-2"> - <video controls id="vid"></video> - </div> - - <div align="center" class="my-2"> - <button id="play-btn" type="button" class="btn btn-primary btn-lg" onclick="sendToServer('play')"> - <svg class="bi bi-play-fill" width="3em" height="1em" viewBox="0 0 16 16" fill="currentColor" - xmlns="http://www.w3.org/2000/svg"> - <path - d="M11.596 8.697l-6.363 3.692c-.54.313-1.233-.066-1.233-.697V4.308c0-.63.692-1.01 1.233-.696l6.363 3.692a.802.802 0 0 1 0 1.393z" /> - </svg> - </button> - <button id="pause-btn" type="button" class="btn btn-primary btn-lg" onclick="sendToServer('pause')"> - <svg class="bi bi-pause-fill" width="3em" height="1em" viewBox="0 0 16 16" fill="currentColor" - xmlns="http://www.w3.org/2000/svg"> - <path - d="M5.5 3.5A1.5 1.5 0 0 1 7 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5zm5 0A1.5 1.5 0 0 1 12 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5z" /> - </svg> - </button> - <button id="sync-btn" type="button" class="btn btn-primary btn-lg" onclick="sendToServer('sync')"> - <svg class="bi bi-arrow-clockwise" width="3em" height="1em" viewBox="0 0 16 16" - fill="currentColor" xmlns="http://www.w3.org/2000/svg"> - <path fill-rule="evenodd" - d="M3.17 6.706a5 5 0 0 1 7.103-3.16.5.5 0 1 0 .454-.892A6 6 0 1 0 13.455 5.5a.5.5 0 0 0-.91.417 5 5 0 1 1-9.375.789z" /> - <path fill-rule="evenodd" - d="M8.147.146a.5.5 0 0 1 .707 0l2.5 2.5a.5.5 0 0 1 0 .708l-2.5 2.5a.5.5 0 1 1-.707-.708L10.293 3 8.147.854a.5.5 0 0 1 0-.708z" /> - </svg> - </button> - <button hidden id="stream-btn" type="button" class="btn btn-primary btn-lg" onclick="streamFromServer()"> - Stream from server - </button> - </div> - </div> - </div> - </div> -</body> -</html> diff --git a/server/index.js b/server/index.js deleted file mode 100644 index 4deab9cbfd4cad1db87605673590c7bb1bb12eb3..0000000000000000000000000000000000000000 --- a/server/index.js +++ /dev/null @@ -1,103 +0,0 @@ - - -'use strict' -var URL = window.URL || window.webkitURL - -var socket - -function openConnection() { - const path = window.location.pathname - socket = new ReconnectingWebSocket('wss://mpvsync.de:8432' + path); - socket.debug = true; - - // Listen for messages - socket.addEventListener('message', function (event) { - console.log('Received message from server: ', event.data); - const cmd = JSON.parse(event.data).command; - const vid = getVideoPlayer(); - if (cmd == "play") { - vid.play(); - } else if (cmd == "pause") { - vid.pause(); - } else if (cmd == "get-playback-time") { - socket.send('{"playback_time": ' + vid.currentTime + '}'); - } else if (cmd == "set-playback-time") { - vid.currentTime = JSON.parse(event.data).data; - } - }); -} - -function getVideoPlayer() { - return document.getElementById("vid"); -} - -function getFileSelector() { - return document.getElementById("fileSelector"); -} - -function getStreamFromServerButton() { - return document.getElementById("stream-btn"); -} - -function commandToJson(com) { - if (com === "play") { - return '{"command": "play", "target": "server"}'; - } else if (com === "pause") { - return '{"command": "pause", "target": "server"}'; - } else if (com === "sync") { - return '{"command": "sync", "target": "server"}'; - } else { - console.log("unknown command " + com); - } -} - -function sendToServer(com) { - socket.send(commandToJson(com)); -} - -function streamFromServer() { - const vid = getVideoPlayer(); - vid.src = "video/index.mp4"; -} - -function urlExists(url) -{ - var http = new XMLHttpRequest(); - http.open('HEAD', url, false); - http.send(); - return http.status!=404; -} - -function getFileUrl() { - var file = getFileSelector().files[0]; - - var fileURL = URL.createObjectURL(file); - return fileURL; -} - -function updateFile(event) { - var videoPlayer = getVideoPlayer(); - var url = getFileUrl(); - setFile(videoPlayer, url); -} - -function setFile(vid, filesource) { - vid.hidden = false; - vid.src = filesource; -} - - -function init() { - openConnection(); - - var fileSelector = getFileSelector(); - fileSelector.addEventListener("change", updateFile); - - const streamBtn = getStreamFromServerButton(); - streamBtn.hidden = !urlExists("video/index.mp4", showStreamFromServerButton); -} - -function showStreamFromServerButton() { - const streamBtn = getStreamFromServerButton(); - streamBtn.hidden = false; -} diff --git a/server/reconnecting-websocket.js b/server/reconnecting-websocket.js deleted file mode 100644 index 0cd4332dcff53bfb10cd9112ccf9bf0625f65571..0000000000000000000000000000000000000000 --- a/server/reconnecting-websocket.js +++ /dev/null @@ -1,365 +0,0 @@ -// MIT License: -// -// Copyright (c) 2010-2012, Joe Walnes -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -/** - * This behaves like a WebSocket in every way, except if it fails to connect, - * or it gets disconnected, it will repeatedly poll until it successfully connects - * again. - * - * It is API compatible, so when you have: - * ws = new WebSocket('ws://....'); - * you can replace with: - * ws = new ReconnectingWebSocket('ws://....'); - * - * The event stream will typically look like: - * onconnecting - * onopen - * onmessage - * onmessage - * onclose // lost connection - * onconnecting - * onopen // sometime later... - * onmessage - * onmessage - * etc... - * - * It is API compatible with the standard WebSocket API, apart from the following members: - * - * - `bufferedAmount` - * - `extensions` - * - `binaryType` - * - * Latest version: https://github.com/joewalnes/reconnecting-websocket/ - * - Joe Walnes - * - * Syntax - * ====== - * var socket = new ReconnectingWebSocket(url, protocols, options); - * - * Parameters - * ========== - * url - The url you are connecting to. - * protocols - Optional string or array of protocols. - * options - See below - * - * Options - * ======= - * Options can either be passed upon instantiation or set after instantiation: - * - * var socket = new ReconnectingWebSocket(url, null, { debug: true, reconnectInterval: 4000 }); - * - * or - * - * var socket = new ReconnectingWebSocket(url); - * socket.debug = true; - * socket.reconnectInterval = 4000; - * - * debug - * - Whether this instance should log debug messages. Accepts true or false. Default: false. - * - * automaticOpen - * - Whether or not the websocket should attempt to connect immediately upon instantiation. The socket can be manually opened or closed at any time using ws.open() and ws.close(). - * - * reconnectInterval - * - The number of milliseconds to delay before attempting to reconnect. Accepts integer. Default: 1000. - * - * maxReconnectInterval - * - The maximum number of milliseconds to delay a reconnection attempt. Accepts integer. Default: 30000. - * - * reconnectDecay - * - The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. Accepts integer or float. Default: 1.5. - * - * timeoutInterval - * - The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. Accepts integer. Default: 2000. - * - */ -(function (global, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module !== 'undefined' && module.exports){ - module.exports = factory(); - } else { - global.ReconnectingWebSocket = factory(); - } -})(this, function () { - - if (!('WebSocket' in window)) { - return; - } - - function ReconnectingWebSocket(url, protocols, options) { - - // Default settings - var settings = { - - /** Whether this instance should log debug messages. */ - debug: false, - - /** Whether or not the websocket should attempt to connect immediately upon instantiation. */ - automaticOpen: true, - - /** The number of milliseconds to delay before attempting to reconnect. */ - reconnectInterval: 1000, - /** The maximum number of milliseconds to delay a reconnection attempt. */ - maxReconnectInterval: 30000, - /** The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. */ - reconnectDecay: 1.5, - - /** The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. */ - timeoutInterval: 2000, - - /** The maximum number of reconnection attempts to make. Unlimited if null. */ - maxReconnectAttempts: null, - - /** The binary type, possible values 'blob' or 'arraybuffer', default 'blob'. */ - binaryType: 'blob' - } - if (!options) { options = {}; } - - // Overwrite and define settings with options if they exist. - for (var key in settings) { - if (typeof options[key] !== 'undefined') { - this[key] = options[key]; - } else { - this[key] = settings[key]; - } - } - - // These should be treated as read-only properties - - /** The URL as resolved by the constructor. This is always an absolute URL. Read only. */ - this.url = url; - - /** The number of attempted reconnects since starting, or the last successful connection. Read only. */ - this.reconnectAttempts = 0; - - /** - * The current state of the connection. - * Can be one of: WebSocket.CONNECTING, WebSocket.OPEN, WebSocket.CLOSING, WebSocket.CLOSED - * Read only. - */ - this.readyState = WebSocket.CONNECTING; - - /** - * A string indicating the name of the sub-protocol the server selected; this will be one of - * the strings specified in the protocols parameter when creating the WebSocket object. - * Read only. - */ - this.protocol = null; - - // Private state variables - - var self = this; - var ws; - var forcedClose = false; - var timedOut = false; - var eventTarget = document.createElement('div'); - - // Wire up "on*" properties as event handlers - - eventTarget.addEventListener('open', function(event) { self.onopen(event); }); - eventTarget.addEventListener('close', function(event) { self.onclose(event); }); - eventTarget.addEventListener('connecting', function(event) { self.onconnecting(event); }); - eventTarget.addEventListener('message', function(event) { self.onmessage(event); }); - eventTarget.addEventListener('error', function(event) { self.onerror(event); }); - - // Expose the API required by EventTarget - - this.addEventListener = eventTarget.addEventListener.bind(eventTarget); - this.removeEventListener = eventTarget.removeEventListener.bind(eventTarget); - this.dispatchEvent = eventTarget.dispatchEvent.bind(eventTarget); - - /** - * This function generates an event that is compatible with standard - * compliant browsers and IE9 - IE11 - * - * This will prevent the error: - * Object doesn't support this action - * - * http://stackoverflow.com/questions/19345392/why-arent-my-parameters-getting-passed-through-to-a-dispatched-event/19345563#19345563 - * @param s String The name that the event should use - * @param args Object an optional object that the event will use - */ - function generateEvent(s, args) { - var evt = document.createEvent("CustomEvent"); - evt.initCustomEvent(s, false, false, args); - return evt; - }; - - this.open = function (reconnectAttempt) { - ws = new WebSocket(self.url, protocols || []); - ws.binaryType = this.binaryType; - - if (reconnectAttempt) { - if (this.maxReconnectAttempts && this.reconnectAttempts > this.maxReconnectAttempts) { - return; - } - } else { - eventTarget.dispatchEvent(generateEvent('connecting')); - this.reconnectAttempts = 0; - } - - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'attempt-connect', self.url); - } - - var localWs = ws; - var timeout = setTimeout(function() { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'connection-timeout', self.url); - } - timedOut = true; - localWs.close(); - timedOut = false; - }, self.timeoutInterval); - - ws.onopen = function(event) { - clearTimeout(timeout); - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onopen', self.url); - } - self.protocol = ws.protocol; - self.readyState = WebSocket.OPEN; - self.reconnectAttempts = 0; - var e = generateEvent('open'); - e.isReconnect = reconnectAttempt; - reconnectAttempt = false; - eventTarget.dispatchEvent(e); - }; - - ws.onclose = function(event) { - clearTimeout(timeout); - ws = null; - if (forcedClose) { - self.readyState = WebSocket.CLOSED; - eventTarget.dispatchEvent(generateEvent('close')); - } else { - self.readyState = WebSocket.CONNECTING; - var e = generateEvent('connecting'); - e.code = event.code; - e.reason = event.reason; - e.wasClean = event.wasClean; - eventTarget.dispatchEvent(e); - if (!reconnectAttempt && !timedOut) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onclose', self.url); - } - eventTarget.dispatchEvent(generateEvent('close')); - } - - var timeout = self.reconnectInterval * Math.pow(self.reconnectDecay, self.reconnectAttempts); - setTimeout(function() { - self.reconnectAttempts++; - self.open(true); - }, timeout > self.maxReconnectInterval ? self.maxReconnectInterval : timeout); - } - }; - ws.onmessage = function(event) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onmessage', self.url, event.data); - } - var e = generateEvent('message'); - e.data = event.data; - eventTarget.dispatchEvent(e); - }; - ws.onerror = function(event) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onerror', self.url, event); - } - eventTarget.dispatchEvent(generateEvent('error')); - }; - } - - // Whether or not to create a websocket upon instantiation - if (this.automaticOpen == true) { - this.open(false); - } - - /** - * Transmits data to the server over the WebSocket connection. - * - * @param data a text string, ArrayBuffer or Blob to send to the server. - */ - this.send = function(data) { - if (ws) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'send', self.url, data); - } - return ws.send(data); - } else { - throw 'INVALID_STATE_ERR : Pausing to reconnect websocket'; - } - }; - - /** - * Closes the WebSocket connection or connection attempt, if any. - * If the connection is already CLOSED, this method does nothing. - */ - this.close = function(code, reason) { - // Default CLOSE_NORMAL code - if (typeof code == 'undefined') { - code = 1000; - } - forcedClose = true; - if (ws) { - ws.close(code, reason); - } - }; - - /** - * Additional public API method to refresh the connection if still open (close, re-open). - * For example, if the app suspects bad data / missed heart beats, it can try to refresh. - */ - this.refresh = function() { - if (ws) { - ws.close(); - } - }; - } - - /** - * An event listener to be called when the WebSocket connection's readyState changes to OPEN; - * this indicates that the connection is ready to send and receive data. - */ - ReconnectingWebSocket.prototype.onopen = function(event) {}; - /** An event listener to be called when the WebSocket connection's readyState changes to CLOSED. */ - ReconnectingWebSocket.prototype.onclose = function(event) {}; - /** An event listener to be called when a connection begins being attempted. */ - ReconnectingWebSocket.prototype.onconnecting = function(event) {}; - /** An event listener to be called when a message is received from the server. */ - ReconnectingWebSocket.prototype.onmessage = function(event) {}; - /** An event listener to be called when an error occurs. */ - ReconnectingWebSocket.prototype.onerror = function(event) {}; - - /** - * Whether all instances of ReconnectingWebSocket should log debug messages. - * Setting this to true is the equivalent of setting all instances of ReconnectingWebSocket.debug to true. - */ - ReconnectingWebSocket.debugAll = false; - - ReconnectingWebSocket.CONNECTING = WebSocket.CONNECTING; - ReconnectingWebSocket.OPEN = WebSocket.OPEN; - ReconnectingWebSocket.CLOSING = WebSocket.CLOSING; - ReconnectingWebSocket.CLOSED = WebSocket.CLOSED; - - return ReconnectingWebSocket; -});