diff --git a/dark.css b/dark.css index 8aa0481d..889afb92 100644 --- a/dark.css +++ b/dark.css @@ -156,11 +156,16 @@ body.ffz-dark, border-color: #32323e !important; } +.ffz-dark .twitch_subwindow_container.two-factor-auth .card, +.ffz-dark .card#passport_modal { + color: #000; +} + .ffz-dark .balloon, .ffz-dark .balloon:after, .ffz-dark .conversation-settings-menu, .ffz-dark .ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, -.ffz-dark .card:not(#passport_modal), +.ffz-dark .twitch_subwindow_container:not(.two-factor-auth) .card:not(#passport_modal), .ffz-dark #flyout .content, .ffz-dark .whatisthis, .ffz-dark .ui-menu, diff --git a/src/FileSaver.js b/src/FileSaver.js index 65281522..6ceec7df 100644 --- a/src/FileSaver.js +++ b/src/FileSaver.js @@ -1,9 +1,9 @@ /* FileSaver.js * A saveAs() FileSaver implementation. - * 1.1.20150716 + * 1.1.20160328 * * By Eli Grey, http://eligrey.com - * License: X11/MIT + * License: MIT * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md */ @@ -30,6 +30,7 @@ var saveAs = saveAs || (function(view) { var event = new MouseEvent("click"); node.dispatchEvent(event); } + , is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent) , webkit_req_fs = view.webkitRequestFileSystem , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem , throw_outside = function(ex) { @@ -39,10 +40,8 @@ var saveAs = saveAs || (function(view) { } , force_saveable_type = "application/octet-stream" , fs_min_size = 0 - // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and - // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047 - // for the reasoning behind the timeout and revocation flow - , arbitrary_revoke_timeout = 500 // in ms + // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to + , arbitrary_revoke_timeout = 1000 * 40 // in ms , revoke = function(file) { var revoker = function() { if (typeof file === "string") { // file is an object URL @@ -51,11 +50,23 @@ var saveAs = saveAs || (function(view) { file.remove(); } }; - if (view.chrome) { - revoker(); - } else { - setTimeout(revoker, arbitrary_revoke_timeout); + /* // Take note W3C: + var + uri = typeof file === "string" ? file : file.toURL() + , revoker = function(evt) { + // idealy DownloadFinishedEvent.data would be the URL requested + if (evt.data === uri) { + if (typeof file === "string") { // file is an object URL + get_URL().revokeObjectURL(file); + } else { // file is a File + file.remove(); + } + } } + ; + view.addEventListener("downloadfinished", revoker); + */ + setTimeout(revoker, arbitrary_revoke_timeout); } , dispatch = function(filesaver, event_types, event) { event_types = [].concat(event_types); @@ -94,6 +105,19 @@ var saveAs = saveAs || (function(view) { } // on any filesys errors revert to saving with object URLs , fs_error = function() { + if (target_view && is_safari && typeof FileReader !== "undefined") { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + reader.onloadend = function() { + var base64Data = reader.result; + target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/)); + filesaver.readyState = filesaver.DONE; + dispatch_all(); + }; + reader.readAsDataURL(blob); + filesaver.readyState = filesaver.INIT; + return; + } // don't create more object URLs than needed if (blob_changed || !object_url) { object_url = get_URL().createObjectURL(blob); @@ -102,7 +126,7 @@ var saveAs = saveAs || (function(view) { target_view.location.href = object_url; } else { var new_tab = view.open(object_url, "_blank"); - if (new_tab == undefined && typeof safari !== "undefined") { + if (new_tab === undefined && is_safari) { //Apple do not allow window.open, see http://bit.ly/1kZffRI view.location.href = object_url } @@ -127,9 +151,9 @@ var saveAs = saveAs || (function(view) { } if (can_use_save_link) { object_url = get_URL().createObjectURL(blob); - save_link.href = object_url; - save_link.download = name; setTimeout(function() { + save_link.href = object_url; + save_link.download = name; click(save_link); dispatch_all(); revoke(object_url); @@ -249,8 +273,8 @@ var saveAs = saveAs || (function(view) { if (typeof module !== "undefined" && module.exports) { module.exports.saveAs = saveAs; -} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) { +} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { define([], function() { return saveAs; }); -} +} \ No newline at end of file diff --git a/src/badges.js b/src/badges.js index 1a1c9f5a..6490abfe 100644 --- a/src/badges.js +++ b/src/badges.js @@ -414,7 +414,8 @@ FFZ.prototype.load_badges = function(callback, tries) { jQuery.getJSON(constants.API_SERVER + "v1/badges") .done(function(data) { var badge_total = 0, - badge_count = 0; + badge_count = 0, + badge_data = {}; for(var i=0; i < data.badges.length; i++) { var badge = data.badges[i]; @@ -430,6 +431,8 @@ FFZ.prototype.load_badges = function(callback, tries) { var badge = f.badges[badge_id], users = data.users[badge_id]; + badge_data[badge.name] = users.length; + for(var i=0; i < users.length; i++) { var user = users[i], ud = f.users[user] = f.users[user] || {}, @@ -451,7 +454,7 @@ FFZ.prototype.load_badges = function(callback, tries) { f.log("Loaded " + utils.number_commas(badge_count) + " total badges across " + badge_total + " types."); - typeof callback === "function" && callback(true); + typeof callback === "function" && callback(true, badge_count, badge_total, badge_data); }).fail(function(data) { if ( data.status === 404 ) diff --git a/src/commands.js b/src/commands.js index 78d8d6a8..6dedb2f9 100644 --- a/src/commands.js +++ b/src/commands.js @@ -26,14 +26,8 @@ FFZ.ffz_commands.reload = function(room, args) { // Badge Information promises.push(new Promise(function(done, fail) { - f._legacy_load_bots(function(success, count) { - done(count || 0); - }); - })); - - promises.push(new Promise(function(done, fail) { - f._legacy_load_donors(function(success, count) { - done(count || 0); + f.load_badges(function(success, badge_count, badge_total, badge_data) { + done(success ? [badge_count, badge_total, badge_data] : [0, 0, {}]); }); })); @@ -52,19 +46,32 @@ FFZ.ffz_commands.reload = function(room, args) { // Do it! Promise.all(promises).then(function(results) { - var success = 0, - bots = results[0], - donors = results[1], - total = results.length - 2; + try { + var success = 0, + badge_count = results[0][0], + badge_total = results[0][1], + badges = results[0][2], + total = results.length - 1, + badge_string = []; - if ( results.length > 2 ) { - for(var i=2; i < results.length; i++) { - if ( results[i] ) - success++; + if ( results.length > 1 ) { + for(var i=1; i < results.length; i++) { + if ( results[i] ) + success++; + } } - } - f.room_message(room, "Loaded " + utils.number_commas(bots) + " new bot badge" + utils.pluralize(bots) + " and " + utils.number_commas(donors) + " new donor badge" + utils.pluralize(donors) + ". Successfully reloaded " + utils.number_commas(success) + " of " + utils.number_commas(total) + " emoticon set" + utils.pluralize(total) + "."); + for(var key in badges) { + if ( badges.hasOwnProperty(key) ) + badge_string.push(key + ': ' + badges[key]) + } + + f.room_message(room, "Loaded " + utils.number_commas(badge_count) + " badge" + utils.pluralize(badge_count) + " across " + utils.number_commas(badge_total) + " badge type" + utils.pluralize(badge_total) + (badge_string.length ? " (" + badge_string.join(", ") + ")" : "") + ". Successfully reloaded " + utils.number_commas(success) + " of " + utils.number_commas(total) + " emoticon set" + utils.pluralize(total) + "."); + + } catch(err) { + f.room_message(room, "An error occured running the command."); + f.error("Error Running FFZ Reload", err); + } }) } diff --git a/src/ember/conversations.js b/src/ember/conversations.js index a0f8839b..f23b93aa 100644 --- a/src/ember/conversations.js +++ b/src/ember/conversations.js @@ -71,34 +71,34 @@ FFZ.prototype.setup_conversations = function() { document.body.classList.toggle('ffz-minimize-conversations', this.settings.minimize_conversations); document.body.classList.toggle('ffz-theatre-conversations', this.settings.hide_conversations_in_theatre); - var ConvWindow = utils.ember_resolve('component:conversation-window'); + var ConvWindow = utils.ember_resolve('component:twitch-conversations/conversation-window'); if ( ConvWindow ) { this.log("Hooking the Ember Conversation Window component."); this._modify_conversation_window(ConvWindow); try { ConvWindow.create().destroy() } catch(err) { } } else - this.log("Unable to resolve: component:conversation-window"); + this.log("Unable to resolve: component:twitch-conversations/conversation-window"); - var ConvSettings = utils.ember_resolve('component:conversation-settings-menu'); + var ConvSettings = utils.ember_resolve('component:twitch-conversations/conversation-settings-menu'); if ( ConvSettings ) { this.log("Hooking the Ember Conversation Settings Menu component."); this._modify_conversation_menu(ConvSettings); try { ConvSettings.create().destroy() } catch(err) { } } else - this.log("Unable to resolve: component:conversation-settings-menu"); + this.log("Unable to resolve: component:twitch-conversations/conversation-settings-menu"); - var ConvLine = utils.ember_resolve('component:conversation-line'); + var ConvLine = utils.ember_resolve('component:twitch-conversations/conversation-line'); if ( ConvLine ) { this.log("Hooking the Ember Conversation Line component."); this._modify_conversation_line(ConvLine); try { ConvLine.create().destroy() } catch(err) { } } else - this.log("Unable to resolve: component:conversation-line"); + this.log("Unable to resolve: component:twitch-conversations/conversation-line"); } diff --git a/src/ember/directory.js b/src/ember/directory.js index e05bcffb..47928037 100644 --- a/src/ember/directory.js +++ b/src/ember/directory.js @@ -221,14 +221,11 @@ FFZ.prototype.setup_directory = function() { } else this.log("Unable to locate the Ember component:creative-preview"); - var CSGOChannel = utils.ember_resolve('view:cs-go-channel'); - if ( CSGOChannel ) { - this._modify_directory_live(CSGOChannel, true); - try { - CSGOChannel.create().destroy(); - } catch(err) { } - } else - this.log("Unable to locate the Ember view:cs-go-channel"); + var CSGOChannel = utils.ember_resolve('component:csgo-channel-preview'); + CSGOChannel = this._modify_directory_live(CSGOChannel, true, 'component:csgo-channel-preview'); + try { + CSGOChannel.create().destroy(); + } catch(err) { } var HostView = utils.ember_resolve('component:host-preview'); HostView = this._modify_directory_host(HostView); @@ -478,11 +475,11 @@ FFZ.prototype._modify_game_follow = function(component) { } -FFZ.prototype._modify_directory_live = function(dir, is_csgo) { +FFZ.prototype._modify_directory_live = function(dir, is_csgo, component_name) { var f = this, - pref = is_csgo ? 'context.model.' : 'stream.'; + pref = is_csgo ? 'channel.' : 'stream.'; - dir.reopen({ + var mutator = { didInsertElement: function() { this._super(); this.ffzInit(); @@ -503,8 +500,7 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo) { el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1); el.classList.toggle('ffz-game-spoilered', f.settings.spoiler_games.indexOf(game && game.toLowerCase()) !== -1); - // CSGO doesn't provide the actual uptime information... - if ( !is_csgo && f.settings.stream_uptime && f.settings.stream_uptime < 3 && cap ) { + if (f.settings.stream_uptime && f.settings.stream_uptime < 3 && cap ) { var t_el = this._ffz_uptime = document.createElement('div'); t_el.className = 'overlay_info length live'; @@ -591,7 +587,16 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo) { this._ffz_uptime.innerHTML = ''; } } - }); + }; + + if ( dir ) + dir.reopen(mutator); + else { + dir = Ember.Component.extend(mutator); + App.__deprecatedInstance__.registry.register(component_name, dir); + } + + return dir; } diff --git a/src/ember/line.js b/src/ember/line.js index 41822be2..c2dbef39 100644 --- a/src/ember/line.js +++ b/src/ember/line.js @@ -371,7 +371,6 @@ FFZ.settings_info.high_contrast_chat = { value: '222', category: "Chat Appearance", - no_bttv: true, name: "High Contrast", help: "Display chat using white and black for maximum contrast. This is suitable for capturing and chroma keying chat to display on stream.", @@ -385,9 +384,9 @@ FFZ.settings_info.high_contrast_chat = { }, on_update: function(val) { - this.toggle_style('chat-hc-text', !this.has_bttv && val[2] === '1'); - this.toggle_style('chat-hc-bold', !this.has_bttv && val[1] === '1'); - this.toggle_style('chat-hc-background', !this.has_bttv && val[0] === '1'); + this.toggle_style('chat-hc-text', val[2] === '1'); + this.toggle_style('chat-hc-bold', val[1] === '1'); + this.toggle_style('chat-hc-background', val[0] === '1'); } }; @@ -588,9 +587,9 @@ FFZ.prototype.setup_line = function() { this.toggle_style('chat-separator-3d-inset', !this.has_bttv && this.settings.chat_separators === 3); this.toggle_style('chat-separator-wide', !this.has_bttv && this.settings.chat_separators === 4); - this.toggle_style('chat-hc-text', !this.has_bttv && this.settings.high_contrast_chat[2] === '1'); - this.toggle_style('chat-hc-bold', !this.has_bttv && this.settings.high_contrast_chat[1] === '1'); - this.toggle_style('chat-hc-background', !this.has_bttv && this.settings.high_contrast_chat[0] === '1'); + this.toggle_style('chat-hc-text', this.settings.high_contrast_chat[2] === '1'); + this.toggle_style('chat-hc-bold', this.settings.high_contrast_chat[1] === '1'); + this.toggle_style('chat-hc-background', this.settings.high_contrast_chat[0] === '1'); this._last_row = {}; diff --git a/src/ember/player.js b/src/ember/player.js index 93f4dd13..58fbdd33 100644 --- a/src/ember/player.js +++ b/src/ember/player.js @@ -18,18 +18,18 @@ FFZ.settings_info.player_stats = { help: "Display your current stream latency (how far behind the broadcast you are) under the player, with a few useful statistics in a tooltip.", on_update: function(val) { - for(var key in this.players) { - var player = this.players[key]; - if ( player && player.player && player.player.ffzSetStatsEnabled ) - player.player.ffzSetStatsEnabled(val || player.player.ffz_stats); - } - - if ( ! this._cindex ) - return; - - this._cindex.ffzUpdatePlayerStats(); + for(var key in this.players) { + var player = this.players[key]; + if ( player && player.player && player.player.ffzSetStatsEnabled ) + player.player.ffzSetStatsEnabled(val || player.player.ffz_stats); } - }; + + if ( ! this._cindex ) + return; + + this._cindex.ffzUpdatePlayerStats(); + } +}; FFZ.settings_info.classic_player = { @@ -37,18 +37,32 @@ FFZ.settings_info.classic_player = { value: false, no_mobile: true, - category: "Appearance", + category: "Player", name: "Classic Player", help: "Alter the appearance of the player to resemble the older Twitch player with always visible controls.", on_update: function(val) { - document.body.classList.toggle('ffz-classic-player', val); - var Layout = utils.ember_lookup('controller:layout'); - if ( Layout ) - Layout.set('PLAYER_CONTROLS_HEIGHT', val ? 32 : 0); - } - }; + utils.toggle_cls('ffz-classic-player')(val); + var Layout = utils.ember_lookup('controller:layout'); + if ( Layout ) + Layout.set('PLAYER_CONTROLS_HEIGHT', val ? 32 : 0); + } +}; + + +FFZ.settings_info.player_volume_bar = { + type: "boolean", + value: false, + no_mobile: true, + + category: "Player", + + name: "Volume Always Expanded", + help: "Keep the volume slider expanded even when not hovering over it with the mouse.", + + on_update: utils.toggle_cls('ffz-player-volume') +}; // --------------- @@ -56,7 +70,9 @@ FFZ.settings_info.classic_player = { // --------------- FFZ.prototype.setup_player = function() { - document.body.classList.toggle('ffz-classic-player', this.settings.classic_player); + utils.toggle_cls('ffz-player-volume')(this.settings.player_volume_bar); + utils.toggle_cls('ffz-classic-player')(this.settings.classic_player); + var Layout = utils.ember_lookup('controller:layout'); if ( Layout ) Layout.set('PLAYER_CONTROLS_HEIGHT', this.settings.classic_player ? 32 : 0); @@ -164,10 +180,6 @@ FFZ.prototype._modify_player = function(player) { var stats = this.$('.player .js-playback-stats'); stats.draggable({cancel: 'li', containment: 'parent'}); - /*// Give the player time to do stuff before we change this - // text. It's a bit weird otherwise. - setTimeout(function(){stats.children('.js-stats-toggle').html(constants.CLOSE);},500);*/ - // Only set up the stats hooks if we need stats. var has_video = false; diff --git a/src/ember/room.js b/src/ember/room.js index aa7a32a7..870f1f74 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -6,6 +6,7 @@ var FFZ = window.FrankerFaceZ, STATUS_BADGES = [ ["r9k", "r9k", "This room is in R9K-mode."], + ["emote", "emoteOnly", "This room is in Twitch emoticons only mode. Emoticons added by extensions are not available in this mode."], ["sub", "subsOnly", "This room is in subscribers-only mode."], ["slow", "slow", function(room) { return "This room is in slow mode. You may send messages every " + utils.number_commas(room && room.get('slow') || 120) + " seconds." }], ["ban", "ffz_banned", "You have been banned from talking in this room."], @@ -245,6 +246,9 @@ FFZ.prototype._modify_rview = function(view) { id = 'ffz-stat-' + info[0]; badge = cont.querySelector('#' + id); visible = typeof info[1] === "function" ? info[1].call(f, room) : room && room.get(info[1]); + if ( typeof visible === "string" ) + visible = visible === "1"; + if ( ! badge ) { badge = utils.createElement('span', 'ffz room-state stat float-right', info[0].charAt(0).toUpperCase() + '' + info[0].substr(1).toUpperCase() + ''); badge.id = id; @@ -972,17 +976,17 @@ FFZ.prototype._modify_room = function(room) { var t = this; if ( user ) { - var duration = undefined, + var duration = Infinity, reason = undefined, current_user = f.get_user(), is_me = current_user && current_user.login === user; - // Read the ban duration and reason from the message tags. if ( tags && tags['ban-duration'] ) duration = parseInt(tags['ban-duration']); - else if ( tags && ! tags.hasOwnProperty('ban-duration') ) - duration = true; + + if ( isNaN(duration) ) + duration = Infinity; if ( tags && tags['ban-reason'] && (is_me || t.get('isModeratorOrHigher')) ) reason = tags['ban-reason']; @@ -1046,44 +1050,98 @@ FFZ.prototype._modify_room = function(room) { } - // Look up the User's Last Ban - // TODO: STUFF and THINGS - var room = f.rooms && f.rooms[t.get('id')], - ban_history, last_ban, identical_ban; + // Now we need to see about displaying a ban notice. + if ( ! disable_log ) { + // Look up the user's last ban. + var show_notice = is_me || this.ffzShouldDisplayNotice(), + show_reason = is_me || this.get('isModeratorOrHigher'), + room = f.rooms && f.rooms[t.get('id')], + now = new Date, + end_time = now + (duration * 1000), + ban_history, last_ban; - if ( room ) { - var now = Date.now(); - ban_history = room.ban_history = room.ban_history || {}; - last_ban = ban_history[user]; - identical_ban = (now - last_ban[2] >= 1000*(typeof last_ban[0] === "number" ? Math.min(last_ban[0], 10) : 10)); - ban_history[user] = [duration, reason, now]; - } + if ( room ) { + ban_history = room.ban_history = room.ban_history || {}; + last_ban = ban_history[user]; + + // Only overwrite a ban in the last 15 seconds. + if ( ! last_ban || Math.abs(now - last_ban.date) > 15000 ) + last_ban = null; + } + + // Display a notice in chat. + var message = (is_me ? "You have" : FFZ.get_capitalization(user) + " has") + " been " + (isFinite(duration) ? "timed out for " + utils.duration_string(duration, true) : "banned"); + + if ( show_notice ) { + if ( ! last_ban ) { + var msg = { + style: "admin", + date: now, + ffz_ban_target: user, + reasons: reason ? [reason] : [], + durations: [duration], + end_time: end_time, + timeouts: 1, + message: message + (show_reason && reason ? ' with reason: ' + reason : '.') + }; + + if ( ban_history ) + ban_history[user] = msg; + + this.addMessage(msg); + + } else { + if ( reason && last_ban.reasons.indexOf(reason) === -1 ) + last_ban.reasons.push(reason); + + if ( last_ban.durations.indexOf(duration) === -1 ) + last_ban.durations.push(duration); + + last_ban.end_time = end_time; + last_ban.timeouts++; + + last_ban.message = message + ' ' + utils.number_commas(last_ban.timeouts) + ' times' + (!show_reason || last_ban.reasons.length === 0 ? '.' : ' with reason' + utils.pluralize(last_ban.reasons.length) + ': ' + last_ban.reasons.join(', ')); + last_ban.cachedTokens = [{type: "text", text: last_ban.message}]; + + // Now that we've reset the tokens, if there's a line for this, + if ( last_ban._line ) + Ember.propertyDidChange(last_ban._line, 'tokenizedMessage'); + } + } - // Show a Notice - var message = (is_me ? 'You have' : FFZ.get_capitalization(user) + ' has') + ' been ' + (duration === undefined ? 'timed out' : duration === true ? 'banned' : 'timed out for ' + utils.number_commas(duration) + utils.pluralize(' second')); - if ( ! identical_ban && ! disable_log && (is_me || this.ffzShouldDisplayNotice()) ) - this.addTmiMessage(message + (reason ? ' with reason: ' + reason : '.')); + // Mod Card History + if ( room && f.settings.mod_card_history ) { + var chat_history = room.user_history = room.user_history || {}, + user_history = room.user_history[user] = room.user_history[user] || [], + last_ban = user_history.length > 0 ? user_history[user_history.length-1] : null; + if ( ! last_ban || ! last_ban.is_delete || Math.abs(now - last_ban.date) > 15000 ) + last_ban = null; - // Mod Card History - if ( room && f.settings.mod_card_history && ! disable_log ) { - var chat_history = room.user_history = room.user_history || {}, - user_history = room.user_history[user] = room.user_history[user] || [], + if ( last_ban ) + last_ban.cachedTokens = [message + ' ' + utils.number_commas(last_ban.timeouts) + ' times' + (last_ban.reasons.length === 0 ? '.' : ' with reason' + utils.pluralize(last_ban.reasons.length) + ': ' + last_ban.reasons.join(', '))]; + else { + user_history.push({ + from: 'jtv', + is_delete: true, + style: 'admin', + date: now, + ffz_ban_target: user, + reasons: reason ? [reason] : [], + durations: [duration], + end_time: end_time, + timeouts: 1, + cachedTokens: message + (reason ? ' with reason: ' + reason : '.') + }) - has_delete = false, - last = user_history.length > 0 ? user_history[user_history.length-1] : null; - - has_delete = last !== null && last.is_delete; - if ( has_delete && (identical_ban || (! last.has_reason && ! reason)) ) { - last.cachedTokens = [message + ' ' + utils.number_commas(++last.deleted_times) + ' times' + (reason ? ' with reason: ' + utils.sanitize(reason) : '.')]; - } else { - user_history.push({from: 'jtv', is_delete: true, style: 'admin', cachedTokens: [message + (reason ? ' with reason: ' + utils.sanitize(reason) : '.')], has_reason: reason !== undefined, deleted_times: 1, date: new Date()}); - while ( user_history.length > 20 ) - user_history.shift(); + while ( user_history.length > 20 ) + user_history.shift(); + } } } + } else { if ( f.settings.prevent_clear ) this.addTmiMessage("A moderator's attempt to clear chat was ignored."); @@ -1321,7 +1379,7 @@ FFZ.prototype._modify_room = function(room) { // Report this message to the dashboard. if ( window !== window.parent && parent.postMessage && msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" ) - parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, location.protocol + "//www.twitch.tv/"); + parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, "*"); //location.protocol + "//www.twitch.tv/"); // Add the message. return this._super(msg); @@ -1438,7 +1496,7 @@ FFZ.prototype._modify_room = function(room) { f._cindex.ffzUpdateChatters(); if ( window !== window.parent && parent.postMessage ) - parent.postMessage({from_ffz: true, command: 'chatter_count', data: Object.keys(this.get('ffz_chatters') || {}).length}, location.protocol + "//www.twitch.tv/"); + parent.postMessage({from_ffz: true, command: 'chatter_count', data: Object.keys(this.get('ffz_chatters') || {}).length}, "*"); //location.protocol + "//www.twitch.tv/"); }, @@ -1446,37 +1504,7 @@ FFZ.prototype._modify_room = function(room) { var tmi = this.get('tmiRoom'), room = this; - // Re-bind clearChat - Ember.run.next(function(){ - tmi = room.get('tmiRoom'); - if ( ! tmi || room.get('ffz_clearchat_patch') ) - return; - - var func = function(user, tags) { room.clearMessages(user, tags) }; - if ( room && room._callbacks ) { - for(var i=0; i < room._callbacks.length; i++) { - var cb = room._callbacks[i]; - if ( cb && cb.eventName === "clearchat" ) { - room._callbacks.splice(i, 1); - tmi.off("clearchat", cb.callback); - } - } - - room._callbacks.push({ - emitter: tmi, - eventName: "clearchat", - callback: func - }); - } else { - f.log("Room Not Fully Initialized -- Expect Double Timeouts", room); - tmi.off("clearchat"); - } - - tmi.on("clearchat", func); - room.set('ffz_clearchat_patch', true); - }); - - if ( this.get('ffz_is_patched') || ! this.get('tmiRoom') ) + if ( this.get('ffz_is_patched') || ! tmi ) return; if ( f.settings.chatter_count ) diff --git a/src/ext/betterttv.js b/src/ext/betterttv.js index e58d34be..7f441135 100644 --- a/src/ext/betterttv.js +++ b/src/ext/betterttv.js @@ -49,7 +49,16 @@ FFZ.prototype.setup_bttv = function(delay) { } document.body.classList.add('ffz-bttv'); - document.body.classList.toggle('ffz-bttv-dark', BetterTTV.settings.get('darkenedMode')); + + var last_dark = BetterTTV.settings.get('darkenedMode'); + document.body.classList.toggle('ffz-bttv-dark', last_dark); + setInterval(function() { + var new_dark = BetterTTV.settings.get('darkenedMode'); + if ( new_dark !== last_dark ) { + document.body.classList.toggle('ffz-bttv-dark', new_dark); + last_dark = new_dark; + } + }, 500); // Disable Chat Tabs if ( this._chatv ) { @@ -82,9 +91,9 @@ FFZ.prototype.setup_bttv = function(delay) { this.toggle_style('chat-separator-3d-inset'); this.toggle_style('chat-separator-wide'); - this.toggle_style('chat-hc-text'); + /*this.toggle_style('chat-hc-text'); this.toggle_style('chat-hc-bold'); - this.toggle_style('chat-hc-background'); + this.toggle_style('chat-hc-background');*/ this.toggle_style('chat-colors-gray'); this.toggle_style('badges-transparent'); diff --git a/src/main.js b/src/main.js index e7edd05d..a6e0c7ee 100644 --- a/src/main.js +++ b/src/main.js @@ -37,7 +37,7 @@ FFZ.msg_commands = {}; // Version var VER = FFZ.version_info = { - major: 3, minor: 5, revision: 176, + major: 3, minor: 5, revision: 182, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } @@ -172,6 +172,7 @@ require('./ext/emote_menu'); require('./featurefriday'); +//require('./ui/chatpane'); require('./ui/popups'); require('./ui/styles'); require('./ui/dark'); @@ -201,32 +202,24 @@ FFZ.prototype.initialize = function(increment, delay) { // Make sure that FrankerFaceZ doesn't start setting itself up until the // Twitch ember application is ready. + // Pages we don't want to interact with at all. + if ( location.hostname === 'passport.twitch.tv' || /^\/user\/two_factor/.test(location.pathname) ) { + this.log("Found authentication sub-page. Not initializing."); + return; + } + // Check for the player if ( location.hostname === 'player.twitch.tv' ) { this.init_player(delay); return; } - - // Check for the transfer page. - if ( location.pathname === "/crossdomain/transfer" ) { - if ( location.hash.indexOf("ffz-settings-transfer") !== -1 ) - this.init_settings_transfer(); - return; - } - // Check for special non-ember pages. if ( /^\/(?:$|search$|user\/|p\/|settings|m\/|messages?\/)/.test(location.pathname) ) { this.init_normal(delay); return; } - if ( location.hostname === 'passport' && /^\/(?:authorize)/.test(location.pathname) ) { - this.log("Running on passport!"); - this.init_normal(delay, true); - return; - } - // Check for the dashboard. if ( /\/[^\/]+\/dashboard/.test(location.pathname) && !/bookmarks$/.test(location.pathname) ) { this.init_dashboard(delay); @@ -248,16 +241,6 @@ FFZ.prototype.initialize = function(increment, delay) { } -FFZ.prototype.init_settings_transfer = function() { - this.log("This is the HTTP Transfer URL. Building a settings backup and posting it to our parent."); - this.load_settings(); - try { this.setup_line(); } catch(err) { } - var msg = {from_ffz: true, command: "http_settings", data: this._get_settings_object()}; - window.opener.postMessage(msg, "https://www.twitch.tv"); - window.close(); -} - - FFZ.prototype.init_player = function(delay) { var start = (window.performance && performance.now) ? performance.now() : Date.now(); this.log("Found Twitch Player after " + (delay||0) + " ms at: " + location); diff --git a/src/settings.js b/src/settings.js index 077ff8b1..4146335d 100644 --- a/src/settings.js +++ b/src/settings.js @@ -72,15 +72,6 @@ FFZ.prototype.load_settings = function() { // Backup and Restore // -------------------- -FFZ.prototype._settings_open_http_window = function() { - window.open("http://www.twitch.tv/crossdomain/transfer#ffz-settings-transfer", "_ffz_settings"); -} - -FFZ.msg_commands.http_settings = function(data) { - this._load_settings_file(data); -} - - FFZ.prototype.reset_settings = function() { if ( ! confirm(this.tr('Are you sure you wish to reset FrankerFaceZ?\n\nThis will force the tab to refresh.')) ) return; @@ -472,10 +463,6 @@ FFZ.menu_pages.settings = { backup_link = createElement('a'), backup_help = createElement('span'), - http_para = createElement('p'), - http_link = createElement('a'), - http_help = createElement('span'), - restore_para = createElement('p'), restore_input = createElement('input'), restore_link = createElement('a'), @@ -526,20 +513,6 @@ FFZ.menu_pages.settings = { restore_para.appendChild(restore_help); restore_cont.appendChild(restore_para); - http_para.className = 'clearfix option'; - http_link.href = '#'; - http_link.innerHTML = 'Import from HTTP'; - http_link.addEventListener('click', this._settings_open_http_window.bind(this)); - - http_help.className = 'help'; - http_help.innerHTML = 'Load your settings from HTTP into HTTPS. (This briefly opens a new window.)'; - - http_para.appendChild(http_link); - http_para.appendChild(http_help); - - if ( location.protocol === "https:" ) - restore_cont.appendChild(http_para); - reset_cont.className = 'chat-menu-content'; reset_head.className = 'heading'; reset_head.innerHTML = this.tr('Reset Settings'); diff --git a/src/styles/chat-hc-background.css b/src/styles/chat-hc-background.css index 87096e93..66734662 100644 --- a/src/styles/chat-hc-background.css +++ b/src/styles/chat-hc-background.css @@ -1,4 +1,7 @@ /* High-Contrast Background */ +body.ffz-bttv .chat-container, +body.ffz-bttv .ember-chat.roomMode, +body.ffz-bttv .chat-messages, .chat-container, .ember-chat-container { background-color: #fff !important; @@ -6,6 +9,9 @@ /* Dark: High-Contrast Background */ +body.ffz-bttv-dark .chat-messages, +body.ffz-bttv-dark .chat-header, +body.ffz-bttv-dark .chat-interface, .theatre .chat-container, .theatre .ember-chat-container, .chat-container.dark, diff --git a/src/styles/chat-hc-text.css b/src/styles/chat-hc-text.css index 867b0e6e..9bbc4589 100644 --- a/src/styles/chat-hc-text.css +++ b/src/styles/chat-hc-text.css @@ -1,4 +1,7 @@ /* High-Contrast Text */ +body.ffz-bttv .chat-line .message, +body.ffz-bttv .chat-line .timestamp, + .chat-container, .ember-chat-container { color: #000 !important; @@ -12,6 +15,10 @@ .ember-chat-container.dark, .ember-chat-container.force-dark, +body.ffz-bttv-dark .chat-container, +body.ffz-bttv-dark .chat-line .message, +body.ffz-bttv-dark .chat-line .timestamp, + .ffz-dark .ember-chat-container.dark .chat-line, .ffz-dark .chat-container.dark .chat-line { diff --git a/src/tokenize.js b/src/tokenize.js index b724c0f0..7e992662 100644 --- a/src/tokenize.js +++ b/src/tokenize.js @@ -147,13 +147,18 @@ FFZ.prototype.setup_tokenization = function() { this.load_twitch_emote_data(); - helpers = window.require && window.require("ember-twitch-chat/helpers/chat-line-helpers"); + try { + helpers = window.require && window.require("ember-twitch-chat/helpers/chat-line-helpers"); + } catch(err) { } + if ( ! helpers ) return this.log("Unable to get chat helper functions."); - conv_helpers = window.require && window.require("ember-twitch-conversations/helpers/conversation-line-helpers"); - if ( ! conv_helpers ) - this.log("Unable to get conversation helper functions."); + try { + conv_helpers = window.require && window.require("web-client/helpers/twitch-conversations/conversation-line-helpers"); + } catch(err) { + this.error("Unable to get conversation helper functions.", err); + } this.log("Hooking Ember chat line helpers."); diff --git a/src/ui/menu.js b/src/ui/menu.js index ada92a6d..234bea45 100644 --- a/src/ui/menu.js +++ b/src/ui/menu.js @@ -208,17 +208,13 @@ FFZ.prototype.build_ui_popup = function(view) { // Start building the DOM. var container = document.createElement('div'), inner = document.createElement('div'), - menu = document.createElement('ul'), - - dark = (this.has_bttv ? BetterTTV.settings.get('darkenedMode') : false); + menu = document.createElement('ul'); container.className = 'emoticon-selector chat-menu ffz-ui-popup'; container.id = 'ffz-chat-menu'; inner.className = 'emoticon-selector-box dropmenu'; container.appendChild(inner); - container.classList.toggle('dark', dark); - // Stuff //jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')}); //jQuery(inner).find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')}); diff --git a/src/ui/menu_button.js b/src/ui/menu_button.js index 8e200d4a..c17ac7f0 100644 --- a/src/ui/menu_button.js +++ b/src/ui/menu_button.js @@ -28,7 +28,6 @@ FFZ.prototype.update_ui_link = function(link) { room = this.rooms[room_id], has_emotes = false, - dark = (this.has_bttv ? BetterTTV.settings.get('darkenedMode') : false), blue = (this.has_bttv ? BetterTTV.settings.get('showBlueButtons') : false), live = (this.feature_friday && this.feature_friday.live); @@ -42,7 +41,6 @@ FFZ.prototype.update_ui_link = function(link) { link.classList.toggle('no-emotes', ! has_emotes); link.classList.toggle('live', live); - link.classList.toggle('dark', dark); link.classList.toggle('blue', blue); //link.classList.toggle('news', this._has_news); } \ No newline at end of file diff --git a/src/utils.js b/src/utils.js index e0ae601c..d141d9f6 100644 --- a/src/utils.js +++ b/src/utils.js @@ -216,10 +216,15 @@ var sanitize_el = document.createElement('span'), if ( ! window.App ) return; - if ( App.__deprecatedInstance__ && App.__deprecatedInstance__.registry && App.__deprecatedInstance__.registry.lookup ) - return App.__deprecatedInstance__.registry.lookup(thing); - if ( App.__container__ && App.__container__.lookup ) - return App.__container__.lookup(thing); + try { + if ( App.__deprecatedInstance__ && App.__deprecatedInstance__.registry && App.__deprecatedInstance__.registry.lookup ) + return App.__deprecatedInstance__.registry.lookup(thing); + if ( App.__container__ && App.__container__.lookup ) + return App.__container__.lookup(thing); + } catch(err) { + FrankerFaceZ.get().error("There was an error looking up an Ember instance: " + thing, err); + return null; + } }; @@ -432,8 +437,8 @@ module.exports = FFZ.utils = { return (days||'') + ((!no_hours || days || hours) ? ((days && hours < 10 ? "0" : "") + hours + ':') : '') + (minutes < 10 ? "0" : "") + minutes + (no_seconds ? "" : (":" + (seconds < 10 ? "0" : "") + seconds)); }, - duration_string: function(val) { - if ( val === 1 ) + duration_string: function(val, no_purge) { + if ( ! no_purge && val === 1 ) return 'Purge'; if ( DURATIONS[val] ) diff --git a/style.css b/style.css index 4c8beb8b..4a4361ce 100644 --- a/style.css +++ b/style.css @@ -53,12 +53,12 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emotic .ember-chat-container.dark .ffz-ui-toggle svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle svg.svg-emoticons path, -.ffz-ui-toggle.dark svg.svg-emoticons path { fill: #888; } +body.ffz-bttv-dark .ffz-ui-toggle svg.svg-emoticons path { fill: #888; } .ember-chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle:hover svg.svg-emoticons path, -.ffz-ui-toggle.dark:hover svg.svg-emoticons path { fill: #777; } +body.ffz-bttv-dark .ffz-ui-toggle:hover svg.svg-emoticons path { fill: #777; } .ffz-ui-toggle.no-emotes svg.svg-emoticons path { fill: rgba(80,0,0,0.2); } @@ -73,44 +73,44 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emotic .ember-chat-container.dark .ffz-ui-toggle.news svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle.news svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle.news svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.news svg.svg-emoticons path, +body.ffz-bttv-dark .ffz-ui-toggle.news svg.svg-emoticons path, .ffz-ui-toggle.news svg.svg-emoticons path { fill: rgba(117, 80, 0, 0.5); } .ember-chat-container.dark .ffz-ui-toggle.news:hover svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle.news:hover svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle.news:hover svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.news:hover svg.svg-emoticons path, +body.ffz-bttv-dark .ffz-ui-toggle.news:hover svg.svg-emoticons path, .ffz-ui-toggle.news:hover svg.svg-emoticons path { fill: rgba(117, 80, 0, 0.8); } .ember-chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle.no-emotes svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes svg.svg-emoticons path { fill: #453434; } +body.ffz-bttv-dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path { fill: #453434; } .ember-chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes:hover svg.svg-emoticons path { fill: #543f3f; } +body.ffz-bttv-dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path { fill: #543f3f; } .ember-chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle.live svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live svg.svg-emoticons path { fill: #513c78; } +body.ffz-bttv-dark .ffz-ui-toggle.live svg.svg-emoticons path { fill: #513c78; } .ember-chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle.live:hover svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live:hover svg.svg-emoticons path { fill: #5b4487; } +body.ffz-bttv-dark .ffz-ui-toggle.live:hover svg.svg-emoticons path { fill: #5b4487; } .ember-chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle.blue.live svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live svg.svg-emoticons path { fill: #3c4e78; } +body.ffz-bttv-dark .ffz-ui-toggle.blue.live svg.svg-emoticons path { fill: #3c4e78; } .ember-chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, .app-main.theatre .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live:hover svg.svg-emoticons path { fill: #445887; } +body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill: #445887; } .ffz-ui-toggle.live { @@ -741,7 +741,7 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emotic .chat-container.force-dark .ffz-ui-popup ul.menu, .ember-chat-container.dark .ffz-ui-popup ul.menu, .ember-chat-container.force-dark .ffz-ui-popup ul.menu, -.ffz-ui-popup.dark ul.menu { +body.ffz-bttv-dark .ffz-ui-popup ul.menu { background-color: #282828; } @@ -766,7 +766,7 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emotic .chat-container.force-dark .ffz-ui-popup ul.sub-menu, .ember-chat-container.dark .ffz-ui-popup ul.sub-menu, .ember-chat-container.force-dark .ffz-ui-popup ul.sub-menu, -.ffz-ui-popup.dark ul.sub-menu { +body.ffz-bttv-dark .ffz-ui-popup ul.sub-menu { background-color: #181818; } @@ -780,7 +780,7 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emotic .chat-container.force-dark .ffz-ui-popup ul.sub-menu a, .ember-chat-container.dark .ffz-ui-popup ul.sub-menu a, .ember-chat-container.force-dark .ffz-ui-popup ul.sub-menu a, -.ffz-ui-popup.dark ul.sub-menu a { +body.ffz-bttv-dark .ffz-ui-popup ul.sub-menu a { color: #d3d3d3 !important; } @@ -822,13 +822,13 @@ span.ffz-handle:after { left: 8px } .chat-container.force-dark span.ffz-handle:before, .ember-chat-container.dark span.ffz-handle:before, .ember-chat-container.force-dark span.ffz-handle:before, -.ffz-ui-popup.dark span.ffz-handle:before, +body.ffz-bttv-dark .ffz-ui-popup span.ffz-handle:before, .app-main.theatre span.ffz-handle:after, .chat-container.dark span.ffz-handle:after, .chat-container.force-dark span.ffz-handle:after, .ember-chat-container.dark span.ffz-handle:after, .ember-chat-container.force-dark span.ffz-handle:after, -.ffz-ui-popup.dark span.ffz-handle:after { +body.ffz-bttv-dark .ffz-ui-popup span.ffz-handle:after { border-color: #666; } @@ -837,13 +837,13 @@ span.ffz-handle:after { left: 8px } .chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:before, .ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before, .ember-chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:before, -.ffz-ui-popup.ui-moved.dark span.ffz-handle:before, +body.ffz-bttv-dark .ffz-ui-popup.ui-moved span.ffz-handle:before, .app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:after, .chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after, .chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:after, .ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after, .ember-chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:after, -.ffz-ui-popup.ui-moved.dark span.ffz-handle:after { +body.ffz-bttv-dark .ffz-ui-popup.ui-moved span.ffz-handle:after { border-color: #d3d3d3; } @@ -878,9 +878,9 @@ span.ffz-handle:after { left: 8px } border-right: 1px solid rgba(0,0,0,0.2); } -.ffz-ui-popup.dark ul.menu { border-top-color: rgba(255,255,255,0.1) } -.ffz-ui-popup.dark ul.menu a { border-left-color: rgba(255,255,255,0.1) } -.ffz-ui-popup.dark ul.sub-menu a { border-right-color: rgba(255,255,255,0.1) } +body.ffz-bttv-dark .ffz-ui-popup ul.menu { border-top-color: rgba(255,255,255,0.1) } +body.ffz-bttv-dark .ffz-ui-popup ul.menu a { border-left-color: rgba(255,255,255,0.1) } +body.ffz-bttv-dark .ffz-ui-popup ul.sub-menu a { border-right-color: rgba(255,255,255,0.1) } .ffz-ui-popup ul.menu li.active { background-color: #fff; @@ -904,7 +904,7 @@ span.ffz-handle:after { left: 8px } .ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active, .ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active, .app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active, -.ffz-ui-popup.dark ul.menu li.active { +body.ffz-bttv-dark .ffz-ui-popup ul.menu li.active { background-color: rgb(16,16,16); } @@ -913,7 +913,7 @@ span.ffz-handle:after { left: 8px } .ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active a, .ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active a, .app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active a, -.ffz-ui-popup.dark ul.menu li.active a { +body.ffz-bttv-dark .ffz-ui-popup ul.menu li.active a { border-top-color: rgb(16,16,16); } @@ -922,7 +922,7 @@ span.ffz-handle:after { left: 8px } .ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, .ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, .app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, -.ffz-ui-popup.dark ul.menu li.active.has-sub-menu { +body.ffz-bttv-dark .ffz-ui-popup ul.menu li.active.has-sub-menu { background-color: #181818; } @@ -931,7 +931,7 @@ span.ffz-handle:after { left: 8px } .ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, .ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, .app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, -.ffz-ui-popup.dark ul.menu li.active.has-sub-menu a { +body.ffz-bttv-dark .ffz-ui-popup li.active.has-sub-menu a { border-top-color: #181818; } @@ -940,7 +940,7 @@ span.ffz-handle:after { left: 8px } .ember-chat-container.dark .chat-interface .ffz-ui-popup a, .ember-chat-container.force-dark .chat-interface .ffz-ui-popup a, .app-main.theatre .chat-container .chat-interface .ffz-ui-popup a, -.ffz-ui-popup.dark .ffz-ui-menu-page a { color: #fff; } +body.ffz-bttv-dark .ffz-ui-popup .ffz-ui-menu-page a { color: #fff; } .chat-container.dark .chat-interface .ffz-ui-popup ul.menu svg path, @@ -949,7 +949,7 @@ span.ffz-handle:after { left: 8px } .ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu svg path, .app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu svg path, .ffz-dark .ffz-ui-popup ul.menu svg path, -.ffz-ui-popup.dark ul.menu svg path { fill: #d3d3d3; } +body.ffz-bttv-dark .ffz-ui-popup ul.menu svg path { fill: #d3d3d3; } .ffz-ui-popup ul.menu svg path { fill: #333; } @@ -970,24 +970,24 @@ span.ffz-handle:after { left: 8px } padding-top: 8px !important; } -.ffz-ui-popup.dark .emoticon-grid .heading, -.ffz-ui-popup.dark li.title { color: #fff; } -.ffz-ui-popup.dark .ffz-ui-menu-page { background-color: #101010; } +body.ffz-bttv-dark .ffz-ui-popup .emoticon-grid .heading, +body.ffz-bttv-dark .ffz-ui-popup li.title { color: #fff; } +body.ffz-bttv-dark .ffz-ui-popup .ffz-ui-menu-page { background-color: #101010; } .ffz-bttv .ffz-ui-popup .chat-menu-content p a { padding: 0; } -.ffz-bttv .ffz-ui-popup.dark ul.menu, -.ffz-bttv .ffz-ui-popup.dark .ffz-ui-menu-page { margin: 0 } +body.ffz-bttv-dark .ffz-ui-popup ul.menu, +body.ffz-bttv-dark .ffz-ui-popup .ffz-ui-menu-page { margin: 0 } -.ffz-ui-popup.dark .ffz-ui-menu-page .chat-menu-content .heading, -.ffz-ui-popup.dark .ffz-ui-menu-page .emoticon-grid .heading { +body.ffz-bttv-dark .ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading, +body.ffz-bttv-dark .ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading { border-color: rgba(255,255,255,0.1); } -.ffz-ui-popup.dark ul.menu:not(.sub-menu), -.ffz-ui-popup.dark .ffz-ui-menu-page { border: 1px solid rgba(255,255,255,0.1) } -.ffz-ui-popup.dark .ffz-ui-menu-page { border-bottom: none } +body.ffz-bttv-dark .ffz-ui-popup ul.menu:not(.sub-menu), +body.ffz-bttv-dark .ffz-ui-popup .ffz-ui-menu-page { border: 1px solid rgba(255,255,255,0.1) } +body.ffz-bttv-dark .ffz-ui-popup .ffz-ui-menu-page { border-bottom: none } .ffz-bttv .emoticon.emoji { padding-top: 0 } @@ -1186,7 +1186,8 @@ img.channel_background[src="null"] { display: none; } .ffz-moderation-card { border: 2px solid #cbcbcb; - max-width: 340px; + max-width: 350px; + min-width: 325px; } .ember-chat .ffz-moderation-card .close-button { @@ -2300,6 +2301,48 @@ li[data-name="following"] a { max-height: 90px; } +/* Player Captions *\/ + +.ffz-dark .player-modal__content, +.theatre .player-modal__content { + background: #101010; + color: #ccc; + box-shadow: 0 1px 1px rgba(255,255,255,.1); +} + +.ffz-dark .player-modal__header, +.theatre .player-modal__header { + color: #ccc; +} + +.ffz-dark .player-modal__content label, +.theatre .player-modal__content label { + color: #aaa; +} + +.ffz-dark .cc-font-size, +.theatre .cc-font-size { + background-color: #101010; + border-color: #333; +} + + + +.ffz-dark .cc-color-palette__square:not(:hover), +.theatre .cc-color-palette__square:not(:hover), + +.ffz-dark .cc-edge-palette__square:not(:hover), +.theatre .cc-edge-palette__square:not(:hover), + +.ffz-dark .cc-preset-square:not(:hover):not(.js-cc-preset-selected), +.theatre .cc-preset-square:not(:hover):not(.js-cc-preset-selected) { + border-color: #101010; +} + +.ffz-dark label.cc-edge-palette__square, +.theatre label.cc-edge-palette__square { color: #fff }*/ + + /* Classic Player */ .ffz-classic-player .player .player-video { @@ -2376,6 +2419,7 @@ li[data-name="following"] a { .ffz-classic-player .player .player-button svg { fill: #aeaeae; } .ffz-classic-player .player .player-seek .player-seek__time { color: #ddd; } +.ffz-player-volume .player .player-volume__slider-container, .ffz-classic-player .player .player-volume__slider-container { width: auto; } @@ -2401,6 +2445,8 @@ li[data-name="following"] a { opacity: 0.8; } +.player-button--close { top: 0 } + /* Directory Logos */ .item .meta .title a a, @@ -2797,4 +2843,9 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 } .ffz-hide-friends-collapsed .drawer--summary.closed .friend-list { display: none } -.warp__anchor { height: 5.5rem } \ No newline at end of file +.warp__anchor { height: 5.5rem } + + +/* Chat Pane Overhaul */ + +.ember-chat.ffz-chat-pane .chat-messages { bottom: 0 }