var FFZ = window.FrankerFaceZ, utils = require('../utils'), constants = require('../constants'); // -------------------- // Initialization // -------------------- FFZ.prototype.setup_channel = function() { // Settings stuff! document.body.classList.toggle("ffz-hide-view-count", !this.settings.channel_views); this.log("Creating channel style element."); var s = this._channel_style = document.createElement('style'); s.id = "ffz-channel-css"; document.head.appendChild(s); this.log("Hooking the Ember Channel Index view."); var Channel = App.__container__.resolve('view:channel/index'), f = this; if ( ! Channel ) return; this._modify_cindex(Channel); // The Stupid View Fix. Is this necessary still? try { Channel.create().destroy(); } catch(err) { } // Update Existing for(var key in Ember.View.views) { if ( ! Ember.View.views.hasOwnProperty(key) ) continue; var view = Ember.View.views[key]; if ( !(view instanceof Channel) ) continue; this.log("Manually updating Channel Index view.", view); this._modify_cindex(view); view.ffzInit(); }; this.log("Hooking the Ember Channel controller."); Channel = App.__container__.lookup('controller:channel'); if ( ! Channel ) return; Channel.reopen({ ffzUpdateUptime: function() { if ( f._cindex ) f._cindex.ffzUpdateUptime(); }.observes("isLive", "content.id"), ffzUpdateTitle: function() { var name = this.get('content.name'), display_name = this.get('content.display_name'); if ( display_name ) FFZ.capitalization[name] = [display_name, Date.now()]; if ( f._cindex ) f._cindex.ffzFixTitle(); }.observes("content.status", "content.id"), ffzHostTarget: function() { var target = this.get('content.hostModeTarget'), name = target && target.get('name'), display_name = target && target.get('display_name'); if ( display_name ) FFZ.capitalization[name] = [display_name, Date.now()]; if ( f.settings.group_tabs && f._chatv ) f._chatv.ffzRebuildTabs(); }.observes("content.hostModeTarget") }); } FFZ.prototype._modify_cindex = function(view) { var f = this; view.reopen({ didInsertElement: function() { this._super(); try { this.ffzInit(); } catch(err) { f.error("CIndex didInsertElement: " + err); } }, willClearRender: function() { try { this.ffzTeardown(); } catch(err) { f.error("CIndex willClearRender: " + err); } return this._super(); }, ffzInit: function() { f._cindex = this; this.get('element').setAttribute('data-channel', this.get('controller.id')); this.ffzFixTitle(); this.ffzUpdateUptime(); this.ffzUpdateChatters(); var el = this.get('element').querySelector('.svg-glyph_views:not(.ffz-svg)') if ( el ) el.parentNode.classList.add('twitch-channel-views'); }, ffzFixTitle: function() { if ( f.has_bttv || ! f.settings.stream_title ) return; var status = this.get("controller.status"), channel = this.get("controller.id"); status = f.render_tokens(f.tokenize_line(channel, channel, status, true)); this.$(".title span").each(function(i, el) { var scripts = el.querySelectorAll("script"); el.innerHTML = scripts[0].outerHTML + status + scripts[1].outerHTML; }); }, ffzUpdateChatters: function() { // Get the counts. var room_id = this.get('controller.id'), room = f.rooms && f.rooms[room_id]; if ( ! room || ! f.settings.chatter_count ) { var el = this.get('element').querySelector('#ffz-chatter-display'); el && el.parentElement.removeChild(el); el = this.get('element').querySelector('#ffz-ffzchatter-display'); el && el.parentElement.removeChild(el); return; } var chatter_count = Object.keys(room.room.get('ffz_chatters') || {}).length, ffz_chatters = room.ffz_chatters || 0; var el = this.get('element').querySelector('#ffz-chatter-display span'); if ( ! el ) { var cont = this.get('element').querySelector('.stats-and-actions .channel-stats'); if ( ! cont ) return; var stat = document.createElement('span'); stat.className = 'ffz stat'; stat.id = 'ffz-chatter-display'; stat.title = "Current Chatters"; stat.innerHTML = constants.ROOMS + " "; el = document.createElement("span"); stat.appendChild(el); var other = cont.querySelector("#ffz-ffzchatter-display"); if ( other ) cont.insertBefore(stat, other); else cont.appendChild(stat); jQuery(stat).tipsy(); } el.innerHTML = utils.number_commas(chatter_count); if ( ! ffz_chatters ) { el = this.get('element').querySelector('#ffz-ffzchatter-display'); el && el.parentNode.removeChild(el); return; } el = this.get('element').querySelector('#ffz-ffzchatter-display span'); if ( ! el ) { var cont = this.get('element').querySelector('.stats-and-actions .channel-stats'); if ( ! cont ) return; var stat = document.createElement('span'); stat.className = 'ffz stat'; stat.id = 'ffz-ffzchatter-display'; stat.title = "Chatters with FrankerFaceZ"; stat.innerHTML = constants.ZREKNARF + " "; el = document.createElement("span"); stat.appendChild(el); var other = cont.querySelector("#ffz-chatter-display"); if ( other ) cont.insertBefore(stat, other.nextSibling); else cont.appendChild(stat); jQuery(stat).tipsy(); } el.innerHTML = utils.number_commas(ffz_chatters); }, ffzUpdateUptime: function() { if ( this._ffz_update_uptime ) { clearTimeout(this._ffz_update_uptime); delete this._ffz_update_uptime; } if ( ! f.settings.stream_uptime || ! this.get("controller.isLiveAccordingToKraken") ) { var el = this.get('element').querySelector('#ffz-uptime-display'); if ( el ) el.parentElement.removeChild(el); return; } // Schedule an update. this._ffz_update_uptime = setTimeout(this.ffzUpdateUptime.bind(this), 1000); // Determine when the channel last went live. var online = this.get("controller.content.stream.created_at"); if ( ! online ) return; online = utils.parse_date(online); if ( ! online ) return; var uptime = Math.floor((Date.now() - online.getTime()) / 1000); if ( uptime < 0 ) return; var el = this.get('element').querySelector('#ffz-uptime-display span'); if ( ! el ) { var cont = this.get('element').querySelector('.stats-and-actions .channel-stats'); if ( ! cont ) return; var stat = document.createElement('span'); stat.className = 'ffz stat'; stat.id = 'ffz-uptime-display'; stat.title = "Stream Uptime (since " + online.toLocaleString() + ")"; stat.innerHTML = constants.CLOCK + " "; el = document.createElement("span"); stat.appendChild(el); var viewers = cont.querySelector(".live-count"); if ( viewers ) cont.insertBefore(stat, viewers.nextSibling); else { try { viewers = cont.querySelector("script:nth-child(0n+2)"); cont.insertBefore(stat, viewers.nextSibling); } catch(err) { cont.insertBefore(stat, cont.childNodes[0]); } } jQuery(stat).tipsy({html: true}); } el.innerHTML = utils.time_to_string(uptime); }, ffzTeardown: function() { this.get('element').setAttribute('data-channel', ''); f._cindex = undefined; if ( this._ffz_update_uptime ) clearTimeout(this._ffz_update_uptime); } }); } // --------------- // Settings // --------------- FFZ.settings_info.chatter_count = { type: "boolean", value: false, category: "Channel Metadata", name: "Chatter Count", help: "Display the current number of users connected to chat beneath the channel.", on_update: function(val) { if ( this._cindex ) this._cindex.ffzUpdateChatters(); if ( ! val || ! this.rooms ) return; // Refresh the data. for(var room_id in this.rooms) this.rooms.hasOwnProperty(room_id) && this.rooms[room_id].room && this.rooms[room_id].room.ffzInitChatterCount(); } }; FFZ.settings_info.channel_views = { type: "boolean", value: true, category: "Channel Metadata", name: "Channel Views", help: 'Display the number of times the channel has been viewed beneath the stream.', on_update: function(val) { document.body.classList.toggle("ffz-hide-view-count", !val); } }; FFZ.settings_info.stream_uptime = { type: "boolean", value: false, category: "Channel Metadata", name: "Stream Uptime", help: 'Display the stream uptime under a channel by the viewer count.', on_update: function(val) { if ( this._cindex ) this._cindex.ffzUpdateUptime(); } }; FFZ.settings_info.stream_title = { type: "boolean", value: true, no_bttv: true, category: "Channel Metadata", name: "Title Links", help: "Make links in stream titles clickable.", on_update: function(val) { if ( this._cindex ) this._cindex.ffzFixTitle(); } };