1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-29 15:55:33 +00:00
FrankerFaceZ/script.min.js

8 lines
243 KiB
JavaScript
Raw Normal View History

!function(t){!function e(t,s,n){function i(a,r){if(!s[a]){if(!t[a]){var d="function"==typeof require&&require;if(!r&&d)return d(a,!0);if(o)return o(a,!0);throw new Error("Cannot find module '"+a+"'")}var u=s[a]={exports:{}};t[a][0].call(u.exports,function(e){var s=t[a][1][e];return i(s?s:e)},u,u.exports,e,t,s,n)}return s[a].exports}for(var o="function"==typeof require&&require,a=0;a<n.length;a++)i(n[a]);return i}({1:[function(e,s){var n=n||function(t){"use strict";if("undefined"==typeof navigator||!/MSIE [1-9]\./.test(navigator.userAgent)){var e=t.document,s=function(){return t.URL||t.webkitURL||t},n=e.createElementNS("http://www.w3.org/1999/xhtml","a"),i="download"in n,o=function(t){var e=new MouseEvent("click");t.dispatchEvent(e)},a=t.webkitRequestFileSystem,r=t.requestFileSystem||a||t.mozRequestFileSystem,d=function(e){(t.setImmediate||t.setTimeout)(function(){throw e},0)},u="application/octet-stream",c=0,l=500,h=function(e){var n=function(){"string"==typeof e?s().revokeObjectURL(e):e.remove()};t.chrome?n():setTimeout(n,l)},f=function(t,e,s){e=[].concat(e);for(var n=e.length;n--;){var i=t["on"+e[n]];if("function"==typeof i)try{i.call(t,s||t)}catch(o){d(o)}}},m=function(t){return/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(t.type)?new Blob(["",t],{type:t.type}):t},_=function(e,d,l){l||(e=m(e));var _,p,g,v=this,b=e.type,y=!1,w=function(){f(v,"writestart progress write writeend".split(" "))},z=function(){if((y||!_)&&(_=s().createObjectURL(e)),p)p.location.href=_;else{var n=t.open(_,"_blank");void 0==n&&"undefined"!=typeof safari&&(t.location.href=_)}v.readyState=v.DONE,w(),h(_)},k=function(t){return function(){return v.readyState!==v.DONE?t.apply(this,arguments):void 0}},E={create:!0,exclusive:!1};return v.readyState=v.INIT,d||(d="download"),i?(_=s().createObjectURL(e),n.href=_,n.download=d,void setTimeout(function(){o(n),w(),h(_),v.readyState=v.DONE})):(t.chrome&&b&&b!==u&&(g=e.slice||e.webkitSlice,e=g.call(e,0,e.size,u),y=!0),a&&"download"!==d&&(d+=".download"),(b===u||a)&&(p=t),r?(c+=e.size,void r(t.TEMPORARY,c,k(function(t){t.root.getDirectory("saved",E,k(function(t){var s=function(){t.getFile(d,E,k(function(t){t.createWriter(k(function(s){s.onwriteend=function(e){p.location.href=t.toURL(),v.readyState=v.DONE,f(v,"writeend",e),h(t)},s.onerror=function(){var t=s.error;t.code!==t.ABORT_ERR&&z()},"writestart progress write abort".split(" ").forEach(function(t){s["on"+t]=v["on"+t]}),s.write(e),v.abort=function(){s.abort(),v.readyState=v.DONE},v.readyState=v.WRITING}),z)}),z)};t.getFile(d,{create:!1},k(function(t){t.remove(),s()}),k(function(t){t.code===t.NOT_FOUND_ERR?s():z()}))}),z)}),z)):void z())},p=_.prototype,g=function(t,e,s){return new _(t,e,s)};return"undefined"!=typeof navigator&&navigator.msSaveOrOpenBlob?function(t,e,s){return s||(t=m(t)),navigator.msSaveOrOpenBlob(t,e||"download")}:(p.abort=function(){var t=this;t.readyState=t.DONE,f(t,"abort")},p.readyState=p.INIT=0,p.WRITING=1,p.DONE=2,p.error=p.onwritestart=p.onprogress=p.onwrite=p.onabort=p.onerror=p.onwriteend=null,g)}}("undefined"!=typeof self&&self||"undefined"!=typeof t&&t||this.content);"undefined"!=typeof s&&s.exports?s.exports.saveAs=n:"undefined"!=typeof define&&null!==define&&null!=define.amd&&define([],function(){return n})},{}],2:[function(e){var s=t.FrankerFaceZ,n=e("./constants"),i=e("./utils");s.settings_info.show_badges={type:"boolean",value:!0,category:"Chat Appearance",name:"Additional Badges",help:"Show additional badges for bots, FrankerFaceZ donors, and other special users."},s.settings_info.transparent_badges={type:"boolean",value:!1,category:"Chat Appearance",no_bttv:!0,name:"Transparent Badges",help:"Make chat badges transparent for a nice, clean look. On light chat, non-subscriber badges are inverted to remain visible.",on_update:function(t){this.has_bttv||document.body.classList.toggle("ffz-transparent-badges",t)}},s.prototype.setup_badges=function(){this.has_bttv||document.body.classList.toggle("ffz-transparent-badges",this.settings.transparent_badges),this.log("Preparing badge system."),t
},{}],6:[function(){var e=t.FrankerFaceZ;e.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()}},e.ffz_commands.developer_mode=function(t,e){var s,e=e&&e.length?e[0].toLowerCase():null;return"y"==e||"yes"==e||"true"==e||"on"==e?s=!0:("n"==e||"no"==e||"false"==e||"off"==e)&&(s=!1),void 0===s?"Developer Mode is currently "+(this.settings.developer_mode?"enabled.":"disabled."):(this.settings.set("developer_mode",s),"Developer Mode is now "+(s?"enabled":"disabled")+". Please refresh your browser.")},e.ffz_commands.developer_mode.help="Usage: /ffz developer_mode <on|off>\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."},{}],7:[function(e){var s=t.FrankerFaceZ,n=e("../utils"),i=e("../constants");s.prototype.setup_channel=function(){this.log("Creating channel style element.");var t=this._channel_style=document.createElement("style");t.id="ffz-channel-css",document.head.appendChild(t),document.body.classList.toggle("ffz-hide-view-count",!this.settings.channel_views),this.log("Creating channel style element.");var t=this._channel_style=document.createElement("style");t.id="ffz-channel-css",document.head.appendChild(t),this.log("Hooking the Ember Channel Index view.");var e=App.__container__.resolve("view:channel/index"),n=this;if(e){this._modify_cindex(e);try{e.create().destroy()}catch(i){}for(var o in Ember.View.views)if(Ember.View.views.hasOwnProperty(o)){var a=Ember.View.views[o];a instanceof e&&(this.log("Manually updating Channel Index view.",a),this._modify_cindex(a),a.ffzInit())}this.log("Hooking the Ember Channel model."),e=App.__container__.resolve("model:channel"),e&&(e.reopen({ffz_host_target:void 0,setHostMode:function(t){return n.settings.hosted_channels?(this.set("ffz_host_target",t.target),this._super(t)):(this.set("ffz_host_target",void 0),this._super({target:void 0,delay:0}))}}),this.log("Hooking the Ember Channel controller."),e=App.__container__.lookup("controller:channel"),e&&(e.reopen({ffzUpdateUptime:function(){n._cindex&&n._cindex.ffzUpdateUptime()}.observes("isLive","content.id"),ffzUpdateInfo:function(){this._ffz_update_timer&&clearTimeout(this._ffz_update_timer),this.get("content.id")&&(this._ffz_update_timer=setTimeout(this.ffzCheckUpdate.bind(this),6e4))}.observes("content.id"),ffzCheckUpdate:function(){var t=this,e=t.get("content.id");e&&Twitch.api&&Twitch.api.get("streams/"+e,{},{version:3}).done(function(e){if(!e||!e.stream)return t.set("stream.created_at",null),void t.set("stream.viewers",0);t.set("stream.created_at",e.stream.created_at||null),t.set("stream.viewers",e.stream.viewers||0);var s=e.stream.game||e.stream.channel&&e.stream.channel.game;s&&(t.set("game",s),t.set("rollbackData.game",s)),e.stream.channel&&(e.stream.channel.status&&t.set("status",e.stream.channel.status),e.stream.channel.views&&t.set("views",e.stream.channel.views),e.stream.channel.followers&&t.get("content.followers.isLoaded")&&t.set("content.followers.total",e.stream.channel.followers))}).always(function(){t.ffzUpdateInfo()})},ffzUpdateTitle:function(){var t=this.get("content.name"),e=this.get("content.display_name");e&&(s.capitalization[t]=[e,Date.now()]),n._cindex&&n._cindex.ffzFixTitle()}.observes("content.status","content.id"),ffzHostTarget:function(){var t=this.get("content.hostModeTarget"),e=t&&t.get("name"),i=t&&t.get("id"),o=t&&t.get("display_name");i!==n.__old_host_target&&(n.__old_host_target&&n.ws_send("unsub_channel",n.__old_host_target),i?(n.ws_send("sub_channel",i),n.__old_host_target=i):delete n.__old_host_target),o&&(s.capitalization[e]=[o,Date.now()]),n.settings.group_tabs&&n._chatv&&n._chatv.ffzRebuildTabs(),n.settings.follow_buttons&&n
if(o){var r=n.format_unread(t===i?0:o.room.get("unreadCount"));a.querySelector("span").innerHTML=r}}}}},ffzBuildTab:function(t,o,a,r){{var d,u,c=document.createElement("span"),l="",h=o.get("id"),f=o.get("isGroupRoom"),m=o===t.get("controller.currentRoom");m||-1!==e.settings.visible_rooms.indexOf(h)}return c.setAttribute("data-room",o.id),c.className="ffz-chat-tab tooltip",c.classList.toggle("current-channel",a),c.classList.toggle("host-channel",r),c.classList.toggle("group-chat",f),c.classList.toggle("active",m),u=n.format_unread(m?0:o.get("unreadCount")),d=o.get("tmiRoom.displayName")||(f?o.get("tmiRoom.name"):s.get_capitalization(o.get("id"),function(t){u=n.format_unread(m?0:o.get("unreadCount")),c.innerHTML=l+n.sanitize(t)+"<span>"+u+"</span>"})),a?(l=i.CAMERA,c.title="Current Channel"):r?(l=i.EYE,c.title="Hosted Channel"):c.title=f?"Group Chat":"Pinned Channel",c.innerHTML=l+n.sanitize(d)+"<span>"+u+"</span>",c.addEventListener("click",function(){var e=t.get("controller");e.focusRoom(o),e.set("showList",!1)}),o._ffz_tab=c,c},ffzDisableTabs:function(){this._ffz_tabs&&(this._ffz_tabs.parentElement.removeChild(this._ffz_tabs),delete this._ffz_tabs,delete this._ffz_invite),this._ffz_host&&(-1===e.settings.pinned_rooms.indexOf(this._ffz_host)&&this._ffz_host_room&&(this.get("controller.currentRoom")===this._ffz_host_room&&this.get("controller").blurRoom(),this._ffz_host_room.destroy()),delete this._ffz_host,delete this._ffz_host_room),this.$(".chat-room").css("top",""),this.$(".chat-header").removeClass("hidden")}})},s.prototype.connect_extra_chat=function(){var t=this.get_user();if(t&&t.login&&(!this.rooms[t.login]||this.rooms[t.login].room)){var e=App.__container__.resolve("model:room");e&&e.findOne(t.login)}if(!this.has_bttv){for(var s=0;s<this.settings.pinned_rooms.length;s++)this._join_room(this.settings.pinned_rooms[s],!0);this._chatv&&(!this.has_bttv&&this.settings.group_tabs&&this._chatv.ffzRebuildTabs(),this._chatv.ffzRebuildMenu())}},s.prototype._join_room=function(t,e){var s=!1;if(-1===this.settings.pinned_rooms.indexOf(t)&&(this.settings.pinned_rooms.push(t),this.settings.set("pinned_rooms",this.settings.pinned_rooms),s=!0),this.rooms[t]&&this.rooms[t].room)return s&&!e&&!this.has_bttv&&this._chatv&&this.settings.group_tabs&&this._chatv.ffzRebuildTabs(),s;{var n=App.__container__.resolve("model:room");n&&n.findOne(t)}return!e&&!this.has_bttv&&this._chatv&&this.settings.group_tabs&&this._chatv.ffzRebuildTabs(),!e&&this._chatv&&this._chatv.ffzRebuildMenu(),s},s.prototype._leave_room=function(t,e){var s=!1;if(-1!==this.settings.pinned_rooms.indexOf(t)&&(this.settings.pinned_rooms.removeObject(t),this.settings.set("pinned_rooms",this.settings.pinned_rooms),s=!0),!this.rooms[t]||!this.rooms[t].room)return s;var n=App.__container__.lookup("controller:chat"),i=this.rooms[t].room,o=this.get_user();return!n||n.get("currentChannelRoom.id")===t||this._chatv&&this._chatv._ffz_host===t?s:(n.get("currentRoom.id")===t&&n.blurRoom(),o&&o.login===t||i.destroy(),!e&&!this.has_bttv&&this._chatv&&this.settings.group_tabs&&this._chatv.ffzRebuildTabs(),!e&&this._chatv&&this._chatv.ffzRebuildMenu(),s)},s.chat_commands.join=function(t,e){if(!e||!e.length||e.length>1)return"Join Usage: /join <channel>";var s=e[0].toLowerCase();return"#"===s.charAt(0)&&(s=s.substr(1)),this._join_room(s)?"Joining "+s+". You will always connect to this channel's chat unless you later /part from it.":"You have already joined "+s+'. Please use "/part '+s+'" to leave it.'},s.chat_commands.part=function(t,e){if(!e||!e.length||e.length>1)return"Part Usage: /part <channel>";var s=e[0].toLowerCase();return"#"===s.charAt(0)&&(s=s.substr(1)),this._leave_room(s)?"Leaving "+s+".":this.rooms[s]?"You do not have "+s+" pinned and you cannot leave the current channel or hosted channels via /part.":"You are not in "+s+"."}},{"../constants":5,"../utils":35}],10:[function(){var e=t.FrankerFaceZ;e.settings_info.swap_sidebars={type:"boolean",value:!1,category:"Appearance",no_mobile:!0,no_bttv:!0,name:"Swap Sidebar Positions",help:"Swap the positions of the left and right s
else if(void 0===a){var r=this;this.set("cardInfo.user.ffz_followers",!1),Twitch.api.get("channels/"+this.get("cardInfo.user.id")+"/follows",{limit:1}).done(function(t){r.set("cardInfo.user.ffz_followers",t._total),r.ffzRebuildInfo()}).fail(function(){r.set("cardInfo.user.ffz_followers",void 0)})}if(n){var d=Math.floor((Date.now()-n.getTime())/1e3);d>0&&(s+='<span class="stat tooltip" title="Member Since: '+(d>86400?n.toLocaleDateString():n.toLocaleString())+'">'+o.CLOCK+" "+i.human_time(d,10)+"</span>")}e.innerHTML=s}}.observes("cardInfo.user.views"),userName:Ember.computed("cardInfo.user.id","cardInfo.user.display_name",function(){var t=this.get("cardInfo.user.id"),e=u.aliases[t];return e||this.get("cardInfo.user.display_name")||t.capitalize()}),didInsertElement:function(){this._super(),t._card=this;try{if(u.has_bttv)return;var e,n=this.get("element"),l=this.get("controller"),h=l.get("cardInfo.user.id"),f=u.aliases[h];if(f){var m=n.querySelector("h3.name"),p=m&&m.querySelector("a");p&&(m=p),m&&(m.classList.add("ffz-alias"),m.title=i.sanitize(l.get("cardInfo.user.display_name")||h.capitalize()),jQuery(m).tipsy())}if(n.classList.add("ffz-moderation-card"),u.settings.mod_card_info){var g=document.createElement("div"),v=n.querySelector("h3.name");v&&(n.classList.add("ffz-has-info"),g.className="info channel-stats",v.parentElement.insertBefore(g,v.nextSibling),this.ffzRebuildInfo())}if(u.settings.mod_card_buttons&&u.settings.mod_card_buttons.length){e=document.createElement("div"),e.className="extra-interface interface clearfix";for(var b={},y=function(t){var e=l.get("cardInfo.user.id"),s=App.__container__.lookup("controller:chat"),n=s&&s.get("currentRoom");n&&n.send(t.replace(/{user}/g,e))},w=function(t){var e=document.createElement("button"),s=t.split(" ",1)[0],n=b[s]>1?t.split(" ",b[s]):[s];return/^[!~./]/.test(n[0])&&(n[0]=n[0].substr(1)),n=_.map(n,function(t){return t.capitalize()}).join(" "),e.className="button",e.innerHTML=i.sanitize(n),e.title=i.sanitize(t.replace(/{user}/g,l.get("cardInfo.user.id")||"{user}")),jQuery(e).tipsy(),e.addEventListener("click",y.bind(this,t)),e},b={},z=0;z<u.settings.mod_card_buttons.length;z++)b[u.settings.mod_card_buttons[z].split(" ",1)[0]]=(b[u.settings.mod_card_buttons[z].split(" ",1)[0]]||0)+1;for(var z=0;z<u.settings.mod_card_buttons.length;z++){var k=u.settings.mod_card_buttons[z],E=k.indexOf("{user}");-1===E&&(k+=" {user}"),e.appendChild(w(k))}n.appendChild(e)}if(n.setAttribute("tabindex",1),u.settings.mod_card_hotkeys&&(n.classList.add("no-mousetrap"),n.addEventListener("keyup",function(t){var e=t.keyCode||t.which,s=l.get("cardInfo.user.id"),n=l.get("cardInfo.isModeratorOrHigher"),i=App.__container__.lookup("controller:chat").get("currentRoom");if(n&&e==a.P)i.send("/timeout "+s+" 1");else if(n&&e==a.B)i.send("/ban "+s);else if(n&&e==a.T)i.send("/timeout "+s+" 600");else if(n&&e==a.U)i.send("/unban "+s);else if(e!=a.ESC)return;l.send("close")})),l.get("cardInfo.isModeratorOrHigher")){n.classList.add("ffz-is-mod"),u.settings.mod_card_hotkeys&&(n.classList.add("no-mousetrap"),n.addEventListener("keyup",function(t){var e=t.keyCode||t.which,s=l.get("cardInfo.user.id"),n=App.__container__.lookup("controller:chat").get("currentRoom");if(e==a.P)n.send("/timeout "+s+" 1");else if(e==a.B)n.send("/ban "+s);else if(e==a.T)n.send("/timeout "+s+" 600");else if(e==a.U)n.send("/unban "+s);else if(e!=a.ESC)return;l.send("close")}));var C=function(t){var e=l.get("cardInfo.user.id"),s=App.__container__.lookup("controller:chat").get("currentRoom");s.send(-1===t?"/unban "+e:"/timeout "+e+" "+t)},x=function(t){var e=document.createElement("button");return e.className="button",e.innerHTML=c(t),e.title="Timeout User for "+i.number_commas(t)+" Second"+(1!=t?"s":""),u.settings.mod_card_hotkeys&&600===t?e.title="(T)"+e.title.substr(1):u.settings.mod_card_hotkeys&&1===t&&(e.title="(P)urge - "+e.title),jQuery(e).tipsy(),e.addEventListener("click",C.bind(this,t)),e};if(u.settings.mod_card_durations&&u.settings.mod_card_durations.length){e=document.createElement("div"),e.className="extra-interface interface
return 65536>e?String.fromCharCode(e):(e-=65536,String.fromCharCode(55296+(e>>10),56320+(1023&e)))};s.prototype.setup_emoticons=function(){this.log("Preparing emoticon system."),this.emoji_data={},this.emoji_names={},this.emote_sets={},this.global_sets=[],this.default_sets=[],this._last_emote_id=0,this.emote_usage={},this.log("Creating emoticon style element.");var t=this._emote_style=document.createElement("style");t.id="ffz-emoticon-css",document.head.appendChild(t),this.log("Loading global emote sets."),this.load_global_sets(),this.log("Loading emoji data."),this.load_emoji_data(),this.log("Watching Twitch emoticon parser to ensure it loads."),this._twitch_emote_check=setTimeout(this.check_twitch_emotes.bind(this),1e4)},s.prototype.add_usage=function(t,e,s){var n=this.emote_usage[e]=this.emote_usage[e]||{};n[t]=(n[t]||0)+(s||1),this._emote_report_scheduled||(this._emote_report_scheduled=setTimeout(this._report_emotes.bind(this),3e4))},s.prototype._report_emotes=function(){this._emote_report_scheduled&&delete this._emote_report_scheduled;var t=this.emote_usage;this.emote_usage={},this.ws_send("emoticon_uses",[t],function(){},!0)},s.prototype.check_twitch_emotes=function(){this._twitch_emote_check&&(clearTimeout(this._twitch_emote_check),delete this._twitch_emote_check);var t;if(this.rooms)for(var e in this.rooms)if(this.rooms.hasOwnProperty(e)){t=this.rooms[e];break}if(!t||!t.room||!t.room.tmiSession)return void(this._twitch_emote_check=setTimeout(this.check_twitch_emotes.bind(this),1e4));var s=t.room.tmiSession._emotesParser,n=Object.keys(s.emoticonRegexToIds).length;if(!(n>0)){var i=s.emoticonSetIds;s.emoticonSetIds="",s.updateEmoticons(i),this._twitch_emote_check=setTimeout(this.check_twitch_emotes.bind(this),1e4)}},s.prototype.getEmotes=function(t,e){var s=this.users&&this.users[t],n=this.rooms&&this.rooms[e];return _.union(s&&s.sets||[],n&&n.set&&[n.set]||[],n&&n.extra_sets||[],this.default_sets)},s.ws_commands.reload_set=function(t){this.emote_sets.hasOwnProperty(t)&&this.load_set(t)},s.ws_commands.load_set=function(t){this.load_set(t)},s.prototype._emote_tooltip=function(t){if(!t)return null;if(t._tooltip)return t._tooltip;var e=this.emote_sets[t.set_id],s=t.owner,n=e&&e.title||"Global";return t._tooltip="Emoticon: "+(t.hidden?"???":t.name)+"\nFFZ "+n+(s?"\nBy: "+s.display_name:""),t._tooltip},s.prototype.load_emoji_data=function(t,e){var s=this;jQuery.getJSON(n.SERVER+"emoji/emoji.json").done(function(e){var i={},o={};for(var a in e){var r=e[a];a=a.toLowerCase(),r.code=a,i[a]=r,o[r.short_name]=a,r.raw=_.map(r.code.split("-"),d).join(""),r.src=n.SERVER+"emoji/"+a+"-1x.png",r.srcSet=r.src+" 1x, "+n.SERVER+"emoji/"+a+"-2x.png 2x, "+n.SERVER+"emoji/"+a+"-4x.png 4x",r.token={srcSet:r.srcSet,emoticonSrc:r.src,ffzEmoji:a,altText:r.raw}}s.emoji_data=i,s.emoji_names=o,s.log("Loaded data on "+Object.keys(i).length+" emoji."),"function"==typeof t&&t(!0,e)}).fail(function(n){return 404===n.status?"function"==typeof t&&t(!1):(e=(e||0)+1,50>e?s.load_emoji(t,e):"function"==typeof t&&t(!1))})},s.prototype.load_global_sets=function(t,e){var s=this;jQuery.getJSON(((e||0)%2===0?n.API_SERVER:n.API_SERVER_2)+"v1/set/global").done(function(t){s.default_sets=t.default_sets;var e=s.global_sets=[],n=t.sets||{};s.feature_friday&&s.feature_friday.set&&(-1===s.global_sets.indexOf(s.feature_friday.set)&&s.global_sets.push(s.feature_friday.set),-1===s.default_sets.indexOf(s.feature_friday.set)&&s.default_sets.push(s.feature_friday.set));for(var i in n)if(n.hasOwnProperty(i)){var o=n[i];e.push(i),s._load_set_json(i,void 0,o)}}).fail(function(n){return 404==n.status?"function"==typeof t&&t(!1):(e=e||0,e++,50>e?s.load_global_sets(t,e):"function"==typeof t&&t(!1))})},s.prototype.load_set=function(t,e,s){var i=this;jQuery.getJSON(((s||0)%2===0?n.API_SERVER:n.API_SERVER_2)+"v1/set/"+t).done(function(s){i._load_set_json(t,e,s&&s.set)}).fail(function(n){return 404==n.status?"function"==typeof e&&e(!1):(s=s||0,s++,10>s?i.load_set(t,e,s):"function"==typeof e&&e(!1))})},s.prototype.unload_set=function(t){var e=this.emote_sets[t];e&&(this.log("Unloadi
e.prototype._ws_open=!1,e.prototype._ws_delay=0,e.prototype._ws_last_iframe=0,e.ws_commands={},e.ws_on_close=[],e.prototype.ws_iframe=function(){this._ws_last_iframe=Date.now();var t=document.createElement("iframe"),e=this;t.src="http://catbag.frankerfacez.com",t.style.visibility="hidden",document.body.appendChild(t),setTimeout(function(){document.body.removeChild(t),e._ws_open||e.ws_create()},2e3)},e.prototype.ws_create=function(){var s,n=this;this._ws_last_req=0,this._ws_callbacks={},this._ws_pending=this._ws_pending||[];try{s=this._ws_sock=new WebSocket("ws://catbag.frankerfacez.com/")}catch(i){return this._ws_exists=!1,this.log("Error Creating WebSocket: "+i)}this._ws_exists=!0,s.onopen=function(){n._ws_open=!0,n._ws_delay=0,n._ws_last_iframe=Date.now(),n.log("Socket connected.");var s=t.RequestFileSystem||t.webkitRequestFileSystem;s?s(t.TEMPORARY,100,n.ws_send.bind(n,"hello",["ffz_"+e.version_info,localStorage.ffzClientId],n._ws_on_hello.bind(n)),n.log.bind(n,"Operating in Incognito Mode.")):n.ws_send("hello",["ffz_"+e.version_info,localStorage.ffzClientId],n._ws_on_hello.bind(n));var i=n.get_user();if(i&&n.ws_send("setuser",i.login),n.is_dashboard){var o=location.pathname.match(/\/([^\/]+)/);o&&(n.ws_send("sub",o[1]),n.ws_send("sub_channel",o[1]))}for(var a in n.rooms)n.rooms.hasOwnProperty(a)&&n.rooms[a]&&(n.ws_send("sub",a),n.rooms[a].needs_history&&(n.rooms[a].needs_history=!1,!n.has_bttv&&n.settings.chat_history&&n.ws_send("chat_history",[a,25],n._load_history.bind(n,a))));if(n._cindex){var r=n._cindex.get("controller.id"),d=n._cindex.get("controller.hostModeTarget.id");r&&n.ws_send("sub_channel",r),d&&n.ws_send("sub_channel",d)}var u=n._ws_pending;n._ws_pending=[];for(var c=0;c<u.length;c++){var l=u[c];n.ws_send(l[0],l[1],l[2])}},s.onclose=function(t){n.log("Socket closed. (Code: "+t.code+", Reason: "+t.reason+")"),n._ws_open=!1;for(var s=0;s<e.ws_on_close.length;s++)try{e.ws_on_close[s].bind(n)()}catch(i){n.log("Error on Socket Close Callback: "+i)}if(n._ws_delay>1e4){var o=navigator.userAgent.toLowerCase();if(Date.now()-n._ws_last_iframe>18e5&&(-1!==o.indexOf("chrome")||-1===o.indexOf("safari")))return n.ws_iframe()}n._ws_delay<6e4?n._ws_delay+=1e3*(Math.floor(10*Math.random())+5):n._ws_delay=1e3*(Math.floor(60*Math.random())+30),setTimeout(n.ws_create.bind(n),n._ws_delay)},s.onmessage=function(t){var s,i,o=t.data.indexOf(" "),a=t.data.substr(o+1),r=parseInt(t.data.slice(0,o));if(o=a.indexOf(" "),-1===o&&(o=a.length),s=a.slice(0,o),a=a.substr(o+1),a&&(i=JSON.parse(a)),-1===r){var d=e.ws_commands[s];d?d.bind(n)(i):n.log("Invalid command: "+s,i,!1,!0)}else{var u="True"===s,c="function"==typeof n._ws_callbacks[r];if(c){try{n._ws_callbacks[r](u,i)}catch(l){n.error("Callback for "+r+": "+l)}n._ws_callbacks[r]=void 0}else n.log("Socket Reply to "+r+" - "+(u?"SUCCESS":"FAIL"),i,!1,!0)}}},e.prototype.ws_send=function(t,e,s,n){if(!this._ws_open){if(n){var i=this._ws_pending=this._ws_pending||[];return i.push([t,e,s]),!0}return!1}var o=++this._ws_last_req;e=void 0!==e?" "+JSON.stringify(e):"",s&&(this._ws_callbacks[o]=s);try{this._ws_sock.send(o+" "+t+e)}catch(a){return this.log("Socket Send Error: "+a),!1}return o},e.prototype._ws_on_hello=function(t,s){if(!t)return this.log("Error Saying Hello: "+s);localStorage.ffzClientId=s,this.log("Client ID: "+s);var n={},i=n.settings={};for(var o in e.settings_info)i[o]=this.settings[o];i.keywords=this.settings.keywords.length,i.banned_words=this.settings.banned_words.length,n.bttv=this.has_bttv||!!document.head.querySelector('script[src*="betterttv"]'),n["user-agent"]=navigator.userAgent,n.screen=[screen.width,screen.height],n.language=navigator.language,n.platform=navigator.platform,this.ws_send("survey",[n])},e.ws_commands.do_authorize=function(t){var s;for(var n in this.rooms)if(this.rooms.hasOwnProperty(n)){var i=this.rooms[n];if(i&&i.room&&!i.room.get("roomProperties.eventchat")&&!i.room.get("isGroupRoom")&&i.room.tmiRoom){var o=i.room.tmiRoom._getConnection();if(o.isConnected){s=o;break}}}s?s._send("PRIVMSG #frankerfacezauthorizer :AUTH "+t):setTimeout(e.ws_commands.do
if(r&&r.length)for(var u=0,c=0,l=r.length;l>c;c++){var h=r[c];if(h&&h.channel){if(u+=1,u>a){e+="<hr><span>And "+n.number_commas(d-a)+" more...</span>";break}var f=this.settings.stream_uptime&&h.created_at&&n.parse_date(h.created_at),m=f&&Math.floor((Date.now()-f.getTime())/1e3)||0,_=Math.floor(m/60)%60,p=Math.floor(m/3600);e+=(0===c?"<hr>":"")+(m>0?'<span class="stat">'+i.CLOCK+" "+(p>0?p+"h":"")+_+"m</span>":"")+'<span class="stat">'+i.LIVE+" "+n.number_commas(h.viewers)+"</span><b>"+n.sanitize(h.channel.display_name||h.channel.name)+'</b><br><span class="playing">'+(h.channel.game?"Playing "+n.sanitize(h.channel.game):"Not Playing")+"</span>"}}else e+="<hr>No one you're following is online.";return setTimeout(function(){var t=document.querySelector(".tipsy"),e=t.getBoundingClientRect(),s=parseInt(t.style.left||"0"),n=e.left+t.scrollWidth;e.left<5?t.style.left=s-e.left+5+"px":n>document.body.clientWidth-5&&(t.style.left=s-(5+n-document.body.clientWidth)+"px")}),e},s.prototype._install_following_tooltips=function(){var t=this,e={html:!0,className:function(){return a(t,this)},title:function(){return t._build_following_tooltip(this)}},s=jQuery('#small_nav ul.game_filters li[data-name="following"] a');if(s&&s.length){var n=s.data("tipsy");n&&n.options?(n.options=_.extend(n.options,e),n.options.gravity=function(){return o(t,this)}):s.tipsy(_.extend({gravity:function(){return o(t,this)}},e))}var i=jQuery('#large_nav #nav_personal li[data-name="following"] a');if(i&&i.length){var n=i.data("tipsy");n&&n.options?n.options=_.extend(n.options,e):i.tipsy(e)}var r=jQuery("#header_actions #header_following");if(r&&r.length){var n=r.data("tipsy");n&&n.options?n.options=_.extend(n.options,e):r.tipsy(e)}},s.prototype._draw_following_channels=function(t,e){this._tooltip_streams=t,this._tooltip_total=e},s.prototype._draw_following_count=function(t){var e=document.querySelector('#small_nav ul.game_filters li[data-name="following"] a');if(e){var s=e.querySelector(".ffz-follow-count");this.has_bttv||!this.settings.following_count?s&&s.parentElement.removeChild(s):(s||(s=document.createElement("span"),s.className="ffz-follow-count",e.appendChild(s)),s.innerHTML=t?n.format_unread(t):"")}var i=document.querySelector('#large_nav #nav_personal li[data-name="following"] a');if(i){var s=i.querySelector(".ffz-follow-count");this.has_bttv||!this.settings.following_count?s&&s.parentElement.removeChild(s):(s||(s=document.createElement("span"),s.className="ffz-follow-count",i.appendChild(s)),s.innerHTML=t?n.format_unread(t):"")}var o=document.querySelector("#header_actions #header_following");if(o){var s=o.querySelector(".ffz-follow-count");this.has_bttv||!this.settings.following_count?s&&s.parentElement.removeChild(s):(s||(s=document.createElement("span"),s.className="ffz-follow-count",o.appendChild(s)),s.innerHTML=t?n.format_unread(t):"")}}},{"../constants":5,"../utils":35}],26:[function(e){var s=t.FrankerFaceZ,n=e("../utils"),i=/^[A-Za-z0-9_]+$/,o=/^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/([A-Za-z0-9_]+)/i;s.prototype.setup_following=function(){this.log("Initializing following support."),this.follow_data={},this.follow_sets={}},s.settings_info.follow_buttons={type:"boolean",value:!0,no_mobile:!0,category:"Channel Metadata",name:"Relevant Follow Buttons",help:"Display additional Follow buttons for channels relevant to the stream, such as people participating in co-operative gameplay.",on_update:function(){this.rebuild_following_ui()}},s.ffz_commands.following=function(t,e){e=e.join(" ").trim().toLowerCase().split(/[ ,]+/);for(var s=[],n=0,i=e.length;i>n;n++){var a=e[n],r=a.match(o);r&&(a=r[1]),""!==a&&-1===s.indexOf(a)&&s.push(a)}var d=this.get_user(),u=this;return!d||d.login!==t.id&&"sirstendec"!==d.login&&"dansalvato"!==d.login?"You must be logged in as the broadcaster to use this command.":this.ws_send("update_follow_buttons",[t.id,s],function(e,s){return e?void(s?u.room_message(t,"The following buttons have been updated."):u.room_message(t,"The following buttons have been disabled.")):void u.room_message(t,"There was an error updating the following
var d={lang:"en-US",dir:"ltr",body:t,tag:n||"FrankerFaceZ",icon:"http://cdn.frankerfacez.com/icon32.png"},u=this,c=new Notification(s,d),l=e._last_notification++;return e._notifications[l]=c,c.addEventListener("click",function(){delete e._notifications[l],o&&o.bind(u)()}),c.addEventListener("close",function(){delete e._notifications[l],a&&a.bind(u)()}),void("number"==typeof i&&c.addEventListener("show",function(){setTimeout(function(){delete e._notifications[l],c.close()},i)}))}var u=this;Notification.requestPermission(function(){u.show_notification(t,s,n)})},e.prototype.show_message=function(e){t.noty({text:e,theme:"ffzTheme",layout:"bottomCenter",closeWith:["button"]}).show()}},{}],31:[function(e){var s=t.FrankerFaceZ,n=e("../utils");s.prototype.setup_races=function(){this.log("Initializing race support."),this.srl_races={}},s.settings_info.srl_races={type:"boolean",value:!0,no_mobile:!0,category:"Channel Metadata",name:"SRL Race Information",help:'Display information about <a href="http://www.speedrunslive.com/" target="_new">SpeedRunsLive</a> races under channels.',on_update:function(){this.rebuild_race_ui()}},s.ws_on_close.push(function(){var e=t.App&&App.__container__.lookup("controller:channel"),s=e&&e.get("id"),n=e&&e.get("hostModeTarget.id"),i=!1;if(e){for(var o in this.srl_races)delete this.srl_races[o],(o===s||o===n)&&(i=!0);i&&this.rebuild_race_ui()}}),s.ws_commands.srl_race=function(t){var e=App.__container__.lookup("controller:channel"),s=e&&e.get("id"),n=e&&e.get("hostModeTarget.id"),i=!1;this.srl_races=this.srl_races||{};for(var o=0;o<t[0].length;o++){var a=t[0][o];this.srl_races[a]=t[1],(a===s||a===n)&&(i=!0)}if(t[1]){var r=t[1],d=r.twitch_entrants={};for(var u in r.entrants)r.entrants.hasOwnProperty(u)&&(r.entrants[u].channel&&(d[r.entrants[u].channel]=u),r.entrants[u].name=u)}i&&this.rebuild_race_ui()},s.prototype.rebuild_race_ui=function(){var t=App.__container__.lookup("controller:channel"),e=t&&t.get("id"),s=t&&t.get("hostModeTarget.id");if(this._cindex){if(e){var n=this.srl_races&&this.srl_races[e],i=this._cindex.get("element"),o=i&&i.querySelector(".stats-and-actions .channel-actions"),a=o&&o.querySelector("#ffz-ui-race");if(o&&this.settings.srl_races&&n){if(!a){a=document.createElement("span"),a.id="ffz-ui-race",a.setAttribute("data-channel",e);var r=document.createElement("span");r.className="button drop action",r.title="SpeedRunsLive Race",r.innerHTML='<span class="logo"></span>',r.addEventListener("click",this._build_race_popup.bind(this,a,e)),a.appendChild(r),o.appendChild(a)}this._update_race(a,!0)}else a&&a.parentElement.removeChild(a)}if(s){var n=this.srl_races&&this.srl_races[s],i=this._cindex.get("element"),o=i&&i.querySelector("#hostmode .channel-actions"),a=o&&o.querySelector("#ffz-ui-race");if(o&&this.settings.srl_races&&n){if(!a){a=document.createElement("span"),a.id="ffz-ui-race",a.setAttribute("data-channel",s);var r=document.createElement("span");r.className="button drop action",r.title="SpeedRunsLive Race",r.innerHTML='<span class="logo"></span>',r.addEventListener("click",this._build_race_popup.bind(this,a,s)),a.appendChild(r),o.appendChild(a)}this._update_race(a,!0)}else a&&a.parentElement.removeChild(a)}}},s.prototype._race_kill=function(){this._race_timer&&(clearTimeout(this._race_timer),delete this._race_timer),delete this._race_game,delete this._race_goal},s.prototype._build_race_popup=function(t,e){var n=this._popup;if((!n||(n.parentElement.removeChild(n),delete this._popup,this._popup_kill&&this._popup_kill(),delete this._popup_kill,"ffz-race-popup"!==n.id||n.getAttribute("data-channel")!==e))&&t){var i=t.querySelector(".button"),o=i.offsetLeft+i.offsetWidth,a=this.srl_races[e],n=document.createElement("div"),r="";n.id="ffz-race-popup",n.setAttribute("data-channel",e),n.className=(o>=300?"right":"left")+" share dropmenu",this._popup_kill=this._race_kill.bind(this),this._popup=n;var d="http://kadgar.net/live",u=!1;for(var c in a.entrants){var l=a.entrants[c].state;a.entrants.hasOwnProperty(c)&&a.entrants[c].channel&&("racing"==l||"entered"==l)&&(d+="/"+a.entrants[c].chann