From dc2189d5f074d8722fd014cc7335e12fb86153b6 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Thu, 26 Feb 2015 00:42:11 -0500 Subject: [PATCH] Update dark theme. Add Bot badge. Add support for badge visibility checks. Enable username color fixes by default and require slightly brighter names in dark mode. Change image tooltips to not use HTML. Add option for global Twitch emoticons in My Emoticons menu. --- dark.css | 205 ++++++++++++++++++++++++++++++++++++++++--- script.js | 179 +++++++++++++++++++++++++++---------- script.min.js | 6 +- src/badges.js | 66 +++++++++++--- src/ember/line.js | 54 ++++++------ src/ember/room.js | 2 +- src/ext/betterttv.js | 2 - src/main.js | 2 +- src/socket.js | 5 +- src/ui/my_emotes.js | 48 ++++++++-- style.css | 20 ++--- 11 files changed, 462 insertions(+), 127 deletions(-) diff --git a/dark.css b/dark.css index e7a651ce..1273e549 100644 --- a/dark.css +++ b/dark.css @@ -54,10 +54,14 @@ border-color: rgba(255, 255, 255, 0.35) transparent transparent!important;; } /* hovering buttons */ -.ffz-dark .button:hover{ +.ffz-dark .button:not(.primary):not(.ffz-donate):hover{ color:rgb(222,222,222)!important; } +.ffz-dark .moderation-card .button:not(.glyph-only):hover { + color: #fff !important; +} + /* stats */ .ffz-dark #channel .player-column .stats-and-actions .channel-stats .stat svg:not(.svg-glyph_live) path{ fill:rgba(255,255,255,0.35)!important; @@ -100,23 +104,65 @@ border-color: rgba(255, 255, 255, 0.35) transparent transparent!important;; color:rgb(255,255,255)!important; } +/* Right Column */ + +.ffz-dark #right_col { + background-color: rgb(25,25,31); + color: #fff; +} + + +/* Popups */ + +.ffz-dark .card, +.ffz-dark #flyout .content, +.ffz-dark .dropmenu, +.ffz-dark form.js-new_panel_form, +.ffz-dark .js-new_panel_btn, +.ffz-dark .manager .videos-grid .video .meta, +.ffz-dark .ember-chat .chat-room-list { + background-color: rgb(16,16,16); + color: rgb(195,195,195); /*#acacbf;*/ + border-color: #32323e; +} + +.ffz-dark #flyout .point::before { + border-right-color: rgb(16,16,16); /*rgb(25,25,31);*/ +} + +.ffz-dark #flyout .point::after { + border-right-color: #32323e; +} + +.ffz-dark .change-banner .banner-preview, +.ffz-dark form.js-new_panel_form input, +.ffz-dark form.js-new_panel_form textarea, +.ffz-dark .card input, +.ffz-dark .card textarea, +.ffz-dark .dropmenu input, +.ffz-dark input.text, +.ffz-dark input.string, +.ffz-dark textarea, +.ffz-dark .directory_header #custom_filter input { + background-color: rgba(255,255,255,0.05); + border-color: rgba(255,255,255,0.1); + color: #fff; +} + + /* Other stuff */ .ffz-dark .panel-formatting .panel { color: #8c8c9c; } -.ffz-dark a { +.ffz-dark .manager .videos-grid .video:hover .meta .actions li a, +.ffz-dark .ember-chat .chat-room-list .room:not(:hover) p.room-title, +.ffz-dark .dropmenu_action:not(:hover) span, +.ffz-dark a:not(.switch):not(.follow) { color: #a68ed2; } -.ffz-dark #flyout a, -.ffz-dark .dropmenu a, -.ffz-dark .ember-chat-container a, -.ffz-dark .chat-container a { - color: #6441a5; -} - .ffz-dark .panel-formatting .panel h3 { color: inherit; } @@ -150,8 +196,77 @@ border-color: rgba(255, 255, 255, 0.35) transparent transparent!important;; color: #fff; } +.ffz-dark .ember-chat .moderation-card img.channel_logo { + border-color: rgb(16,16,16); +} + +/* Video Manager */ + +.ffz-dark .manager .videos-grid .video .meta .actions { + border-top-color: rgba(255,255,255,0.25); +} + +.ffz-dark #highlighter .highlight-content .form-container li label { + color: #fff; +} + + +/* Subscriptions Page */ + +.ffz-dark .tickets .ticket .benefits { + background-color: rgb(16,16,16); + color: rgb(195,195,195); /*#acacbf;*/ + border-color: #32323e; +} + + +/* Directory Pages */ + +.ffz-dark .following-col .col-header .search-contain .search .search-button svg path { + fill: rgba(255,255,255,0.25); +} + +.ffz-dark .following-col .col-header .search-contain .search .search-button:hover svg path { + fill: rgba(255,255,255,0.5); +} + +.ffz-dark .following-col .col-header, +.ffz-dark .following-col .header { + border-color: #32323e; +} + +.ffz-dark .following-col .following-list .load-more span, +.ffz-dark .viewall a { + background-color: rgb(25,25,31); +} + +.ffz-dark .following-col .following-list .load-more:hover span { + color: #fff; +} + +.ffz-dark .following-col .following-list .load-more:hover span, +.ffz-dark .viewall a:hover { + background-color: rgb(35,35,41); +} + +.ffz-dark .viewall a .text span:first-child { + color: #a68ed2; +} + + /* Profile page fixes */ +.ffz-dark .streams .stream .content .thumb .boxart, +.ffz-dark .videos .video .content .thumb .boxart { + border-color: rgb(16,16,16); +} + +.ffz-dark .ember-chat .moderation-card img.channel_logo, +.ffz-dark .channel-link .profile-photo { + background-color: rgb(16,16,16); +} + +.ffz-dark .items-grid .meta .title, .ffz-dark .items-grid .meta p a { color: #9c9c9c; } @@ -160,10 +275,74 @@ border-color: rgba(255, 255, 255, 0.35) transparent transparent!important;; color: #6c6c6c; } -.ffz-dark ul.tabs li>a:hover, .ffz-dark .directory_header .nav li>a:hover, .ffz-dark ul.tabs_fake li>a:hover, .ffz-dark ul.tabs li>a.active, .ffz-dark .directory_header .nav li>a.active, .ffz-dark ul.tabs_fake li>a.active { - color: #aaa; - border-color: #ccc !important; +.ffz-dark ul.tabs li > a, +.ffz-dark .directory_header .nav li > a, +.ffz-dark ul.tabs_fake li > a { + color: #a68ed2; +} + +.ffz-dark ul.tabs:before, +.ffz-dark .direcotry_header .nav:before, +.ffz-dark ul.tabs_fake:before { + border-color: #32323e; +} + +.ffz-dark ul.tabs li.selected a, +.ffz-dark .directory_header .nav li.selected a, +.ffz-dark ul.tabs_fake li.selected a, +.ffz-dark ul.tabs li>a:hover, +.ffz-dark .directory_header .nav li>a:hover, +.ffz-dark ul.tabs_fake li>a:hover, +.ffz-dark ul.tabs li>a.active, +.ffz-dark .directory_header .nav li>a.active, +.ffz-dark ul.tabs_fake li>a.active { + color: #aaa; + border-color: #ccc !important; } /* Hide the chat Dark Mode control */ -.ffz-dark .toggle-darkmode { display: none; } \ No newline at end of file +.ffz-dark .toggle-darkmode { display: none; } + +/* Chat Text Contrast */ +.ffz-dark .ember-chat-container.dark .chat-line, +.ffz-dark .chat-container.dark .chat-line { + color: #acacbf; +} + +.ffz-dark .ember-chat .chat-settings .chat-colors .chat-colors-swatch:hover, +.ffz-dark .ember-chat .chat-settings .chat-colors .chat-colors-switch.selected { + border-color: #777; + box-shadow: inset 0 0 0 1px #32323e; +} + +/* FrankerFaceZ Menu */ + +.ffz-dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading, +.ffz-dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading, +.ffz-dark .ffz-ui-popup ul.menu, +.ffz-dark .ffz-ui-popup ul.menu a { + border-color: #32323e; +} + +.ffz-dark .ffz-ui-popup ul.menu { + background-color: rgb(33,33,33); +} + +.ffz-dark .ffz-ui-popup ul.menu li.active { + background-color: rgb(16,16,16); +} + +.ffz-dark .ffz-ui-popup ul.menu li.active a { + border-top-color: rgb(16,16,16); +} + +/* New User Prompt */ + +.ffz-dark #new-user-prompt { + background-color: rgb(25,25,31); + color: #acacbf; +} + +.ffz-dark #new-user-prompt .message .title { + color: #fff; +} \ No newline at end of file diff --git a/script.js b/script.js index 3484f421..b2c5d590 100644 --- a/script.js +++ b/script.js @@ -4,6 +4,20 @@ var FFZ = window.FrankerFaceZ, utils = require('./utils'); +// -------------------- +// Settings +// -------------------- + +FFZ.settings_info.bot_badges = { + type: "boolean", + value: true, + + category: "Chat", + name: "Bot Badges", + help: "Give special badges to known bots." + }; + + // -------------------- // Initialization // -------------------- @@ -39,7 +53,8 @@ FFZ.prototype.bttv_badges = function(data) { var user_id = data.sender, user = this.users[user_id], badges_out = [], - insert_at = -1; + insert_at = -1, + alpha = BetterTTV.settings.get('alphaTags'); if ( ! user || ! user.badges ) return; @@ -53,7 +68,6 @@ FFZ.prototype.bttv_badges = function(data) { } } - for (var slot in user.badges) { if ( ! user.badges.hasOwnProperty(slot) ) continue; @@ -61,8 +75,16 @@ FFZ.prototype.bttv_badges = function(data) { var badge = user.badges[slot], full_badge = this.badges[badge.id] || {}, desc = badge.title || full_badge.title, - style = "", - alpha = BetterTTV.settings.get('alphaTags'); + style = ""; + + if ( full_badge.visible !== undefined ) { + var visible = full_badge.visible; + if ( typeof visible == "function" ) + visible = visible.bind(this)(null, user_id); + + if ( ! visible ) + continue; + } if ( badge.image ) style += 'background-image: url(\\"' + badge.image + '\\"); '; @@ -117,12 +139,21 @@ FFZ.prototype.render_badge = function(view) { if ( full_badge.visible !== undefined ) { var visible = full_badge.visible; if ( typeof visible == "function" ) - try { visible = visible.bind(this)(room_id, user); } catch(err) { } + visible = visible.bind(this)(room_id, user); if ( ! visible ) continue; } + if ( full_badge.replaces ) { + var el = badges[0].querySelector('.badge.' + full_badge.replaces); + if ( el ) { + el.style.backgroundImage = 'url("' + (badge.image || full_badge.image) + '")'; + el.title += ", " + (badge.title || full_badge.title); + return; + } + } + var el = document.createElement('div'); el.className = 'badge float-left tooltip ffz-badge-' + badge.id; el.setAttribute('title', badge.title || full_badge.title); @@ -155,24 +186,33 @@ FFZ.prototype.render_badge = function(view) { // Legacy Support // -------------------- -FFZ.known_bots = ["quoteconut", "quoconut", "zenwan", "nightbot", "moobot", "xanbot"]; +FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"]; +FFZ.known_bots = ["quoteconut", "quoconut", "zenwan", "triiharder", "wobblerbot", "theroflbotr", "acebot"]; + FFZ.prototype._legacy_add_donors = function(tries) { this.badges[1] = {id: 1, title: "FFZ Donor", color: "#755000", image: "//cdn.frankerfacez.com/channel/global/donoricon.png"}; utils.update_css(this._badge_style, 1, badge_css(this.badges[1])); - // Developer Badges + // Developer Badge this.badges[0] = {id: 0, title: "FFZ Developer", color: "#FAAF19", image: "//cdn.frankerfacez.com/channel/global/devicon.png"}; utils.update_css(this._badge_style, 0, badge_css(this.badges[0])); - this.users.sirstendec = {badges: {0: {id:0}}}; - // Bot Badges - /*this.badges[2] = {id: 2, title: "Bot", color: "#595959", image: "//cdn.frankerfacez.com/channel/global/boticon.png", - visible: function(r,user) { return !(this.has_bttv && FFZ.bttv_known_bots[user]); }}; + // Bot Badge + this.badges[2] = {id: 2, title: "Bot", color: "#595959", image: "//cdn.frankerfacez.com/channel/global/boticon.png", + replaces: 'moderator', + visible: function(r,user) { return this.settings.bot_badges && !(this.has_bttv && FFZ.bttv_known_bots.indexOf(user)!==-1); }}; utils.update_css(this._badge_style, 2, badge_css(this.badges[2])); + for(var i=0;i", - set = data.set, + var set = data.set, set_type = data.set_type; if ( set_type === undefined ) @@ -457,12 +496,7 @@ var FFZ = window.FrankerFaceZ, set_type = null; } - if ( ! set_type ) - output += '' + set + ''; - else - output += "" + set_type + "" + set + ""; - - return '' + output + '
'; + return "Emoticon: " + data.code + "\n" + (set_type ? set_type + ": " : "") + set; }, build_tooltip = function(id) { @@ -578,7 +612,7 @@ FFZ.settings_info.keywords = { FFZ.settings_info.fix_color = { type: "boolean", - value: false, + value: true, category: "Chat", visible: function() { return ! this.has_bttv }, @@ -647,6 +681,7 @@ FFZ.prototype.setup_line = function() { var tokens = this._super(); try { + var start = performance.now(); tokens = f._remove_banned(tokens); tokens = f._emoticonize(this, tokens); var user = f.get_user(); @@ -654,6 +689,10 @@ FFZ.prototype.setup_line = function() { if ( ! user || this.get("model.from") != user.login ) tokens = f._mentionize(this, tokens); + var end = performance.now(); + if ( end - start > 5 ) + f.log("Tokenizing Message Took Too Long - " + (end-start) + "ms - " + JSON.stringify(tokens)); + } catch(err) { try { f.error("LineController tokenizedMessage: " + err); @@ -673,6 +712,8 @@ FFZ.prototype.setup_line = function() { didInsertElement: function() { this._super(); try { + var start = performance.now(); + var el = this.get('element'), controller = this.get('context'), user = controller.get('model.from'), @@ -715,7 +756,7 @@ FFZ.prototype.setup_line = function() { if ( mentioned ) { el.classList.add("ffz-mentioned"); - if ( ! document.hasFocus() && ! this.get('context.model.ffz_notified') && f.settings.highlight_notifications ) { + if ( f.settings.highlight_notifications && !document.hasFocus() && !this.get('context.model.ffz_notified') ) { var cap_room = FFZ.get_capitalization(room), cap_user = FFZ.get_capitalization(user), room_name = cap_room, @@ -746,7 +787,7 @@ FFZ.prototype.setup_line = function() { // Banned Links var bad_links = el.querySelectorAll('a.deleted-link'); for(var i=0; i < bad_links.length; i++) { - var link = bad_links[i]; + var link = bad_links[i]; link.addEventListener("click", function(e) { if ( ! this.classList.contains("deleted-link") ) @@ -783,7 +824,7 @@ FFZ.prototype.setup_line = function() { // Enhanced Emotes - var images = el.querySelectorAll('img'); + var images = el.querySelectorAll('img.emoticon'); for(var i=0; i < images.length; i++) { var img = images[i], name = img.alt, @@ -806,8 +847,6 @@ FFZ.prototype.setup_line = function() { f.ws_send("twitch_emote", id, load_emote_data.bind(f, id, img.alt)); } - jQuery(img).tipsy({html:true}); - } else if ( img.getAttribute('data-ffz-emote') ) { var data = JSON.parse(decodeURIComponent(img.getAttribute('data-ffz-emote'))), id = data && data[0] || null, @@ -835,13 +874,15 @@ FFZ.prototype.setup_line = function() { set: set_name, set_type: set_type }); - - jQuery(img).tipsy({html:true}); - - } else - jQuery(img).tipsy(); + } } + jQuery(images).tipsy(); + + + var duration = performance.now() - start; + if ( duration > 5 ) + f.log("Line Took Too Long - " + duration + "ms - " + el.innerHTML); } catch(err) { try { @@ -887,7 +928,7 @@ FFZ.prototype._handle_color = function(color) { // Color Too Bright. We need a lum of 0.3 or less. matched = true; - var s = 255, + var s = 127, nc = rgb; while(s--) { nc = utils.darken(nc); @@ -899,15 +940,15 @@ FFZ.prototype._handle_color = function(color) { } else output += '.ffz-chat-colors .ember-chat-container:not(.dark) .chat-line ' + rule + ', .ffz-chat-colors .chat-container:not(.dark) .chat-line ' + rule + ' { color: ' + color + ' !important; }\n'; - if ( lum < 0.1 ) { + if ( lum < 0.15 ) { // Color Too Dark. We need a lum of 0.1 or more. matched = true; - var s = 255, + var s = 127, nc = rgb; while(s--) { nc = utils.brighten(nc); - if ( utils.get_luminance(nc) >= 0.1 ) + if ( utils.get_luminance(nc) >= 0.15 ) break; } @@ -962,8 +1003,11 @@ FFZ.get_capitalization = function(name, callback) { FFZ.prototype.capitalize = function(view, user) { var name = FFZ.get_capitalization(user, this.capitalize.bind(this, view)); - if ( name && view ) - view.$('.from').text(name); + if ( !name || !view ) + return; + + var from = view.$('.from'); + from && from.text(name); } @@ -1396,7 +1440,7 @@ var FFZ = window.FrankerFaceZ, if ( ! room.moderator_badge ) return ""; - return '.chat-line[data-room="' + room.id + '"] .badges .moderator { background-image:url("' + room.moderator_badge + '") !important; }'; + return '.chat-line[data-room="' + room.id + '"] .badges .moderator { background-image:url("' + room.moderator_badge + '"); }'; } @@ -2052,8 +2096,6 @@ var FFZ = window.FrankerFaceZ, SENDER_REGEX = /(\sdata-sender="[^"]*"(?=>))/; -FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"]; - // -------------------- // Initialization // -------------------- @@ -2291,7 +2333,7 @@ FFZ.get = function() { return FFZ.instance; } // Version var VER = FFZ.version_info = { - major: 3, minor: 2, revision: 1, + major: 3, minor: 2, revision: 2, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } @@ -3051,7 +3093,10 @@ FFZ.prototype.ws_create = function() { } else { var success = cmd === 'True', callback = f._ws_callbacks[request]; - f.log("Socket Reply to " + request + " - " + (success ? "SUCCESS" : "FAIL"), data); + + if ( ! success || ! callback ) + f.log("Socket Reply to " + request + " - " + (success ? "SUCCESS" : "FAIL"), data); + if ( callback ) { delete f._ws_callbacks[request]; callback(success, data); @@ -3623,6 +3668,22 @@ var FFZ = window.FrankerFaceZ, TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/", BANNED_SETS = {"00000turbo":true}, + KNOWN_CODES = { + "B-?\\)": "B-)", + "\\:-?[z|Z|\\|]": ":-Z", + "\\:-?\\)": ":-)", + "\\:-?\\(": ":-(", + "\\:-?(p|P)": ":-P", + "\\;-?(p|P)": ";-P", + "\\<\\;3": "<3", + "\\:-?(?:\\/|\\\\)(?!\\/)": ":-/", + "\\;-?\\)": ";-)", + "R-?\\)": "R-)", + "[o|O](_|\\.)[o|O]": "O.o", + "\\:-?D": ":-D", + "\\:-?(o|O)": ":-O", + "\\>\\;\\(": ">(", + }, get_emotes = function(ffz) { var Chat = App.__container__.lookup('controller:chat'), @@ -3637,6 +3698,9 @@ var FFZ = window.FrankerFaceZ, // Remove the 'default' set. set_ids = set_ids.split(",").removeObject("0") + if ( ffz.settings.global_emotes_in_menu ) + set_ids.push("0"); + return [set_ids, user_sets]; }; @@ -3645,6 +3709,15 @@ var FFZ = window.FrankerFaceZ, // Initialization // ------------------- +FFZ.settings_info.global_emotes_in_menu = { + type: "boolean", + value: false, + + name: "Display Global Emotes in My Emotes", + help: "Display the global Twitch emotes in the My Emoticons menu." + }; + + FFZ.prototype.setup_my_emotes = function() { this._twitch_emote_sets = {}; this._twitch_set_to_channel = {}; @@ -3654,6 +3727,8 @@ FFZ.prototype.setup_my_emotes = function() { this._twitch_set_to_channel = JSON.parse(localStorage.ffzTwitchSets); } catch(err) { } } + + this._twitch_set_to_channel[0] = "twitch_global"; } @@ -3715,6 +3790,13 @@ FFZ.menu_pages.my_emotes = { if ( !name || BANNED_SETS[name] ) return; + if ( name == "twitch_global" ) { + FFZ.capitalization["global emoticons"] = ["Global Emoticons", Date.now()]; + set.channel = "Global Emoticons"; + set.badge = "//cdn.frankerfacez.com/channel/global/twitch_logo.png"; + return; + } + if ( name == "turbo" ) { set.channel = "Twitch Turbo"; set.badge = "//cdn.frankerfacez.com/script/turbo_badge.png"; @@ -3839,10 +3921,10 @@ FFZ.menu_pages.my_emotes = { var an = a[1].toLowerCase(), bn = b[1].toLowerCase(); - if ( an === "twitch turbo" ) + if ( an === "twitch turbo" || an === "global emoticons" ) an = "zzz" + an; - if ( bn === "twitch turbo" ) + if ( bn === "twitch turbo" || bn === "global emoticons" ) bn = "zzz" + bn; if ( an < bn ) return -1; @@ -3864,7 +3946,8 @@ FFZ.menu_pages.my_emotes = { menu.appendChild(heading); for(var x=0; x < set.emotes.length; x++) { - var emote = set.emotes[x]; + var emote = set.emotes[x], + code = KNOWN_CODES[emote.code] || emote.code; var s = document.createElement('span'); s.className = 'emoticon tooltip'; @@ -3876,8 +3959,8 @@ FFZ.menu_pages.my_emotes = { s.style.backgroundImage = '-ms-' + img_set; s.style.backgroundImage = img_set; - s.title = emote.code; - s.addEventListener('click', f._add_emote.bind(f, view, emote.code)); + s.title = code; + s.addEventListener('click', f._add_emote.bind(f, view, code)); menu.appendChild(s); } diff --git a/script.min.js b/script.min.js index ad96a0a3..8064ad97 100644 --- a/script.min.js +++ b/script.min.js @@ -1,3 +1,3 @@ -!function(e){!function t(e,n,o){function i(s,a){if(!n[s]){if(!e[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(r)return r(s,!0);throw new Error("Cannot find module '"+s+"'")}var c=n[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return i(n?n:t)},c,c.exports,t,e,n,o)}return n[s].exports}for(var r="function"==typeof require&&require,s=0;se?this._legacy_add_donors(e):void 0):void 0})},n.prototype._legacy_parse_donors=function(e){var t=0;if(null!=e)for(var n=e.trim().split(/\W+/),o=0;o50)return"Each user you unmod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var o=t.length;t.length;){var i=t.shift();e.room.tmiRoom.sendMessage("/unmod "+i)}return"Sent unmod command for "+o+" users."},t.ffz_commands.massunmod.help="Usage: /ffz massunmod \nBroadcaster only. Unmod all the users in the provided list.",t.ffz_commands.massmod=function(e,t){if(t=t.join(" ").trim(),!t.length)return"You must provide a list of users to mod.";t=t.split(/\W*,\W*/);var n=this.get_user();if(!n||!n.login==e.id)return"You must be the broadcaster to use massmod.";if(t.length>50)return"Each user you mod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var o=t.length;t.length;){var i=t.shift();e.room.tmiRoom.sendMessage("/mod "+i)}return"Sent mod command for "+o+" users."},t.ffz_commands.massmod.help="Usage: /ffz massmod \nBroadcaster only. Mod all the users in the provided list."},{}],3:[function(e,t){var n='',o="true"==localStorage.ffzDebugMode&&document.body.classList.contains("ffz-dev");t.exports={DEBUG:o,SERVER:o?"//localhost:8000/":"//cdn.frankerfacez.com/",SVGPATH:n,ZREKNARF:''+n+"",CHAT_BUTTON:''+n+"",GEAR:'',HEART:'',EMOTE:''}},{}],4:[function(){var t=e.FrankerFaceZ;t.settings_info.developer_mode={type:"boolean",value:!1,storage_key:"ffzDebugMode",visible:function(){return this.settings.developer_mode||Date.now()-parseInt(localStorage.ffzLastDevMode||"0")<6048e5},category:"Debugging",name:"Developer Mode",help:"Load FrankerFaceZ from the local development server instead of the CDN. Please refresh after changing this setting.",on_update:function(){localStorage.ffzLastDevMode=Date.now()}},t.ffz_commands.developer_mode=function(e,t){var n,t=t&&t.length?t[0].toLowerCase():null;return"y"==t||"yes"==t||"true"==t||"on"==t?n=!0:("n"==t||"no"==t||"false"==t||"off"==t)&&(n=!1),void 0===n?"Developer Mode is currently "+(this.settings.developer_mode?"enabled.":"disabled."):(this.settings.set("developer_mode",n),"Developer Mode is now "+(n?"enabled":"disabled")+". Please refresh your browser.")},t.ffz_commands.developer_mode.help="Usage: /ffz developer_mode \nEnable or disable Developer Mode. When Developer Mode is enabled, the script will be reloaded from //localhost:8000/script.js instead of from the CDN."},{}],5:[function(){var t=e.FrankerFaceZ;t.prototype.setup_chatview=function(){this.log("Hooking the Ember Chat view.");var e=App.__container__.resolve("view:chat");this._modify_cview(e);try{e.create().destroy()}catch(t){}for(var n in Ember.View.views)if(Ember.View.views.hasOwnProperty(n)){var o=Ember.View.views[n];if(o instanceof e){this.log("Adding UI link manually to Chat view.",o);try{o.$(".textarea-contain").append(this.build_ui_link(o))}catch(t){this.error("setup: build_ui_link: "+t)}}}},t.prototype._modify_cview=function(e){var t=this;e.reopen({didInsertElement:function(){this._super();try{this.$()&&this.$(".textarea-contain").append(t.build_ui_link(this))}catch(e){t.error("didInsertElement: build_ui_link: "+e)}},willClearRender:function(){this._super();try{this.$(".ffz-ui-toggle").remove()}catch(e){t.error("willClearRender: remove ui link: "+e)}},ffzUpdateLink:Ember.observer("controller.currentRoom",function(){try{t.update_ui_link()}catch(e){t.error("ffzUpdateLink: update_ui_link: "+e)}})})}},{}],6:[function(t){var n=e.FrankerFaceZ,o=t("../utils"),i=function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},r="[\\s`~<>!-#%-\\x2A,-/:;\\x3F@\\x5B-\\x5D_\\x7B}\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E3B\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]",s=new RegExp(r+"*,"+r+"*"),a=function(e){return(e+"").replace(/&/g,"&").replace(/'/g,"'").replace(/"/g,""").replace(//g,">")},l="http://static-cdn.jtvnw.net/emoticons/v1/",c=function(e){return l+e+"/1.0 1x, "+l+e+"/2.0 2x, "+l+e+"/3.0 4x"},u=function(e){var t="Emoticon"+e.code+"",n=e.set,o=e.set_type;return void 0===o&&(o="Channel"),n?(("00000turbo"==n||"turbo"==n)&&(n="Twitch Turbo",o=null),t+=o?""+o+""+n+"":''+n+"",''+t+"
"):e.code},d=function(e){{var t=this._twitch_emotes[e];t?t.set:null}return t?"string"==typeof t?t:t.tooltip?t.tooltip:t.tooltip=u(t):"???"},h=function(e,t,n,o){if(n){t&&(o.code=t),this._twitch_emotes[e]=o;for(var i=d.bind(this)(e),r=document.querySelectorAll('img[emote-id="'+e+'"]'),s=0;s-1&&(-1===t.indexOf("/")||t.indexOf("@")>16,t>>8&255,255&t],i=o.get_luminance(n),r="",s='span[style="color:'+e+'"]',a=!1;if(i>.3){a=!0;for(var l=255,c=n;l--&&(c=o.darken(c),!(o.get_luminance(c)<=.3)););r+=".ffz-chat-colors .ember-chat-container:not(.dark) .chat-line "+s+", .ffz-chat-colors .chat-container:not(.dark) .chat-line "+s+" { color: "+o.rgb_to_css(c)+" !important; }\n"}else r+=".ffz-chat-colors .ember-chat-container:not(.dark) .chat-line "+s+", .ffz-chat-colors .chat-container:not(.dark) .chat-line "+s+" { color: "+e+" !important; }\n";if(.1>i){a=!0;for(var l=255,c=n;l--&&(c=o.brighten(c),!(o.get_luminance(c)>=.1)););r+=".ffz-chat-colors .theatre .chat-container .chat-line "+s+", .ffz-chat-colors .chat-container.dark .chat-line "+s+", .ffz-chat-colors .ember-chat-container.dark .chat-line "+s+" { color: "+o.rgb_to_css(c)+" !important; }\n"}else r+=".ffz-chat-colors .theatre .chat-container .chat-line "+s+", .ffz-chat-colors .chat-container.dark .chat-line "+s+", .ffz-chat-colors .ember-chat-container.dark .chat-line "+s+" { color: "+e+" !important; }\n";a&&(this._fix_color_style.innerHTML+=r)}},n.capitalization={},n._cap_fetching=0,n.get_capitalization=function(t,o){if(e.BetterTTV&&BetterTTV.chat&&BetterTTV.chat.helpers.lookupDisplayName)return BetterTTV.chat.helpers.lookupDisplayName(t);if(!t)return t;if(t=t.toLowerCase(),"jtv"==t||"twitchnotify"==t)return t;var i=n.capitalization[t];return i&&Date.now()-i[1]<36e5?i[0]:(n._cap_fetching<25&&(n._cap_fetching++,n.get().ws_send("get_display_name",t,function(e,i){var r=e?i:t;n.capitalization[t]=[r,Date.now()],n._cap_fetching--,"function"==typeof o&&o(r)})),i?i[0]:t)},n.prototype.capitalize=function(e,t){var o=n.get_capitalization(t,this.capitalize.bind(this,e));o&&e&&e.$(".from").text(o)},n._regex_cache={},n._get_regex=function(e){return n._regex_cache[e]=n._regex_cache[e]||RegExp("\\b"+i(e)+"\\b","ig")},n._words_to_regex=function(e){var t=n._regex_cache[e];if(!t){for(var o="",s=0;s<banned link>',own:!0}:s)}return i},n.prototype._emoticonize=function(e,t){var n=e.get("parentController.model.id"),o=e.get("model.from"),i=this,r=this.getEmotes(o,n),s=[];return _.each(r,function(e){var n=i.emote_sets[e];n&&_.each(n.emotes,function(e){_.any(t,function(t){return _.isString(t)&&t.match(e.regex)})&&s.push(e)})}),s.length?("string"==typeof t&&(t=[t]),_.each(s,function(e){var n={isEmoticon:!0,cls:e.klass,emoticonSrc:e.url+'" data-ffz-emote="'+encodeURIComponent(JSON.stringify([e.id,e.set_id])),altText:e.hidden?"???":e.name};t=_.compact(_.flatten(_.map(t,function(t){if(_.isObject(t))return t;var o=t.split(e.regex),i=[];return o.forEach(function(e,t){i.push(e),t!==o.length-1&&i.push(n)}),i})))}),t):t}},{"../utils":27}],7:[function(t){var n=e.FrankerFaceZ,o=t("../utils"),i={ESC:27,P:80,B:66,T:84},r=[["5m",300],["10m",600],["1hr",3600],["12hr",43200],["24hr",86400]],s='',a='';n.settings_info.enhanced_moderation={type:"boolean",value:!1,visible:function(){return!this.has_bttv},category:"Chat",name:"Enhanced Moderation",help:"Use /p, /t, /u and /b in chat to moderate chat, or use hotkeys with moderation cards."},n.prototype.setup_mod_card=function(){this.log("Hooking the Ember Moderation Card view.");var e=App.__container__.resolve("view:moderation-card"),t=this;e.reopen({didInsertElement:function(){this._super();try{if(t.has_bttv||!t.settings.enhanced_moderation)return;var e=this.get("element"),n=this.get("context");if(e.classList.add("ffz-moderation-card"),n.get("parentController.model.isModeratorOrHigher")){e.classList.add("ffz-is-mod"),e.setAttribute("tabindex",1),e.addEventListener("keyup",function(e){var t=e.keyCode||e.which,o=n.get("model.user.id"),r=n.get("parentController.model");if(t==i.P)r.send("/timeout "+o+" 1");else if(t==i.B)r.send("/ban "+o);else if(t==i.T)r.send("/timeout "+o+" 600");else if(t!=i.ESC)return;n.send("hideModOverlay")});var l=document.createElement("div");l.className="interface clearfix";var c=function(e){var t=n.get("model.user.id"),o=n.get("parentController.model");o.send(-1===e?"/unban "+t:"/timeout "+t+" "+e)},u=function(e,t){var n=document.createElement("button");return n.className="button",n.innerHTML=e,n.title="Timeout User for "+o.number_commas(t)+" Second"+(1!=t?"s":""),600===t?n.title="(T)"+n.title.substr(1):1===t&&(n.title="(P)urge - "+n.title),jQuery(n).tipsy(),n.addEventListener("click",c.bind(this,t)),n};l.appendChild(u("Purge",1));var d=document.createElement("span");d.className="right",l.appendChild(d);for(var h=0;h button");v&&"button"==v.className&&(v.innerHTML=s,v.classList.add("glyph-only"),v.classList.add("message"),v.title="Message User",jQuery(v).tipsy()),this.$().draggable({start:function(){e.focus()}}),e.focus()}catch(b){try{t.error("ModerationCardView didInsertElement: "+b)}catch(b){}}}})},n.chat_commands.purge=n.chat_commands.p=function(e,t){if(!t||!t.length)return"Purge Usage: /p username [more usernames separated by spaces]";if(t.length>10)return"Please only purge up to 10 users at once.";for(var n=0;n10)return"Please only ban up to 10 users at once.";for(var n=0;n10)return"Please only unban up to 10 users at once.";for(var n=0;nn?this._legacy_add_room(e,t,n):void 0)})},n.prototype._legacy_load_room_css=function(e,t,n){var s=e,a=s.match(r);a&&a[1]&&(s=a[1]);var l={id:e,menu_sets:[s],sets:[s],moderator_badge:null,css:null};return n&&(n=n.replace(o,"").trim()),n&&(n=n.replace(i,function(e,t){return l.moderator_badge||"modicon.png"!==t.substr(-11)?e:(l.moderator_badge=t,"")})),l.css=n||null,this._load_room_json(e,t,l)}},{"../constants":3,"../utils":27}],9:[function(){var t=e.FrankerFaceZ;t.prototype.setup_viewers=function(){this.log("Hooking the Ember Viewers controller.");var e=App.__container__.resolve("controller:viewers");this._modify_viewers(e)},t.prototype._modify_viewers=function(e){var n=this;e.reopen({lines:function(){var e=this._super();try{var o=[],i={},r=null,s=App.__container__.lookup("controller:channel"),a=this.get("parentController.model.id"),l=s&&s.get("id");if(l){var c=s.get("display_name");c&&(t.capitalization[l]=[c,Date.now()])}a!=l&&(l=null);for(var u=0;un?this._legacy_load_set(e,t,n):"function"==typeof t&&t(!1))})},n.prototype._legacy_load_css=function(e,t,n){var r={},s={id:e,emotes:r,extra_css:null},a=this;n=n.replace(o,function(t,n,o,i,s,c,u,d){s=parseInt(s),c=parseInt(c),u=l(u,s);var h="."===i.substr(i.lastIndexOf("/")+1,1),p=++a._last_emote_id,m={id:p,set_id:e,hidden:h,name:o,height:s,width:c,url:i,margins:u,extra_css:d};return r[p]=m,""}).trim(),n&&n.replace(i,function(e,t){s.icon||"modicon.png"!==t.substr(-11)||(s.icon=t)}),this._load_set_json(e,t,s)}},{"./constants":3,"./utils":27}],11:[function(){var t=e.FrankerFaceZ,n=/(\sdata-sender="[^"]*"(?=>))/;t.bttv_known_bots=["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"],t.prototype.find_bttv=function(t,n){return this.has_bttv=!1,e.BTTVLOADED?this.setup_bttv(n||0):void(n>=6e4?this.log("BetterTTV was not detected after 60 seconds."):setTimeout(this.find_bttv.bind(this,t,(n||0)+t),t))},t.prototype.setup_bttv=function(e){this.log("BetterTTV was detected after "+e+"ms. Hooking."),this.has_bttv=!0,document.body.classList.remove("ffz-dark"),this._dark_style&&(this._dark_style.parentElement.removeChild(this._dark_style),delete this._dark_style),document.body.classList.remove("ffz-chat-colors"),document.body.classList.remove("ffz-chat-background");var t=BetterTTV.chat.helpers.sendMessage,o=this;BetterTTV.chat.helpers.sendMessage=function(e){var n=e.split(" ",1)[0].toLowerCase();return"/ffz"!==n?t(e):void o.run_ffz_command(e.substr(5),BetterTTV.chat.store.currentRoom)};var i,r=BetterTTV.chat.handlers.privmsg;BetterTTV.chat.handlers.privmsg=function(e,t){i=e;var n=r(e,t);return i=null,n};var s=BetterTTV.chat.templates.privmsg;BetterTTV.chat.templates.privmsg=function(e,t,r,a,l){o.bttv_badges(l);var c=s(e,t,r,a,l);return c.replace(n,'$1 data-room="'+i+'"')};var a,l=BetterTTV.chat.templates.message;BetterTTV.chat.templates.message=function(e,t,n,o){a=e;var i=l(e,t,n,o);return a=null,i};var c=BetterTTV.chat.templates.emoticonize;BetterTTV.chat.templates.emoticonize=function(e,t){var n=c(e,t),r=o.getEmotes(a,i),t=[];return _.each(r,function(e){var i=o.emote_sets[e];i&&_.each(i.emotes,function(e){_.any(n,function(t){return _.isString(t)&&t.match(e.regex)})&&t.push(e)})}),t.length?(_.each(t,function(e){var t=[''+e.name+''],o=n;if(n=[],!o||!o.length)return n;for(var i=0;i=6e4?this.log("Emote Menu for Twitch was not detected after 60 seconds."):setTimeout(this.find_emote_menu.bind(this,t,(n||0)+t),t))},t.prototype.setup_emote_menu=function(e){this.log("Emote Menu for Twitch was detected after "+e+"ms. Registering emote enumerator."),emoteMenu.registerEmoteGetter("FrankerFaceZ",this._emote_menu_enumerator.bind(this))},t.prototype._emote_menu_enumerator=function(){for(var e=this.get_user(),n=e?e.login:null,o=App.__container__.lookup("controller:chat"),i=o?o.get("currentRoom.id"):null,r=this.getEmotes(n,i),s=[],a=0;a=6e4?this.log('Twitch application not detected in "'+location.toString()+'". Aborting.'):setTimeout(this.initialize.bind(this,t,(n||0)+t),t)))},n.prototype.setup_ember=function(t){var o=e.performance&&performance.now?performance.now():Date.now();this.log("Found Twitch application after "+(t||0)+' ms in "'+location+'". Initializing FrankerFaceZ version '+n.version_info),this.users={},this.load_settings(),this.setup_dark(),this.ws_create(),this.setup_emoticons(),this.setup_badges(),this.setup_room(),this.setup_line(),this.setup_chatview(),this.setup_viewers(),this.setup_mod_card(),this.setup_notifications(),this.setup_css(),this.setup_menu(),this.setup_my_emotes(),this.setup_races(),this.find_bttv(10),this.find_emote_menu(10),this.check_ff();var i=e.performance&&performance.now?performance.now():Date.now(),r=i-o;this.log("Initialization complete in "+r+"ms")}},{"./badges":1,"./commands":2,"./debug":4,"./ember/chatview":5,"./ember/line":6,"./ember/moderation-card":7,"./ember/room":8,"./ember/viewers":9,"./emoticons":10,"./ext/betterttv":11,"./ext/emote_menu":12,"./featurefriday":14,"./settings":15,"./shims":16,"./socket":17,"./ui/about_page":18,"./ui/dark":19,"./ui/menu":20,"./ui/menu_button":21,"./ui/my_emotes":22,"./ui/notifications":23,"./ui/races":24,"./ui/styles":25,"./ui/viewer_count":26}],14:[function(t){var n=e.FrankerFaceZ,o=t("./constants");n.prototype.feature_friday=null,n.prototype.check_ff=function(e){e||this.log("Checking for Feature Friday data..."),jQuery.ajax(o.SERVER+"script/event.json",{cache:!1,dataType:"json",context:this}).done(function(e){return this._load_ff(e)}).fail(function(t){return 404==t.status?this._load_ff(null):(e=e||0,e++,10>e?setTimeout(this.check_ff.bind(this,e),250):this._load_ff(null))})},n.ws_commands.reload_ff=function(){this.check_ff()},n.prototype._feature_friday_ui=function(e,t,n){if(this.feature_friday&&this.feature_friday.channel!=e){this._emotes_for_sets(t,n,[this.feature_friday.set],"Feature Friday");var o=App.__container__.lookup("controller:channel");if(!o||o.get("id")!=this.feature_friday.channel){var i=this.feature_friday,r=document.createElement("div"),s=document.createElement("a");r.className="chat-menu-content",r.style.textAlign="center";var a=i.display_name+(i.live?" is live now!":"");s.className="button primary",s.classList.toggle("live",i.live),s.classList.toggle("blue",this.has_bttv&&BetterTTV.settings.get("showBlueButtons")),s.href="http://www.twitch.tv/"+i.channel,s.title=a,s.target="_new",s.innerHTML=""+a+"",r.appendChild(s),t.appendChild(r)}}},n.prototype._load_ff=function(e){if(this.feature_friday){this.global_sets.removeObject(this.feature_friday.set);var t=this.emote_sets[this.feature_friday.set];t&&(t.global=!1),this.feature_friday=null,this.update_ui_link()}e&&e.set&&e.channel&&(this.feature_friday={set:e.set,channel:e.channel,live:!1,display_name:n.get_capitalization(e.channel,this._update_ff_name.bind(this))},this.global_sets.push(e.set),this.load_set(e.set,this._update_ff_set.bind(this)),this._update_ff_live())},n.prototype._update_ff_live=function(){if(this.feature_friday){var e=this;Twitch.api.get("streams/"+this.feature_friday.channel).done(function(t){e.feature_friday.live=null!=t.stream,e.update_ui_link()}).always(function(){e.feature_friday.timer=setTimeout(e._update_ff_live.bind(e),12e4)})}},n.prototype._update_ff_set=function(e,t){t&&(t.global=!0)},n.prototype._update_ff_name=function(e){this.feature_friday&&(this.feature_friday.display_name=e)}},{"./constants":3}],15:[function(t){var n=e.FrankerFaceZ,o=t("./constants");make_ls=function(e){return"ffz_setting_"+e},toggle_setting=function(e,t){var n=!this.settings.get(t);this.settings.set(t,n),e.classList.toggle("active",n)},n.settings_info={},n.prototype.load_settings=function(){this.log("Loading settings."),this.settings={};for(var t in n.settings_info)if(n.settings_info.hasOwnProperty(t)){var o=n.settings_info[t],i=o.storage_key||make_ls(t),r=o.hasOwnProperty("value")?o.value:void 0;if(localStorage.hasOwnProperty(i))try{r=JSON.parse(localStorage.getItem(i))}catch(s){this.log('Error loading value for "'+t+'": '+s)}this.settings[t]=r}this.settings.get=this._setting_get.bind(this),this.settings.set=this._setting_set.bind(this),this.settings.del=this._setting_del.bind(this),e.addEventListener("storage",this._setting_update.bind(this),!1)},n.menu_pages.settings={render:function(e,t){var o={},i=[];for(var r in n.settings_info)if(n.settings_info.hasOwnProperty(r)){var s=n.settings_info[r],a=s.category||"Miscellaneous",l=o[a];if(void 0!==s.visible&&null!==s.visible){var c=s.visible;if("function"==typeof s.visible&&(c=s.visible.bind(this)()),!c)continue}l||(i.push(a),l=o[a]=[]),l.push([r,s])}i.sort(function(e,t){var e=e.toLowerCase(),t=t.toLowerCase();return"debugging"===e&&(e="zzz"+e),"debugging"===t&&(t="zzz"+t),t>e?-1:e>t?1:0});for(var u=0;un?-1:n>o?1:r>i?-1:i>r?1:0});for(var _=0;_",b.className="switch-label",b.innerHTML=s.name,f.appendChild(v),f.appendChild(b),v.addEventListener("click",toggle_setting.bind(this,v,r))}else{f.classList.add("option");var y=document.createElement("a");y.innerHTML=s.name,y.href="#",f.appendChild(y),y.addEventListener("click",s.method.bind(this))}if(s.help){var w=document.createElement("span");w.className="help",w.innerHTML=s.help,f.appendChild(w)}p.appendChild(f)}t.appendChild(p)}},name:"Settings",icon:o.GEAR,sort_order:99999},n.prototype._setting_update=function(t){if(t||(t=e.event),this.log("Storage Event",t),t.key&&"ffz_setting_"===t.key.substr(0,12)){var o=t.key,i=o.substr(12),r=void 0,s=n.settings_info[i];if(!s){for(i in n.settings_info)if(n.settings_info.hasOwnProperty(i)&&(s=n.settings_info[i],s.storage_key==o))break;if(s.storage_key!=o)return}this.log("Updated Setting: "+i);try{r=JSON.parse(t.newValue)}catch(a){this.log('Error loading new value for "'+i+'": '+a),r=s.value||void 0}if(this.settings[i]=r,s.on_update)try{s.on_update.bind(this)(r,!1)}catch(a){this.log('Error running updater for setting "'+i+'": '+a)}}},n.prototype._setting_get=function(e){return this.settings[e]},n.prototype._setting_set=function(e,t){var o=n.settings_info[e],i=o.storage_key||make_ls(e),r=JSON.stringify(t);if(this.settings[e]=t,localStorage.setItem(i,r),this.log('Changed Setting "'+e+'" to: '+r),o.on_update)try{o.on_update.bind(this)(t,!0)}catch(s){this.log('Error running updater for setting "'+e+'": '+s)}},n.prototype._setting_del=function(e){var t=n.settings_info[e],o=t.storage_key||make_ls(e),i=void 0;if(localStorage.hasOwnProperty(o)&&localStorage.removeItem(o),delete this.settings[e],t&&(i=this.settings[e]=t.hasOwnProperty("value")?t.value:void 0),t.on_update)try{t.on_update.bind(this)(i,!0)}catch(r){this.log('Error running updater for setting "'+e+'": '+r)}}},{"./constants":3}],16:[function(){Array.prototype.equals=function(e){if(!e)return!1;if(this.length!=e.length)return!1;for(var t=0,n=this.length;n>t;t++)if(this[t]instanceof Array&&e[t]instanceof Array){if(!this[t].equals(e[t]))return!1}else if(this[t]!=e[t])return!1;return!0}},{}],17:[function(){var t=e.FrankerFaceZ;t.prototype._ws_open=!1,t.prototype._ws_delay=0,t.ws_commands={},t.ws_on_close=[],t.prototype.ws_create=function(){var e,n=this;this._ws_last_req=0,this._ws_callbacks={},this._ws_pending=this._ws_pending||[];try{e=this._ws_sock=new WebSocket("ws://ffz.stendec.me/")}catch(o){return this._ws_exists=!1,this.log("Error Creating WebSocket: "+o)}this._ws_exists=!0,e.onopen=function(){n._ws_open=!0,n._ws_delay=0,n.log("Socket connected.");var e=n.get_user();e&&n.ws_send("setuser",e.login);for(var t in n.rooms)n.rooms.hasOwnProperty(t)&&n.ws_send("sub",t);var o=n._ws_pending;n._ws_pending=[];for(var i=0;i0){i=!0;break}}var l=document.createElement("div"),c="";c+="

FrankerFaceZ

",c+='
new ways to woof
',l.className="chat-menu-content center",l.innerHTML=c,t.appendChild(l);var u=document.createElement("div"),d=document.createElement("a"),h="To use custom emoticons in "+(i?"this channel":"tons of channels")+", get FrankerFaceZ from http://www.frankerfacez.com";d.className="button primary",d.innerHTML="Advertise in Chat",d.addEventListener("click",this._add_emote.bind(this,e,h)),u.appendChild(d);var p=document.createElement("a");p.className="button ffz-donate",p.href="http://www.frankerfacez.com/donate.html",p.target="_new",p.innerHTML="Donate",u.appendChild(p),u.className="chat-menu-content center",t.appendChild(u);var m=document.createElement("div");c='',c+='',c+='',c+='',c+='',m.className="chat-menu-content center",m.innerHTML=c;var _=!1;m.querySelector("#ffz-debug-logs").addEventListener("click",function(){_||(_=!0,r._pastebin(r._log_data.join("\n"),function(e){_=!1,e?prompt("Your FrankerFaceZ logs have been uploaded to the URL:",e):alert("There was an error uploading the FrankerFaceZ logs.")}))}),t.appendChild(m)}}},{"../constants":3}],19:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.settings_info.twitch_chat_dark={type:"boolean",value:!1,visible:!1},n.settings_info.dark_twitch={type:"boolean",value:!1,visible:function(){return!this.has_bttv},name:"Dark Twitch Beta",help:"Apply a dark background to channels and other related pages for easier viewing.",on_update:function(e){if(!this.has_bttv){document.body.classList.toggle("ffz-dark",e);var t=App.__container__.lookup("controller:settings").get("model");e?(this._load_dark_css(),this.settings.set("twitch_chat_dark",t.get("darkMode")),t.set("darkMode",!0)):t.set("darkMode",this.settings.twitch_chat_dark)}}},n.prototype.setup_dark=function(){this.has_bttv||(document.body.classList.toggle("ffz-dark",this.settings.dark_twitch),this.settings.dark_twitch&&App.__container__.lookup("controller:settings").set("model.darkMode",!0),this.settings.dark_twitch&&this._load_dark_css())},n.prototype._load_dark_css=function(){if(!this._dark_style){this.log("Injecting FrankerFaceZ Dark Twitch CSS.");var e=this._dark_style=document.createElement("link");e.id="ffz-dark-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",o.SERVER+"script/dark.css"),document.head.appendChild(e)}}},{"../constants":3}],20:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.prototype.setup_menu=function(){this.log("Installing mouse-up event to auto-close menus.");var e=this;jQuery(document).mouseup(function(t){var n,o=e._popup;o&&(o=jQuery(o),n=o.parent(),n.is(t.target)||0!==n.has(t.target).length||(o.remove(),delete e._popup,e._popup_kill&&e._popup_kill(),delete e._popup_kill))})},n.menu_pages={},n.prototype.build_ui_popup=function(e){var t=this._popup;if(t)return t.parentElement.removeChild(t),delete this._popup,this._popup_kill&&this._popup_kill(),void delete this._popup_kill;var i=document.createElement("div"),r=document.createElement("div"),s=document.createElement("ul"),a=this.has_bttv?BetterTTV.settings.get("darkenedMode"):!1;i.className="emoticon-selector chat-menu ffz-ui-popup",r.className="emoticon-selector-box dropmenu",i.appendChild(r),i.classList.toggle("dark",a);var l=document.createElement("div");l.className="ffz-ui-menu-page",r.appendChild(l),s.className="menu clearfix",r.appendChild(s);var c=document.createElement("li");c.className="title",c.innerHTML=""+(o.DEBUG?"[DEV] ":"")+"FrankerFaceZ",s.appendChild(c);var u=[];for(var d in n.menu_pages)if(n.menu_pages.hasOwnProperty(d)){var h=n.menu_pages[d];h&&(!h.hasOwnProperty("visible")||h.visible&&("function"!=typeof h.visible||h.visible.bind(this)()))&&u.push([h.sort_order||0,d,h])}u.sort(function(e,t){if(e[0]t[0])return-1;var n=e[1].toLowerCase(),o=t[1].toLowerCase();return o>n?1:n>o?-1:0});for(var p=0;p0){i=!0;break}}e.classList.toggle("no-emotes",!i),e.classList.toggle("live",a),e.classList.toggle("dark",r),e.classList.toggle("blue",s)}}},{"../constants":3}],22:[function(t){var n=e.FrankerFaceZ,o=t("../constants"),i="http://static-cdn.jtvnw.net/emoticons/v1/",r={"00000turbo":!0},s=function(e){var t=App.__container__.lookup("controller:chat"),n=t.get("currentRoom.id"),o=e.rooms[n],i=o?o.room.tmiSession:null,r=i&&i._emotesParser&&i._emotesParser.emoticonSetIds||"0",s=e.get_user(),a=s&&e.users[s.login]&&e.users[s.login].sets||[];return r=r.split(",").removeObject("0"),[r,a]};n.prototype.setup_my_emotes=function(){if(this._twitch_emote_sets={},this._twitch_set_to_channel={},localStorage.ffzTwitchSets)try{this._twitch_set_to_channel=JSON.parse(localStorage.ffzTwitchSets)}catch(e){}},n.menu_pages.my_emotes={name:"My Emoticons",icon:o.EMOTE,visible:function(){var e=s(this);return e[0].length>0||e[1].length>0},render:function(e,t){var o=s(this),a=this;new RSVP.Promise(function(e){for(var t=[],i=0;i0?(a.ws_send("twitch_sets",t,function(e,n){if(t=[],e){for(var o in n)n.hasOwnProperty(o)&&(a._twitch_set_to_channel[o]=n[o],s(o,n[o]));localStorage.ffzTwitchSets=JSON.stringify(a._twitch_set_to_channel)}l()}),setTimeout(function(){t.length&&l()},5e3)):l()})]).then(function(){for(var t={},n=0;nt[0])return 1;var n=e[1].toLowerCase(),o=t[1].toLowerCase();return"twitch turbo"===n&&(n="zzz"+n),"twitch turbo"===o&&(o="zzz"+o),o>n?-1:n>o?1:0});for(var c=0;c'+l.source+""+n.get_capitalization(l.channel),l.badge&&(u.style.backgroundImage='url("'+l.badge+'")'),d.className="emoticon-grid",d.appendChild(u);for(var h=0;hSpeedRunsLive races under channels.',on_update:function(){this.rebuild_race_ui()}},n.ws_on_close.push(function(){var e=App.__container__.lookup("controller:channel"),t=e.get("id"),n=!1;for(var o in this.srl_races)delete this.srl_races[o],o==t&&(n=!0);n&&this.rebuild_race_ui()}),n.ws_commands.srl_race=function(e){for(var t=App.__container__.lookup("controller:channel"),n=t.get("id"),o=!1,i=0;i=300?"right":"left")+" share dropmenu",this._popup_kill=this._race_kill.bind(this),this._popup=e;var l="http://kadgar.net/live",c=!1;for(var u in s.entrants){var d=s.entrants[u].state;s.entrants.hasOwnProperty(u)&&s.entrants[u].channel&&("racing"==d||"entered"==d)&&(l+="/"+s.entrants[u].channel,c=!0)}var h=document.querySelector(".app-main.theatre")?document.body.clientHeight-300:t.parentElement.offsetTop-175,p=App.__container__.lookup("controller:channel"),m=p?p.get("display_name"):n.get_capitalization(r),_=encodeURIComponent("I'm watching "+m+" race "+s.goal+" in "+s.game+" on SpeedRunsLive!");a='
',a+='
Developers
Dan Salvato  
Stendec  
Version '+n.version_info+'Logs
',a+="
#Entrant Time
",a+='
',a+='',a+='

SRL',c&&(a+='   Multitwitch'),a+="

",e.innerHTML=a,t.appendChild(e),this._update_race(!0)}}},n.prototype._update_race=function(e){this._race_timer&&e&&(clearTimeout(this._race_timer),delete this._race_timer);var t=document.querySelector("#ffz-ui-race");if(t){var n=t.getAttribute("data-channel"),i=this.srl_races[n];if(!i)return t.parentElement.removeChild(t),this._popup_kill&&this._popup_kill(),void(this._popup&&(delete this._popup,delete this._popup_kill));var r=i.twitch_entrants[n],s=i.entrants[r],a=t.querySelector("#ffz-race-popup"),l=Date.now()/1e3,c=Math.floor(l-i.time);if(t.querySelector(".logo").innerHTML=o.placement(s),a){var u=a.querySelector("tbody"),d=a.querySelector(".heading span"),h=a.querySelector(".heading div");u.innerHTML="";var p=[],m=!0;for(var _ in i.entrants)i.entrants.hasOwnProperty(_)&&("racing"==i.entrants[_].state&&(m=!1),p.push(i.entrants[_]));p.sort(function(e,t){var n=e.place||9999,o=t.place||9999,i=e.time||c,r=t.time||c;return("forfeit"==e.state||"dq"==e.state)&&(n=1e4),("forfeit"==t.state||"dq"==t.state)&&(o=1e4),o>n?-1:n>o?1:e.namet.name?1:r>i?-1:i>r?1:void 0});for(var f=0;f'+_.display_name+"",v=_.channel?'':"",b=_.hitbox?'':"",y=c?o.time_to_string(_.time||c):"",w=o.place_string(_.place),k=_.comment?o.sanitize(_.comment):"";u.innerHTML+="'+w+""+g+""+v+b+''+("forfeit"==_.state?"Forfeit":y)+""}if(this._race_game!=i.game||this._race_goal!=i.goal){this._race_game=i.game,this._race_goal=i.goal;var F=o.sanitize(i.game),E=o.sanitize(i.goal);h.innerHTML='

'+F+"

Goal: "+E}c?m?d.innerHTML="Done":(d.innerHTML=o.time_to_string(c),this._race_timer=setTimeout(this._update_race.bind(this),1e3)):d.innerHTML="Entry Open"}}}},{"../utils":27}],25:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.prototype.setup_css=function(){this.log("Injecting main FrankerFaceZ CSS.");var e=this._main_style=document.createElement("link");e.id="ffz-ui-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",o.SERVER+"script/style.css?_="+Date.now()),document.head.appendChild(e),jQuery.noty.themes.ffzTheme={name:"ffzTheme",style:function(){this.$bar.removeClass().addClass("noty_bar").addClass("ffz-noty").addClass(this.options.type)},callback:{onShow:function(){},onClose:function(){}}}}},{"../constants":3}],26:[function(t){var n=e.FrankerFaceZ,o=t("../constants"),i=t("../utils");n.ws_commands.viewers=function(e){var t=e[0],n=e[1],r=App.__container__.lookup("controller:channel"),s=r&&r.get&&r.get("id");if(s===t){var a=document.querySelector(".channel-stats .ffz.stat"),l=o.ZREKNARF+" "+i.number_commas(n);if(a)a.innerHTML=l;else{var c=document.querySelector(".channel-stats");if(!c)return;a=document.createElement("span"),a.className="ffz stat",a.title="Viewers with FrankerFaceZ",a.innerHTML=l,c.appendChild(a),jQuery(a).tipsy()}}}},{"../constants":3,"../utils":27}],27:[function(t,n){var o=(e.FrankerFaceZ,t("./constants"),{}),i=document.createElement("span"),r=function(e){return 1==e?"1st":2==e?"2nd":3==e?"3rd":null==e?"---":e+"th"},s=function(e,t){t=0===t?0:t||1,t=Math.round(255*-(t/100));var n=Math.max(0,Math.min(255,e[0]-t)),o=Math.max(0,Math.min(255,e[1]-t)),i=Math.max(0,Math.min(255,e[2]-t));return[n,o,i]},a=function(e){return"rgb("+e[0]+", "+e[1]+", "+e[2]+")"},l=function(e,t){return t=0===t?0:t||1,s(e,-t)},c=function(e){e=[e[0]/255,e[1]/255,e[2]/255];for(var t=0;ts;(l||n)&&(l&&(o=o.substr(0,s)+o.substr(a+r.length)),n&&(o+=i+n+r),e.innerHTML=o)},get_luminance:c,brighten:s,darken:l,rgb_to_css:a,number_commas:function(e){var t=e.toString().split(".");return t[0]=t[0].replace(/\B(?=(\d{3})+(?!\d))/g,","),t.join(".")},place_string:r,placement:function(e){return"forfeit"==e.state?"Forfeit":"dq"==e.state?"DQed":e.place?r(e.place):""},sanitize:function(e){var t=o[e];return t||(i.textContent=e,t=o[e]=i.innerHTML,i.innerHTML=""),t},time_to_string:function(e){var t=e%60,n=Math.floor(e/60),o=Math.floor(n/60);return n%=60,(10>o?"0":"")+o+":"+(10>n?"0":"")+n+":"+(10>t?"0":"")+t}}},{"./constants":3}]},{},[13]),e.ffz=new FrankerFaceZ}(window); \ No newline at end of file +!function(e){!function t(e,n,o){function i(r,a){if(!n[r]){if(!e[r]){var l="function"==typeof require&&require;if(!a&&l)return l(r,!0);if(s)return s(r,!0);throw new Error("Cannot find module '"+r+"'")}var c=n[r]={exports:{}};e[r][0].call(c.exports,function(t){var n=e[r][1][t];return i(n?n:t)},c,c.exports,t,e,n,o)}return n[r].exports}for(var s="function"==typeof require&&require,r=0;re?this._legacy_add_donors(e):void 0):void 0})},n.prototype._legacy_parse_donors=function(e){var t=0;if(null!=e)for(var n=e.trim().split(/\W+/),o=0;o50)return"Each user you unmod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var o=t.length;t.length;){var i=t.shift();e.room.tmiRoom.sendMessage("/unmod "+i)}return"Sent unmod command for "+o+" users."},t.ffz_commands.massunmod.help="Usage: /ffz massunmod \nBroadcaster only. Unmod all the users in the provided list.",t.ffz_commands.massmod=function(e,t){if(t=t.join(" ").trim(),!t.length)return"You must provide a list of users to mod.";t=t.split(/\W*,\W*/);var n=this.get_user();if(!n||!n.login==e.id)return"You must be the broadcaster to use massmod.";if(t.length>50)return"Each user you mod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var o=t.length;t.length;){var i=t.shift();e.room.tmiRoom.sendMessage("/mod "+i)}return"Sent mod command for "+o+" users."},t.ffz_commands.massmod.help="Usage: /ffz massmod \nBroadcaster only. Mod all the users in the provided list."},{}],3:[function(e,t){var n='',o="true"==localStorage.ffzDebugMode&&document.body.classList.contains("ffz-dev");t.exports={DEBUG:o,SERVER:o?"//localhost:8000/":"//cdn.frankerfacez.com/",SVGPATH:n,ZREKNARF:''+n+"",CHAT_BUTTON:''+n+"",GEAR:'',HEART:'',EMOTE:''}},{}],4:[function(){var t=e.FrankerFaceZ;t.settings_info.developer_mode={type:"boolean",value:!1,storage_key:"ffzDebugMode",visible:function(){return this.settings.developer_mode||Date.now()-parseInt(localStorage.ffzLastDevMode||"0")<6048e5},category:"Debugging",name:"Developer Mode",help:"Load FrankerFaceZ from the local development server instead of the CDN. Please refresh after changing this setting.",on_update:function(){localStorage.ffzLastDevMode=Date.now()}},t.ffz_commands.developer_mode=function(e,t){var n,t=t&&t.length?t[0].toLowerCase():null;return"y"==t||"yes"==t||"true"==t||"on"==t?n=!0:("n"==t||"no"==t||"false"==t||"off"==t)&&(n=!1),void 0===n?"Developer Mode is currently "+(this.settings.developer_mode?"enabled.":"disabled."):(this.settings.set("developer_mode",n),"Developer Mode is now "+(n?"enabled":"disabled")+". Please refresh your browser.")},t.ffz_commands.developer_mode.help="Usage: /ffz developer_mode \nEnable or disable Developer Mode. When Developer Mode is enabled, the script will be reloaded from //localhost:8000/script.js instead of from the CDN."},{}],5:[function(){var t=e.FrankerFaceZ;t.prototype.setup_chatview=function(){this.log("Hooking the Ember Chat view.");var e=App.__container__.resolve("view:chat");this._modify_cview(e);try{e.create().destroy()}catch(t){}for(var n in Ember.View.views)if(Ember.View.views.hasOwnProperty(n)){var o=Ember.View.views[n];if(o instanceof e){this.log("Adding UI link manually to Chat view.",o);try{o.$(".textarea-contain").append(this.build_ui_link(o))}catch(t){this.error("setup: build_ui_link: "+t)}}}},t.prototype._modify_cview=function(e){var t=this;e.reopen({didInsertElement:function(){this._super();try{this.$()&&this.$(".textarea-contain").append(t.build_ui_link(this))}catch(e){t.error("didInsertElement: build_ui_link: "+e)}},willClearRender:function(){this._super();try{this.$(".ffz-ui-toggle").remove()}catch(e){t.error("willClearRender: remove ui link: "+e)}},ffzUpdateLink:Ember.observer("controller.currentRoom",function(){try{t.update_ui_link()}catch(e){t.error("ffzUpdateLink: update_ui_link: "+e)}})})}},{}],6:[function(t){var n=e.FrankerFaceZ,o=t("../utils"),i=function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},s="[\\s`~<>!-#%-\\x2A,-/:;\\x3F@\\x5B-\\x5D_\\x7B}\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E3B\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]",r=new RegExp(s+"*,"+s+"*"),a=function(e){return(e+"").replace(/&/g,"&").replace(/'/g,"'").replace(/"/g,""").replace(//g,">")},l="http://static-cdn.jtvnw.net/emoticons/v1/",c=function(e){return l+e+"/1.0 1x, "+l+e+"/2.0 2x, "+l+e+"/3.0 4x"},u=function(e){var t=e.set,n=e.set_type;return void 0===n&&(n="Channel"),t?(("00000turbo"==t||"turbo"==t)&&(t="Twitch Turbo",n=null),"Emoticon: "+e.code+"\n"+(n?n+": ":"")+t):e.code},d=function(e){{var t=this._twitch_emotes[e];t?t.set:null}return t?"string"==typeof t?t:t.tooltip?t.tooltip:t.tooltip=u(t):"???"},h=function(e,t,n,o){if(n){t&&(o.code=t),this._twitch_emotes[e]=o;for(var i=d.bind(this)(e),s=document.querySelectorAll('img[emote-id="'+e+'"]'),r=0;r5&&i.log("Tokenizing Message Took Too Long - "+(o-t)+"ms - "+JSON.stringify(e))}catch(s){try{i.error("LineController tokenizedMessage: "+s)}catch(s){}}return e}.property("model.message","isModeratorOrHigher")}),this.log("Hooking the Ember Line view.");var o=App.__container__.resolve("view:line");o.reopen({didInsertElement:function(){this._super();try{var t=performance.now(),o=this.get("element"),s=this.get("context"),r=s.get("model.from"),a=s.get("parentController.content.id"),l=s.get("model.color"),d=s.get("model.ffz_alternate");l&&i._handle_color(l),void 0===d&&(d=i._last_row[a]=i._last_row.hasOwnProperty(a)?!i._last_row[a]:!1,this.set("context.model.ffz_alternate",d)),o.classList.toggle("ffz-alternate",d),o.setAttribute("data-room",a),o.setAttribute("data-sender",r),i.render_badge(this),i.settings.capitalize&&i.capitalize(this,r);var m=o.querySelector("span.mentioned");if(m&&(o.classList.add("ffz-mentioned"),i.settings.highlight_notifications&&!document.hasFocus()&&!this.get("context.model.ffz_notified"))){var _=n.get_capitalization(a),p=n.get_capitalization(r),f=_,g=this.get("context.model.message");this.get("context.parentController.content.isGroupRoom")&&(f=this.get("context.parentController.content.tmiRoom.displayName")),g="action"==this.get("context.model.style")?"* "+p+" "+g:p+": "+g,i.show_notification(g,"Twitch Chat Mention in "+f,_,6e4,e.focus.bind(e))}this.set("context.model.ffz_notified",!0);for(var v=o.querySelectorAll("a.deleted-link"),b=0;b-1&&(-1===t.indexOf("/")||t.indexOf("@")5&&i.log("Line Took Too Long - "+M+"ms - "+o.innerHTML)}catch(D){try{i.error("LineView didInsertElement: "+D)}catch(D){}}}});var s=this.get_user();s&&s.name&&(n.capitalization[s.login]=[s.name,Date.now()])},n.prototype._handle_color=function(e){if(e&&!this._colors[e]){this._colors[e]=!0;var t=parseInt(e.substr(1),16),n=[t>>16,t>>8&255,255&t],i=o.get_luminance(n),s="",r='span[style="color:'+e+'"]',a=!1;if(i>.3){a=!0;for(var l=127,c=n;l--&&(c=o.darken(c),!(o.get_luminance(c)<=.3)););s+=".ffz-chat-colors .ember-chat-container:not(.dark) .chat-line "+r+", .ffz-chat-colors .chat-container:not(.dark) .chat-line "+r+" { color: "+o.rgb_to_css(c)+" !important; }\n"}else s+=".ffz-chat-colors .ember-chat-container:not(.dark) .chat-line "+r+", .ffz-chat-colors .chat-container:not(.dark) .chat-line "+r+" { color: "+e+" !important; }\n";if(.15>i){a=!0;for(var l=127,c=n;l--&&(c=o.brighten(c),!(o.get_luminance(c)>=.15)););s+=".ffz-chat-colors .theatre .chat-container .chat-line "+r+", .ffz-chat-colors .chat-container.dark .chat-line "+r+", .ffz-chat-colors .ember-chat-container.dark .chat-line "+r+" { color: "+o.rgb_to_css(c)+" !important; }\n"}else s+=".ffz-chat-colors .theatre .chat-container .chat-line "+r+", .ffz-chat-colors .chat-container.dark .chat-line "+r+", .ffz-chat-colors .ember-chat-container.dark .chat-line "+r+" { color: "+e+" !important; }\n";a&&(this._fix_color_style.innerHTML+=s)}},n.capitalization={},n._cap_fetching=0,n.get_capitalization=function(t,o){if(e.BetterTTV&&BetterTTV.chat&&BetterTTV.chat.helpers.lookupDisplayName)return BetterTTV.chat.helpers.lookupDisplayName(t);if(!t)return t;if(t=t.toLowerCase(),"jtv"==t||"twitchnotify"==t)return t;var i=n.capitalization[t];return i&&Date.now()-i[1]<36e5?i[0]:(n._cap_fetching<25&&(n._cap_fetching++,n.get().ws_send("get_display_name",t,function(e,i){var s=e?i:t;n.capitalization[t]=[s,Date.now()],n._cap_fetching--,"function"==typeof o&&o(s)})),i?i[0]:t)},n.prototype.capitalize=function(e,t){var o=n.get_capitalization(t,this.capitalize.bind(this,e));if(o&&e){var i=e.$(".from");i&&i.text(o)}},n._regex_cache={},n._get_regex=function(e){return n._regex_cache[e]=n._regex_cache[e]||RegExp("\\b"+i(e)+"\\b","ig")},n._words_to_regex=function(e){var t=n._regex_cache[e];if(!t){for(var o="",r=0;r<banned link>',own:!0}:r)}return i},n.prototype._emoticonize=function(e,t){var n=e.get("parentController.model.id"),o=e.get("model.from"),i=this,s=this.getEmotes(o,n),r=[];return _.each(s,function(e){var n=i.emote_sets[e];n&&_.each(n.emotes,function(e){_.any(t,function(t){return _.isString(t)&&t.match(e.regex)})&&r.push(e)})}),r.length?("string"==typeof t&&(t=[t]),_.each(r,function(e){var n={isEmoticon:!0,cls:e.klass,emoticonSrc:e.url+'" data-ffz-emote="'+encodeURIComponent(JSON.stringify([e.id,e.set_id])),altText:e.hidden?"???":e.name};t=_.compact(_.flatten(_.map(t,function(t){if(_.isObject(t))return t;var o=t.split(e.regex),i=[];return o.forEach(function(e,t){i.push(e),t!==o.length-1&&i.push(n)}),i})))}),t):t}},{"../utils":27}],7:[function(t){var n=e.FrankerFaceZ,o=t("../utils"),i={ESC:27,P:80,B:66,T:84},s=[["5m",300],["10m",600],["1hr",3600],["12hr",43200],["24hr",86400]],r='',a='';n.settings_info.enhanced_moderation={type:"boolean",value:!1,visible:function(){return!this.has_bttv},category:"Chat",name:"Enhanced Moderation",help:"Use /p, /t, /u and /b in chat to moderate chat, or use hotkeys with moderation cards."},n.prototype.setup_mod_card=function(){this.log("Hooking the Ember Moderation Card view.");var e=App.__container__.resolve("view:moderation-card"),t=this;e.reopen({didInsertElement:function(){this._super();try{if(t.has_bttv||!t.settings.enhanced_moderation)return;var e=this.get("element"),n=this.get("context");if(e.classList.add("ffz-moderation-card"),n.get("parentController.model.isModeratorOrHigher")){e.classList.add("ffz-is-mod"),e.setAttribute("tabindex",1),e.addEventListener("keyup",function(e){var t=e.keyCode||e.which,o=n.get("model.user.id"),s=n.get("parentController.model");if(t==i.P)s.send("/timeout "+o+" 1");else if(t==i.B)s.send("/ban "+o);else if(t==i.T)s.send("/timeout "+o+" 600");else if(t!=i.ESC)return;n.send("hideModOverlay")});var l=document.createElement("div");l.className="interface clearfix";var c=function(e){var t=n.get("model.user.id"),o=n.get("parentController.model");o.send(-1===e?"/unban "+t:"/timeout "+t+" "+e)},u=function(e,t){var n=document.createElement("button");return n.className="button",n.innerHTML=e,n.title="Timeout User for "+o.number_commas(t)+" Second"+(1!=t?"s":""),600===t?n.title="(T)"+n.title.substr(1):1===t&&(n.title="(P)urge - "+n.title),jQuery(n).tipsy(),n.addEventListener("click",c.bind(this,t)),n};l.appendChild(u("Purge",1));var d=document.createElement("span");d.className="right",l.appendChild(d);for(var h=0;h button");v&&"button"==v.className&&(v.innerHTML=r,v.classList.add("glyph-only"),v.classList.add("message"),v.title="Message User",jQuery(v).tipsy()),this.$().draggable({start:function(){e.focus()}}),e.focus()}catch(b){try{t.error("ModerationCardView didInsertElement: "+b)}catch(b){}}}})},n.chat_commands.purge=n.chat_commands.p=function(e,t){if(!t||!t.length)return"Purge Usage: /p username [more usernames separated by spaces]";if(t.length>10)return"Please only purge up to 10 users at once.";for(var n=0;n10)return"Please only ban up to 10 users at once.";for(var n=0;n10)return"Please only unban up to 10 users at once.";for(var n=0;nn?this._legacy_add_room(e,t,n):void 0)})},n.prototype._legacy_load_room_css=function(e,t,n){var r=e,a=r.match(s);a&&a[1]&&(r=a[1]);var l={id:e,menu_sets:[r],sets:[r],moderator_badge:null,css:null};return n&&(n=n.replace(o,"").trim()),n&&(n=n.replace(i,function(e,t){return l.moderator_badge||"modicon.png"!==t.substr(-11)?e:(l.moderator_badge=t,"")})),l.css=n||null,this._load_room_json(e,t,l)}},{"../constants":3,"../utils":27}],9:[function(){var t=e.FrankerFaceZ;t.prototype.setup_viewers=function(){this.log("Hooking the Ember Viewers controller.");var e=App.__container__.resolve("controller:viewers");this._modify_viewers(e)},t.prototype._modify_viewers=function(e){var n=this;e.reopen({lines:function(){var e=this._super();try{var o=[],i={},s=null,r=App.__container__.lookup("controller:channel"),a=this.get("parentController.model.id"),l=r&&r.get("id");if(l){var c=r.get("display_name");c&&(t.capitalization[l]=[c,Date.now()])}a!=l&&(l=null);for(var u=0;un?this._legacy_load_set(e,t,n):"function"==typeof t&&t(!1))})},n.prototype._legacy_load_css=function(e,t,n){var s={},r={id:e,emotes:s,extra_css:null},a=this;n=n.replace(o,function(t,n,o,i,r,c,u,d){r=parseInt(r),c=parseInt(c),u=l(u,r);var h="."===i.substr(i.lastIndexOf("/")+1,1),m=++a._last_emote_id,_={id:m,set_id:e,hidden:h,name:o,height:r,width:c,url:i,margins:u,extra_css:d};return s[m]=_,""}).trim(),n&&n.replace(i,function(e,t){r.icon||"modicon.png"!==t.substr(-11)||(r.icon=t)}),this._load_set_json(e,t,r)}},{"./constants":3,"./utils":27}],11:[function(){var t=e.FrankerFaceZ,n=/(\sdata-sender="[^"]*"(?=>))/;t.prototype.find_bttv=function(t,n){return this.has_bttv=!1,e.BTTVLOADED?this.setup_bttv(n||0):void(n>=6e4?this.log("BetterTTV was not detected after 60 seconds."):setTimeout(this.find_bttv.bind(this,t,(n||0)+t),t))},t.prototype.setup_bttv=function(e){this.log("BetterTTV was detected after "+e+"ms. Hooking."),this.has_bttv=!0,document.body.classList.remove("ffz-dark"),this._dark_style&&(this._dark_style.parentElement.removeChild(this._dark_style),delete this._dark_style),document.body.classList.remove("ffz-chat-colors"),document.body.classList.remove("ffz-chat-background");var t=BetterTTV.chat.helpers.sendMessage,o=this;BetterTTV.chat.helpers.sendMessage=function(e){var n=e.split(" ",1)[0].toLowerCase();return"/ffz"!==n?t(e):void o.run_ffz_command(e.substr(5),BetterTTV.chat.store.currentRoom)};var i,s=BetterTTV.chat.handlers.privmsg;BetterTTV.chat.handlers.privmsg=function(e,t){i=e;var n=s(e,t);return i=null,n};var r=BetterTTV.chat.templates.privmsg;BetterTTV.chat.templates.privmsg=function(e,t,s,a,l){o.bttv_badges(l);var c=r(e,t,s,a,l);return c.replace(n,'$1 data-room="'+i+'"')};var a,l=BetterTTV.chat.templates.message;BetterTTV.chat.templates.message=function(e,t,n,o){a=e;var i=l(e,t,n,o);return a=null,i};var c=BetterTTV.chat.templates.emoticonize;BetterTTV.chat.templates.emoticonize=function(e,t){var n=c(e,t),s=o.getEmotes(a,i),t=[];return _.each(s,function(e){var i=o.emote_sets[e];i&&_.each(i.emotes,function(e){_.any(n,function(t){return _.isString(t)&&t.match(e.regex)})&&t.push(e)})}),t.length?(_.each(t,function(e){var t=[''+e.name+''],o=n;if(n=[],!o||!o.length)return n;for(var i=0;i=6e4?this.log("Emote Menu for Twitch was not detected after 60 seconds."):setTimeout(this.find_emote_menu.bind(this,t,(n||0)+t),t))},t.prototype.setup_emote_menu=function(e){this.log("Emote Menu for Twitch was detected after "+e+"ms. Registering emote enumerator."),emoteMenu.registerEmoteGetter("FrankerFaceZ",this._emote_menu_enumerator.bind(this))},t.prototype._emote_menu_enumerator=function(){for(var e=this.get_user(),n=e?e.login:null,o=App.__container__.lookup("controller:chat"),i=o?o.get("currentRoom.id"):null,s=this.getEmotes(n,i),r=[],a=0;a=6e4?this.log('Twitch application not detected in "'+location.toString()+'". Aborting.'):setTimeout(this.initialize.bind(this,t,(n||0)+t),t)))},n.prototype.setup_ember=function(t){var o=e.performance&&performance.now?performance.now():Date.now();this.log("Found Twitch application after "+(t||0)+' ms in "'+location+'". Initializing FrankerFaceZ version '+n.version_info),this.users={},this.load_settings(),this.setup_dark(),this.ws_create(),this.setup_emoticons(),this.setup_badges(),this.setup_room(),this.setup_line(),this.setup_chatview(),this.setup_viewers(),this.setup_mod_card(),this.setup_notifications(),this.setup_css(),this.setup_menu(),this.setup_my_emotes(),this.setup_races(),this.find_bttv(10),this.find_emote_menu(10),this.check_ff();var i=e.performance&&performance.now?performance.now():Date.now(),s=i-o;this.log("Initialization complete in "+s+"ms")}},{"./badges":1,"./commands":2,"./debug":4,"./ember/chatview":5,"./ember/line":6,"./ember/moderation-card":7,"./ember/room":8,"./ember/viewers":9,"./emoticons":10,"./ext/betterttv":11,"./ext/emote_menu":12,"./featurefriday":14,"./settings":15,"./shims":16,"./socket":17,"./ui/about_page":18,"./ui/dark":19,"./ui/menu":20,"./ui/menu_button":21,"./ui/my_emotes":22,"./ui/notifications":23,"./ui/races":24,"./ui/styles":25,"./ui/viewer_count":26}],14:[function(t){var n=e.FrankerFaceZ,o=t("./constants");n.prototype.feature_friday=null,n.prototype.check_ff=function(e){e||this.log("Checking for Feature Friday data..."),jQuery.ajax(o.SERVER+"script/event.json",{cache:!1,dataType:"json",context:this}).done(function(e){return this._load_ff(e)}).fail(function(t){return 404==t.status?this._load_ff(null):(e=e||0,e++,10>e?setTimeout(this.check_ff.bind(this,e),250):this._load_ff(null))})},n.ws_commands.reload_ff=function(){this.check_ff()},n.prototype._feature_friday_ui=function(e,t,n){if(this.feature_friday&&this.feature_friday.channel!=e){this._emotes_for_sets(t,n,[this.feature_friday.set],"Feature Friday");var o=App.__container__.lookup("controller:channel");if(!o||o.get("id")!=this.feature_friday.channel){var i=this.feature_friday,s=document.createElement("div"),r=document.createElement("a");s.className="chat-menu-content",s.style.textAlign="center";var a=i.display_name+(i.live?" is live now!":"");r.className="button primary",r.classList.toggle("live",i.live),r.classList.toggle("blue",this.has_bttv&&BetterTTV.settings.get("showBlueButtons")),r.href="http://www.twitch.tv/"+i.channel,r.title=a,r.target="_new",r.innerHTML=""+a+"",s.appendChild(r),t.appendChild(s)}}},n.prototype._load_ff=function(e){if(this.feature_friday){this.global_sets.removeObject(this.feature_friday.set);var t=this.emote_sets[this.feature_friday.set];t&&(t.global=!1),this.feature_friday=null,this.update_ui_link()}e&&e.set&&e.channel&&(this.feature_friday={set:e.set,channel:e.channel,live:!1,display_name:n.get_capitalization(e.channel,this._update_ff_name.bind(this))},this.global_sets.push(e.set),this.load_set(e.set,this._update_ff_set.bind(this)),this._update_ff_live())},n.prototype._update_ff_live=function(){if(this.feature_friday){var e=this;Twitch.api.get("streams/"+this.feature_friday.channel).done(function(t){e.feature_friday.live=null!=t.stream,e.update_ui_link()}).always(function(){e.feature_friday.timer=setTimeout(e._update_ff_live.bind(e),12e4)})}},n.prototype._update_ff_set=function(e,t){t&&(t.global=!0)},n.prototype._update_ff_name=function(e){this.feature_friday&&(this.feature_friday.display_name=e)}},{"./constants":3}],15:[function(t){var n=e.FrankerFaceZ,o=t("./constants");make_ls=function(e){return"ffz_setting_"+e},toggle_setting=function(e,t){var n=!this.settings.get(t);this.settings.set(t,n),e.classList.toggle("active",n)},n.settings_info={},n.prototype.load_settings=function(){this.log("Loading settings."),this.settings={};for(var t in n.settings_info)if(n.settings_info.hasOwnProperty(t)){var o=n.settings_info[t],i=o.storage_key||make_ls(t),s=o.hasOwnProperty("value")?o.value:void 0;if(localStorage.hasOwnProperty(i))try{s=JSON.parse(localStorage.getItem(i))}catch(r){this.log('Error loading value for "'+t+'": '+r)}this.settings[t]=s}this.settings.get=this._setting_get.bind(this),this.settings.set=this._setting_set.bind(this),this.settings.del=this._setting_del.bind(this),e.addEventListener("storage",this._setting_update.bind(this),!1)},n.menu_pages.settings={render:function(e,t){var o={},i=[];for(var s in n.settings_info)if(n.settings_info.hasOwnProperty(s)){var r=n.settings_info[s],a=r.category||"Miscellaneous",l=o[a];if(void 0!==r.visible&&null!==r.visible){var c=r.visible;if("function"==typeof r.visible&&(c=r.visible.bind(this)()),!c)continue}l||(i.push(a),l=o[a]=[]),l.push([s,r])}i.sort(function(e,t){var e=e.toLowerCase(),t=t.toLowerCase();return"debugging"===e&&(e="zzz"+e),"debugging"===t&&(t="zzz"+t),t>e?-1:e>t?1:0});for(var u=0;un?-1:n>o?1:s>i?-1:i>s?1:0});for(var p=0;p",b.className="switch-label",b.innerHTML=r.name,f.appendChild(v),f.appendChild(b),v.addEventListener("click",toggle_setting.bind(this,v,s))}else{f.classList.add("option");var y=document.createElement("a");y.innerHTML=r.name,y.href="#",f.appendChild(y),y.addEventListener("click",r.method.bind(this))}if(r.help){var w=document.createElement("span");w.className="help",w.innerHTML=r.help,f.appendChild(w)}m.appendChild(f)}t.appendChild(m)}},name:"Settings",icon:o.GEAR,sort_order:99999},n.prototype._setting_update=function(t){if(t||(t=e.event),this.log("Storage Event",t),t.key&&"ffz_setting_"===t.key.substr(0,12)){var o=t.key,i=o.substr(12),s=void 0,r=n.settings_info[i];if(!r){for(i in n.settings_info)if(n.settings_info.hasOwnProperty(i)&&(r=n.settings_info[i],r.storage_key==o))break;if(r.storage_key!=o)return}this.log("Updated Setting: "+i);try{s=JSON.parse(t.newValue)}catch(a){this.log('Error loading new value for "'+i+'": '+a),s=r.value||void 0}if(this.settings[i]=s,r.on_update)try{r.on_update.bind(this)(s,!1)}catch(a){this.log('Error running updater for setting "'+i+'": '+a)}}},n.prototype._setting_get=function(e){return this.settings[e]},n.prototype._setting_set=function(e,t){var o=n.settings_info[e],i=o.storage_key||make_ls(e),s=JSON.stringify(t);if(this.settings[e]=t,localStorage.setItem(i,s),this.log('Changed Setting "'+e+'" to: '+s),o.on_update)try{o.on_update.bind(this)(t,!0)}catch(r){this.log('Error running updater for setting "'+e+'": '+r)}},n.prototype._setting_del=function(e){var t=n.settings_info[e],o=t.storage_key||make_ls(e),i=void 0;if(localStorage.hasOwnProperty(o)&&localStorage.removeItem(o),delete this.settings[e],t&&(i=this.settings[e]=t.hasOwnProperty("value")?t.value:void 0),t.on_update)try{t.on_update.bind(this)(i,!0)}catch(s){this.log('Error running updater for setting "'+e+'": '+s)}}},{"./constants":3}],16:[function(){Array.prototype.equals=function(e){if(!e)return!1;if(this.length!=e.length)return!1;for(var t=0,n=this.length;n>t;t++)if(this[t]instanceof Array&&e[t]instanceof Array){if(!this[t].equals(e[t]))return!1}else if(this[t]!=e[t])return!1;return!0}},{}],17:[function(){var t=e.FrankerFaceZ;t.prototype._ws_open=!1,t.prototype._ws_delay=0,t.ws_commands={},t.ws_on_close=[],t.prototype.ws_create=function(){var e,n=this;this._ws_last_req=0,this._ws_callbacks={},this._ws_pending=this._ws_pending||[];try{e=this._ws_sock=new WebSocket("ws://ffz.stendec.me/")}catch(o){return this._ws_exists=!1,this.log("Error Creating WebSocket: "+o)}this._ws_exists=!0,e.onopen=function(){n._ws_open=!0,n._ws_delay=0,n.log("Socket connected.");var e=n.get_user();e&&n.ws_send("setuser",e.login);for(var t in n.rooms)n.rooms.hasOwnProperty(t)&&n.ws_send("sub",t);var o=n._ws_pending;n._ws_pending=[];for(var i=0;i0){i=!0;break}}var l=document.createElement("div"),c="";c+="

FrankerFaceZ

",c+='
new ways to woof
',l.className="chat-menu-content center",l.innerHTML=c,t.appendChild(l);var u=document.createElement("div"),d=document.createElement("a"),h="To use custom emoticons in "+(i?"this channel":"tons of channels")+", get FrankerFaceZ from http://www.frankerfacez.com";d.className="button primary",d.innerHTML="Advertise in Chat",d.addEventListener("click",this._add_emote.bind(this,e,h)),u.appendChild(d);var m=document.createElement("a");m.className="button ffz-donate",m.href="http://www.frankerfacez.com/donate.html",m.target="_new",m.innerHTML="Donate",u.appendChild(m),u.className="chat-menu-content center",t.appendChild(u);var _=document.createElement("div");c='',c+='',c+='',c+='',c+='',_.className="chat-menu-content center",_.innerHTML=c;var p=!1;_.querySelector("#ffz-debug-logs").addEventListener("click",function(){p||(p=!0,s._pastebin(s._log_data.join("\n"),function(e){p=!1,e?prompt("Your FrankerFaceZ logs have been uploaded to the URL:",e):alert("There was an error uploading the FrankerFaceZ logs.")}))}),t.appendChild(_)}}},{"../constants":3}],19:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.settings_info.twitch_chat_dark={type:"boolean",value:!1,visible:!1},n.settings_info.dark_twitch={type:"boolean",value:!1,visible:function(){return!this.has_bttv},name:"Dark Twitch Beta",help:"Apply a dark background to channels and other related pages for easier viewing.",on_update:function(e){if(!this.has_bttv){document.body.classList.toggle("ffz-dark",e);var t=App.__container__.lookup("controller:settings").get("model");e?(this._load_dark_css(),this.settings.set("twitch_chat_dark",t.get("darkMode")),t.set("darkMode",!0)):t.set("darkMode",this.settings.twitch_chat_dark)}}},n.prototype.setup_dark=function(){this.has_bttv||(document.body.classList.toggle("ffz-dark",this.settings.dark_twitch),this.settings.dark_twitch&&App.__container__.lookup("controller:settings").set("model.darkMode",!0),this.settings.dark_twitch&&this._load_dark_css())},n.prototype._load_dark_css=function(){if(!this._dark_style){this.log("Injecting FrankerFaceZ Dark Twitch CSS.");var e=this._dark_style=document.createElement("link");e.id="ffz-dark-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",o.SERVER+"script/dark.css"),document.head.appendChild(e)}}},{"../constants":3}],20:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.prototype.setup_menu=function(){this.log("Installing mouse-up event to auto-close menus.");var e=this;jQuery(document).mouseup(function(t){var n,o=e._popup;o&&(o=jQuery(o),n=o.parent(),n.is(t.target)||0!==n.has(t.target).length||(o.remove(),delete e._popup,e._popup_kill&&e._popup_kill(),delete e._popup_kill))})},n.menu_pages={},n.prototype.build_ui_popup=function(e){var t=this._popup;if(t)return t.parentElement.removeChild(t),delete this._popup,this._popup_kill&&this._popup_kill(),void delete this._popup_kill;var i=document.createElement("div"),s=document.createElement("div"),r=document.createElement("ul"),a=this.has_bttv?BetterTTV.settings.get("darkenedMode"):!1;i.className="emoticon-selector chat-menu ffz-ui-popup",s.className="emoticon-selector-box dropmenu",i.appendChild(s),i.classList.toggle("dark",a);var l=document.createElement("div");l.className="ffz-ui-menu-page",s.appendChild(l),r.className="menu clearfix",s.appendChild(r);var c=document.createElement("li");c.className="title",c.innerHTML=""+(o.DEBUG?"[DEV] ":"")+"FrankerFaceZ",r.appendChild(c);var u=[];for(var d in n.menu_pages)if(n.menu_pages.hasOwnProperty(d)){var h=n.menu_pages[d];h&&(!h.hasOwnProperty("visible")||h.visible&&("function"!=typeof h.visible||h.visible.bind(this)()))&&u.push([h.sort_order||0,d,h])}u.sort(function(e,t){if(e[0]t[0])return-1;var n=e[1].toLowerCase(),o=t[1].toLowerCase();return o>n?1:n>o?-1:0});for(var m=0;m0){i=!0;break}}e.classList.toggle("no-emotes",!i),e.classList.toggle("live",a),e.classList.toggle("dark",s),e.classList.toggle("blue",r)}}},{"../constants":3}],22:[function(t){var n=e.FrankerFaceZ,o=t("../constants"),i="http://static-cdn.jtvnw.net/emoticons/v1/",s={"00000turbo":!0},r={"B-?\\)":"B-)","\\:-?[z|Z|\\|]":":-Z","\\:-?\\)":":-)","\\:-?\\(":":-(","\\:-?(p|P)":":-P","\\;-?(p|P)":";-P","\\<\\;3":"<3","\\:-?(?:\\/|\\\\)(?!\\/)":":-/","\\;-?\\)":";-)","R-?\\)":"R-)","[o|O](_|\\.)[o|O]":"O.o","\\:-?D":":-D","\\:-?(o|O)":":-O","\\>\\;\\(":">("},a=function(e){var t=App.__container__.lookup("controller:chat"),n=t.get("currentRoom.id"),o=e.rooms[n],i=o?o.room.tmiSession:null,s=i&&i._emotesParser&&i._emotesParser.emoticonSetIds||"0",r=e.get_user(),a=r&&e.users[r.login]&&e.users[r.login].sets||[];return s=s.split(",").removeObject("0"),e.settings.global_emotes_in_menu&&s.push("0"),[s,a]};n.settings_info.global_emotes_in_menu={type:"boolean",value:!1,name:"Display Global Emotes in My Emotes",help:"Display the global Twitch emotes in the My Emoticons menu."},n.prototype.setup_my_emotes=function(){if(this._twitch_emote_sets={},this._twitch_set_to_channel={},localStorage.ffzTwitchSets)try{this._twitch_set_to_channel=JSON.parse(localStorage.ffzTwitchSets)}catch(e){}this._twitch_set_to_channel[0]="twitch_global"},n.menu_pages.my_emotes={name:"My Emoticons",icon:o.EMOTE,visible:function(){var e=a(this);return e[0].length>0||e[1].length>0},render:function(e,t){var o=a(this),l=this;new RSVP.Promise(function(e){for(var t=[],i=0;i0?(l.ws_send("twitch_sets",t,function(e,n){if(t=[],e){for(var o in n)n.hasOwnProperty(o)&&(l._twitch_set_to_channel[o]=n[o],r(o,n[o]));localStorage.ffzTwitchSets=JSON.stringify(l._twitch_set_to_channel)}a()}),setTimeout(function(){t.length&&a()},5e3)):a()})]).then(function(){for(var t={},n=0;nt[0])return 1;var n=e[1].toLowerCase(),o=t[1].toLowerCase();return("twitch turbo"===n||"global emoticons"===n)&&(n="zzz"+n),("twitch turbo"===o||"global emoticons"===o)&&(o="zzz"+o),o>n?-1:n>o?1:0});for(var u=0;u'+c.source+""+n.get_capitalization(c.channel),c.badge&&(d.style.backgroundImage='url("'+c.badge+'")'),h.className="emoticon-grid",h.appendChild(d);for(var m=0;mSpeedRunsLive races under channels.',on_update:function(){this.rebuild_race_ui()}},n.ws_on_close.push(function(){var e=App.__container__.lookup("controller:channel"),t=e.get("id"),n=!1;for(var o in this.srl_races)delete this.srl_races[o],o==t&&(n=!0);n&&this.rebuild_race_ui()}),n.ws_commands.srl_race=function(e){for(var t=App.__container__.lookup("controller:channel"),n=t.get("id"),o=!1,i=0;i=300?"right":"left")+" share dropmenu",this._popup_kill=this._race_kill.bind(this),this._popup=e;var l="http://kadgar.net/live",c=!1;for(var u in r.entrants){var d=r.entrants[u].state;r.entrants.hasOwnProperty(u)&&r.entrants[u].channel&&("racing"==d||"entered"==d)&&(l+="/"+r.entrants[u].channel,c=!0)}var h=document.querySelector(".app-main.theatre")?document.body.clientHeight-300:t.parentElement.offsetTop-175,m=App.__container__.lookup("controller:channel"),_=m?m.get("display_name"):n.get_capitalization(s),p=encodeURIComponent("I'm watching "+_+" race "+r.goal+" in "+r.game+" on SpeedRunsLive!");a='
',a+='
Developers
Dan Salvato  
Stendec  
Version '+n.version_info+'Logs
',a+="
#Entrant Time
",a+='
',a+='',a+='

SRL',c&&(a+='   Multitwitch'),a+="

",e.innerHTML=a,t.appendChild(e),this._update_race(!0)}}},n.prototype._update_race=function(e){this._race_timer&&e&&(clearTimeout(this._race_timer),delete this._race_timer);var t=document.querySelector("#ffz-ui-race");if(t){var n=t.getAttribute("data-channel"),i=this.srl_races[n];if(!i)return t.parentElement.removeChild(t),this._popup_kill&&this._popup_kill(),void(this._popup&&(delete this._popup,delete this._popup_kill));var s=i.twitch_entrants[n],r=i.entrants[s],a=t.querySelector("#ffz-race-popup"),l=Date.now()/1e3,c=Math.floor(l-i.time);if(t.querySelector(".logo").innerHTML=o.placement(r),a){var u=a.querySelector("tbody"),d=a.querySelector(".heading span"),h=a.querySelector(".heading div");u.innerHTML="";var m=[],_=!0;for(var p in i.entrants)i.entrants.hasOwnProperty(p)&&("racing"==i.entrants[p].state&&(_=!1),m.push(i.entrants[p]));m.sort(function(e,t){var n=e.place||9999,o=t.place||9999,i=e.time||c,s=t.time||c;return("forfeit"==e.state||"dq"==e.state)&&(n=1e4),("forfeit"==t.state||"dq"==t.state)&&(o=1e4),o>n?-1:n>o?1:e.namet.name?1:s>i?-1:i>s?1:void 0});for(var f=0;f'+p.display_name+"",v=p.channel?'':"",b=p.hitbox?'':"",y=c?o.time_to_string(p.time||c):"",w=o.place_string(p.place),k=p.comment?o.sanitize(p.comment):"";u.innerHTML+="'+w+""+g+""+v+b+''+("forfeit"==p.state?"Forfeit":y)+""}if(this._race_game!=i.game||this._race_goal!=i.goal){this._race_game=i.game,this._race_goal=i.goal;var F=o.sanitize(i.game),E=o.sanitize(i.goal);h.innerHTML='

'+F+"

Goal: "+E}c?_?d.innerHTML="Done":(d.innerHTML=o.time_to_string(c),this._race_timer=setTimeout(this._update_race.bind(this),1e3)):d.innerHTML="Entry Open"}}}},{"../utils":27}],25:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.prototype.setup_css=function(){this.log("Injecting main FrankerFaceZ CSS.");var e=this._main_style=document.createElement("link");e.id="ffz-ui-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",o.SERVER+"script/style.css?_="+Date.now()),document.head.appendChild(e),jQuery.noty.themes.ffzTheme={name:"ffzTheme",style:function(){this.$bar.removeClass().addClass("noty_bar").addClass("ffz-noty").addClass(this.options.type)},callback:{onShow:function(){},onClose:function(){}}}}},{"../constants":3}],26:[function(t){var n=e.FrankerFaceZ,o=t("../constants"),i=t("../utils");n.ws_commands.viewers=function(e){var t=e[0],n=e[1],s=App.__container__.lookup("controller:channel"),r=s&&s.get&&s.get("id");if(r===t){var a=document.querySelector(".channel-stats .ffz.stat"),l=o.ZREKNARF+" "+i.number_commas(n);if(a)a.innerHTML=l;else{var c=document.querySelector(".channel-stats");if(!c)return;a=document.createElement("span"),a.className="ffz stat",a.title="Viewers with FrankerFaceZ",a.innerHTML=l,c.appendChild(a),jQuery(a).tipsy()}}}},{"../constants":3,"../utils":27}],27:[function(t,n){var o=(e.FrankerFaceZ,t("./constants"),{}),i=document.createElement("span"),s=function(e){return 1==e?"1st":2==e?"2nd":3==e?"3rd":null==e?"---":e+"th"},r=function(e,t){t=0===t?0:t||1,t=Math.round(255*-(t/100));var n=Math.max(0,Math.min(255,e[0]-t)),o=Math.max(0,Math.min(255,e[1]-t)),i=Math.max(0,Math.min(255,e[2]-t));return[n,o,i]},a=function(e){return"rgb("+e[0]+", "+e[1]+", "+e[2]+")"},l=function(e,t){return t=0===t?0:t||1,r(e,-t)},c=function(e){e=[e[0]/255,e[1]/255,e[2]/255];for(var t=0;tr;(l||n)&&(l&&(o=o.substr(0,r)+o.substr(a+s.length)),n&&(o+=i+n+s),e.innerHTML=o)},get_luminance:c,brighten:r,darken:l,rgb_to_css:a,number_commas:function(e){var t=e.toString().split(".");return t[0]=t[0].replace(/\B(?=(\d{3})+(?!\d))/g,","),t.join(".")},place_string:s,placement:function(e){return"forfeit"==e.state?"Forfeit":"dq"==e.state?"DQed":e.place?s(e.place):""},sanitize:function(e){var t=o[e];return t||(i.textContent=e,t=o[e]=i.innerHTML,i.innerHTML=""),t},time_to_string:function(e){var t=e%60,n=Math.floor(e/60),o=Math.floor(n/60);return n%=60,(10>o?"0":"")+o+":"+(10>n?"0":"")+n+":"+(10>t?"0":"")+t}}},{"./constants":3}]},{},[13]),e.ffz=new FrankerFaceZ}(window); \ No newline at end of file diff --git a/src/badges.js b/src/badges.js index 50b4e7e3..f921fa2f 100644 --- a/src/badges.js +++ b/src/badges.js @@ -3,6 +3,20 @@ var FFZ = window.FrankerFaceZ, utils = require('./utils'); +// -------------------- +// Settings +// -------------------- + +FFZ.settings_info.bot_badges = { + type: "boolean", + value: true, + + category: "Chat", + name: "Bot Badges", + help: "Give special badges to known bots." + }; + + // -------------------- // Initialization // -------------------- @@ -38,7 +52,8 @@ FFZ.prototype.bttv_badges = function(data) { var user_id = data.sender, user = this.users[user_id], badges_out = [], - insert_at = -1; + insert_at = -1, + alpha = BetterTTV.settings.get('alphaTags'); if ( ! user || ! user.badges ) return; @@ -52,7 +67,6 @@ FFZ.prototype.bttv_badges = function(data) { } } - for (var slot in user.badges) { if ( ! user.badges.hasOwnProperty(slot) ) continue; @@ -60,8 +74,16 @@ FFZ.prototype.bttv_badges = function(data) { var badge = user.badges[slot], full_badge = this.badges[badge.id] || {}, desc = badge.title || full_badge.title, - style = "", - alpha = BetterTTV.settings.get('alphaTags'); + style = ""; + + if ( full_badge.visible !== undefined ) { + var visible = full_badge.visible; + if ( typeof visible == "function" ) + visible = visible.bind(this)(null, user_id); + + if ( ! visible ) + continue; + } if ( badge.image ) style += 'background-image: url(\\"' + badge.image + '\\"); '; @@ -116,12 +138,21 @@ FFZ.prototype.render_badge = function(view) { if ( full_badge.visible !== undefined ) { var visible = full_badge.visible; if ( typeof visible == "function" ) - try { visible = visible.bind(this)(room_id, user); } catch(err) { } + visible = visible.bind(this)(room_id, user); if ( ! visible ) continue; } + if ( full_badge.replaces ) { + var el = badges[0].querySelector('.badge.' + full_badge.replaces); + if ( el ) { + el.style.backgroundImage = 'url("' + (badge.image || full_badge.image) + '")'; + el.title += ", " + (badge.title || full_badge.title); + return; + } + } + var el = document.createElement('div'); el.className = 'badge float-left tooltip ffz-badge-' + badge.id; el.setAttribute('title', badge.title || full_badge.title); @@ -154,24 +185,33 @@ FFZ.prototype.render_badge = function(view) { // Legacy Support // -------------------- -FFZ.known_bots = ["quoteconut", "quoconut", "zenwan", "nightbot", "moobot", "xanbot"]; +FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"]; +FFZ.known_bots = ["quoteconut", "quoconut", "zenwan", "triiharder", "wobblerbot", "theroflbotr", "acebot"]; + FFZ.prototype._legacy_add_donors = function(tries) { this.badges[1] = {id: 1, title: "FFZ Donor", color: "#755000", image: "//cdn.frankerfacez.com/channel/global/donoricon.png"}; utils.update_css(this._badge_style, 1, badge_css(this.badges[1])); - // Developer Badges + // Developer Badge this.badges[0] = {id: 0, title: "FFZ Developer", color: "#FAAF19", image: "//cdn.frankerfacez.com/channel/global/devicon.png"}; utils.update_css(this._badge_style, 0, badge_css(this.badges[0])); - this.users.sirstendec = {badges: {0: {id:0}}}; - // Bot Badges - /*this.badges[2] = {id: 2, title: "Bot", color: "#595959", image: "//cdn.frankerfacez.com/channel/global/boticon.png", - visible: function(r,user) { return !(this.has_bttv && FFZ.bttv_known_bots[user]); }}; + // Bot Badge + this.badges[2] = {id: 2, title: "Bot", color: "#595959", image: "//cdn.frankerfacez.com/channel/global/boticon.png", + replaces: 'moderator', + visible: function(r,user) { return this.settings.bot_badges && !(this.has_bttv && FFZ.bttv_known_bots.indexOf(user)!==-1); }}; utils.update_css(this._badge_style, 2, badge_css(this.badges[2])); + for(var i=0;i", - set = data.set, + var set = data.set, set_type = data.set_type; if ( set_type === undefined ) @@ -40,12 +39,7 @@ var FFZ = window.FrankerFaceZ, set_type = null; } - if ( ! set_type ) - output += '' + set + ''; - else - output += "" + set_type + "" + set + ""; - - return '' + output + '
'; + return "Emoticon: " + data.code + "\n" + (set_type ? set_type + ": " : "") + set; }, build_tooltip = function(id) { @@ -161,7 +155,7 @@ FFZ.settings_info.keywords = { FFZ.settings_info.fix_color = { type: "boolean", - value: false, + value: true, category: "Chat", visible: function() { return ! this.has_bttv }, @@ -230,6 +224,7 @@ FFZ.prototype.setup_line = function() { var tokens = this._super(); try { + var start = performance.now(); tokens = f._remove_banned(tokens); tokens = f._emoticonize(this, tokens); var user = f.get_user(); @@ -237,6 +232,10 @@ FFZ.prototype.setup_line = function() { if ( ! user || this.get("model.from") != user.login ) tokens = f._mentionize(this, tokens); + var end = performance.now(); + if ( end - start > 5 ) + f.log("Tokenizing Message Took Too Long - " + (end-start) + "ms - " + JSON.stringify(tokens)); + } catch(err) { try { f.error("LineController tokenizedMessage: " + err); @@ -256,6 +255,8 @@ FFZ.prototype.setup_line = function() { didInsertElement: function() { this._super(); try { + var start = performance.now(); + var el = this.get('element'), controller = this.get('context'), user = controller.get('model.from'), @@ -298,7 +299,7 @@ FFZ.prototype.setup_line = function() { if ( mentioned ) { el.classList.add("ffz-mentioned"); - if ( ! document.hasFocus() && ! this.get('context.model.ffz_notified') && f.settings.highlight_notifications ) { + if ( f.settings.highlight_notifications && !document.hasFocus() && !this.get('context.model.ffz_notified') ) { var cap_room = FFZ.get_capitalization(room), cap_user = FFZ.get_capitalization(user), room_name = cap_room, @@ -329,7 +330,7 @@ FFZ.prototype.setup_line = function() { // Banned Links var bad_links = el.querySelectorAll('a.deleted-link'); for(var i=0; i < bad_links.length; i++) { - var link = bad_links[i]; + var link = bad_links[i]; link.addEventListener("click", function(e) { if ( ! this.classList.contains("deleted-link") ) @@ -366,7 +367,7 @@ FFZ.prototype.setup_line = function() { // Enhanced Emotes - var images = el.querySelectorAll('img'); + var images = el.querySelectorAll('img.emoticon'); for(var i=0; i < images.length; i++) { var img = images[i], name = img.alt, @@ -389,8 +390,6 @@ FFZ.prototype.setup_line = function() { f.ws_send("twitch_emote", id, load_emote_data.bind(f, id, img.alt)); } - jQuery(img).tipsy({html:true}); - } else if ( img.getAttribute('data-ffz-emote') ) { var data = JSON.parse(decodeURIComponent(img.getAttribute('data-ffz-emote'))), id = data && data[0] || null, @@ -418,13 +417,15 @@ FFZ.prototype.setup_line = function() { set: set_name, set_type: set_type }); - - jQuery(img).tipsy({html:true}); - - } else - jQuery(img).tipsy(); + } } + jQuery(images).tipsy(); + + + var duration = performance.now() - start; + if ( duration > 5 ) + f.log("Line Took Too Long - " + duration + "ms - " + el.innerHTML); } catch(err) { try { @@ -470,7 +471,7 @@ FFZ.prototype._handle_color = function(color) { // Color Too Bright. We need a lum of 0.3 or less. matched = true; - var s = 255, + var s = 127, nc = rgb; while(s--) { nc = utils.darken(nc); @@ -482,15 +483,15 @@ FFZ.prototype._handle_color = function(color) { } else output += '.ffz-chat-colors .ember-chat-container:not(.dark) .chat-line ' + rule + ', .ffz-chat-colors .chat-container:not(.dark) .chat-line ' + rule + ' { color: ' + color + ' !important; }\n'; - if ( lum < 0.1 ) { + if ( lum < 0.15 ) { // Color Too Dark. We need a lum of 0.1 or more. matched = true; - var s = 255, + var s = 127, nc = rgb; while(s--) { nc = utils.brighten(nc); - if ( utils.get_luminance(nc) >= 0.1 ) + if ( utils.get_luminance(nc) >= 0.15 ) break; } @@ -545,8 +546,11 @@ FFZ.get_capitalization = function(name, callback) { FFZ.prototype.capitalize = function(view, user) { var name = FFZ.get_capitalization(user, this.capitalize.bind(this, view)); - if ( name && view ) - view.$('.from').text(name); + if ( !name || !view ) + return; + + var from = view.$('.from'); + from && from.text(name); } diff --git a/src/ember/room.js b/src/ember/room.js index d4732367..db6c6d83 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -10,7 +10,7 @@ var FFZ = window.FrankerFaceZ, if ( ! room.moderator_badge ) return ""; - return '.chat-line[data-room="' + room.id + '"] .badges .moderator { background-image:url("' + room.moderator_badge + '") !important; }'; + return '.chat-line[data-room="' + room.id + '"] .badges .moderator { background-image:url("' + room.moderator_badge + '"); }'; } diff --git a/src/ext/betterttv.js b/src/ext/betterttv.js index c3388624..2369f6f0 100644 --- a/src/ext/betterttv.js +++ b/src/ext/betterttv.js @@ -2,8 +2,6 @@ var FFZ = window.FrankerFaceZ, SENDER_REGEX = /(\sdata-sender="[^"]*"(?=>))/; -FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"]; - // -------------------- // Initialization // -------------------- diff --git a/src/main.js b/src/main.js index 28863a7b..1520a67b 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: 2, revision: 1, + major: 3, minor: 2, revision: 2, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } diff --git a/src/socket.js b/src/socket.js index ab9c9f9d..8e1d10f3 100644 --- a/src/socket.js +++ b/src/socket.js @@ -99,7 +99,10 @@ FFZ.prototype.ws_create = function() { } else { var success = cmd === 'True', callback = f._ws_callbacks[request]; - f.log("Socket Reply to " + request + " - " + (success ? "SUCCESS" : "FAIL"), data); + + if ( ! success || ! callback ) + f.log("Socket Reply to " + request + " - " + (success ? "SUCCESS" : "FAIL"), data); + if ( callback ) { delete f._ws_callbacks[request]; callback(success, data); diff --git a/src/ui/my_emotes.js b/src/ui/my_emotes.js index 1f4bb7dd..d53f2d64 100644 --- a/src/ui/my_emotes.js +++ b/src/ui/my_emotes.js @@ -4,6 +4,22 @@ var FFZ = window.FrankerFaceZ, TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/", BANNED_SETS = {"00000turbo":true}, + KNOWN_CODES = { + "B-?\\)": "B-)", + "\\:-?[z|Z|\\|]": ":-Z", + "\\:-?\\)": ":-)", + "\\:-?\\(": ":-(", + "\\:-?(p|P)": ":-P", + "\\;-?(p|P)": ";-P", + "\\<\\;3": "<3", + "\\:-?(?:\\/|\\\\)(?!\\/)": ":-/", + "\\;-?\\)": ";-)", + "R-?\\)": "R-)", + "[o|O](_|\\.)[o|O]": "O.o", + "\\:-?D": ":-D", + "\\:-?(o|O)": ":-O", + "\\>\\;\\(": ">(", + }, get_emotes = function(ffz) { var Chat = App.__container__.lookup('controller:chat'), @@ -18,6 +34,9 @@ var FFZ = window.FrankerFaceZ, // Remove the 'default' set. set_ids = set_ids.split(",").removeObject("0") + if ( ffz.settings.global_emotes_in_menu ) + set_ids.push("0"); + return [set_ids, user_sets]; }; @@ -26,6 +45,15 @@ var FFZ = window.FrankerFaceZ, // Initialization // ------------------- +FFZ.settings_info.global_emotes_in_menu = { + type: "boolean", + value: false, + + name: "Display Global Emotes in My Emotes", + help: "Display the global Twitch emotes in the My Emoticons menu." + }; + + FFZ.prototype.setup_my_emotes = function() { this._twitch_emote_sets = {}; this._twitch_set_to_channel = {}; @@ -35,6 +63,8 @@ FFZ.prototype.setup_my_emotes = function() { this._twitch_set_to_channel = JSON.parse(localStorage.ffzTwitchSets); } catch(err) { } } + + this._twitch_set_to_channel[0] = "twitch_global"; } @@ -96,6 +126,13 @@ FFZ.menu_pages.my_emotes = { if ( !name || BANNED_SETS[name] ) return; + if ( name == "twitch_global" ) { + FFZ.capitalization["global emoticons"] = ["Global Emoticons", Date.now()]; + set.channel = "Global Emoticons"; + set.badge = "//cdn.frankerfacez.com/channel/global/twitch_logo.png"; + return; + } + if ( name == "turbo" ) { set.channel = "Twitch Turbo"; set.badge = "//cdn.frankerfacez.com/script/turbo_badge.png"; @@ -220,10 +257,10 @@ FFZ.menu_pages.my_emotes = { var an = a[1].toLowerCase(), bn = b[1].toLowerCase(); - if ( an === "twitch turbo" ) + if ( an === "twitch turbo" || an === "global emoticons" ) an = "zzz" + an; - if ( bn === "twitch turbo" ) + if ( bn === "twitch turbo" || bn === "global emoticons" ) bn = "zzz" + bn; if ( an < bn ) return -1; @@ -245,7 +282,8 @@ FFZ.menu_pages.my_emotes = { menu.appendChild(heading); for(var x=0; x < set.emotes.length; x++) { - var emote = set.emotes[x]; + var emote = set.emotes[x], + code = KNOWN_CODES[emote.code] || emote.code; var s = document.createElement('span'); s.className = 'emoticon tooltip'; @@ -257,8 +295,8 @@ FFZ.menu_pages.my_emotes = { s.style.backgroundImage = '-ms-' + img_set; s.style.backgroundImage = img_set; - s.title = emote.code; - s.addEventListener('click', f._add_emote.bind(f, view, emote.code)); + s.title = code; + s.addEventListener('click', f._add_emote.bind(f, view, code)); menu.appendChild(s); } diff --git a/style.css b/style.css index 22b39ce6..14b166ab 100644 --- a/style.css +++ b/style.css @@ -352,7 +352,7 @@ .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading, .chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading { margin-bottom: 5px; - border-bottom: 1px solid rgba(0,0,0, 0.2); + border-bottom: 1px solid rgba(0,0,0,0.2); text-align: left; } @@ -433,7 +433,9 @@ .ffz-ui-popup.dark .ffz-ui-menu-page a { color: #fff; } +.ffz-dark .ffz-ui-popup ul.menu svg path, .ffz-ui-popup.dark ul.menu svg path { fill: #d3d3d3; } + .ffz-ui-popup ul.menu svg path { fill: #333; } @@ -588,22 +590,10 @@ /* Emoticon Tooltips */ -.tipsy table.emote-data td { padding: 0 2px; } - -.tipsy table.emote-data td:first-of-type { - text-align: right; - font-weight: bold; - padding-left: 0; +.tipsy .tipsy-inner { + white-space: pre-wrap; } -.tipsy table.emote-data td:last-of-type { - text-align: left; - padding-right: 0; - white-space: nowrap; -} - -.tipsy table.emote-data td.center { text-align: center; } - /* Menu Page Loader */ .ffz-ui-menu-page:empty {