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 ) ;
2016-10-05 23:07:10 -04:00
document . body . classList . toggle ( 'ffz-theater-stats' , this . settings . theater _stats === 2 ) ;
document . body . classList . toggle ( 'ffz-theater-basic-stats' , this . settings . theater _stats > 0 ) ;
2016-10-01 13:43:08 -04:00
var banner _hidden = this . settings . hide _channel _banner ;
banner _hidden = banner _hidden === 1 ? this . settings . channel _bar _bottom : banner _hidden > 0 ;
utils . toggle _cls ( 'ffz-hide-channel-banner' ) ( banner _hidden ) ;
utils . toggle _cls ( 'ffz-channel-bar-bottom' ) ( this . settings . channel _bar _bottom ) ;
2016-09-30 13:09:03 -04:00
utils . toggle _cls ( 'ffz-minimal-channel-title' ) ( this . settings . channel _title _top === 2 ) ;
utils . toggle _cls ( 'ffz-channel-title-top' ) ( this . settings . channel _title _top > 0 ) ;
utils . toggle _cls ( 'ffz-minimal-channel-bar' ) ( this . settings . channel _bar _collapse ) ;
2015-05-17 19:02:57 -04:00
2016-09-30 13:09:03 -04:00
this . log ( "Hooking the Ember Channel Index redesign." ) ;
this . update _views ( 'component:channel-redesign' , this . modify _channel _redesign ) ;
2016-10-01 13:43:08 -04:00
this . update _views ( 'component:channel-redesign/live' , this . modify _channel _live ) ;
2016-09-30 13:09:03 -04:00
2016-10-11 21:41:35 -04:00
this . update _views ( 'component:share-box' , this . modify _channel _share _box ) ;
this . update _views ( 'component:channel-options' , this . modify _channel _options ) ;
this . update _views ( 'component:edit-broadcast-link' , this . modify _channel _broadcast _link ) ;
2016-10-03 18:35:32 -04:00
/ * t h i s . l o g ( " H o o k i n g t h e E m b e r C h a n n e l I n d e x c o m p o n e n t . " ) ;
2016-09-30 13:09:03 -04:00
if ( ! this . update _views ( 'component:legacy-channel' , this . modify _channel _index ) )
2016-10-03 18:35:32 -04:00
return ; * /
2015-05-17 19:02:57 -04:00
2016-07-13 02:06:50 -04:00
var f = this ,
2016-10-01 13:43:08 -04:00
Channel = utils . ember _lookup ( 'controller:channel' ) ;
2015-07-13 21:52:44 -04:00
if ( ! Channel )
2016-10-01 13:43:08 -04:00
return f . error ( "Unable to find the Ember Channel controller" ) ;
2015-06-05 03:59:28 -04:00
this . log ( "Hooking the Ember Channel controller." ) ;
2015-05-17 19:02:57 -04:00
Channel . reopen ( {
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
2016-10-02 18:01:40 -04:00
if ( ! this . get ( 'channelModel.id' ) )
2015-07-29 01:03:10 -04:00
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 ) ) ;
2016-10-02 18:01:40 -04:00
} . observes ( "channelModel" ) ,
2015-08-04 01:43:08 -04:00
2015-07-29 01:03:10 -04:00
ffzCheckUpdate : function ( ) {
var t = this ,
2016-10-02 18:01:40 -04:00
channel _id = t . get ( 'channelModel.id' ) ;
2015-07-29 01:03:10 -04:00
2016-10-02 18:01:40 -04:00
channel _id && utils . api . get ( "streams/" + channel _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-10-02 18:01:40 -04:00
t . set ( 'channelModel.stream.createdAt' , null ) ;
t . set ( 'channelModel.stream.viewers' , 0 ) ;
2015-07-29 01:03:10 -04:00
return ;
}
2016-10-02 18:01:40 -04:00
t . set ( 'channelModel.stream.createdAt' , utils . parse _date ( data . stream . created _at ) || null ) ;
t . set ( 'channelModel.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-10-02 18:01:40 -04:00
t . set ( 'channelModel.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-10-02 18:01:40 -04:00
t . set ( 'channelModel.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-10-02 18:01:40 -04:00
t . set ( 'channelModel.views' , data . stream . channel . views ) ;
2015-07-29 01:03:10 -04:00
2016-10-02 18:01:40 -04:00
if ( data . stream . channel . followers && t . get ( 'channelModel.followers.isFulfilled' ) )
t . set ( 'channelModel.followers.content.meta.total' , data . stream . channel . followers ) ;
2015-07-29 01:03:10 -04:00
}
} )
. always ( function ( data ) {
t . ffzUpdateInfo ( ) ;
} ) ;
} ,
2015-06-10 18:46:04 -04:00
ffzHostTarget : function ( ) {
2016-10-02 18:01:40 -04:00
var target = this . get ( 'channelModel.hostModeTarget' ) ,
2015-06-05 03:59:28 -04:00
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-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 ( ) ;
2016-10-02 18:01:40 -04:00
} . observes ( "channelModel.hostModeTarget" )
2015-06-05 03:59:28 -04:00
} ) ;
2015-08-04 01:43:08 -04:00
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-10-13 23:05:54 -04:00
// These have to be done in order to ensure the channel metadata all sorts correctly.
2016-10-11 21:41:35 -04:00
FFZ . prototype . modify _channel _share _box = function ( view ) {
utils . ember _reopen _view ( view , {
ffz _init : function ( ) {
this . get ( 'element' ) . classList . toggle ( 'ffz-share-box' , true )
}
} ) ;
}
FFZ . prototype . modify _channel _options = function ( view ) {
utils . ember _reopen _view ( view , {
ffz _init : function ( ) {
this . get ( 'element' ) . classList . toggle ( 'ffz-channel-options' , true )
}
} ) ;
}
FFZ . prototype . modify _channel _broadcast _link = function ( view ) {
utils . ember _reopen _view ( view , {
ffz _init : function ( ) {
this . get ( 'element' ) . classList . toggle ( 'ffz-channel-broadcast-link' , true )
}
} ) ;
}
2015-05-17 19:02:57 -04:00
2016-10-13 23:05:54 -04:00
// Channel Live
2016-10-01 13:43:08 -04:00
FFZ . prototype . modify _channel _live = function ( view ) {
2016-09-30 13:09:03 -04:00
var f = this ;
utils . ember _reopen _view ( view , {
2016-10-01 13:43:08 -04:00
ffz _host : null ,
2016-09-30 13:09:03 -04:00
ffz _init : function ( ) {
var channel _id = this . get ( "channel.id" ) ,
el = this . get ( "element" ) ;
f . _cindex = this ;
2016-10-01 13:43:08 -04:00
f . ws _sub ( "channel." + channel _id ) ;
2016-09-30 13:09:03 -04:00
2016-10-01 13:43:08 -04:00
this . ffzUpdateAttributes ( ) ;
2016-09-30 13:09:03 -04:00
this . ffzFixTitle ( ) ;
2016-10-13 23:05:54 -04:00
this . ffzUpdateMetadata ( ) ;
2016-09-30 13:09:03 -04:00
if ( f . settings . auto _theater ) {
2016-10-11 21:41:35 -04:00
var layout = this . get ( 'layout' ) ,
player = f . players && f . players [ channel _id ] && f . players [ channel _id ] . get ( 'player' ) ,
func = function ( ) {
if ( player . isLoading ( ) )
return setTimeout ( func , 500 ) ;
// In case this happens before the event bindings are in, we just set
// the layout into theater mode manually.
player . setTheatre ( true ) ;
layout . setTheatreMode ( true ) ;
}
2016-09-30 13:09:03 -04:00
if ( player )
2016-10-11 21:41:35 -04:00
func ( ) ;
2016-09-30 13:09:03 -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 ;
} ) ;
} ,
2016-10-01 13:43:08 -04:00
ffzUpdateAttributes : function ( ) {
var channel _id = this . get ( "channel.id" ) ,
hosted _id = this . get ( "channel.hostModeTarget.id" ) ,
el = this . get ( "element" ) ;
2016-09-30 13:09:03 -04:00
2016-10-01 13:43:08 -04:00
if ( hosted _id !== this . ffz _host ) {
if ( this . ffz _host )
f . ws _unsub ( "channel." + this . ffz _host ) ;
2016-09-30 13:09:03 -04:00
2016-10-01 13:43:08 -04:00
if ( hosted _id )
f . ws _sub ( "channel." + hosted _id ) ;
this . ffz _host = hosted _id ;
}
2016-09-30 13:09:03 -04:00
2016-10-01 13:43:08 -04:00
el . classList . add ( 'ffz-channel' ) ;
el . classList . toggle ( 'ffz-host' , hosted _id || false ) ;
el . setAttribute ( 'data-channel' , channel _id || '' ) ;
el . setAttribute ( 'data-hosted' , hosted _id || '' ) ;
} . observes ( 'channel.id' , 'channel.hostModeTarget' ) ,
ffz _destroy : function ( ) {
var channel _id = this . get ( "channel.id" ) ,
el = this . get ( "element" ) ;
if ( channel _id )
f . ws _unsub ( "channel." + channel _id ) ;
if ( this . ffz _host ) {
f . ws _unsub ( "channel." + this . ffz _host ) ;
this . ffz _host = null ;
}
if ( f . _cindex === this )
f . _cindex = null ;
if ( this . _ffz _update _uptime )
clearTimeout ( this . _ffz _update _uptime ) ;
if ( this . _ffz _update _stats )
clearTimeout ( this . _ffz _update _stats ) ;
document . body . classList . remove ( 'ffz-small-player' ) ;
utils . update _css ( f . _channel _style , channel _id , null ) ;
} ,
2016-09-30 13:09:03 -04:00
ffzFixTitle : function ( ) {
if ( ! f . settings . stream _title )
return ;
var channel _id = this . get ( "channel.id" ) ,
status = this . get ( "channel.status" ) ,
game = this . get ( "channel.game" ) ,
tokens = f . tokenize _line ( channel _id , channel _id , status , true ) ;
if ( game === 'Creative' )
tokens = f . tokenize _ctags ( tokens ) ;
var el = this . $ ( ".cn-metabar__title .card__title" ) ;
el && el . html ( f . render _tokens ( tokens ) ) ;
} . observes ( 'channel.id' , 'channel.status' , 'channel.game' ) ,
2016-10-13 23:05:54 -04:00
ffzUpdateMetadata : function ( key ) {
var t = this ,
keys = key ? [ key ] : Object . keys ( FFZ . channel _metadata ) ,
basic _info = [ this , this . get ( 'channel' ) ] ,
timers = this . ffz _timers = this . ffz _timers || { } ,
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
container = this . get ( 'element' ) ,
metabar = container && container . querySelector ( '.cn-metabar__more' ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
// Stop once this is destroyed.
if ( this . isDestroyed || ! metabar )
return ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
for ( var i = 0 ; i < keys . length ; i ++ )
this . _ffzUpdateStat ( keys [ i ] , basic _info , timers , metabar ) ;
} ,
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
_ffzUpdateStat : function ( key , basic _info , timers , metabar ) {
var t = this ,
info = FFZ . channel _metadata [ key ] ;
if ( ! info )
2016-09-30 13:09:03 -04:00
return ;
2016-10-13 23:05:54 -04:00
if ( timers [ key ] )
clearTimeout ( timers [ key ] ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
// Build the data we use for function calls.
var data = info . setup ? info . setup . apply ( f , basic _info ) : basic _info ,
refresh = typeof info . refresh === "function" ? info . refresh . apply ( f , data ) : info . refresh ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
// If we have a positive refresh value, schedule another go.
if ( refresh )
timers [ key ] = setTimeout ( this . ffzUpdateMetadata . bind ( this , key ) , typeof refresh === "number" ? refresh : 1000 ) ;
2016-10-11 21:41:35 -04:00
2016-10-13 23:05:54 -04:00
var el = metabar . querySelector ( '.cn-metabar__ffz[data-key="' + key + '"]' ) ,
je ,
stat ,
dynamic _tooltip = typeof info . tooltip === "function" ,
label = typeof info . label === "function" ? info . label . apply ( f , data ) : info . label ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
if ( ! label ) {
if ( el )
el . parentElement . removeChild ( el ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
if ( f . _popup && f . _popup . id === 'ffz-metadata-popup' && f . _popup . getAttribute ( 'data-key' ) === key )
f . close _popup ( ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
return ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
} else if ( ! el ) {
var btn ,
static _label = typeof info . static _label === "function" ? info . static _label . apply ( f , data ) : info . static _label ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
if ( ! static _label )
static _label = '' ;
else if ( static _label . substr ( 0 , 4 ) === '<svg' )
static _label = utils . createElement ( 'figure' , 'icon cn-metabar__icon' , static _label + ' ' ) ;
2016-10-11 21:41:35 -04:00
2016-10-13 23:05:54 -04:00
if ( info . popup ) {
btn = utils . createElement ( 'button' , 'button button--dropmenu' , static _label )
el = utils . createElement ( 'div' , 'cn-metabar__ffz flex__item ember-view balloon-wrapper inline-block' , btn ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
btn . classList . add ( info . button ? 'button--hollow' : 'button--text' ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
} else if ( info . button ) {
btn = utils . createElement ( 'button' , 'button' , static _label ) ;
el = utils . createElement ( 'div' , 'cn-metabar__ffz flex__item ember-view inline-block' , btn ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
btn . classList . add ( typeof info . button === 'string' ? info . button : 'button--hollow' ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
} else
btn = el = utils . createElement ( 'div' , 'cn-metabar__ffz flex__item' , static _label ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
el . setAttribute ( 'data-key' , key ) ;
if ( info . order )
el . style . order = info . order ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
if ( ! dynamic _tooltip && info . tooltip ) {
btn . classList . add ( 'html-tooltip' ) ;
btn . title = info . tooltip ;
}
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
stat = utils . createElement ( 'span' , 'ffz-label' ) ;
btn . appendChild ( stat ) ;
if ( dynamic _tooltip ) {
je = jQuery ( btn )
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' ) ,
title : function ( ) {
var data = [ t , t . get ( 'channel' ) ] ;
data = info . setup ? info . setup . apply ( f , data ) : data ;
return info . tooltip . apply ( f , data ) ;
}
} )
}
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
if ( info . click )
btn . addEventListener ( 'click' , function ( e ) {
if ( btn . disabled || btn . classList . contains ( 'disabled' ) )
return false ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
e . update _stat = t . _ffzUpdateStat . bind ( t , key , basic _info , timers , metabar ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
var data = [ t , t . get ( 'channel' ) ] ;
data = info . setup ? info . setup . apply ( f , data ) : data ;
data . unshift ( btn ) ;
data . unshift ( e ) ;
return info . click . apply ( f , data ) ;
} ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
if ( info . popup ) {
btn . classList . add ( 'button--dropmenu' ) ;
btn . addEventListener ( 'click' , function ( el , e ) {
if ( btn . disabled || btn . classList . contains ( 'disabled' ) )
return false ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
var popup = f . close _popup ( ) ;
if ( popup && popup . id === 'ffz-metadata-popup' && popup . getAttribute ( 'data-key' ) === key )
return ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
var data = [ t , t . get ( 'channel' ) ] ;
data = info . setup ? info . setup . apply ( f , data ) : data ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
var balloon = utils . createElement ( 'div' , 'balloon balloon--up show' ) ;
data . unshift ( balloon ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
balloon . id = 'ffz-metadata-popup' ;
balloon . setAttribute ( 'data-key' , key ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
var result = info . popup . apply ( f , data ) ;
if ( result === false )
return false ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
// Set the balloon to face away from the nearest side of the channel.
var container = t . get ( 'element' ) ,
outer = container . getBoundingClientRect ( ) ,
rect = el . getBoundingClientRect ( ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
balloon . classList . toggle ( 'balloon--right' , ( rect . left - outer . left ) > ( outer . right - rect . right ) ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
f . _popup _kill = info . on _popup _close ? function ( ) { info . on _popup _close . apply ( f , data ) } : null ;
f . _popup _allow _parent = true ;
f . _popup = balloon ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
el . appendChild ( balloon ) ;
} . bind ( this , el ) ) ;
2016-09-30 13:09:03 -04:00
}
2016-10-13 23:05:54 -04:00
metabar . appendChild ( el ) ;
el = btn ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
} else {
stat = el . querySelector ( 'span.ffz-label' ) ;
if ( dynamic _tooltip )
je = jQuery ( el ) ;
2016-09-30 13:09:03 -04:00
}
2016-10-13 23:05:54 -04:00
stat . innerHTML = label ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
if ( dynamic _tooltip && je . data ( "hover" ) )
je . tipsy ( "hide" ) . tipsy ( "show" ) ;
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
if ( info . hasOwnProperty ( 'disabled' ) )
el . classList . toggle ( 'disabled' , typeof info . disabled === "function" ? info . disabled . apply ( f , data ) : info . disabled ) ;
} ,
2016-09-30 13:09:03 -04:00
2016-10-13 23:05:54 -04:00
ffzUpdateHostButton : function ( ) {
this . set ( 'ffz_host_updating' , false ) ;
return this . ffzUpdateMetadata ( 'host' ) ;
} . observes ( 'channel.id' , 'channel.hostModeTarget.id' )
2016-10-01 13:43:08 -04:00
} ) ;
}
FFZ . prototype . modify _channel _redesign = function ( view ) {
2016-10-11 21:41:35 -04:00
var f = this ,
Layout = utils . ember _lookup ( 'service:layout' ) ;
2016-10-01 13:43:08 -04:00
utils . ember _reopen _view ( view , {
ffz _init : function ( ) {
// Twitch y u make me do dis
// (If this isn't the outer channel-redesign abort)
if ( this . parentView instanceof view )
return ;
var channel _id = this . get ( "channel.id" ) ,
el = this . get ( "element" ) ;
f . _credesign = this ;
this . ffzUpdateCoverHeight ( ) ;
el . setAttribute ( 'data-channel' , channel _id ) ;
el . classList . add ( 'ffz-channel-container' ) ;
} ,
ffz _destroy : function ( ) {
var channel _id = this . get ( "channel.id" ) ,
el = this . get ( "element" ) ;
el . setAttribute ( 'data-channel' , '' ) ;
el . classList . remove ( 'ffz-channel-container' ) ;
if ( f . _credesign === this )
f . _credesign = null ;
} ,
2016-10-11 21:41:35 -04:00
handleScroll : function ( top ) {
this . _super ( ) ;
2016-10-12 11:11:06 -04:00
var height = this . get ( 'channelCoverHeight' ) + Layout . get ( 'playerSize.1' ) ;
2016-10-11 21:41:35 -04:00
document . body . classList . toggle ( 'ffz-small-player' , f . settings . small _player && top >= ( height * . 8 ) ) ;
} ,
2016-10-01 13:43:08 -04:00
ffzUpdateCoverHeight : function ( ) {
var old _height = this . get ( 'channelCoverHeight' ) ,
setting = f . settings . hide _channel _banner ,
banner _hidden = setting === 1 ? f . settings . channel _bar _bottom : setting > 0 ,
new _height = banner _hidden ? 0 : 380 ;
this . set ( 'channelCoverHeight' , new _height ) ;
this . $ ( "#channel" ) . toggleClass ( 'ffz-bar-fixed' , this . get ( 'isFixed' ) ) ;
if ( old _height !== new _height )
this . scrollTo ( this . $scrollContainer . scrollTop ( ) + ( new _height - old _height ) ) ;
} . observes ( 'isFixed' )
2016-09-30 13:09:03 -04:00
} )
}
2016-10-03 18:35:32 -04:00
/ * F F Z . p r o t o t y p e . m o d i f y _ c h a n n e l _ i n d e x = f u n c t i o n ( v i e w ) {
2016-07-13 02:06:50 -04:00
var f = this ;
utils . ember _reopen _view ( view , {
ffz _init : function ( ) {
2016-09-30 13:09:03 -04:00
var channel _id = this . get ( 'model.id' ) ,
2015-07-04 17:06:36 -04:00
el = this . get ( 'element' ) ;
2015-06-05 03:59:28 -04:00
f . _cindex = this ;
2016-09-30 13:09:03 -04:00
f . ws _send ( "sub" , "channel." + channel _id ) ;
2015-07-04 17:06:36 -04:00
2016-09-30 13:09:03 -04:00
el . setAttribute ( 'data-channel' , channel _id ) ;
2015-07-04 17:06:36 -04:00
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-09-30 13:09:03 -04:00
var player = f . players && f . players [ channel _id ] && f . players [ channel _id ] . get ( 'player' ) ;
2016-06-22 14:23:03 -04:00
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 ( ) {
2016-09-30 13:09:03 -04:00
var channel _id = this . get ( 'model.id' ) ;
if ( channel _id )
f . ws _send ( "unsub" , "channel." + channel _id ) ;
2016-07-13 02:06:50 -04:00
this . get ( 'element' ) . setAttribute ( 'data-channel' , '' ) ;
2016-09-30 13:09:03 -04:00
if ( f . _cindex === this )
f . _cindex = null ;
2016-07-13 02:06:50 -04:00
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' ) ;
2016-09-30 13:09:03 -04:00
utils . update _css ( f . _channel _style , channel _id , null ) ;
2016-07-13 02:06:50 -04:00
} ,
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-09-30 13:09:03 -04:00
var channel _id = this . get ( 'model.id' ) ,
status = this . get ( 'model.status' ) ,
game = this . get ( 'model.game' ) ,
2015-06-05 03:59:28 -04:00
2016-09-30 13:09:03 -04:00
tokens = f . tokenize _line ( channel _id , channel _id , 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 ) ) ;
2016-09-30 13:09:03 -04:00
status = this . get ( 'hostModeTarget.status' ) ;
channel _id = this . get ( 'hostModeTarget.id' ) ;
game = this . get ( 'hostModeTarget.game' ) ;
2016-05-06 02:23:12 -04:00
2016-09-30 13:09:03 -04:00
if ( channel _id ) {
tokens = f . tokenize _line ( channel _id , channel _id , status , true ) ;
2016-05-06 02:23:12 -04:00
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-09-30 13:09:03 -04:00
var channel _id = this . get ( 'model.id' ) ,
hosted _id = this . get ( 'hostModeTarget.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 ,
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 ,
2016-09-30 13:09:03 -04:00
target = is _host ? this . get ( 'hostModeTarget.id' ) : this . get ( 'model.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-09-30 13:09:03 -04:00
var room _id = this . get ( 'model.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-09-30 13:09:03 -04:00
var channel _id = this . get ( 'model.id' ) ,
hosted _id = this . get ( 'hostModeTarget.id' ) ,
2015-07-29 01:03:10 -04:00
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 ;
}
2016-09-30 13:09:03 -04:00
var controller = utils . ember _lookup ( 'controller:channel' ) ;
if ( ! f . settings . stream _uptime || ! ( controller && controller . get ( 'isLiveAccordingToKraken' ) ) ) {
2015-06-05 03:59:28 -04:00
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.
2016-09-30 13:09:03 -04:00
var online = this . get ( "model.stream.created_at" ) ,
2015-11-19 02:45:56 -05:00
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
} ) ;
2016-10-03 18:35:32 -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
2016-10-01 13:43:08 -04:00
var Chat = utils . ember _lookup ( 'controller:chat' ) ,
room = Chat && Chat . get ( 'currentChannelRoom' ) ;
2015-08-04 01:43:08 -04:00
2016-10-01 13:43:08 -04:00
if ( room )
room . setHostMode ( {
hostTarget : room . ffz _host _target ,
recentlyJoined : true
} ) ;
2015-07-13 21:52:44 -04:00
}
} ;
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 ,
2016-10-01 14:11:49 -04:00
process _value : utils . process _int ( 1 , 0 , 2 ) ,
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
} ;
2016-09-30 13:09:03 -04:00
FFZ . settings _info . channel _bar _bottom = {
type : "boolean" ,
value : false ,
no _bttv : true ,
no _mobile : true ,
category : "Appearance" ,
name : "Channel Bar on Bottom" ,
help : "Hide the profile banner and position the channel bar at the bottom of the screen." ,
on _update : function ( val ) {
if ( this . has _bttv )
return ;
2016-10-01 13:43:08 -04:00
var banner _hidden = this . settings . hide _channel _banner ;
banner _hidden = banner _hidden === 1 ? val : banner _hidden > 0 ;
2016-09-30 13:09:03 -04:00
utils . toggle _cls ( 'ffz-channel-bar-bottom' ) ( val ) ;
2016-10-01 13:43:08 -04:00
utils . toggle _cls ( 'ffz-hide-channel-banner' ) ( banner _hidden ) ;
if ( this . _credesign )
this . _credesign . ffzUpdateCoverHeight ( ) ;
2016-09-30 13:09:03 -04:00
var Layout = utils . ember _lookup ( 'service:layout' ) ;
if ( Layout )
2016-10-02 18:01:40 -04:00
Ember . propertyDidChange ( Layout , 'ffzExtraHeight' ) ;
2016-09-30 13:09:03 -04:00
}
}
2016-10-01 13:43:08 -04:00
FFZ . settings _info . hide _channel _banner = {
type : "select" ,
options : {
0 : "Never" ,
1 : "When Channel Bar is on Bottom" ,
2 : "Always"
} ,
value : 1 ,
process _value : utils . process _int ( 1 ) ,
no _bttv : true ,
no _mobile : true ,
category : "Appearance" ,
name : "Hide Channel Banner" ,
help : "Hide the banner at the top of channel pages." ,
on _update : function ( val ) {
if ( this . has _bttv )
return ;
var is _hidden = val === 1 ? this . settings . channel _bar _bottom : val > 0 ;
utils . toggle _cls ( 'ffz-hide-channel-banner' ) ( is _hidden ) ;
if ( this . _credesign )
this . _credesign . ffzUpdateCoverHeight ( ) ;
var Layout = utils . ember _lookup ( 'service:layout' ) ;
if ( Layout )
2016-10-02 18:01:40 -04:00
Ember . propertyDidChange ( Layout , 'ffzExtraHeight' ) ;
2016-10-01 13:43:08 -04:00
}
}
2016-09-30 13:09:03 -04:00
FFZ . settings _info . channel _bar _collapse = {
type : "boolean" ,
value : false ,
no _bttv : true ,
no _mobile : true ,
category : "Appearance" ,
name : "Minimal Channel Bar" ,
help : "Slide the channel bar mostly out of view when it's not being used." ,
on _update : function ( val ) {
if ( this . has _bttv )
return ;
utils . toggle _cls ( 'ffz-minimal-channel-bar' ) ( val ) ;
var Layout = utils . ember _lookup ( 'service:layout' ) ;
if ( Layout )
2016-10-02 18:01:40 -04:00
Ember . propertyDidChange ( Layout , 'ffzExtraHeight' ) ;
2016-09-30 13:09:03 -04:00
}
}
FFZ . settings _info . channel _title _top = {
type : "select" ,
options : {
0 : "Disabled" ,
1 : "On Top" ,
2 : "On Top, Minimal"
} ,
value : 0 ,
2016-10-01 14:11:49 -04:00
process _value : utils . process _int ( 0 ) ,
2016-09-30 13:09:03 -04:00
no _bttv : true ,
no _mobile : true ,
category : "Appearance" ,
name : "Channel Title on Top" ,
help : "Display the channel title and game above the player rather than below." ,
on _update : function ( val ) {
if ( this . has _bttv )
return ;
document . body . classList . toggle ( 'ffz-minimal-channel-title' , val === 2 ) ;
document . body . classList . toggle ( 'ffz-channel-title-top' , val > 0 ) ;
var Layout = utils . ember _lookup ( 'service:layout' ) ;
if ( Layout )
2016-10-02 18:01:40 -04:00
Ember . propertyDidChange ( Layout , 'ffzExtraHeight' ) ;
2016-09-30 13:09:03 -04:00
}
}
2015-11-07 22:56:15 -05:00
FFZ . settings _info . theater _stats = {
2016-10-05 23:07:10 -04:00
type : "select" ,
options : {
0 : "Disabled" ,
1 : "Basic" ,
2 : "Full"
} ,
value : 2 ,
process _value : utils . process _int ( 2 , 0 , 2 ) ,
2015-11-07 22:56:15 -05:00
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." ,
2016-10-05 23:07:10 -04:00
2015-11-07 22:56:15 -05:00
on _update : function ( val ) {
2016-10-05 23:07:10 -04:00
document . body . classList . toggle ( 'ffz-theater-stats' , val === 2 ) ;
document . body . classList . toggle ( 'ffz-theater-basic-stats' , val > 0 ) ;
2015-11-07 22:56:15 -05:00
}
} ;
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 ) ;
}
}