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-11-07 22:56:15 -05:00
document . body . classList . toggle ( 'ffz-theater-stats' , this . settings . theater _stats ) ;
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
this . log ( "Hooking the Ember Channel Index view." ) ;
2016-07-13 02:06:50 -04:00
if ( ! this . update _views ( 'view:channel/index' , this . modify _channel _index ) )
2015-05-17 19:02:57 -04:00
return ;
2015-07-13 21:52:44 -04:00
this . log ( "Hooking the Ember Channel model." ) ;
2016-07-13 02:06:50 -04:00
var f = this ,
Channel = utils . ember _resolve ( 'model:deprecated-channel' ) ;
2015-07-13 21:52:44 -04:00
if ( ! Channel )
2016-07-13 02:06:50 -04:00
return this . log ( "Unable to find the Ember model:deprecated-channel" ) ;
2015-07-13 21:52:44 -04:00
2016-07-13 02:06:50 -04:00
this . _modify _cmodel ( Channel ) ;
2015-08-04 01:43:08 -04:00
2016-07-13 02:06:50 -04:00
var Store = utils . ember _lookup ( 'service:store' ) ,
type _map = Store && Store . typeMapFor ( Channel ) ;
2015-07-13 21:52:44 -04:00
2016-07-13 02:06:50 -04:00
if ( type _map && type _map . records )
for ( var i = 0 ; i < type _map . records . length ; i ++ )
this . _modify _cmodel ( type _map . records [ i ] ) ;
2015-06-05 03:59:28 -04:00
this . log ( "Hooking the Ember Channel controller." ) ;
2016-03-23 20:23:04 -04:00
Channel = utils . ember _lookup ( 'controller:channel' ) ;
2015-06-05 03:59:28 -04:00
if ( ! Channel )
return ;
2015-05-17 19:02:57 -04:00
Channel . reopen ( {
2016-08-12 14:25:19 -04:00
/ * i s E d i t a b l e : f u n c t i o n ( ) {
var channel _id = this . get ( 'content.id' ) ,
user = this . get ( 'login.userData' ) ;
if ( ! user || ! user . login )
return false ;
else if ( user . login === channel _id || user . is _admin || user . is _staff )
return true ;
// Okay, have we loaded this user's editor status? Try that.
if ( f . _editor _of )
return f . _editor _of . indexOf ( channel _id ) !== - 1 ;
var t = this ;
f . get _user _editor _of ( ) . then ( function ( result ) {
// Once editor status is loaded, if the user does have editor
// status for this channel, update this property.
if ( result . indexOf ( channel _id ) !== - 1 )
Ember . propertyDidChange ( t , 'isEditable' ) ;
} ) ;
return false ;
} . property ( 'content.id' , 'login.userData' , 'login.userData.login' ) , * /
2015-05-17 19:02:57 -04:00
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-07-29 01:03:10 -04:00
ffzUpdateInfo : function ( ) {
if ( this . _ffz _update _timer )
clearTimeout ( this . _ffz _update _timer ) ;
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
if ( ! this . get ( 'content.id' ) )
return ;
2015-08-04 01:43:08 -04:00
2016-07-13 02:06:50 -04:00
this . _ffz _update _timer = setTimeout ( this . ffzCheckUpdate . bind ( this ) , 55000 + ( Math . random ( ) * 10000 ) ) ;
2015-07-29 01:03:10 -04:00
} . observes ( "content.id" ) ,
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
ffzCheckUpdate : function ( ) {
var t = this ,
id = t . get ( 'content.id' ) ;
2016-03-23 19:28:22 -04:00
id && utils . api . get ( "streams/" + id , { } , { version : 3 } )
2015-07-29 01:03:10 -04:00
. done ( function ( data ) {
if ( ! data || ! data . stream ) {
// If the stream is offline, clear its created_at time and set it to zero viewers.
2016-03-23 19:28:22 -04:00
t . set ( 'content.stream.created_at' , null ) ;
t . set ( 'content.stream.viewers' , 0 ) ;
2015-07-29 01:03:10 -04:00
return ;
}
2016-03-23 19:28:22 -04:00
t . set ( 'content.stream.created_at' , data . stream . created _at || null ) ;
t . set ( 'content.stream.viewers' , data . stream . viewers || 0 ) ;
2015-07-29 01:03:10 -04:00
var game = data . stream . game || ( data . stream . channel && data . stream . channel . game ) ;
if ( game ) {
2016-03-23 19:28:22 -04:00
t . set ( 'content.game' , game ) ;
2015-07-29 01:03:10 -04:00
}
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
if ( data . stream . channel ) {
if ( data . stream . channel . status )
2016-03-23 19:28:22 -04:00
t . set ( 'content.status' , data . stream . channel . status ) ;
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
if ( data . stream . channel . views )
2016-03-23 19:28:22 -04:00
t . set ( 'content.views' , data . stream . channel . views ) ;
2015-07-29 01:03:10 -04:00
if ( data . stream . channel . followers && t . get ( 'content.followers.isLoaded' ) )
t . set ( 'content.followers.total' , data . stream . channel . followers ) ;
}
} )
. always ( function ( data ) {
t . ffzUpdateInfo ( ) ;
} ) ;
} ,
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 ( ) ;
2016-08-09 20:45:28 -04:00
} . observes ( "content.status" , "content.game" , "content.id" , "hostModeTarget.status" , "hostModeTarget.id" , "hostModeTarget.game" ) ,
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 )
2015-10-26 12:13:28 -07:00
f . ws _send ( "unsub" , "channel." + f . _ _old _host _target ) ;
2015-07-04 17:06:36 -04:00
if ( id ) {
2015-10-26 12:13:28 -07:00
f . ws _send ( "sub" , "channel." + id ) ;
2015-07-04 17:06:36 -04:00
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-12-12 13:28:35 -05:00
if ( f . _chatv )
f . _chatv . ffzUpdateHost ( target ) ;
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-08-04 01:43:08 -04:00
2016-08-12 14:25:19 -04:00
Ember . propertyDidChange ( Channel , 'isEditable' ) ;
2015-07-29 01:03:10 -04:00
Channel . ffzUpdateInfo ( ) ;
2015-06-05 03:59:28 -04:00
}
2015-05-17 19:02:57 -04:00
2016-07-13 02:06:50 -04:00
FFZ . prototype . _modify _cmodel = function ( model ) {
2015-06-05 03:59:28 -04:00
var f = this ;
2016-07-13 02:06:50 -04:00
model . reopen ( {
ffz _host _target : undefined ,
2015-05-17 19:02:57 -04:00
2016-07-13 02:06:50 -04:00
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
}
2016-07-13 02:06:50 -04:00
}
} ) ;
}
2015-05-17 19:02:57 -04:00
2015-06-05 03:59:28 -04:00
2016-07-13 02:06:50 -04:00
FFZ . prototype . modify _channel _index = function ( view ) {
var f = this ;
utils . ember _reopen _view ( view , {
ffz _init : function ( ) {
2016-03-23 19:28:22 -04:00
var id = this . get ( 'controller.content.id' ) || this . get ( 'controller.id' ) ,
2015-07-04 17:06:36 -04:00
el = this . get ( 'element' ) ;
2015-06-05 03:59:28 -04:00
f . _cindex = this ;
2015-10-26 12:13:28 -07:00
f . ws _send ( "sub" , "channel." + id ) ;
2015-07-04 17:06:36 -04:00
el . setAttribute ( 'data-channel' , id ) ;
el . classList . add ( 'ffz-channel' ) ;
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-07-29 01:03:10 -04:00
this . ffzUpdatePlayerStats ( ) ;
2015-06-05 03:59:28 -04:00
2016-07-13 02:06:50 -04:00
// Listen to scrolling.
this . _ffz _scroller = this . ffzOnScroll . bind ( this ) ;
jQuery ( el ) . parents ( '.tse-scroll-content' ) . on ( 'scroll' , this . _ffz _scroller ) ;
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-07-31 17:44:20 -04:00
if ( f . settings . auto _theater ) {
2016-06-22 14:23:03 -04:00
var player = f . players && f . players [ id ] && f . players [ id ] . get ( 'player' ) ;
if ( player )
player . setTheatre ( true ) ;
2015-07-31 17:44:20 -04:00
}
2016-05-06 02:23:12 -04:00
this . $ ( ) . on ( "click" , ".ffz-creative-tag-link" , function ( e ) {
if ( e . button !== 0 || e . altKey || e . ctrlKey || e . shiftKey || e . metaKey )
return ;
utils . ember _lookup ( "router:main" ) . transitionTo ( 'creative.hashtag.index' , this . getAttribute ( 'data-tag' ) ) ;
e . preventDefault ( ) ;
return false ;
} ) ;
2015-06-05 03:59:28 -04:00
} ,
2016-07-13 02:06:50 -04:00
ffz _destroy : function ( ) {
var id = this . get ( 'controller.content.id' ) || this . get ( 'controller.id' ) ;
if ( id )
f . ws _send ( "unsub" , "channel." + id ) ;
this . get ( 'element' ) . setAttribute ( 'data-channel' , '' ) ;
f . _cindex = undefined ;
if ( this . _ffz _update _uptime )
clearTimeout ( this . _ffz _update _uptime ) ;
if ( this . _ffz _update _stats )
clearTimeout ( this . _ffz _update _stats ) ;
if ( this . _ffz _scroller ) {
jQuery ( this . get ( 'element' ) ) . parents ( '.tse-scroll-content' ) . off ( 'scroll' , this . _ffz _scroller ) ;
this . _ffz _scroller = null ;
}
document . body . classList . remove ( 'ffz-small-player' ) ;
utils . update _css ( f . _channel _style , id , null ) ;
} ,
ffzOnScroll : function ( event ) {
// When we scroll past the bottom of the player, do stuff!
var top = event && event . target && event . target . scrollTop ,
height = this . get ( 'layout.playerSize.1' ) ;
2016-07-13 02:31:26 -04:00
if ( ! top )
top = jQuery ( this . get ( 'element' ) ) . parents ( '.tse-scroll-content' ) . scrollTop ( ) ;
2016-07-13 02:06:50 -04:00
document . body . classList . toggle ( 'ffz-small-player' , f . settings . small _player && top >= height ) ;
} ,
2015-06-05 03:59:28 -04:00
ffzFixTitle : function ( ) {
if ( f . has _bttv || ! f . settings . stream _title )
return ;
2016-05-06 02:23:12 -04:00
var status = this . get ( "controller.content.status" ) ,
channel = this . get ( "controller.content.id" ) ,
game = this . get ( "controller.content.game" ) ,
2015-06-05 03:59:28 -04:00
2016-05-06 02:23:12 -04:00
tokens = f . tokenize _line ( channel , channel , status , true ) ;
2015-06-05 03:59:28 -04:00
2016-05-06 02:23:12 -04:00
if ( game === 'Creative' )
tokens = f . tokenize _ctags ( tokens ) ;
this . $ ( "#broadcast-meta .title" ) . html ( f . render _tokens ( tokens ) ) ;
status = this . get ( 'controller.hostModeTarget.status' ) ;
channel = this . get ( 'controller.hostModeTarget.id' ) ;
game = this . get ( 'controller.hostModeTarget.game' ) ;
if ( channel ) {
tokens = f . tokenize _line ( channel , channel , status , true ) ;
if ( game === 'Creative' )
tokens = f . tokenize _ctags ( tokens ) ;
this . $ ( ".target-meta .target-title" ) . html ( f . render _tokens ( tokens ) ) ;
}
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 ( ) {
2016-03-23 19:28:22 -04:00
var channel _id = this . get ( 'controller.content.id' ) || this . get ( 'controller.id' ) ,
2015-07-13 21:52:44 -04:00
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 ,
2015-08-04 01:43:08 -04:00
hosts _left = room && room . ffz _hosts _left ,
2015-07-13 21:52:44 -04:00
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' ;
2016-06-22 14:23:03 -04:00
btn . className = 'button button--text' ;
2015-08-04 01:43:08 -04:00
2016-05-25 01:06:27 -04:00
btn . addEventListener ( 'click' , this . ffzClickHost . bind ( this , false ) ) ;
2015-08-04 01:43:08 -04:00
2015-07-31 17:44:20 -04:00
var before ;
try { before = container . querySelector ( ':scope > .theatre-button' ) ; }
catch ( err ) { before = undefined ; }
2015-08-04 01:43:08 -04:00
2015-07-13 21:52:44 -04:00
if ( before )
container . insertBefore ( btn , before ) ;
else
container . appendChild ( btn ) ;
2015-11-14 23:52:49 -05:00
jQuery ( btn ) . tipsy ( { html : true , gravity : utils . tooltip _placement ( constants . TOOLTIP _DISTANCE , 'n' ) } ) ;
2015-07-13 21:52:44 -04:00
}
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.' ;
}
}
2015-08-04 01:43:08 -04:00
2015-07-13 21:52:44 -04:00
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' ;
2016-06-22 14:23:03 -04:00
btn . className = 'button button--text' ;
2015-08-04 01:43:08 -04:00
2016-05-25 01:06:27 -04:00
btn . addEventListener ( 'click' , this . ffzClickHost . bind ( this , true ) ) ;
2015-08-04 01:43:08 -04:00
2015-07-31 17:44:20 -04:00
var before ;
try { before = container . querySelector ( ':scope > .theatre-button' ) ; }
catch ( err ) { before = undefined ; }
2015-07-13 21:52:44 -04:00
if ( before )
container . insertBefore ( btn , before ) ;
else
container . appendChild ( btn ) ;
2015-11-14 23:52:49 -05:00
jQuery ( btn ) . tipsy ( { html : true , gravity : utils . tooltip _placement ( constants . TOOLTIP _DISTANCE , 'n' ) } ) ;
2015-07-13 21:52:44 -04:00
}
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.' ;
}
2015-08-04 01:43:08 -04:00
}
2015-07-13 21:52:44 -04:00
} ,
2015-08-04 01:43:08 -04:00
2016-05-25 01:06:27 -04:00
ffzClickHost : function ( is _host , e ) {
var btn = e . target ,
target = is _host ? this . get ( 'controller.hostModeTarget.id' ) : ( this . get ( 'controller.content.id' ) || this . get ( 'controller.id' ) ) ,
2015-07-13 21:52:44 -04:00
user = f . get _user ( ) ,
room = user && f . rooms && f . rooms [ user . login ] && f . rooms [ user . login ] . room ,
now _hosting = room && room . ffz _host _target ;
2016-05-25 01:06:27 -04:00
if ( ! room || this . get ( 'ffz_host_updating' ) )
2015-07-13 21:52:44 -04:00
return ;
2016-05-25 01:06:27 -04:00
btn . classList . add ( 'disabled' ) ;
btn . title = 'Updating...' ;
2015-07-13 21:52:44 -04:00
2016-05-25 01:06:27 -04:00
this . set ( 'ffz_host_updating' , true ) ;
2015-07-13 21:52:44 -04:00
if ( now _hosting === target )
2015-10-17 18:05:44 -04:00
room . send ( "/unhost" , true ) ;
2015-07-13 21:52:44 -04:00
else
2015-10-17 18:05:44 -04:00
room . send ( "/host " + target , true ) ;
2015-07-13 21:52:44 -04:00
} ,
2015-06-05 03:59:28 -04:00
ffzUpdateChatters : function ( ) {
// Get the counts.
2016-03-23 19:28:22 -04:00
var room _id = this . get ( 'controller.content.id' ) || this . get ( 'controller.id' ) ,
2015-06-05 03:59:28 -04:00
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-11-14 23:52:49 -05:00
jQuery ( stat ) . tipsy ( { html : true , gravity : utils . tooltip _placement ( constants . TOOLTIP _DISTANCE , 'n' ) } ) ;
2015-06-05 03:59:28 -04:00
}
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-11-14 23:52:49 -05:00
jQuery ( stat ) . tipsy ( { html : true , gravity : utils . tooltip _placement ( constants . TOOLTIP _DISTANCE , 'n' ) } ) ;
2015-06-05 03:59:28 -04:00
}
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-07-29 01:03:10 -04:00
ffzUpdatePlayerStats : function ( ) {
2016-07-13 02:06:50 -04:00
if ( this . _ffz _update _stats ) {
clearTimeout ( this . _ffz _update _stats ) ;
this . _ffz _update _stats = null ;
}
// Schedule an update.
if ( f . settings . player _stats )
this . _ffz _update _stats = setTimeout ( this . ffzUpdatePlayerStats . bind ( this ) , 1000 ) ;
2016-03-23 19:28:22 -04:00
var channel _id = this . get ( 'controller.content.id' ) || this . get ( 'controller.id' ) ,
2015-07-29 01:03:10 -04:00
hosted _id = this . get ( 'controller.hostModeTarget.id' ) ,
el = this . get ( 'element' ) ;
if ( channel _id ) {
var container = el && el . querySelector ( '.stats-and-actions .channel-stats' ) ,
stat _el = container && container . querySelector ( '#ffz-ui-player-stats' ) ,
el = stat _el && stat _el . querySelector ( 'span' ) ,
2016-07-13 03:54:42 -04:00
je ,
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
player _cont = f . players && f . players [ channel _id ] ,
2015-11-01 17:28:19 -05:00
player = undefined , stats = undefined ;
try {
2016-03-23 19:28:22 -04:00
player = player _cont && player _cont . get && player _cont . get ( 'player' ) ;
2016-07-13 02:06:50 -04:00
stats = player && player . getVideoInfo ( ) ;
2015-11-01 17:28:19 -05:00
} catch ( err ) {
2016-07-13 02:06:50 -04:00
f . error ( "Channel ffzUpdatePlayerStats: player.getVideoInfo: " + err ) ;
2015-11-01 17:28:19 -05:00
}
2015-07-29 01:03:10 -04:00
2016-07-13 02:06:50 -04:00
if ( ! container || ! f . settings . player _stats || ! stats || ! stats . hls _latency _broadcaster || Number . isNaN ( stats . hls _latency _broadcaster ) ) {
2015-07-29 01:03:10 -04:00
if ( stat _el )
stat _el . parentElement . removeChild ( stat _el ) ;
} else {
if ( ! stat _el ) {
stat _el = document . createElement ( 'span' ) ;
stat _el . id = 'ffz-ui-player-stats' ;
2015-11-14 23:52:49 -05:00
stat _el . className = 'ffz stat' ;
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
stat _el . innerHTML = constants . GRAPH + " " ;
el = document . createElement ( 'span' ) ;
stat _el . appendChild ( el ) ;
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
var other = container . querySelector ( '#ffz-uptime-display' ) ;
if ( other )
container . insertBefore ( stat _el , other . nextSibling ) ;
else
container . appendChild ( stat _el ) ;
2015-11-14 23:52:49 -05:00
2016-07-13 03:54:42 -04:00
je = jQuery ( stat _el ) ;
je . hover (
function ( ) { je . data ( "hover" , true ) . tipsy ( "show" ) } ,
function ( ) { je . data ( "hover" , false ) . tipsy ( "hide" ) } )
. data ( "hover" , false )
. tipsy ( { trigger : 'manual' , html : true , gravity : utils . tooltip _placement ( constants . TOOLTIP _DISTANCE , 'n' ) } ) ;
} else
je = jQuery ( stat _el ) ;
2015-08-04 01:43:08 -04:00
2016-07-13 02:06:50 -04:00
var delay = Math . round ( stats . hls _latency _broadcaster / 10 ) / 100 ,
2016-08-09 20:45:28 -04:00
dropped = utils . number _commas ( stats . dropped _frames || 0 ) ,
bitrate ;
if ( stats . playback _bytes _per _second )
2016-07-13 03:54:42 -04:00
bitrate = Math . round ( stats . playback _bytes _per _second * 8 / 10.24 ) / 100 ;
2016-08-09 20:45:28 -04:00
else
bitrate = Math . round ( stats . current _bitrate * 100 ) / 100 ;
2015-10-17 18:05:44 -04:00
if ( delay > 180 ) {
delay = Math . floor ( delay ) ;
2016-08-09 20:45:28 -04:00
stat _el . setAttribute ( 'original-title' , 'Video Information<br>Broadcast ' + utils . time _to _string ( delay , true ) + ' Ago<br><br>Video: ' + stats . vid _width + 'x' + stats . vid _height + 'p @ ' + stats . current _fps + '<br>Playback Rate: ' + bitrate + ' Kbps<br>Dropped Frames: ' + dropped ) ;
2015-10-17 18:05:44 -04:00
el . textContent = utils . time _to _string ( Math . floor ( delay ) , true , delay > 172800 ) + ' old' ;
} else {
2016-08-09 20:45:28 -04:00
stat _el . setAttribute ( 'original-title' , 'Stream Latency<br>Video: ' + stats . vid _width + 'x' + stats . vid _height + 'p @ ' + stats . current _fps + '<br>Playback Rate: ' + bitrate + ' Kbps<br>Dropped Frames: ' + dropped ) ;
2016-07-13 02:06:50 -04:00
delay = delay . toString ( ) ;
var ind = delay . indexOf ( '.' ) ;
if ( ind === - 1 )
2015-10-17 18:05:44 -04:00
delay = delay + '.00' ;
2016-07-13 02:06:50 -04:00
else if ( ind >= delay . length - 2 )
2015-10-17 18:05:44 -04:00
delay = delay + '0' ;
el . textContent = delay + 's' ;
}
2016-07-13 03:54:42 -04:00
if ( je . data ( "hover" ) )
je . tipsy ( "hide" ) . tipsy ( "show" ) ;
2015-07-29 01:03:10 -04:00
}
}
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
if ( hosted _id ) {
var container = el && el . querySelector ( '#hostmode .channel-stats' ) ,
stat _el = container && container . querySelector ( '#ffz-ui-player-stats' ) ,
el = stat _el && stat _el . querySelector ( 'span' ) ,
2016-07-13 03:54:42 -04:00
je ,
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
player _cont = f . players && f . players [ hosted _id ] ,
2015-11-01 17:28:19 -05:00
player = undefined , stats = undefined ;
try {
player = player _cont && player _cont . ffz _player ;
2016-07-13 03:54:42 -04:00
stats = player && player . getVideoInfo ( ) ;
2015-11-01 17:28:19 -05:00
} catch ( err ) {
2016-07-13 03:54:42 -04:00
f . error ( "Channel ffzUpdatePlayerStats: player.getVideoInfo: " + err ) ;
2015-11-01 17:28:19 -05:00
}
2015-07-29 01:03:10 -04:00
2016-07-13 02:06:50 -04:00
if ( ! container || ! f . settings . player _stats || ! stats || ! stats . hls _latency _broadcaster || Number . isNaN ( stats . hls _latency _broadcaster ) ) {
2015-07-29 01:03:10 -04:00
if ( stat _el )
stat _el . parentElement . removeChild ( stat _el ) ;
} else {
if ( ! stat _el ) {
stat _el = document . createElement ( 'span' ) ;
stat _el . id = 'ffz-ui-player-stats' ;
2015-11-14 23:52:49 -05:00
stat _el . className = 'ffz stat' ;
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
stat _el . innerHTML = constants . GRAPH + " " ;
el = document . createElement ( 'span' ) ;
stat _el . appendChild ( el ) ;
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
var other = container . querySelector ( '#ffz-uptime-display' ) ;
if ( other )
container . insertBefore ( stat _el , other . nextSibling ) ;
else
container . appendChild ( stat _el ) ;
2015-11-14 23:52:49 -05:00
2016-07-13 03:54:42 -04:00
je = jQuery ( stat _el ) ;
je . hover (
function ( ) { je . data ( "hover" , true ) . tipsy ( "show" ) } ,
function ( ) { je . data ( "hover" , false ) . tipsy ( "hide" ) } )
. data ( "hover" , false )
. tipsy ( { trigger : 'manual' , html : true , gravity : utils . tooltip _placement ( constants . TOOLTIP _DISTANCE , 'n' ) } ) ;
} else
je = jQuery ( stat _el ) ;
2015-08-04 01:43:08 -04:00
2016-07-13 02:06:50 -04:00
var delay = Math . round ( stats . hls _latency _broadcaster / 10 ) / 100 ,
2016-08-09 20:45:28 -04:00
dropped = utils . number _commas ( stats . dropped _frames || 0 ) ,
bitrate ;
if ( stats . playback _bytes _per _second )
2016-07-13 03:54:42 -04:00
bitrate = Math . round ( stats . playback _bytes _per _second * 8 / 10.24 ) / 100 ;
2016-08-09 20:45:28 -04:00
else
bitrate = Math . round ( stats . current _bitrate * 100 ) / 100 ;
2015-10-17 18:05:44 -04:00
if ( delay > 180 ) {
delay = Math . floor ( delay ) ;
2016-08-09 20:45:28 -04:00
stat _el . setAttribute ( 'original-title' , 'Video Information<br>Broadcast ' + utils . time _to _string ( delay , true ) + ' Ago<br><br>Video: ' + stats . vid _width + 'x' + stats . vid _height + 'p @ ' + stats . current _fps + '<br>Playback Rate: ' + bitrate + ' Kbps<br>Dropped Frames: ' + dropped ) ;
2015-10-17 18:05:44 -04:00
el . textContent = utils . time _to _string ( Math . floor ( delay ) , true , delay > 172800 ) + ' old' ;
} else {
2016-08-09 20:45:28 -04:00
stat _el . setAttribute ( 'original-title' , 'Stream Latency<br>Video: ' + stats . vid _width + 'x' + stats . vid _height + 'p @ ' + stats . current _fps + '<br>Playback Rate: ' + bitrate + ' Kbps<br>Dropped Frames: ' + dropped ) ;
2016-07-13 02:06:50 -04:00
delay = delay . toString ( ) ;
var ind = delay . indexOf ( '.' ) ;
if ( ind === - 1 )
2015-10-17 18:05:44 -04:00
delay = delay + '.00' ;
2016-07-13 02:06:50 -04:00
else if ( ind >= delay . length - 2 )
2015-10-17 18:05:44 -04:00
delay = delay + '0' ;
el . textContent = delay + 's' ;
}
2016-07-13 03:54:42 -04:00
if ( je . data ( "hover" ) )
je . tipsy ( "hide" ) . tipsy ( "show" ) ;
2015-07-29 01:03:10 -04:00
}
2015-08-04 01:43:08 -04:00
}
2015-07-29 01:03:10 -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.
2015-11-19 02:45:56 -05:00
var online = this . get ( "controller.content.stream.created_at" ) ,
now = Date . now ( ) - ( f . _ws _server _offset || 0 ) ;
2015-07-29 01:03:10 -04:00
online = online && utils . parse _date ( online ) ;
2015-06-05 03:59:28 -04:00
2015-11-19 02:45:56 -05:00
var uptime = online && Math . floor ( ( now - online . getTime ( ) ) / 1000 ) || - 1 ;
2015-07-29 01:03:10 -04:00
if ( uptime < 0 ) {
var el = this . get ( 'element' ) . querySelector ( '#ffz-uptime-display' ) ;
if ( el )
el . parentElement . removeChild ( el ) ;
2015-06-05 03:59:28 -04:00
return ;
2015-07-29 01:03:10 -04:00
}
2015-06-05 03:59:28 -04:00
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 ] ) ;
}
}
2015-11-14 23:52:49 -05:00
jQuery ( stat ) . tipsy ( { html : true , gravity : utils . tooltip _placement ( constants . TOOLTIP _DISTANCE , 'n' ) } ) ;
2015-06-05 03:59:28 -04:00
}
2015-10-17 18:05:44 -04:00
el . innerHTML = utils . time _to _string ( uptime , false , false , false , f . settings . stream _uptime === 1 || f . settings . stream _uptime === 3 ) ;
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
// ---------------
2015-07-31 17:44:20 -04:00
FFZ . settings _info . auto _theater = {
type : "boolean" ,
value : false ,
category : "Appearance" ,
no _mobile : true ,
no _bttv : true ,
name : "Automatic Theater Mode" ,
help : "Automatically enter theater mode when opening a channel."
} ;
2016-07-13 02:06:50 -04:00
FFZ . settings _info . small _player = {
type : "boolean" ,
value : false ,
no _mobile : true ,
no _bttv : true ,
category : "Appearance" ,
name : "Mini-Player on Scroll" ,
help : "When you scroll down on the page, shrink the player and put it in the upper right corner so you can still watch." ,
on _update : function ( val ) {
if ( ! val )
return document . body . classList . remove ( 'ffz-small-player' ) ;
else if ( this . _vodc )
this . _vodc . ffzOnScroll ( ) ;
else if ( this . _cindex )
this . _cindex . ffzOnScroll ( ) ;
}
}
2015-06-05 03:59:28 -04:00
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 ;
2015-08-04 01:43:08 -04:00
2015-07-13 21:52:44 -04:00
if ( ! this . _cindex )
return ;
2015-08-04 01:43:08 -04:00
2015-07-13 21:52:44 -04:00
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 = {
2015-10-17 18:05:44 -04:00
type : "select" ,
options : {
0 : "Disabled" ,
1 : "Enabled" ,
2 : "Enabled (with Seconds)" ,
3 : "Enabled (Channel Only)" ,
4 : "Enabled (Channel Only with Seconds)"
} ,
value : 1 ,
process _value : function ( val ) {
if ( val === false )
return 0 ;
if ( val === true )
return 2 ;
if ( typeof val === "string" )
return parseInt ( val || "0" ) || 0 ;
return val ;
} ,
2015-06-05 03:59:28 -04:00
2015-10-17 18:05:44 -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 ( ) ;
}
2015-10-17 18:05:44 -04:00
} ;
2015-11-07 22:56:15 -05:00
FFZ . settings _info . theater _stats = {
type : "boolean" ,
value : true ,
no _mobile : true ,
category : "Channel Metadata" ,
name : "Display on Theater Mode Hover" ,
help : "Show the channel metadata and actions over the video player in theater mode when you hover it with your mouse." ,
on _update : function ( val ) {
document . body . classList . toggle ( 'ffz-theater-stats' , val ) ;
}
} ;
2015-10-17 18:05:44 -04:00
FFZ . basic _settings . channel _info = {
type : "select" ,
options : {
0 : "Disabled" ,
1 : "Enabled" ,
2 : "Enabled (with Seconds)" ,
3 : "Enabled (Channel Only)" ,
4 : "Enabled (Channel Only with Seconds)"
} ,
category : "General" ,
name : "Stream Uptime" ,
help : "Display the current stream's uptime under the player." ,
get : function ( ) {
return this . settings . stream _uptime ;
} ,
set : function ( val ) {
if ( typeof val === 'string' )
val = parseInt ( val || "0" ) ;
this . settings . set ( 'stream_uptime' , val ) ;
}
}