2015-05-17 19:02:57 -04:00
var FFZ = window . FrankerFaceZ ,
utils = require ( '../utils' ) ,
constants = require ( '../constants' ) ;
// --------------------
// Initialization
// --------------------
FFZ . prototype . setup _channel = function ( ) {
2015-07-04 17:06:36 -04:00
// Style Stuff!
this . log ( "Creating channel style element." ) ;
var s = this . _channel _style = document . createElement ( "style" ) ;
s . id = "ffz-channel-css" ;
document . head . appendChild ( s ) ;
2015-06-05 03:59:28 -04:00
// Settings stuff!
document . body . classList . toggle ( "ffz-hide-view-count" , ! this . settings . channel _views ) ;
2015-05-17 19:02:57 -04:00
this . log ( "Creating channel style element." ) ;
var s = this . _channel _style = document . createElement ( 'style' ) ;
s . id = "ffz-channel-css" ;
document . head . appendChild ( s ) ;
2015-06-05 03:59:28 -04:00
this . log ( "Hooking the Ember Channel Index view." ) ;
var Channel = App . _ _container _ _ . resolve ( 'view:channel/index' ) ,
2015-05-17 19:02:57 -04:00
f = this ;
if ( ! Channel )
return ;
2015-06-05 03:59:28 -04:00
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 ( ) ;
} ;
2015-07-13 21:52:44 -04:00
this . log ( "Hooking the Ember Channel model." ) ;
Channel = App . _ _container _ _ . resolve ( 'model:channel' ) ;
if ( ! Channel )
return ;
Channel . reopen ( {
ffz _host _target : undefined ,
setHostMode : function ( e ) {
if ( f . settings . hosted _channels ) {
this . set ( 'ffz_host_target' , e . target ) ;
return this . _super ( e ) ;
} else {
this . set ( 'ffz_host_target' , undefined ) ;
return this . _super ( { target : void 0 , delay : 0 } ) ;
}
}
} ) ;
2015-06-05 03:59:28 -04:00
this . log ( "Hooking the Ember Channel controller." ) ;
Channel = App . _ _container _ _ . lookup ( 'controller:channel' ) ;
if ( ! Channel )
return ;
2015-05-17 19:02:57 -04:00
Channel . reopen ( {
ffzUpdateUptime : function ( ) {
2015-06-05 03:59:28 -04:00
if ( f . _cindex )
f . _cindex . ffzUpdateUptime ( ) ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
} . observes ( "isLive" , "content.id" ) ,
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
ffzUpdateTitle : function ( ) {
var name = this . get ( 'content.name' ) ,
display _name = this . get ( 'content.display_name' ) ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
if ( display _name )
FFZ . capitalization [ name ] = [ display _name , Date . now ( ) ] ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
if ( f . _cindex )
f . _cindex . ffzFixTitle ( ) ;
2015-06-10 18:46:04 -04:00
} . observes ( "content.status" , "content.id" ) ,
2015-05-17 19:02:57 -04:00
2015-06-10 18:46:04 -04:00
ffzHostTarget : function ( ) {
2015-06-05 03:59:28 -04:00
var target = this . get ( 'content.hostModeTarget' ) ,
name = target && target . get ( 'name' ) ,
2015-07-04 17:06:36 -04:00
id = target && target . get ( 'id' ) ,
2015-06-05 03:59:28 -04:00
display _name = target && target . get ( 'display_name' ) ;
2015-05-17 19:02:57 -04:00
2015-07-04 17:06:36 -04:00
if ( id !== f . _ _old _host _target ) {
if ( f . _ _old _host _target )
f . ws _send ( "unsub_channel" , f . _ _old _host _target ) ;
if ( id ) {
f . ws _send ( "sub_channel" , id ) ;
f . _ _old _host _target = id ;
} else
delete f . _ _old _host _target ;
}
2015-06-05 03:59:28 -04:00
if ( display _name )
FFZ . capitalization [ name ] = [ display _name , Date . now ( ) ] ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
if ( f . settings . group _tabs && f . _chatv )
f . _chatv . ffzRebuildTabs ( ) ;
2015-07-04 17:06:36 -04:00
if ( f . settings . follow _buttons )
f . rebuild _following _ui ( ) ;
if ( f . settings . srl _races )
f . rebuild _race _ui ( ) ;
2015-06-10 18:46:04 -04:00
} . observes ( "content.hostModeTarget" )
2015-06-05 03:59:28 -04:00
} ) ;
}
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
FFZ . prototype . _modify _cindex = function ( view ) {
var f = this ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
view . reopen ( {
didInsertElement : function ( ) {
this . _super ( ) ;
try {
this . ffzInit ( ) ;
} catch ( err ) {
f . error ( "CIndex didInsertElement: " + err ) ;
}
} ,
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
willClearRender : function ( ) {
try {
this . ffzTeardown ( ) ;
} catch ( err ) {
f . error ( "CIndex willClearRender: " + err ) ;
}
return this . _super ( ) ;
} ,
ffzInit : function ( ) {
2015-07-04 17:06:36 -04:00
var id = this . get ( 'controller.id' ) ,
el = this . get ( 'element' ) ;
2015-06-05 03:59:28 -04:00
f . _cindex = this ;
2015-07-04 17:06:36 -04:00
f . ws _send ( "sub_channel" , id ) ;
el . setAttribute ( 'data-channel' , id ) ;
el . classList . add ( 'ffz-channel' ) ;
2015-07-06 00:09:21 -04:00
// Try changing the theater mode tooltip.
this . $ ( '.theatre-button a' ) . attr ( 'title' , 'Theater Mode (Alt+T)' ) ;
2015-06-05 03:59:28 -04:00
this . ffzFixTitle ( ) ;
this . ffzUpdateUptime ( ) ;
this . ffzUpdateChatters ( ) ;
2015-07-13 21:52:44 -04:00
this . ffzUpdateHostButton ( ) ;
2015-06-05 03:59:28 -04:00
2015-07-04 17:06:36 -04:00
var views = this . get ( 'element' ) . querySelector ( '.svg-glyph_views:not(.ffz-svg)' )
if ( views )
views . parentNode . classList . add ( 'twitch-channel-views' ) ;
if ( f . settings . follow _buttons )
f . rebuild _following _ui ( ) ;
if ( f . settings . srl _races )
f . rebuild _race _ui ( ) ;
2015-06-05 03:59:28 -04:00
} ,
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" ) ;
2015-07-04 17:06:36 -04:00
if ( ! scripts . length )
el . innerHTML = status ;
else
el . innerHTML = scripts [ 0 ] . outerHTML + status + scripts [ 1 ] . outerHTML ;
2015-06-05 03:59:28 -04:00
} ) ;
} ,
2015-05-17 19:02:57 -04:00
2015-07-13 21:52:44 -04:00
ffzUpdateHostButton : function ( ) {
var channel _id = this . get ( 'controller.id' ) ,
hosted _id = this . get ( 'controller.hostModeTarget.id' ) ,
user = f . get _user ( ) ,
room = user && f . rooms && f . rooms [ user . login ] && f . rooms [ user . login ] . room ,
now _hosting = room && room . ffz _host _target ,
hosts _left = room && room . ffz _hosts _left ,
el = this . get ( 'element' ) ;
this . set ( 'ffz_host_updating' , false ) ;
if ( channel _id ) {
var container = el && el . querySelector ( '.stats-and-actions .channel-actions' ) ,
btn = container && container . querySelector ( '#ffz-ui-host-button' ) ;
if ( ! container || ! f . settings . stream _host _button || ! user || user . login === channel _id ) {
if ( btn )
btn . parentElement . removeChild ( btn ) ;
} else {
if ( ! btn ) {
btn = document . createElement ( 'span' ) ;
btn . id = 'ffz-ui-host-button' ;
btn . className = 'button action tooltip' ;
btn . addEventListener ( 'click' , this . ffzClickHost . bind ( btn , this , false ) ) ;
var before = container . querySelector ( ':scope > .theatre-button' ) ;
if ( before )
container . insertBefore ( btn , before ) ;
else
container . appendChild ( btn ) ;
}
btn . classList . remove ( 'disabled' ) ;
btn . innerHTML = channel _id === now _hosting ? 'Unhost' : 'Host' ;
if ( now _hosting )
btn . title = 'You are now hosting ' + utils . sanitize ( FFZ . get _capitalization ( now _hosting ) ) + '.' ;
else
btn . title = 'You are not hosting any channel.' ;
if ( typeof hosts _left === "number" )
btn . title += ' You have ' + hosts _left + ' host command' + utils . pluralize ( hosts _left ) + ' remaining this half hour.' ;
}
}
if ( hosted _id ) {
var container = el && el . querySelector ( '#hostmode .channel-actions' ) ,
btn = container && container . querySelector ( '#ffz-ui-host-button' ) ;
if ( ! container || ! f . settings . stream _host _button || ! user || user . login === hosted _id ) {
if ( btn )
btn . parentElement . removeChild ( btn ) ;
} else {
if ( ! btn ) {
btn = document . createElement ( 'span' ) ;
btn . id = 'ffz-ui-host-button' ;
btn . className = 'button action tooltip' ;
btn . addEventListener ( 'click' , this . ffzClickHost . bind ( btn , this , true ) ) ;
var before = container . querySelector ( ':scope > .theatre-button' ) ;
if ( before )
container . insertBefore ( btn , before ) ;
else
container . appendChild ( btn ) ;
}
btn . classList . remove ( 'disabled' ) ;
btn . innerHTML = hosted _id === now _hosting ? 'Unhost' : 'Host' ;
if ( now _hosting )
btn . title = 'You are currently hosting ' + utils . sanitize ( FFZ . get _capitalization ( now _hosting ) ) + '. Click to ' + ( hosted _id === now _hosting ? 'unhost' : 'host' ) + ' this channel.' ;
else
btn . title = 'You are not currently hosting any channel. Click to host this channel.' ;
if ( typeof hosts _left === "number" )
btn . title += ' You have ' + hosts _left + ' host command' + utils . pluralize ( hosts _left ) + ' remaining this half hour.' ;
}
}
} ,
ffzClickHost : function ( controller , is _host ) {
var target = controller . get ( is _host ? 'controller.hostModeTarget.id' : 'controller.id' ) ,
user = f . get _user ( ) ,
room = user && f . rooms && f . rooms [ user . login ] && f . rooms [ user . login ] . room ,
now _hosting = room && room . ffz _host _target ;
if ( ! room || controller . get ( 'ffz_host_updating' ) )
return ;
this . classList . add ( 'disabled' ) ;
this . title = 'Updating...' ;
controller . set ( 'ffz_host_updating' , true ) ;
if ( now _hosting === target )
room . send ( "/unhost" ) ;
else
room . send ( "/host " + target ) ;
} ,
2015-06-05 03:59:28 -04:00
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 ) ;
2015-05-17 19:02:57 -04:00
return ;
2015-06-05 03:59:28 -04:00
}
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
var chatter _count = Object . keys ( room . room . get ( 'ffz_chatters' ) || { } ) . length ,
2015-07-04 17:06:36 -04:00
ffz _chatters = room . ffz _chatters || 0 ,
ffz _viewers = room . ffz _viewers || 0 ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
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 ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
var stat = document . createElement ( 'span' ) ;
stat . className = 'ffz stat' ;
stat . id = 'ffz-chatter-display' ;
2015-07-04 17:06:36 -04:00
stat . title = "Currently in Chat" ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
stat . innerHTML = constants . ROOMS + " " ;
el = document . createElement ( "span" ) ;
stat . appendChild ( el ) ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
var other = cont . querySelector ( "#ffz-ffzchatter-display" ) ;
if ( other )
cont . insertBefore ( stat , other ) ;
else
cont . appendChild ( stat ) ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
jQuery ( stat ) . tipsy ( ) ;
}
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
el . innerHTML = utils . number _commas ( chatter _count ) ;
2015-05-17 19:02:57 -04:00
2015-07-04 17:06:36 -04:00
if ( ! ffz _chatters && ! ffz _viewers ) {
2015-06-05 03:59:28 -04:00
el = this . get ( 'element' ) . querySelector ( '#ffz-ffzchatter-display' ) ;
el && el . parentNode . removeChild ( el ) ;
return ;
}
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
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 ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
var stat = document . createElement ( 'span' ) ;
stat . className = 'ffz stat' ;
stat . id = 'ffz-ffzchatter-display' ;
2015-07-04 17:06:36 -04:00
stat . title = "Viewers (In Chat) with FrankerFaceZ" ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
stat . innerHTML = constants . ZREKNARF + " " ;
el = document . createElement ( "span" ) ;
stat . appendChild ( el ) ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
var other = cont . querySelector ( "#ffz-chatter-display" ) ;
if ( other )
cont . insertBefore ( stat , other . nextSibling ) ;
else
cont . appendChild ( stat ) ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
jQuery ( stat ) . tipsy ( ) ;
}
2015-05-17 19:02:57 -04:00
2015-07-04 17:06:36 -04:00
el . innerHTML = utils . number _commas ( ffz _viewers ) + " (" + utils . number _commas ( ffz _chatters ) + ")" ;
2015-06-05 03:59:28 -04:00
} ,
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
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 ;
2015-05-17 19:02:57 -04:00
}
2015-06-05 03:59:28 -04:00
// 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 <nobr>(since " + online . toLocaleString ( ) + ")</nobr>" ;
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 ( ) {
2015-07-04 17:06:36 -04:00
var id = this . get ( 'controller.id' ) ;
if ( id )
f . ws _send ( "unsub_channel" , id ) ;
2015-06-05 03:59:28 -04:00
this . get ( 'element' ) . setAttribute ( 'data-channel' , '' ) ;
f . _cindex = undefined ;
if ( this . _ffz _update _uptime )
clearTimeout ( this . _ffz _update _uptime ) ;
2015-07-04 17:06:36 -04:00
utils . update _css ( f . _channel _style , id , null ) ;
2015-05-17 19:02:57 -04:00
}
2015-06-05 03:59:28 -04:00
} ) ;
}
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
// ---------------
// Settings
// ---------------
FFZ . settings _info . chatter _count = {
type : "boolean" ,
value : false ,
2015-07-18 21:10:27 -04:00
no _mobile : true ,
2015-06-05 03:59:28 -04:00
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 ,
2015-07-18 21:10:27 -04:00
no _mobile : true ,
2015-06-05 03:59:28 -04:00
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 ) ;
}
} ;
2015-07-13 21:52:44 -04:00
FFZ . settings _info . hosted _channels = {
type : "boolean" ,
value : true ,
2015-07-18 21:10:27 -04:00
no _mobile : true ,
2015-07-13 21:52:44 -04:00
category : "Channel Metadata" ,
name : "Channel Hosting" ,
help : "Display other channels that have been featured by the current channel." ,
on _update : function ( val ) {
var cb = document . querySelector ( 'input.ffz-setting-hosted-channels' ) ;
if ( cb )
cb . checked = val ;
if ( ! this . _cindex )
return ;
var chan = this . _cindex . get ( 'controller.model' ) ,
room = chan && this . rooms && this . rooms [ chan . get ( 'id' ) ] ,
target = room && room . room && room . room . get ( 'ffz_host_target' ) ;
if ( ! chan || ! room )
return ;
chan . setHostMode ( { target : target , delay : 0 } ) ;
}
} ;
FFZ . settings _info . stream _host _button = {
type : "boolean" ,
value : true ,
2015-07-18 21:10:27 -04:00
no _mobile : true ,
2015-07-13 21:52:44 -04:00
category : "Channel Metadata" ,
name : "Host This Channel Button" ,
help : "Display a button underneath streams that make it easy to host them with your own channel." ,
on _update : function ( val ) {
if ( this . _cindex )
this . _cindex . ffzUpdateHostButton ( ) ;
}
} ;
2015-06-05 03:59:28 -04:00
FFZ . settings _info . stream _uptime = {
type : "boolean" ,
value : false ,
2015-07-18 21:10:27 -04:00
no _mobile : true ,
2015-06-05 03:59:28 -04:00
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 ,
2015-07-18 21:10:27 -04:00
no _mobile : true ,
2015-06-05 03:59:28 -04:00
category : "Channel Metadata" ,
name : "Title Links" ,
help : "Make links in stream titles clickable." ,
on _update : function ( val ) {
if ( this . _cindex )
this . _cindex . ffzFixTitle ( ) ;
}
} ;