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);