From 10da2b4fd5da591ebcaf25236e9037a6b4060c92 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Sun, 1 Nov 2015 17:28:19 -0500 Subject: [PATCH] 3.5.41 to 3.5.50. Viewer list sorting is now optional. CSS is now embedded in the script to prevent loading issues. Started testing new socket server. Added chat batching option to display new messages in batches for performance reasons. Changed socket server rotation logic. Added error checks for Stream Latency. Socket protocol now uses ok instead of True. Added deploy and clear_cache commands to gulp for convenience. --- .gitignore | 1 + gulpfile.js | 101 +++++++++++++++++- package.json | 4 +- src/constants.js | 8 +- src/ember/channel.js | 16 ++- src/ember/chatview.js | 30 ++++++ src/ember/player.js | 15 ++- src/ember/room.js | 82 +++++++++++--- src/main.js | 2 +- src/socket.js | 170 ++++++++++++++++++++++-------- style.css => src/styles/style.css | 15 +-- src/ui/dark.js | 3 +- src/ui/styles.js | 9 +- 13 files changed, 371 insertions(+), 85 deletions(-) rename style.css => src/styles/style.css (99%) diff --git a/.gitignore b/.gitignore index a524bdc7..60225f6d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ Extension Building *.iml script.js script.min.js +credentials.json /socketserver/cmd/socketserver/socketserver diff --git a/gulpfile.js b/gulpfile.js index baa2333e..411e6b64 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -13,7 +13,13 @@ var fs = require('fs'), // Templates var jsEscape = require('gulp-js-escape'), wrap = require('gulp-wrap'), - declare = require('gulp-declare'); + declare = require('gulp-declare'), + minifyCss = require('gulp-minify-css'); + + +// Deploy Dependencies +var ftp = require('vinyl-ftp'), + request = require('request'); // Server Dependencies @@ -56,7 +62,25 @@ gulp.task('templates', ['prepare'], function() { }); -gulp.task('scripts', ['prepare', 'templates'], function() { +gulp.task('styles', ['prepare'], function() { + gulp.src(['build/styles/**/*.css']) + .pipe(minifyCss()) + .pipe(jsEscape()) + .pipe(declare({ + root: 'exports', + noRedeclare: true, + processName: function(filePath) { + var match = filePath.match(/build[\\\/]styles[\\\/](.*)\.css$/); + return declare.processNameByPath((match && match.length > 1) ? match[1] : filePath); + } + })) + .pipe(concat('styles.js')) + .pipe(gulp.dest('build/')) + .on('error', util.log) +}); + + +gulp.task('scripts', ['prepare', 'templates', 'styles'], function() { gulp.src(['build/main.js']) .pipe(browserify()) .pipe(concat('script.js')) @@ -76,6 +100,79 @@ gulp.task('watch', ['default', 'server'], function() { gulp.task('default', ['scripts']); +// Deploy + +gulp.task('upload', ['default'], function() { + // Load credentials from an external file. + var contents = fs.readFileSync('credentials.json', 'utf8'), + cred = JSON.parse(contents); + + cred.log = util.log; + + // Create the connection. + var conn = ftp.create(cred); + + // What we're transfering. + var ftp_path = cred.remote_path, + + globs = [ + "script.min.js", + "style.css", + "dark.css", + "changelog.html" + ]; + + util.log(cred.remote_path); + + return gulp.src(globs, {base: '.', buffer: false}) + .pipe(conn.newerOrDifferentSize(ftp_path)) + .pipe(conn.dest(ftp_path)) + .on('error', util.log); +}); + +gulp.task('clear_cache', ['upload'], function() { + // Load credentials from an external file. + var contents = fs.readFileSync('credentials.json', 'utf8'), + cred = JSON.parse(contents); + + // Build the URLs. + var base = "://cdn.frankerfacez.com/script/", + files = [], + globs = [ + "script.min.js", + "style.css", + "dark.css", + "changelog.html" + ]; + + for(var i=0; i < globs.length; i++) { + files.push("http" + base + globs[i]); + files.push("https" + base + globs[i]); + } + + request({ + method: 'DELETE', + uri: "https://api.cloudflare.com/client/v4/zones/" + cred.cloudflare_zone + "/purge_cache", + headers: { + "X-Auth-Email": cred.cloudflare_email, + "X-Auth-Key": cred.cloudflare_key + }, + json: { + "files": files + } + }, function(error, request, body) { + if ( error ) + return util.log("[FAIL] Error: " + error); + else if ( request.statusCode !== 200 ) + return util.log("[FAIL] Non-200 Status: " + request.statusCode); + + util.log("[SUCCESS] Cache cleared."); + }); +}); + +gulp.task('deploy', ['upload', 'clear_cache']); + + // Server gulp.task('server', function() { diff --git a/package.json b/package.json index c3fffe8c..1d4b18e7 100755 --- a/package.json +++ b/package.json @@ -15,11 +15,13 @@ "gulp-footer": "^1.0.5", "gulp-header": "^1.2.2", "gulp-js-escape": "^1.0.1", + "gulp-minify-css": "^1.2.1", "gulp-rename": "^1.2.0", "gulp-uglify": "^1.0.2", "gulp-util": "^3.0.2", "gulp-wrap": "^0.11.0", - "request": "^2.51.0" + "request": "^2.65.0", + "vinyl-ftp": "^0.4.5" }, "repository": { "type": "git", diff --git a/src/constants.js b/src/constants.js index 0a1da39b..32d35656 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,15 +1,19 @@ var SVGPATH = '', + DEBUG = localStorage.ffzDebugMode == "true" && document.body.classList.contains('ffz-dev'), - WS_SERVERS = DEBUG ? ["localhost:8001", "catbag.frankerfacez.com"] : ["catbag.frankerfacez.com"], SERVER = DEBUG ? "//localhost:8000/" : "//cdn.frankerfacez.com/"; module.exports = { DEBUG: DEBUG, SERVER: SERVER, - WS_SERVERS: WS_SERVERS, API_SERVER: "//api.frankerfacez.com/", API_SERVER_2: "//direct-api.frankerfacez.com/", + WS_SERVER_POOLS: { + 1: ["ws://catbag.frankerfacez.com/", "ws://andknuckles.frankerfacez.com/"], + 2: ["ws://localhost:8001/"] + }, + KNOWN_CODES: { "#-?[\\\\/]": "#-/", ":-?(?:7|L)": ":-7", diff --git a/src/ember/channel.js b/src/ember/channel.js index a7adb41b..57cc4c67 100644 --- a/src/ember/channel.js +++ b/src/ember/channel.js @@ -456,8 +456,14 @@ FFZ.prototype._modify_cindex = function(view) { el = stat_el && stat_el.querySelector('span'), player_cont = f.players && f.players[channel_id], - player = player_cont && player_cont.ffz_player, + player = undefined, stats = undefined; + + try { + player = player_cont && player_cont.ffz_player; stats = player && player.stats; + } catch(err) { + f.error("Channel ffzUpdatePlayerStats: player.stats: " + err); + } if ( ! container || ! f.settings.player_stats || ! stats || stats.hlsLatencyBroadcaster === 'NaN' || stats.hlsLatencyBroadcaster === NaN ) { if ( stat_el ) @@ -508,8 +514,14 @@ FFZ.prototype._modify_cindex = function(view) { el = stat_el && stat_el.querySelector('span'), player_cont = f.players && f.players[hosted_id], - player = player_cont && player_cont.ffz_player, + player = undefined, stats = undefined; + + try { + player = player_cont && player_cont.ffz_player; stats = player && player.stats; + } catch(err) { + f.error("Channel ffzUpdatePlayerStats: player.stats: " + err); + } if ( ! container || ! f.settings.player_stats || ! stats || stats.hlsLatencyBroadcaster === 'NaN' || stats.hlsLatencyBroadcaster === NaN ) { diff --git a/src/ember/chatview.js b/src/ember/chatview.js index 06ce3945..0ef7b468 100644 --- a/src/ember/chatview.js +++ b/src/ember/chatview.js @@ -98,6 +98,36 @@ FFZ.settings_info.minimal_chat = { }; +FFZ.settings_info.chat_batching = { + type: "select", + options: { + 0: "No Batching", + 250: "Minor (0.25s)", + 500: "Normal (0.5s)", + 750: "Large (0.75s)", + 1000: "Extreme (1s)" + }, + value: 0, + + category: "Chat Appearance", + no_bttv: true, + + name: "Chat Message Batching", + help: "Display chat messages in batches to improve performance in extremely fast chats.", + + process_value: function(val) { + if ( typeof val === "string" ) + return parseInt(val) || 0; + return val; + }, + + on_update: function(val) { + if ( this._roomv ) + this._roomv.ffzUpdateStatus(); + } +}; + + FFZ.settings_info.chat_delay = { type: "select", options: { diff --git a/src/ember/player.js b/src/ember/player.js index 8b714677..67c8e888 100644 --- a/src/ember/player.js +++ b/src/ember/player.js @@ -159,14 +159,23 @@ FFZ.prototype._modify_player = function(player) { return; player = tp2.getPlayer(); - if ( ! player ) + if ( ! player || ! player.getVideo ) + // We can't get a valid player. :-( return; } this.set('ffz_player', player); // Only set up the stats hooks if we need stats. - if ( ! player.getVideo() ) + var has_video; + + try { + has_video = player.getVideo(); + } catch(err) { + f.error("Player2 ffzPostPlayer: getVideo: " + err); + } + + if ( ! has_video ) this.ffzInitStats(); }, @@ -186,7 +195,7 @@ FFZ.prototype._modify_player = function(player) { player.ffz_stats = player.getStatsEnabled(); } catch(err) { // Assume stats are off. - f.log("player ffzInitStats: getStatsEnabled still doesn't work: " + err); + f.error("Player2 ffzInitStats: getStatsEnabled still doesn't work: " + err); player.ffz_stats = false; } diff --git a/src/ember/room.js b/src/ember/room.js index 0978d6c5..a6f9cbbe 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -190,6 +190,7 @@ FFZ.prototype._modify_rview = function(view) { slow_badge = cont.querySelector('#ffz-stat-slow'), banned_badge = cont.querySelector('#ffz-stat-banned'), delay_badge = cont.querySelector('#ffz-stat-delay'), + batch_badge = cont.querySelector('#ffz-stat-batch'), btn = cont.querySelector('button'); if ( f.has_bttv || ! f.settings.room_status ) { @@ -199,6 +200,10 @@ FFZ.prototype._modify_rview = function(view) { sub_badge.parentElement.removeChild(sub_badge); if ( slow_badge ) slow_badge.parentElement.removeChild(slow_badge); + if ( delay_badge ) + delay_badge.parentElement.removeChild(delay_badge); + if ( batch_badge ) + batch_badge.parentElement.removeChild(batch_badge); if ( btn ) btn.classList.remove('ffz-waiting'); @@ -209,7 +214,7 @@ FFZ.prototype._modify_rview = function(view) { r9k_badge = document.createElement('span'); r9k_badge.className = 'ffz room-state stat float-right'; r9k_badge.id = 'ffz-stat-r9k'; - r9k_badge.innerHTML = 'R9K'; + r9k_badge.innerHTML = 'R9K'; r9k_badge.title = "This room is in R9K-mode."; cont.appendChild(r9k_badge); jQuery(r9k_badge).tipsy({gravity:"s", offset:15}); @@ -219,7 +224,7 @@ FFZ.prototype._modify_rview = function(view) { sub_badge = document.createElement('span'); sub_badge.className = 'ffz room-state stat float-right'; sub_badge.id = 'ffz-stat-sub'; - sub_badge.innerHTML = 'SUB'; + sub_badge.innerHTML = 'SUB'; sub_badge.title = "This room is in subscribers-only mode."; cont.appendChild(sub_badge); jQuery(sub_badge).tipsy({gravity:"s", offset:15}); @@ -229,8 +234,7 @@ FFZ.prototype._modify_rview = function(view) { slow_badge = document.createElement('span'); slow_badge.className = 'ffz room-state stat float-right'; slow_badge.id = 'ffz-stat-slow'; - slow_badge.innerHTML = 'SLOW'; - slow_badge.title = "This room is in slow mode. You may send messages every 120 seconds."; + slow_badge.innerHTML = 'SLOW'; cont.appendChild(slow_badge); jQuery(slow_badge).tipsy({gravity:"s", offset:15}); } @@ -239,7 +243,7 @@ FFZ.prototype._modify_rview = function(view) { banned_badge = document.createElement('span'); banned_badge.className = 'ffz room-state stat float-right'; banned_badge.id = 'ffz-stat-banned'; - banned_badge.innerHTML = 'BAN'; + banned_badge.innerHTML = 'BAN'; banned_badge.title = "You have been banned from talking in this room."; cont.appendChild(banned_badge); jQuery(banned_badge).tipsy({gravity:"s", offset:15}); @@ -249,21 +253,54 @@ FFZ.prototype._modify_rview = function(view) { delay_badge = document.createElement('span'); delay_badge.className = 'ffz room-state stat float-right'; delay_badge.id = 'ffz-stat-delay'; - delay_badge.innerHTML = 'DELAY'; - delay_badge.title = "You have enabled artificial chat delay. Messages are displayed after 0.3 seconds."; + delay_badge.innerHTML = 'DELAY'; cont.appendChild(delay_badge); jQuery(delay_badge).tipsy({gravity:"s", offset:15}); } - r9k_badge.classList.toggle('hidden', !(room && room.get('r9k'))); - sub_badge.classList.toggle('hidden', !(room && room.get('subsOnly'))); - banned_badge.classList.toggle('hidden', !(room && room.get('ffz_banned'))); + if ( ! batch_badge ) { + batch_badge = document.createElement('span'); + batch_badge.className = 'ffz room-state stat float-right'; + batch_badge.id = 'ffz-stat-batch'; + batch_badge.innerHTML = 'BATCH'; + cont.appendChild(batch_badge); + jQuery(batch_badge).tipsy({gravity:"s", offset:15}); + } - slow_badge.classList.toggle('hidden', !(room && room.get('slowMode'))); + var vis_count = 0, + r9k_vis = room && room.get('r9k'), + sub_vis = room && room.get('subsOnly'), + ban_vis = room && room.get('ffz_banned'), + slow_vis = room && room.get('slowMode'), + delay_vis = f.settings.chat_delay !== 0, + batch_vis = f.settings.chat_batching !== 0; + + if ( r9k_vis ) vis_count += 1; + if ( sub_vis ) vis_count += 1; + if ( ban_vis ) vis_count += 1; + if ( slow_vis ) vis_count += 1; + if ( delay_vis ) vis_count += 1; + if ( batch_vis ) vis_count += 1; + + r9k_badge.classList.toggle('truncated', vis_count > 3); + sub_badge.classList.toggle('truncated', vis_count > 3); + banned_badge.classList.toggle('truncated', vis_count > 3); + slow_badge.classList.toggle('truncated', vis_count > 3); + delay_badge.classList.toggle('truncated', vis_count > 3); + batch_badge.classList.toggle('truncated', vis_count > 3); + + r9k_badge.classList.toggle('hidden', ! r9k_vis); + sub_badge.classList.toggle('hidden', ! sub_vis); + banned_badge.classList.toggle('hidden', ! ban_vis); + + slow_badge.classList.toggle('hidden', ! slow_vis); slow_badge.title = "This room is in slow mode. You may send messages every " + utils.number_commas(room && room.get('slow')||120) + " seconds."; delay_badge.title = "You have enabled artificial chat delay. Messages are displayed after " + (f.settings.chat_delay/1000) + " seconds."; - delay_badge.classList.toggle('hidden', f.settings.chat_delay === 0); + delay_badge.classList.toggle('hidden', ! delay_vis); + + batch_badge.title = "You have enabled chat message batching. Messages are displayed in " + (f.settings.chat_batching/1000) + " second increments."; + batch_badge.classList.toggle('hidden', ! batch_vis); if ( btn ) { btn.classList.toggle('ffz-waiting', (room && room.get('slowWait') || 0)); @@ -1022,7 +1059,7 @@ FFZ.prototype._modify_room = function(room) { // Artificial chat delay pushMessage: function(msg) { - if ( f.settings.chat_delay !== 0 || (this.ffzPending && this.ffzPending.length) ) { + if ( f.settings.chat_batching !== 0 || f.settings.chat_delay !== 0 || (this.ffzPending && this.ffzPending.length) ) { if ( ! this.ffzPending ) this.ffzPending = []; @@ -1056,11 +1093,21 @@ FFZ.prototype._modify_room = function(room) { // Instead of just blindly looping every x seconds, we want to calculate the time until // the next message should be displayed, and then set the timeout for that. We'll // end up looping a bit more frequently, but it'll make chat feel more responsive. + + // If we have a pending flush, don't reschedule. It wouldn't change. if ( this._ffz_pending_flush ) - clearTimeout(this._ffz_pending_flush); + return; + + /*if ( this._ffz_pending_flush ) + clearTimeout(this._ffz_pending_flush);*/ if ( this.ffzPending && this.ffzPending.length ) { - var delay = 50 + Math.max(0, (f.settings.chat_delay + (this.ffzPending[0].time||0)) - (now || Date.now())); + // We need either the amount of chat delay past the first message, if chat_delay is on, or the + // amount of time from the last batch. + var delay = Math.max( + (f.settings.chat_delay !== 0 ? 50 + Math.max(0, (f.settings.chat_delay + (this.ffzPending[0].time||0)) - (now || Date.now())) : 0), + (f.settings.chat_batching !== 0 ? Math.max(0, f.settings.chat_batching - ((now || Date.now()) - (this._ffz_last_batch||0))) : 0)); + this._ffz_pending_flush = setTimeout(this.ffzPendingFlush.bind(this), delay); } }, @@ -1068,13 +1115,14 @@ FFZ.prototype._modify_room = function(room) { ffzPendingFlush: function() { this._ffz_pending_flush = null; - var now = Date.now(); + var now = this._ffz_last_batch = Date.now(); + for (var i = 0, l = this.ffzPending.length; i < l; i++) { var msg = this.ffzPending[i]; if ( msg.removed ) continue; - if ( f.settings.chat_delay + msg.time > now ) + if ( f.settings.chat_delay !== 0 && (f.settings.chat_delay + msg.time > now) ) break; this.ffzActualPushMessage(msg); diff --git a/src/main.js b/src/main.js index 655e8d6f..3eb6c92c 100644 --- a/src/main.js +++ b/src/main.js @@ -22,7 +22,7 @@ FFZ.get = function() { return FFZ.instance; } // Version var VER = FFZ.version_info = { - major: 3, minor: 5, revision: 42, + major: 3, minor: 5, revision: 50, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } diff --git a/src/socket.js b/src/socket.js index 99847bfc..0ebceab2 100644 --- a/src/socket.js +++ b/src/socket.js @@ -3,50 +3,106 @@ var FFZ = window.FrankerFaceZ, FFZ.prototype._ws_open = false; FFZ.prototype._ws_delay = 0; -FFZ.prototype._ws_last_iframe = 0; -FFZ.prototype._ws_host_idx = Math.floor(Math.random() * constants.WS_SERVERS.length) + 1; -if (constants.DEBUG) { - FFZ.prototype._ws_host_idx = 0; -} +FFZ.prototype._ws_host_idx = -1; +FFZ.prototype._ws_current_pool = -1; + FFZ.ws_commands = {}; FFZ.ws_on_close = []; // ---------------- -// Socket Creation +// Settings // ---------------- -// Attempt to authenticate to the socket server as a real browser by loading the root page. -// e.g. cloudflare ddos check -FFZ.prototype.ws_iframe = function() { - this._ws_last_iframe = Date.now(); - var ifr = document.createElement('iframe'), - f = this; +var ffz_socket_seed; - ifr.src = 'http://catbag.frankerfacez.com'; - ifr.style.visibility = 'hidden'; - document.body.appendChild(ifr); - setTimeout(function() { - document.body.removeChild(ifr); - if ( ! f._ws_open ) - f.ws_create(); - }, 2000); +try { + ffz_socket_seed = JSON.parse(localStorage.ffz_socket_seed); +} catch(err) { } + +if ( ! ffz_socket_seed ) { + ffz_socket_seed = Math.random(); + localStorage.ffz_socket_seed = JSON.stringify(ffz_socket_seed); } -FFZ.prototype.ws_create = function() { - // Disable sockets for now. - return; +FFZ.settings_info.socket_server_pool = { + type: "select", + options: { + 0: "Disabled", + 1: "Production", + 2: "Development" + }, + value: ffz_socket_seed > 0.65 ? 1 : 0, + + process_value: function(val) { + if ( typeof val === "string" ) + return parseInt(val) || 0; + return val; + }, + + visible: function() { return (localStorage.hasOwnProperty('ffz_socket_server_pool') && this.settings.socket_server_pool !== 1) || this.settings.developer_mode || (Date.now() - parseInt(localStorage.ffzLastDevMode || "0")) < 604800000; }, + + category: "Debugging", + name: "Socket Server Cluster", + help: "Select which cluster of socket servers to connect to.", + + on_update: function(val) { + if ( val === this._ws_current_pool ) + return; + + try { + this._ws_sock.close(); + } catch(err) { } + + this._ws_open = false; + this._ws_delay = 0; + this._ws_host_idx = -1; + + if ( this._ws_recreate_timer ) { + clearTimeout(this._ws_recreate_timer); + this._ws_recreate_timer = null; + } + + if ( val === 0 ) + return; + + this.ws_create(); + } +}; + + +// ---------------- +// Socket Creation +// ---------------- + +FFZ.prototype.ws_create = function() { var f = this, ws; - this._ws_last_req = 0; - this._ws_callbacks = {}; + this._ws_last_req = 1; + this._ws_callbacks = {1: f._ws_on_hello.bind(f)}; this._ws_pending = this._ws_pending || []; + this._ws_recreate_timer = null; + + var pool_id = this.settings.socket_server_pool, + pool = constants.WS_SERVER_POOLS[pool_id]; + + this._ws_current_pool = pool_id; + + if ( ! pool ) + return; + + if ( this._ws_host_idx < 0 ) + this._ws_host_idx = Math.floor(Math.random() * pool.length); + + var server = pool[this._ws_host_idx]; + + this.log("Using Socket Server: " + server + " [" + pool_id + ":" + this._ws_host_idx + "]"); try { - ws = this._ws_sock = new WebSocket("ws://" + constants.WS_SERVERS[this._ws_host_idx] + "/"); + ws = this._ws_sock = new WebSocket(pool[this._ws_host_idx]); } catch(err) { this._ws_exists = false; return this.log("Error Creating WebSocket: " + err); @@ -57,10 +113,10 @@ FFZ.prototype.ws_create = function() { ws.onopen = function(e) { f._ws_open = true; f._ws_delay = 0; - f._ws_last_iframe = Date.now(); - f.log("Socket connected."); + f.log("Socket Connected."); - f.ws_send("hello", ["ffz_" + FFZ.version_info, localStorage.ffzClientId], f._ws_on_hello.bind(f)); + // Hard-code the first command. + ws.send("1 hello " + JSON.stringify(["ffz_" + FFZ.version_info, localStorage.ffzClientId])); var user = f.get_user(); if ( user ) @@ -70,7 +126,6 @@ FFZ.prototype.ws_create = function() { if ( f.is_dashboard ) { var match = location.pathname.match(/\/([^\/]+)/); if ( match ) { - f.ws_send("sub", "room." + match[1]); f.ws_send("sub", "channel." + match[1]); } } @@ -124,13 +179,16 @@ FFZ.prototype.ws_create = function() { if ( ! f._ws_offline_time ) { f._ws_offline_time = new Date().getTime(); } - - // Cycle selected server - f._ws_host_idx = (f._ws_host_idx + 1) % constants.WS_SERVERS.length; } ws.onclose = function(e) { + var was_open = f._ws_open; f.log("Socket closed. (Code: " + e.code + ", Reason: " + e.reason + ")"); + + // If a recreate is already scheduled, this is expected. + if ( f._ws_recreate_timer ) + return; + f._ws_open = false; if ( ! f._ws_offline_time ) { f._ws_offline_time = new Date().getTime(); @@ -145,14 +203,11 @@ FFZ.prototype.ws_create = function() { } } - // Cycle selected server - f._ws_host_idx = (f._ws_host_idx + 1) % constants.WS_SERVERS.length; - - if ( f._ws_delay > 10000 ) { - var ua = navigator.userAgent.toLowerCase(); - if ( Date.now() - f._ws_last_iframe > 1800000 && !(ua.indexOf('chrome') === -1 && ua.indexOf('safari') !== -1) ) - return f.ws_iframe(); - } + // Cycle selected server if our last attempt to connect didn't + // actually connect. + if ( ! was_open ) + // Actually, let's get a random new server instead. + f._ws_host_idx = -1; //(f._ws_host_idx + 1) % pool.length; // We never ever want to not have a socket. if ( f._ws_delay < 60000 ) @@ -161,7 +216,7 @@ FFZ.prototype.ws_create = function() { // Randomize delay. f._ws_delay = (Math.floor(Math.random()*60)+30)*1000; - setTimeout(f.ws_create.bind(f), f._ws_delay); + f._ws_recreate_timer = setTimeout(f.ws_create.bind(f), f._ws_delay); } ws.onmessage = function(e) { @@ -193,7 +248,7 @@ FFZ.prototype.ws_create = function() { delete f._ws_callbacks[request]; } else { - var success = cmd === 'True', + var success = cmd === 'ok', has_callback = typeof f._ws_callbacks[request] === "function"; if ( ! has_callback ) @@ -251,7 +306,7 @@ FFZ.prototype._ws_on_hello = function(success, data) { localStorage.ffzClientId = data; this.log("Client ID: " + data); - var survey = {}, + /*var survey = {}, set = survey['settings'] = {}; for(var key in FFZ.settings_info) @@ -271,10 +326,35 @@ FFZ.prototype._ws_on_hello = function(success, data) { survey['language'] = navigator.language; survey['platform'] = navigator.platform; - this.ws_send("survey", [survey]); + this.ws_send("survey", [survey]);*/ } +// ---------------- +// Reconnect Logic +// ---------------- + +FFZ.ws_commands.reconnect = function() { + this.log("Socket Reconnect Command Received"); + + // Set the socket as closed and close it. + this._ws_open = false; + this._ws_sock.close(); + + // Socket Close Callbacks + for(var i=0; i < FFZ.ws_on_close.length; i++) { + try { + FFZ.ws_on_close[i].bind(this)(); + } catch(err) { + this.log("Error on Socket Close Callback: " + err); + } + } + + // Randomize the reconnect delay to avoid a complete hammering. + this._ws_delay = Math.floor(Math.random() * 5) * 1000; + this._ws_recreate_timer = setTimeout(this.ws_create.bind(this), this._ws_delay); +} + // ---------------- // Authorization diff --git a/style.css b/src/styles/style.css similarity index 99% rename from style.css rename to src/styles/style.css index 651dd885..766e3640 100644 --- a/style.css +++ b/src/styles/style.css @@ -850,6 +850,7 @@ span.ffz-handle:after { left: 8px } /* Chat Mentions */ + .ember-chat .mentioned:empty, .ember-chat .mentioning:empty { display: none; @@ -1155,7 +1156,7 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; } .ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before { background-color: rgba(255,0,0, 0.3); } - +*/ /* The New Whispers */ @@ -1643,6 +1644,8 @@ body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textar margin-right: 15px; } +.ffz.room-state.truncated span { font-size: 8px; } + .button.primary.ffz-waiting:not(:hover) { background-color: rgba(0,0,0,0.1); color: #32323e; @@ -1932,28 +1935,28 @@ li[data-name="following"] a { .ffz-legacy-mod-badges .ember-chat .badges .moderator, .ffz-legacy-badges .ember-chat .badges .moderator { background-color: #068c10; - background-image: url('legacy-mod.png'); + background-image: url('//cdn.frankerfacez.com/script/legacy-mod.png'); } .ffz-legacy-badges .ember-chat .badges .staff { background-color: #6441a5; - background-image: url('legacy-staff.png'); + background-image: url('//cdn.frankerfacez.com/script/legacy-staff.png'); } .ffz-legacy-badges .ember-chat .badges .broadcaster { background-color: #000; - background-image: url('legacy-broadcaster.png'); + background-image: url('//cdn.frankerfacez.com/script/legacy-broadcaster.png'); } .ffz-legacy-badges .ember-chat .badges .admin { background-color: #ff0303; - background-image: url('legacy-admin.png'); + background-image: url('//cdn.frankerfacez.com/script/legacy-admin.png'); } .ffz-legacy-turbo-badges .ember-chat .badges .turbo, .ffz-legacy-badges .ember-chat .badges .turbo { background-color: #6441a3; - background-image: url('legacy-turbo.png'); + background-image: url('//cdn.frankerfacez.com/script/legacy-turbo.png'); } /* High Contrast Chat */ diff --git a/src/ui/dark.js b/src/ui/dark.js index a625892e..65d98a80 100644 --- a/src/ui/dark.js +++ b/src/ui/dark.js @@ -1,5 +1,6 @@ var FFZ = window.FrankerFaceZ, - constants = require("../constants"); + constants = require("../constants"), + styles = require("../styles"); // --------------------- diff --git a/src/ui/styles.js b/src/ui/styles.js index d8312d29..a10b1684 100644 --- a/src/ui/styles.js +++ b/src/ui/styles.js @@ -1,17 +1,16 @@ var FFZ = window.FrankerFaceZ, - constants = require('../constants'); + constants = require('../constants'), + styles = require('../styles'); FFZ.prototype.setup_css = function() { document.body.classList.toggle('ffz-flip-dashboard', this.settings.flip_dashboard); this.log("Injecting main FrankerFaceZ CSS."); - var s = this._main_style = document.createElement('link'); + var s = this._main_style = document.createElement('style'); + s.textContent = styles.style; s.id = "ffz-ui-css"; - s.setAttribute('rel', 'stylesheet'); - s.setAttribute('href', constants.SERVER + "script/style.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info)); - s.onerror = "this.href = this.href + '_';" document.head.appendChild(s);