1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-30 08:08:32 +00:00

3.5.22 to 3.5.30. I need to commit more. Added basic setting for Stream Uptime, made Uptime seconds configurable. Tooltip for Stream Latency includes resolution. Added Stream Uptime to the directory. Added Reset Settings button. Added customizable in-line moderation icons. Added option to show channel logos in the directory. Added option to swap columns on the dashboard. Split Minimalistic Chat into two configurable sub-options.

This commit is contained in:
SirStendec 2015-10-17 18:05:44 -04:00
parent 4072f3c82a
commit f62132cc7e
22 changed files with 1067 additions and 306 deletions

View file

@ -161,6 +161,7 @@
.ffz-dark .ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, .ffz-dark .ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box,
.ffz-dark .card, .ffz-dark .card,
.ffz-dark #flyout .content, .ffz-dark #flyout .content,
.ffz-dark .whatisthis,
.ffz-dark .ui-menu, .ffz-dark .ui-menu,
.ffz-dark .dropmenu, .ffz-dark .dropmenu,
.ffz-dark .top-dropdown, .ffz-dark .top-dropdown,
@ -782,10 +783,17 @@
} }
.ffz-dark .whatisthis { .ffz-dark .whatisthis {
background-color: #333;
box-shadow: 0 0 0 1px rgba(255,255,255,0.2); box-shadow: 0 0 0 1px rgba(255,255,255,0.2);
} }
.ffz-dark .whatisthis:before {
border-top-color: #101010;
}
.ffz-dark .whatisthis:after {
border-top-color: #32323e;
}
.ffz-dark #chart_container svg rect[fill="#FFFFFF"] { .ffz-dark #chart_container svg rect[fill="#FFFFFF"] {
fill: rgb(32,32,32) !important; fill: rgb(32,32,32) !important;
} }
@ -843,6 +851,7 @@
background-color: transparent; background-color: transparent;
} }
.ffz-dark .whatisthis .actions .divider,
.ffz-dark .dash-chat-column { .ffz-dark .dash-chat-column {
border-color: rgba(255,255,255,0.2); border-color: rgba(255,255,255,0.2);
} }
@ -895,3 +904,19 @@
filter: invert(100%); filter: invert(100%);
-webkit-filter: invert(100%); -webkit-filter: invert(100%);
} }
/* Playlist */
.ffz-dark .ember-chat .chat-header {
box-shadow: inset 0 -1px 0 0 rgba(255,255,255,0.2);
}
.ffz-dark .playlist-controller,
.ffz-dark .playlist-item {
border-color: rgba(255,255,255,0.2);
}
.ffz-dark .playlist-container:not(.playlist-enabled) .playlist-item:hover,
.ffz-dark .playlist-container:not(.playlist-enabled) .ui-sortable-helper {
background-color: rgba(255,255,255,0.2);
}

View file

@ -1,38 +0,0 @@
<!DOCTYPE html>
<style>
html,body{overflow:hidden; margin:0; padding:0; background:transparent; height: 100%; position: relative }
img {
max-width: 186px; max-height: 186px;
position: absolute;
top: 50%; left: 50%;
transform: translateX(-50%) translateY(-50%);
}
</style>
<script type="text/javascript">window.onload=function(){
var IMGUR_REGEX = /(?:https?:\/\/)?(?:i\.)?imgur\.com\/(?:gallery\/)?([A-Za-z0-9]+)(?:\.(.*))?/,
GYAZO_REGEX = /(?:https?:\/\/)?(?:i\.)?gyazo\.com\/([a-z0-9]+)/,
YOUTUBE_REGEX = /^(?:https?:\/\/)?(?:m\.|www\.)?youtu(?:be\.com|\.be)\/(?:v\/|watch\/|.*?(?:embed|watch).*?v=)?([a-zA-Z0-9\-_]+)$/;
var url = location.search.substr(1),
image_url = url;
imgur = url.match(IMGUR_REGEX);
if ( imgur )
image_url = 'http://i.imgur.com/' + imgur[1] + 't.' + (imgur[2] || "png");
else {
var yt = url.match(YOUTUBE_REGEX);
if ( yt ) {
image_url = 'http://img.youtube.com/vi/' + yt[1] + '/1.jpg'
} else {
var gyazo = url.match(GYAZO_REGEX);
if ( gyazo )
image_url = 'http://i.gyazo.com/' + gyazo[1] + '.png';
}
}
var el = document.createElement('img');
el.src = image_url;
document.body.appendChild(el);
}</script>

View file

@ -431,7 +431,7 @@ FFZ.prototype._legacy_add_donors = function() {
} }
FFZ.prototype._legacy_load_bots = function(tries) { FFZ.prototype._legacy_load_bots = function(tries) {
jQuery.ajax(constants.SERVER + "script/bots.txt", {cache: false, context: this}) jQuery.ajax(constants.SERVER + "script/bots.txt", {context: this})
.done(function(data) { .done(function(data) {
this._legacy_parse_badges(data, 0, 2, "Bot (By: {})"); this._legacy_parse_badges(data, 0, 2, "Bot (By: {})");
@ -446,7 +446,7 @@ FFZ.prototype._legacy_load_bots = function(tries) {
} }
FFZ.prototype._legacy_load_donors = function(tries) { FFZ.prototype._legacy_load_donors = function(tries) {
jQuery.ajax(constants.SERVER + "script/donors.txt", {cache: false, context: this}) jQuery.ajax(constants.SERVER + "script/donors.txt", {context: this})
.done(function(data) { .done(function(data) {
this._legacy_parse_badges(data, 1, 1); this._legacy_parse_badges(data, 1, 1);

View file

@ -361,9 +361,9 @@ FFZ.prototype._modify_cindex = function(view) {
controller.set('ffz_host_updating', true); controller.set('ffz_host_updating', true);
if ( now_hosting === target ) if ( now_hosting === target )
room.send("/unhost"); room.send("/unhost", true);
else else
room.send("/host " + target); room.send("/host " + target, true);
}, },
@ -480,8 +480,25 @@ FFZ.prototype._modify_cindex = function(view) {
container.appendChild(stat_el); container.appendChild(stat_el);
} }
stat_el.title = 'Stream Latency\nFPS: ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps'; var delay = parseFloat(stats.hlsLatencyBroadcaster);
el.textContent = stats.hlsLatencyBroadcaster + 's';
if ( delay > 180 ) {
delay = Math.floor(delay);
stat_el.setAttribute('original-title', 'Video Information\nBroadcast ' + utils.time_to_string(delay, true) + ' Ago\n\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps')
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
} else {
stat_el.setAttribute('original-title', 'Stream Latency\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps');
delay = stats.hlsLatencyBroadcaster;
var pos = delay.lastIndexOf('.');
if ( pos === -1 )
delay = delay + '.00';
else if ( delay.length - pos < 3 )
delay = delay + '0';
el.textContent = delay + 's';
}
} }
} }
@ -516,8 +533,25 @@ FFZ.prototype._modify_cindex = function(view) {
container.appendChild(stat_el); container.appendChild(stat_el);
} }
stat_el.title = 'Stream Latency\nFPS: ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps'; var delay = parseFloat(stats.hlsLatencyBroadcaster);
el.textContent = stats.hlsLatencyBroadcaster + 's';
if ( delay > 180 ) {
delay = Math.floor(delay);
stat_el.setAttribute('original-title', 'Video Information\nBroadcast ' + utils.time_to_string(delay, true) + ' Ago\n\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps')
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
} else {
stat_el.setAttribute('original-title', 'Stream Latency\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps');
delay = stats.hlsLatencyBroadcaster;
var pos = delay.lastIndexOf('.');
if ( pos === -1 )
delay = delay + '.00';
else if ( delay.length - pos < 3 )
delay = delay + '0';
el.textContent = delay + 's';
}
} }
} }
}, },
@ -581,7 +615,7 @@ FFZ.prototype._modify_cindex = function(view) {
jQuery(stat).tipsy({html: true}); jQuery(stat).tipsy({html: true});
} }
el.innerHTML = utils.time_to_string(uptime); el.innerHTML = utils.time_to_string(uptime, false, false, false, f.settings.stream_uptime === 1 || f.settings.stream_uptime === 3);
}, },
ffzTeardown: function() { ffzTeardown: function() {
@ -698,10 +732,27 @@ FFZ.settings_info.stream_host_button = {
FFZ.settings_info.stream_uptime = { FFZ.settings_info.stream_uptime = {
type: "boolean", type: "select",
value: false, options: {
no_mobile: true, 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;
},
no_mobile: true,
category: "Channel Metadata", category: "Channel Metadata",
name: "Stream Uptime", name: "Stream Uptime",
help: 'Display the stream uptime under a channel by the viewer count.', help: 'Display the stream uptime under a channel by the viewer count.',
@ -726,3 +777,30 @@ FFZ.settings_info.stream_title = {
this._cindex.ffzFixTitle(); this._cindex.ffzFixTitle();
} }
}; };
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);
}
}

View file

@ -177,7 +177,7 @@ FFZ.prototype._modify_chat_input = function(component) {
// Input Control // Input Control
ffzOnInput: function() { ffzOnInput: function() {
if ( ! f._chat_style || ! f.settings.minimal_chat || is_android ) if ( ! f._chat_style || f.settings.minimal_chat < 2 || is_android )
return; return;
var now = Date.now(), var now = Date.now(),
@ -194,17 +194,17 @@ FFZ.prototype._modify_chat_input = function(component) {
var el = this.get('element'), var el = this.get('element'),
t = el && el.querySelector('textarea'); t = el && el.querySelector('textarea');
if ( ! t || ! f._chat_style || ! f.settings.minimal_chat ) if ( ! t || ! f._chat_style || f.settings.minimal_chat < 2 )
return; return;
// Unfortunately, we need to change this with CSS. // Unfortunately, we need to change this with CSS.
this._ffz_minimal_style.innerHTML = 'body.ffz-minimal-chat .ember-chat .chat-interface .textarea-contain textarea { height: auto !important; }'; this._ffz_minimal_style.innerHTML = 'body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textarea { height: auto !important; }';
var height = Math.max(32, Math.min(128, t.scrollHeight)); var height = Math.max(32, Math.min(128, t.scrollHeight));
this._ffz_minimal_style.innerHTML = 'body.ffz-minimal-chat .ember-chat .chat-interface .textarea-contain textarea { height: ' + height + 'px !important; }'; this._ffz_minimal_style.innerHTML = 'body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textarea { height: ' + height + 'px !important; }';
if ( height !== this._ffz_last_height ) { if ( height !== this._ffz_last_height ) {
utils.update_css(f._chat_style, "input_height", 'body.ffz-minimal-chat .ember-chat .chat-interface { height: ' + height + 'px !important; }' + utils.update_css(f._chat_style, "input_height", 'body.ffz-minimal-chat-input .ember-chat .chat-interface { height: ' + height + 'px !important; }' +
'body.ffz-minimal-chat .ember-chat .chat-messages, body.ffz-minimal-chat .ember-chat .chat-interface .emoticon-selector { bottom: ' + height + 'px !important; }'); 'body.ffz-minimal-chat-input .ember-chat .chat-messages, body.ffz-minimal-chat-input .ember-chat .chat-interface .emoticon-selector { bottom: ' + height + 'px !important; }');
f._roomv && f._roomv.get('stuckToBottom') && f._roomv._scrollToBottom(); f._roomv && f._roomv.get('stuckToBottom') && f._roomv._scrollToBottom();
} }

View file

@ -40,16 +40,35 @@ FFZ.basic_settings.delayed_chat = {
FFZ.settings_info.minimal_chat = { FFZ.settings_info.minimal_chat = {
type: "boolean", type: "select",
value: false, options: {
0: "Disabled",
1: "No Heading",
2: "Minimalistic Input",
3: "All"
},
value: 0,
category: "Chat Appearance", category: "Chat Appearance",
name: "Minimalistic Chat", name: "Minimalistic Chat",
help: "Hide all of the chat user interface, only showing messages and an input box.", help: "Hide all of the chat user interface, only showing messages and an input box.",
process_value: function(val) {
if ( val === false )
return 0;
else if ( val === true )
return 3;
else if ( typeof val === "string" )
return parseInt(val) || 0;
return val;
},
on_update: function(val) { on_update: function(val) {
document.body.classList.toggle("ffz-minimal-chat", val); document.body.classList.toggle("ffz-minimal-chat-head", val === 1 || val === 3);
document.body.classList.toggle("ffz-minimal-chat-input", val > 1);
if ( this.settings.group_tabs && this._chatv && this._chatv._ffz_tabs ) { if ( this.settings.group_tabs && this._chatv && this._chatv._ffz_tabs ) {
var f = this; var f = this;
setTimeout(function() { setTimeout(function() {
@ -58,11 +77,11 @@ FFZ.settings_info.minimal_chat = {
},0); },0);
} }
if ( this._chatv && this._chatv.get('controller.showList') ) if ( (val === 1 || val === 3) && this._chatv && this._chatv.get('controller.showList') )
this._chatv.set('controller.showList', false); this._chatv.set('controller.showList', false);
// Remove the style if we have it. // Remove the style if we have it.
if ( ! val && this._chat_style ) { if ( ! (val > 1) && this._chat_style ) {
if ( this._inputv ) { if ( this._inputv ) {
if ( this._inputv._ffz_minimal_style ) if ( this._inputv._ffz_minimal_style )
this._inputv._ffz_minimal_style.innerHTML = ''; this._inputv._ffz_minimal_style.innerHTML = '';
@ -73,7 +92,7 @@ FFZ.settings_info.minimal_chat = {
utils.update_css(this._chat_style, "input_height", ''); utils.update_css(this._chat_style, "input_height", '');
this._roomv && this._roomv.get('stuckToBottom') && this._roomv._scrollToBottom(); this._roomv && this._roomv.get('stuckToBottom') && this._roomv._scrollToBottom();
} else if ( this._inputv ) } else if ( val > 1 && this._inputv )
this._inputv.ffzResizeInput(); this._inputv.ffzResizeInput();
} }
}; };
@ -247,7 +266,8 @@ FFZ.settings_info.visible_rooms = {
// -------------------- // --------------------
FFZ.prototype.setup_chatview = function() { FFZ.prototype.setup_chatview = function() {
document.body.classList.toggle("ffz-minimal-chat", this.settings.minimal_chat); document.body.classList.toggle("ffz-minimal-chat-head", this.settings.minimal_chat === 1 || this.settings.minimal_chat === 3);
document.body.classList.toggle("ffz-minimal-chat-input", this.settings.minimal_chat === 2 || this.settings.minimal_chat === 3);
this.log("Hooking the Ember Chat controller."); this.log("Hooking the Ember Chat controller.");

191
src/ember/directory.js Normal file
View file

@ -0,0 +1,191 @@
var FFZ = window.FrankerFaceZ,
utils = require('../utils'),
constants = require('../constants');
// --------------------
// Settings
// --------------------
FFZ.settings_info.directory_logos = {
type: "boolean",
value: false,
category: "Appearance",
no_mobile: true,
name: "Directory Logos",
help: "Display channel logos in the Twitch directory."
};
// --------------------
// Initialization
// --------------------
FFZ.prototype.setup_directory = function() {
this.log("Hooking the Ember Directory View.");
var ChannelView = App.__container__.resolve('view:channel');
if ( ChannelView )
this._modify_directory_live(ChannelView);
var HostView = App.__container__.resolve('view:host');
if ( HostView )
this._modify_directory_host(HostView);
var VideoView = App.__container__.resolve('view:video');
if ( VideoView )
this._modify_directory_video(VideoView);
// TODO: Process existing views.
}
FFZ.prototype._modify_directory_video = function(dir) {
var f = this;
dir.reopen({
didInsertElement: function() {
this._super();
f.log("New Video View", this);
window.v = this;
}
});
try {
dir.create().destroy();
} catch(err) { }
}
FFZ.prototype._modify_directory_live = function(dir) {
var f = this;
dir.reopen({
didInsertElement: function() {
this._super();
var el = this.get('element'),
meta = el && el.querySelector('.meta'),
thumb = el && el.querySelector('.thumb'),
cap = thumb && thumb.querySelector('.cap');
if ( f.settings.stream_uptime && f.settings.stream_uptime < 3 && cap ) {
var t_el = this._ffz_uptime = document.createElement('div');
t_el.className = 'overlay_info length live';
jQuery(t_el).tipsy({html: true});
cap.appendChild(t_el);
this._ffz_uptime_timer = setInterval(this.ffzUpdateUptime.bind(this), 1000);
this.ffzUpdateUptime();
}
if ( f.settings.directory_logos ) {
el.classList.add('ffz-directory-logo');
var link = document.createElement('a'),
logo = document.createElement('img'),
t = this,
target = this.get('context.model.channel.name');
logo.className = 'profile-photo';
logo.src = this.get('context.model.channel.logo') || "http://static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_150x150.png";
logo.alt = this.get('context.model.channel.display_name');
link.href = '/' + target;
link.addEventListener('click', function(e) {
var Channel = App.__container__.resolve('model:channel');
if ( ! Channel )
return;
e.preventDefault();
t.get('controller').transitionTo('channel.index', Channel.find({id: target}).load());
return false;
});
link.appendChild(logo);
meta.insertBefore(link, meta.firstChild);
}
},
willClearRender: function() {
if ( this._ffz_uptime ) {
this._ffz_uptime.parentElement.removeChild(this._ffz_uptime);
this._ffz_uptime = null;
}
if ( this._ffz_uptime_timer )
clearInterval(this._ffz_uptime_timer);
this._super();
},
ffzUpdateUptime: function() {
var raw_created = this.get('context.model.created_at'),
up_since = raw_created && utils.parse_date(raw_created),
uptime = up_since && Math.floor((Date.now() - up_since.getTime()) / 1000) || 0;
if ( uptime > 0 ) {
this._ffz_uptime.innerHTML = constants.CLOCK + utils.time_to_string(uptime, false, false, false, f.settings.stream_uptime === 1);
this._ffz_uptime.setAttribute('original-title', 'Stream Uptime <nobr>(since ' + up_since.toLocaleString() + ')</nobr>');;
} else {
this._ffz_uptime.setAttribute('original-title', '');
this._ffz_uptime.innerHTML = '';
}
}
});
try {
dir.create().destroy();
} catch(err) { }
}
FFZ.prototype._modify_directory_host = function(dir) {
var f = this;
dir.reopen({
didInsertElement: function() {
this._super();
var el = this.get('element'),
meta = el && el.querySelector('.meta'),
thumb = el && el.querySelector('.thumb'),
cap = thumb && thumb.querySelector('.cap');
if ( f.settings.directory_logos ) {
el.classList.add('ffz-directory-logo');
var link = document.createElement('a'),
logo = document.createElement('img'),
t = this,
target = this.get('context.model.target.channel.name');
logo.className = 'profile-photo';
logo.src = this.get('context.model.target.channel.logo') || "http://static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_150x150.png";
logo.alt = this.get('context.model.target.channel.display_name');
link.href = '/' + target;
link.addEventListener('click', function(e) {
var Channel = App.__container__.resolve('model:channel');
if ( ! Channel )
return;
e.preventDefault();
t.get('controller').transitionTo('channel.index', Channel.find({id: target}).load());
return false;
});
link.appendChild(logo);
meta.insertBefore(link, meta.firstChild);
}
}
});
try {
dir.create().destroy();
} catch(err) { }
}

View file

@ -26,6 +26,26 @@ FFZ.settings_info.swap_sidebars = {
}; };
FFZ.settings_info.flip_dashboard = {
type: "boolean",
value: false,
category: "Appearance",
no_mobile: true,
no_bttv: true,
name: "Swap Dashboard Positions",
help: "Swap the positions of the left and right columns of the dashboard.",
on_update: function(val) {
if ( this.has_bttv )
return;
document.body.classList.toggle("ffz-flip-dashboard", val);
}
};
FFZ.settings_info.right_column_width = { FFZ.settings_info.right_column_width = {
type: "button", type: "button",
value: 340, value: 340,
@ -102,6 +122,22 @@ FFZ.prototype.setup_layout = function() {
}.property("windowWidth", "isRightColumnClosed", "isLeftColumnClosed", "rightColumnWidth"), }.property("windowWidth", "isRightColumnClosed", "isLeftColumnClosed", "rightColumnWidth"),
playerStyle: function() {
var h = this.get('windowHeight'),
c = this.get('PLAYER_CONTROLS_HEIGHT'),
r = this.get('contentWidth'),
i = (9 * r / 16) + c,
d = h - 120 - 60,
c = h - 94 - 185,
l = Math.floor(r),
o = Math.floor(Math.min(i, d)),
s = Math.floor(Math.min(i, c));
return "<style>.dynamic-player, .dynamic-player object, .dynamic-player video{width:" + l + "px !important;height:" + o + "px !important} .dynamic-target-player,.dynamic-target-player object, .dynamic-target-player video{width:" + l + "px !important;height:" + s + "px !important}</style><style>.dynamic-player .player object{width:100% !important; height:100% !important}</style>";
}.property("contentWidth", "windowHeight", "PLAYER_CONTROLS_HEIGHT"),
/*ffzUpdateWidth: _.throttle(function() { /*ffzUpdateWidth: _.throttle(function() {
var rc = document.querySelector('#right_close'); var rc = document.querySelector('#right_close');
if ( ! rc ) if ( ! rc )

View file

@ -27,25 +27,6 @@ FFZ.settings_info.room_status = {
}; };
FFZ.settings_info.line_purge_icon = {
type: "boolean",
value: false,
no_bttv: true,
category: "Chat Moderation",
name: "Purge Icon in Mod Icons",
help: "Display a Purge Icon in chat line Mod Icons for quickly purging users.",
on_update: function(val) {
if ( this.has_bttv )
return;
document.body.classList.toggle("ffz-chat-purge-icon", val);
}
};
FFZ.settings_info.replace_bad_emotes = { FFZ.settings_info.replace_bad_emotes = {
type: "boolean", type: "boolean",
value: true, value: true,
@ -297,18 +278,22 @@ FFZ.settings_info.chat_separators = {
options: { options: {
0: "Disabled", 0: "Disabled",
1: "Basic Line (1px solid)", 1: "Basic Line (1px solid)",
2: "3D Line (2px groove)" 2: "3D Line (2px groove)",
3: "3D Line (2px groove inset)",
4: "Wide Line (2px solid)"
}, },
value: '0', value: 0,
category: "Chat Appearance", category: "Chat Appearance",
no_bttv: true, no_bttv: true,
process_value: function(val) { process_value: function(val) {
if ( val === false ) if ( val === false )
return '0'; return 0;
else if ( val === true ) else if ( val === true )
return '1'; return 1;
else if ( typeof val === "string" )
return parseInt(val) || 0;
return val; return val;
}, },
@ -316,8 +301,10 @@ FFZ.settings_info.chat_separators = {
help: "Display thin lines between chat messages for further visual separation.", help: "Display thin lines between chat messages for further visual separation.",
on_update: function(val) { on_update: function(val) {
document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && val !== '0'); document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && val !== 0);
document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && val === '2'); document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && val === 2);
document.body.classList.toggle("ffz-chat-separator-3d-inset", !this.has_bttv && val === 3);
document.body.classList.toggle("ffz-chat-separator-wide", !this.has_bttv && val === 4);
} }
}; };
@ -543,10 +530,11 @@ FFZ.prototype.setup_line = function() {
document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && this.settings.fix_color === '-1'); document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && this.settings.fix_color === '-1');
document.body.classList.toggle('ffz-chat-background', !this.has_bttv && this.settings.chat_rows); document.body.classList.toggle('ffz-chat-background', !this.has_bttv && this.settings.chat_rows);
document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && this.settings.chat_separators !== '0'); document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && this.settings.chat_separators !== 0);
document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && this.settings.chat_separators === '2'); document.body.classList.toggle("ffz-chat-separator-wide", !this.has_bttv && this.settings.chat_separators === 4);
document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && this.settings.chat_separators === 2);
document.body.classList.toggle("ffz-chat-separator-3d-inset", !this.has_bttv && this.settings.chat_separators === 3);
document.body.classList.toggle("ffz-chat-padding", !this.has_bttv && this.settings.chat_padding); document.body.classList.toggle("ffz-chat-padding", !this.has_bttv && this.settings.chat_padding);
document.body.classList.toggle("ffz-chat-purge-icon", !this.has_bttv && this.settings.line_purge_icon);
document.body.classList.toggle("ffz-high-contrast-chat-text", !this.has_bttv && this.settings.high_contrast_chat[2] === '1'); document.body.classList.toggle("ffz-high-contrast-chat-text", !this.has_bttv && this.settings.high_contrast_chat[2] === '1');
document.body.classList.toggle("ffz-high-contrast-chat-bold", !this.has_bttv && this.settings.high_contrast_chat[1] === '1'); document.body.classList.toggle("ffz-high-contrast-chat-bold", !this.has_bttv && this.settings.high_contrast_chat[1] === '1');
@ -645,16 +633,30 @@ FFZ.prototype._modify_line = function(component) {
if ( e.target && e.target.classList.contains('mod-icon') ) { if ( e.target && e.target.classList.contains('mod-icon') ) {
jQuery(e.target).trigger('mouseout'); jQuery(e.target).trigger('mouseout');
if ( e.target.classList.contains('purge') ) { /*if ( e.target.classList.contains('purge') ) {
var i = this.get('msgObject.from'), var i = this.get('msgObject.from'),
room_id = this.get('msgObject.room'), room_id = this.get('msgObject.room'),
room = room_id && f.rooms[room_id] && f.rooms[room_id].room; room = room_id && f.rooms[room_id] && f.rooms[room_id].room;
if ( room ) { if ( room ) {
room.send("/timeout " + i + " 1"); room.send("/timeout " + i + " 1", true);
room.clearMessages(i); room.clearMessages(i);
} }
return; return;
}*/
if ( e.target.classList.contains('custom') ) {
var room_id = this.get('msgObject.room'),
room = room_id && f.rooms[room_id] && f.rooms[room_id].room,
cmd = e.target.getAttribute('data-cmd');
if ( room ) {
room.send(cmd, true);
if ( e.target.classList.contains('is-timeout') )
room.clearMessages(this.get('msgObject.from'));
}
return;
} }
} }
@ -678,7 +680,7 @@ FFZ.prototype._modify_line = function(component) {
return 4; return 4;
else if ( this.get('isBroadcaster') ) else if ( this.get('isBroadcaster') )
return 3; return 3;
else if ( this.get('isGlobalModerator') ) else if ( this.get('isGlobalMod') )
return 2; return 2;
else if ( this.get('isModerator') ) else if ( this.get('isModerator') )
return 1; return 1;
@ -712,13 +714,34 @@ FFZ.prototype._modify_line = function(component) {
if ( ! is_whisper && this_ul < other_ul ) { if ( ! is_whisper && this_ul < other_ul ) {
e.push('<span class="mod-icons float-left">'); e.push('<span class="mod-icons float-left">');
for(var i=0, l = f.settings.mod_buttons.length; i < l; i++) {
var pair = f.settings.mod_buttons[i],
prefix = pair[0], btn = pair[1],
cmd, tip;
if ( btn === false ) {
if ( deleted ) if ( deleted )
e.push('<a class="mod-icon float-left tooltip unban" title="Unban User" href="#">Unban</a>'); e.push('<a class="mod-icon float-left tooltip unban" title="Unban User" href="#">Unban</a>');
else else
e.push('<a class="mod-icon float-left tooltip ban" title="Ban User" href="#">Ban</a>'); e.push('<a class="mod-icon float-left tooltip ban" title="Ban User" href="#">Ban</a>');
} else if ( btn === 600 )
e.push('<a class="mod-icon float-left tooltip timeout" title="Timeout User (10m)" href="#">Timeout</a>'); e.push('<a class="mod-icon float-left tooltip timeout" title="Timeout User (10m)" href="#">Timeout</a>');
e.push('<a class="mod-icon float-left tooltip purge" title="Purge User (Timeout 1s)" href="#">Purge</a>');
else {
if ( typeof btn === "string" ) {
cmd = btn.replace(/{user}/g, user);
tip = 'Custom Command\n' + cmd;
} else {
cmd = "/timeout " + user + " " + btn;
tip = "Timeout User (" + utils.duration_string(btn) + ")";
}
e.push('<a class="mod-icon float-left tooltip' + (cmd.substr(0, 9) === '/timeout' ? ' is-timeout' : '') + ' custom" data-cmd="' + utils.quote_attr(cmd) + '" title="' + utils.quote_attr(tip) + '" href="#">' + prefix + '</a>');
}
}
e.push('</span>'); e.push('</span>');
} }
@ -730,7 +753,7 @@ FFZ.prototype._modify_line = function(component) {
else if ( this.get('isAdmin') ) else if ( this.get('isAdmin') )
badges[0] = {klass: 'admin', title: 'Admin'}; badges[0] = {klass: 'admin', title: 'Admin'};
else if ( this.get('isGlobalMod') ) else if ( this.get('isGlobalMod') )
badges[0] = {klass: 'global-moderator', title: 'Global Moderator'}; badges[0] = {klass: 'global-mod', title: 'Global Moderator'};
else if ( ! is_whisper && this.get('isModerator') ) else if ( ! is_whisper && this.get('isModerator') )
badges[0] = {klass: 'moderator', title: 'Moderator'}; badges[0] = {klass: 'moderator', title: 'Moderator'};
@ -881,7 +904,7 @@ FFZ.get_capitalization = function(name, callback) {
FFZ.prototype._remove_banned = function(tokens) { FFZ.prototype._remove_banned = function(tokens) {
var banned_words = this.settings.banned_words, var banned_words = this.settings.banned_words,
banned_links = this.settings.filter_bad_shorteners ? ['goo.gl', 'j.mp', 'bit.ly'] : null, banned_links = this.settings.filter_bad_shorteners ? ['apo.af', 'goo.gl', 'j.mp', 'bit.ly'] : null,
has_banned_words = banned_words && banned_words.length; has_banned_words = banned_words && banned_words.length;

View file

@ -12,33 +12,7 @@ var FFZ = window.FrankerFaceZ,
}, },
MESSAGE = '<svg class="svg-messages" height="16px" version="1.1" viewBox="0 0 18 18" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="M1,15V3h16v12H1z M15.354,5.354l-0.707-0.707L9,10.293L3.354,4.646L2.646,5.354L6.293,9l-3.646,3.646l0.707,0.707L7,9.707l1.646,1.646h0.707L11,9.707l3.646,3.646l0.707-0.707L11.707,9L15.354,5.354z" fill-rule="evenodd"></path></svg>', MESSAGE = '<svg class="svg-messages" height="16px" version="1.1" viewBox="0 0 18 18" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="M1,15V3h16v12H1z M15.354,5.354l-0.707-0.707L9,10.293L3.354,4.646L2.646,5.354L6.293,9l-3.646,3.646l0.707,0.707L7,9.707l1.646,1.646h0.707L11,9.707l3.646,3.646l0.707-0.707L11.707,9L15.354,5.354z" fill-rule="evenodd"></path></svg>',
CHECK = '<svg class="svg-unban" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path fill-rule="evenodd" clip-rule="evenodd" fill="#888888" d="M6.5,12.75L2,8.25l2-2l2.5,2.5l5.5-5.5l2,2L6.5,12.75z"/></svg>', CHECK = '<svg class="svg-unban" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path fill-rule="evenodd" clip-rule="evenodd" fill="#888888" d="M6.5,12.75L2,8.25l2-2l2.5,2.5l5.5-5.5l2,2L6.5,12.75z"/></svg>';
DURATIONS = {},
duration_string = function(val) {
if ( val === 1 )
return 'Purge';
if ( DURATIONS[val] )
return DURATIONS[val];
var weeks, days, hours, minutes, seconds;
weeks = Math.floor(val / 604800);
seconds = val % 604800;
days = Math.floor(seconds / 86400);
seconds %= 86400;
hours = Math.floor(seconds / 3600);
seconds %= 3600;
minutes = Math.floor(seconds / 60);
seconds %= 60;
var out = DURATIONS[val] = (weeks ? weeks + 'w' : '') + ((days || (weeks && (hours || minutes || seconds))) ? days + 'd' : '') + ((hours || ((weeks || days) && (minutes || seconds))) ? hours + 'h' : '') + ((minutes || ((weeks || days || hours) && seconds)) ? minutes + 'm' : '') + (seconds ? seconds + 's' : '');
return out;
};
try { try {
@ -169,6 +143,127 @@ FFZ.settings_info.mod_card_history = {
}; };
FFZ.settings_info.mod_buttons = {
type: "button",
// Special Values
// false = Ban/Unban
// integer = Timeout (that amount of time)
value: [['', false, false], ['',600, false]], //, ['', 1, false]],
category: "Chat Moderation",
no_bttv: true,
name: "Custom In-Line Moderation Icons",
help: "Change out the different in-line moderation icons to use any command quickly.",
method: function() {
var old_val = "";
for(var i=0; i < this.settings.mod_buttons.length; i++) {
var pair = this.settings.mod_buttons[i],
prefix = pair[0], cmd = pair[1], had_prefix = pair[2];
if ( cmd === false )
cmd = "<BAN>";
else if ( typeof cmd !== "string" )
cmd = '' + cmd;
if ( ! had_prefix )
prefix = '';
else
prefix += '=';
if ( cmd.substr(cmd.length - 7) === ' {user}' )
cmd = cmd.substr(0, cmd.length - 7);
if ( cmd.indexOf(' ') !== -1 )
old_val += ' ' + prefix + '"' + cmd + '"';
else
old_val += ' ' + prefix + cmd;
}
var new_val = prompt("Custom In-Line Moderation Icons\n\nPlease enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. To include spaces in a command, surround the command with double quotes (\"). Use \"{user}\" to insert the user's username into the command, otherwise it will be appended to the end.\n\nExample: !permit \"!reg add {user}\"\n\nNumeric values will become timeout buttons for that number of seconds. The text \"<BAN>\" is a special value that will act like the normal Ban button in chat.\n\nTo assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.\n\nExample: A=\"!reg add\"\n\nDefault: <BAN> 600", old_val);
if ( new_val === null || new_val === undefined )
return;
var vals = [], prefix = '';
new_val = new_val.trim();
while(new_val) {
if ( new_val.charAt(1) === '=' ) {
prefix = new_val.charAt(0);
new_val = new_val.substr(2);
continue;
}
if ( new_val.charAt(0) === '"' ) {
var end = new_val.indexOf('"', 1);
if ( end === -1 )
end = new_val.length;
var segment = new_val.substr(1, end - 1);
if ( segment ) {
vals.push([prefix, segment]);
prefix = '';
}
new_val = new_val.substr(end + 1);
} else {
var ind = new_val.indexOf(' ');
if ( ind === -1 ) {
if ( new_val ) {
vals.push([prefix, new_val]);
prefix = '';
}
new_val = '';
} else {
var segment = new_val.substr(0, ind);
if ( segment ) {
vals.push([prefix, segment]);
prefix = '';
}
new_val = new_val.substr(ind + 1);
}
}
}
var final = [];
for(var i=0; i < vals.length; i++) {
var had_prefix = false, prefix = vals[i][0], val = vals[i][1];
if ( val === "<BAN>" )
val = false;
var num = parseInt(val);
if ( num > 0 && num !== NaN )
val = num;
if ( ! prefix ) {
var tmp;
if ( typeof val === "string" )
tmp = /\w/.exec(val);
else
tmp = utils.duration_string(val);
prefix = tmp && tmp.length ? tmp[0].toUpperCase() : "C";
} else
had_prefix = true;
if ( typeof val === "string" && val.indexOf('{user}') === -1 )
val += ' {user}';
final.push([prefix, val, had_prefix]);
}
this.settings.set('mod_buttons', final);
}
};
FFZ.settings_info.mod_card_buttons = { FFZ.settings_info.mod_card_buttons = {
type: "button", type: "button",
value: [], value: [],
@ -351,6 +446,8 @@ FFZ.prototype.setup_mod_card = function() {
controller = this.get('controller'), controller = this.get('controller'),
line, line,
is_mod = controller.get('cardInfo.isModeratorOrHigher'),
user_id = controller.get('cardInfo.user.id'), user_id = controller.get('cardInfo.user.id'),
alias = f.aliases[user_id]; alias = f.aliases[user_id];
@ -384,7 +481,7 @@ FFZ.prototype.setup_mod_card = function() {
} }
// Additional Buttons // Additional Buttons
if ( f.settings.mod_card_buttons && f.settings.mod_card_buttons.length ) { if ( is_mod && f.settings.mod_card_buttons && f.settings.mod_card_buttons.length ) {
line = document.createElement('div'); line = document.createElement('div');
line.className = 'extra-interface interface clearfix'; line.className = 'extra-interface interface clearfix';
@ -394,7 +491,7 @@ FFZ.prototype.setup_mod_card = function() {
cont = App.__container__.lookup('controller:chat'), cont = App.__container__.lookup('controller:chat'),
room = cont && cont.get('currentRoom'); room = cont && cont.get('currentRoom');
room && room.send(cmd.replace(/{user}/g, user_id)); room && room.send(cmd.replace(/{user}/g, user_id), true);
}, },
add_btn_make = function(cmd) { add_btn_make = function(cmd) {
@ -446,16 +543,16 @@ FFZ.prototype.setup_mod_card = function() {
room = App.__container__.lookup('controller:chat').get('currentRoom'); room = App.__container__.lookup('controller:chat').get('currentRoom');
if ( is_mod && key == keycodes.P ) if ( is_mod && key == keycodes.P )
room.send("/timeout " + user_id + " 1"); room.send("/timeout " + user_id + " 1", true);
else if ( is_mod && key == keycodes.B ) else if ( is_mod && key == keycodes.B )
room.send("/ban " + user_id); room.send("/ban " + user_id, true);
else if ( is_mod && key == keycodes.T ) else if ( is_mod && key == keycodes.T )
room.send("/timeout " + user_id + " 600"); room.send("/timeout " + user_id + " 600", true);
else if ( is_mod && key == keycodes.U ) else if ( is_mod && key == keycodes.U )
room.send("/unban " + user_id); room.send("/unban " + user_id, true);
else if ( key != keycodes.ESC ) else if ( key != keycodes.ESC )
return; return;
@ -466,51 +563,23 @@ FFZ.prototype.setup_mod_card = function() {
// Only do the big stuff if we're mod. // Only do the big stuff if we're mod.
if ( controller.get('cardInfo.isModeratorOrHigher') ) { if ( is_mod ) {
el.classList.add('ffz-is-mod'); el.classList.add('ffz-is-mod');
// Key Handling
if ( f.settings.mod_card_hotkeys ) {
el.classList.add('no-mousetrap');
el.addEventListener('keyup', function(e) {
var key = e.keyCode || e.which,
user_id = controller.get('cardInfo.user.id'),
room = App.__container__.lookup('controller:chat').get('currentRoom');
if ( key == keycodes.P )
room.send("/timeout " + user_id + " 1");
else if ( key == keycodes.B )
room.send("/ban " + user_id);
else if ( key == keycodes.T )
room.send("/timeout " + user_id + " 600");
else if ( key == keycodes.U )
room.send("/unban " + user_id);
else if ( key != keycodes.ESC )
return;
controller.send('close');
});
}
var btn_click = function(timeout) { var btn_click = function(timeout) {
var user_id = controller.get('cardInfo.user.id'), var user_id = controller.get('cardInfo.user.id'),
room = App.__container__.lookup('controller:chat').get('currentRoom'); room = App.__container__.lookup('controller:chat').get('currentRoom');
if ( timeout === -1 ) if ( timeout === -1 )
room.send("/unban " + user_id); room.send("/unban " + user_id, true);
else else
room.send("/timeout " + user_id + " " + timeout); room.send("/timeout " + user_id + " " + timeout, true);
}, },
btn_make = function(timeout) { btn_make = function(timeout) {
var btn = document.createElement('button') var btn = document.createElement('button')
btn.className = 'button'; btn.className = 'button';
btn.innerHTML = duration_string(timeout); btn.innerHTML = utils.duration_string(timeout);
btn.title = "Timeout User for " + utils.number_commas(timeout) + " Second" + (timeout != 1 ? "s" : ""); btn.title = "Timeout User for " + utils.number_commas(timeout) + " Second" + (timeout != 1 ? "s" : "");
if ( f.settings.mod_card_hotkeys && timeout === 600 ) if ( f.settings.mod_card_hotkeys && timeout === 600 )
@ -746,7 +815,7 @@ FFZ.chat_commands.purge = function(room, args) {
for(var i=0; i < args.length; i++) { for(var i=0; i < args.length; i++) {
var name = args[i]; var name = args[i];
if ( name ) if ( name )
room.room.send("/timeout " + name + " 1"); room.room.send("/timeout " + name + " 1", true);
} }
} }
@ -760,7 +829,7 @@ FFZ.chat_commands.p.enabled = function() { return this.settings.short_commands;
FFZ.chat_commands.t = function(room, args) { FFZ.chat_commands.t = function(room, args) {
if ( ! args || ! args.length ) if ( ! args || ! args.length )
return "Timeout Usage: /t username [duration]"; return "Timeout Usage: /t username [duration]";
room.room.send("/timeout " + args.join(" ")); room.room.send("/timeout " + args.join(" "), true);
} }
FFZ.chat_commands.t.enabled = function() { return this.settings.short_commands; } FFZ.chat_commands.t.enabled = function() { return this.settings.short_commands; }
@ -776,7 +845,7 @@ FFZ.chat_commands.b = function(room, args) {
for(var i=0; i < args.length; i++) { for(var i=0; i < args.length; i++) {
var name = args[i]; var name = args[i];
if ( name ) if ( name )
room.room.send("/ban " + name); room.room.send("/ban " + name, true);
} }
} }
@ -793,7 +862,7 @@ FFZ.chat_commands.u = function(room, args) {
for(var i=0; i < args.length; i++) { for(var i=0; i < args.length; i++) {
var name = args[i]; var name = args[i];
if ( name ) if ( name )
room.room.send("/unban " + name); room.room.send("/unban " + name, true);
} }
} }

View file

@ -13,9 +13,15 @@ FFZ.settings_info.player_stats = {
category: "Channel Metadata", category: "Channel Metadata",
name: "Stream Latency", name: "Stream Latency",
help: "<i>New HTML5 Player Only.</i> Display your current stream latency (how far behind the broadcast you are) under the player, with a few useful statistics in a tooltip.", help: "Display your current stream latency (how far behind the broadcast you are) under the player, with a few useful statistics in a tooltip.",
on_update: function(val) { on_update: function(val) {
for(var key in this.players) {
var player = this.players[key];
if ( player && player.player && player.player.ffzSetStatsEnabled )
player.player.ffzSetStatsEnabled(val || player.player.ffz_stats);
}
if ( ! this._cindex ) if ( ! this._cindex )
return; return;
@ -24,11 +30,35 @@ FFZ.settings_info.player_stats = {
}; };
FFZ.settings_info.classic_player = {
type: "boolean",
value: false,
no_mobile: true,
category: "Appearance",
name: "Classic Player",
help: "Alter the appearance of the player to resemble the older Twitch player with always visible controls.",
on_update: function(val) {
document.body.classList.toggle('ffz-classic-player', val);
var Layout = window.App && App.__container__.lookup('controller:layout');
if ( Layout )
Layout.set('PLAYER_CONTROLS_HEIGHT', val ? 32 : 0);
}
};
// --------------- // ---------------
// Initialization // Initialization
// --------------- // ---------------
FFZ.prototype.setup_player = function() { FFZ.prototype.setup_player = function() {
document.body.classList.toggle('ffz-classic-player', this.settings.classic_player);
var Layout = window.App && App.__container__.lookup('controller:layout');
if ( Layout )
Layout.set('PLAYER_CONTROLS_HEIGHT', this.settings.classic_player ? 32 : 0);
this.players = {}; this.players = {};
var Player2 = App && App.__container__.resolve('component:twitch-player2'); var Player2 = App && App.__container__.resolve('component:twitch-player2');
@ -39,6 +69,9 @@ FFZ.prototype.setup_player = function() {
this._modify_player(Player2) this._modify_player(Player2)
// Modify all existing players. // Modify all existing players.
if ( ! window.Ember )
return;
for(var key in Ember.View.views) { for(var key in Ember.View.views) {
if ( ! Ember.View.views.hasOwnProperty(key) ) if ( ! Ember.View.views.hasOwnProperty(key) )
continue; continue;
@ -49,6 +82,7 @@ FFZ.prototype.setup_player = function() {
this.log("Manually updating existing Player instance.", view); this.log("Manually updating existing Player instance.", view);
try { try {
this._modify_player(view);
view.ffzInit(); view.ffzInit();
if ( view.get('player') ) if ( view.get('player') )
view.ffzPostPlayer(); view.ffzPostPlayer();
@ -65,7 +99,12 @@ FFZ.prototype.setup_player = function() {
// --------------- // ---------------
FFZ.prototype._modify_player = function(player) { FFZ.prototype._modify_player = function(player) {
var f = this; var f = this,
update_stats = function() {
f._cindex && f._cindex.ffzUpdatePlayerStats();
};
player.reopen({ player.reopen({
didInsertElement: function() { didInsertElement: function() {
this._super(); this._super();
@ -97,18 +136,17 @@ FFZ.prototype._modify_player = function(player) {
ffzInit: function() { ffzInit: function() {
var id = this.get('channel.id'); var id = this.get('channel.id');
f.players[id] = this; f.players[id] = this;
this._ffz_stat_update = this.ffzStatUpdate.bind(this);
}, },
ffzTeardown: function() { ffzTeardown: function() {
var id = this.get('channel.id'); var id = this.get('channel.id');
if ( f.players[id] === this ) if ( f.players[id] === this )
f.players[id] = undefined; f.players[id] = undefined;
},
ffzStatUpdate: function() { if ( this._ffz_stat_interval ) {
f._cindex && f._cindex.ffzUpdatePlayerStats(); clearInterval(this._ffz_stat_interval);
this._ffz_stat_interval = null;
}
}, },
ffzPostPlayer: function() { ffzPostPlayer: function() {
@ -116,32 +154,79 @@ FFZ.prototype._modify_player = function(player) {
if ( ! player ) if ( ! player )
return; return;
// Make it so stats can no longer be disabled. // Subscribe to the qualities event.
player.ffzSetStatsEnabled = player.setStatsEnabled; //player.addEventListener('qualitieschange', this.ffzQualitiesUpdated.bind(this));
player.setStatsEnabled = function() {} //this.ffzQualitiesUpdated();
// We can't just request stats straight away... // Only set up the stats hooks if we need stats.
this.ffzWaitForStats(); if ( ! player.getVideo() )
this.ffzInitStats();
}, },
ffzWaitForStats: function() { ffzInitStats: function() {
if ( this.get('ffzStatsInitialized') )
return;
var player = this.get('player'); var player = this.get('player');
if ( ! player ) if ( ! player )
return; return;
if ( player.stats ) { this.set('ffzStatsInitialized', true);
// Add the event listener.
player.addEventListener('statschange', this._ffz_stat_update); // Make it so stats can no longer be disabled if we want them.
player.ffzSetStatsEnabled = player.setStatsEnabled;
player.ffz_stats = player.getStatsEnabled();
} else {
// Keep going until we've got it.
player.ffzSetStatsEnabled(false);
var t = this; var t = this;
setTimeout(function() {
player.setStatsEnabled = function(e, s) {
if ( s !== false )
player.ffz_stats = e;
var out = player.ffzSetStatsEnabled(e || f.settings.player_stats);
if ( ! t._ffz_player_stats_initialized ) {
t._ffz_player_stats_initialized = true;
player.addEventListener('statschange', update_stats);
}
return out;
}
this._ffz_stat_interval = setInterval(function() {
if ( f.settings.player_stats || player.ffz_stats ) {
player.ffzSetStatsEnabled(false);
player.ffzSetStatsEnabled(true); player.ffzSetStatsEnabled(true);
setTimeout(t.ffzWaitForStats.bind(t), 1250);
}, 250);
} }
}, 5000);
if ( f.settings.player_stats && ! player.ffz_stats ) {
this._ffz_player_stats_initialized = true;
player.addEventListener('statschange', update_stats);
player.ffzSetStatsEnabled(true);
} }
},
ffzSetQuality: function(q) {
var player = this.get('player');
if ( ! player )
return;
this.$(".js-quality-display-contain").attr("data-q", "loading");
player.setQuality(q);
var t = this.$(".js-player-alert");
t.find(".js-player-alert__message").text();
t.attr("data-active", !0);
},
ffzGetQualities: function() {
var player = this.get('player');
if ( ! player )
return [];
return player.getQualities();
},
}); });
} }

View file

@ -1180,12 +1180,12 @@ FFZ.prototype._modify_room = function(room) {
return this._super(e); return this._super(e);
}, },
send: function(text) { send: function(text, ignore_history) {
if ( f.settings.group_tabs && f.settings.whisper_room && this.ffz_whisper_room ) if ( f.settings.group_tabs && f.settings.whisper_room && this.ffz_whisper_room )
return; return;
try { try {
if ( text ) { if ( text && ! ignore_history ) {
// Command History // Command History
var mru = this.get('mru_list'), var mru = this.get('mru_list'),
ind = mru.indexOf(text); ind = mru.indexOf(text);

View file

@ -66,7 +66,10 @@ FFZ.prototype.setup_bttv = function(delay) {
document.body.classList.remove("ffz-chat-padding"); document.body.classList.remove("ffz-chat-padding");
document.body.classList.remove("ffz-chat-separator"); document.body.classList.remove("ffz-chat-separator");
document.body.classList.remove("ffz-chat-separator-3d"); document.body.classList.remove("ffz-chat-separator-3d");
document.body.classList.remove("ffz-chat-separator-wide");
document.body.classList.remove("ffz-chat-separator-3d-inset");
document.body.classList.remove("ffz-sidebar-swap"); document.body.classList.remove("ffz-sidebar-swap");
document.body.classList.remove("ffz-flip-dashboard");
document.body.classList.remove("ffz-transparent-badges"); document.body.classList.remove("ffz-transparent-badges");
document.body.classList.remove("ffz-high-contrast-chat-text"); document.body.classList.remove("ffz-high-contrast-chat-text");
document.body.classList.remove("ffz-high-contrast-chat-bg"); document.body.classList.remove("ffz-high-contrast-chat-bg");

View file

@ -17,7 +17,7 @@ FFZ.prototype.check_ff = function(tries) {
if ( ! tries ) if ( ! tries )
this.log("Checking for Feature Friday data..."); this.log("Checking for Feature Friday data...");
jQuery.ajax(constants.SERVER + "script/event.json", {cache: false, dataType: "json", context: this}) jQuery.ajax(constants.SERVER + "script/event.json", {dataType: "json", context: this})
.done(function(data) { .done(function(data) {
return this._load_ff(data); return this._load_ff(data);
}).fail(function(data) { }).fail(function(data) {

6
src/localization.js Normal file
View file

@ -0,0 +1,6 @@
var FFZ = window.FrankerFaceZ;
FFZ.prototype.tr = function(s) {
return s;
}

View file

@ -21,7 +21,7 @@ FFZ.get = function() { return FFZ.instance; }
// Version // Version
var VER = FFZ.version_info = { var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 21, major: 3, minor: 5, revision: 30,
toString: function() { toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
} }
@ -103,6 +103,7 @@ FFZ.prototype.get_user = function() {
// ------------------- // -------------------
// Import these first to set up data structures // Import these first to set up data structures
require('./localization');
require('./ui/menu'); require('./ui/menu');
require('./settings'); require('./settings');
require('./socket'); require('./socket');
@ -111,11 +112,12 @@ require('./colors');
require('./emoticons'); require('./emoticons');
require('./badges'); require('./badges');
require('./tokenize'); require('./tokenize');
//require('./filtering');
// Analytics: require('./ember/router'); // Analytics: require('./ember/router');
require('./ember/channel'); require('./ember/channel');
//require('./ember/player'); require('./ember/player');
require('./ember/room'); require('./ember/room');
require('./ember/layout'); require('./ember/layout');
require('./ember/line'); require('./ember/line');
@ -124,6 +126,7 @@ require('./ember/viewers');
require('./ember/moderation-card'); require('./ember/moderation-card');
require('./ember/chat-input'); require('./ember/chat-input');
//require('./ember/teams'); //require('./ember/teams');
require('./ember/directory');
require('./debug'); require('./debug');
@ -158,7 +161,7 @@ FFZ.prototype.initialize = function(increment, delay) {
// Check for the player // Check for the player
if ( location.hostname === 'player.twitch.tv' ) { if ( location.hostname === 'player.twitch.tv' ) {
//this.init_player(delay); this.init_player(delay);
return; return;
} }
@ -211,6 +214,8 @@ FFZ.prototype.init_player = function(delay) {
// Literally only make it dark. // Literally only make it dark.
this.load_settings(); this.load_settings();
this.setup_dark(); this.setup_dark();
this.setup_css();
this.setup_player();
var end = (window.performance && performance.now) ? performance.now() : Date.now(), var end = (window.performance && performance.now) ? performance.now() : Date.now(),
duration = end - start; duration = end - start;
@ -279,7 +284,9 @@ FFZ.prototype.init_dashboard = function(delay) {
this.setup_tokenization(); this.setup_tokenization();
this.setup_notifications(); this.setup_notifications();
this.setup_following_count(false);
this.setup_css(); this.setup_css();
this.setup_menu();
this._update_subscribers(); this._update_subscribers();
@ -318,7 +325,9 @@ FFZ.prototype.init_ember = function(delay) {
//this.setup_router(); //this.setup_router();
this.setup_colors(); this.setup_colors();
this.setup_tokenization(); this.setup_tokenization();
//this.setup_player(); //this.setup_filtering();
this.setup_player();
this.setup_channel(); this.setup_channel();
this.setup_room(); this.setup_room();
this.setup_line(); this.setup_line();
@ -327,6 +336,7 @@ FFZ.prototype.init_ember = function(delay) {
this.setup_viewers(); this.setup_viewers();
this.setup_mod_card(); this.setup_mod_card();
this.setup_chat_input(); this.setup_chat_input();
this.setup_directory();
//this.setup_teams(); //this.setup_teams();

View file

@ -89,11 +89,37 @@ FFZ.prototype.load_settings = function() {
// Backup and Restore // Backup and Restore
// -------------------- // --------------------
FFZ.prototype.reset_settings = function() {
if ( ! confirm(this.tr('Are you sure you wish to reset FrankerFaceZ?\n\nThis will force the tab to refresh.')) )
return;
// Clear Settings
for(var key in FFZ.settings_info) {
if ( ! FFZ.settings_info.hasOwnProperty(key) )
continue;
this.settings.del(key);
}
// Clear Aliases
this.aliases = {};
localStorage.ffz_aliases = '{}';
// TODO: Filters
// Refresh
window.location.reload();
}
FFZ.prototype.save_settings_file = function() { FFZ.prototype.save_settings_file = function() {
var data = { var data = {
version: 1, version: 1,
script_version: FFZ.version_info + '', script_version: FFZ.version_info + '',
aliases: this.aliases, aliases: this.aliases,
filters: this.filters,
settings: {} settings: {}
}; };
@ -135,8 +161,8 @@ FFZ.prototype._load_settings_file = function(data) {
this.log("Loading Settings Data", data); this.log("Loading Settings Data", data);
var skipped = [], var skipped = [], applied = [],
applied = []; aliases = 0;
if ( data.settings ) { if ( data.settings ) {
for(var key in data.settings) { for(var key in data.settings) {
@ -158,9 +184,26 @@ FFZ.prototype._load_settings_file = function(data) {
} }
} }
if ( data.aliases ) {
for(var key in data.aliases) {
if ( this.aliases[key] === data.aliases[key] )
continue;
this.aliases[key] = data.aliases[key];
aliases++;
}
if ( aliases )
localStorage.ffz_aliases = JSON.stringify(this.aliases);
}
if ( data.filters ) {
// TODO: Load filters!
}
// Do this in a timeout so that any styles have a moment to update. // Do this in a timeout so that any styles have a moment to update.
setTimeout(function(){ setTimeout(function(){
alert('Successfully loaded ' + applied.length + ' settings and skipped ' + skipped.length + ' settings.'); alert('Successfully loaded ' + applied.length + ' settings and skipped ' + skipped.length + ' settings. Added ' + aliases + ' user nicknames.');
}); });
} }
@ -257,8 +300,11 @@ FFZ.menu_pages.settings = {
render_save: function(view, container) { render_save: function(view, container) {
var backup_head = document.createElement('div'), var backup_head = document.createElement('div'),
restore_head = document.createElement('div'), restore_head = document.createElement('div'),
reset_head = document.createElement('div'),
backup_cont = document.createElement('div'), backup_cont = document.createElement('div'),
restore_cont = document.createElement('div'), restore_cont = document.createElement('div'),
reset_cont = document.createElement('div'),
backup_para = document.createElement('p'), backup_para = document.createElement('p'),
backup_link = document.createElement('a'), backup_link = document.createElement('a'),
@ -268,6 +314,10 @@ FFZ.menu_pages.settings = {
restore_input = document.createElement('input'), restore_input = document.createElement('input'),
restore_link = document.createElement('a'), restore_link = document.createElement('a'),
restore_help = document.createElement('span'), restore_help = document.createElement('span'),
reset_para = document.createElement('p'),
reset_link = document.createElement('a'),
reset_help = document.createElement('span'),
f = this; f = this;
@ -310,8 +360,27 @@ FFZ.menu_pages.settings = {
restore_para.appendChild(restore_help); restore_para.appendChild(restore_help);
restore_cont.appendChild(restore_para); restore_cont.appendChild(restore_para);
reset_cont.className = 'chat-menu-content';
reset_head.className = 'heading';
reset_head.innerHTML = this.tr('Reset Settings');
reset_cont.appendChild(reset_head);
reset_para.className = 'clearfix option';
reset_link.href = '#';
reset_link.innerHTML = this.tr('Reset FrankerFaceZ');
reset_link.addEventListener('click', this.reset_settings.bind(this));
reset_help.className = 'help';
reset_help.innerHTML = this.tr('This resets all of your FFZ data. That includes chat filters, nicknames for users, and settings.');
reset_para.appendChild(reset_link);
reset_para.appendChild(reset_help);
reset_cont.appendChild(reset_para);
container.appendChild(backup_cont); container.appendChild(backup_cont);
container.appendChild(restore_cont); container.appendChild(restore_cont);
container.appendChild(reset_cont);
}, },
render_basic: function(view, container) { render_basic: function(view, container) {
@ -797,11 +866,11 @@ FFZ.prototype._setting_del = function(key) {
if ( localStorage.hasOwnProperty(ls_key) ) if ( localStorage.hasOwnProperty(ls_key) )
localStorage.removeItem(ls_key); localStorage.removeItem(ls_key);
delete this.settings[key];
if ( info ) if ( info )
val = this.settings[key] = info.hasOwnProperty("value") ? info.value : undefined; val = this.settings[key] = info.hasOwnProperty("value") ? info.value : undefined;
this.settings[key] = val;
if ( info.on_update ) if ( info.on_update )
try { try {
info.on_update.bind(this)(val, true); info.on_update.bind(this)(val, true);

View file

@ -108,7 +108,7 @@ var FFZ = window.FrankerFaceZ,
} }
image_iframe = function(href, extra_class) { image_iframe = function(href, extra_class) {
return '<iframe class="ffz-image-hover' + (extra_class ? ' ' + extra_class : '') + '" allowtransparency="true" src="' + constants.SERVER + 'script/image-proxy.html?' + utils.quote_attr(href) + '"></iframe>'; return '<iframe class="ffz-image-hover' + (extra_class ? ' ' + extra_class : '') + '" allowtransparency="true" src="' + constants.SERVER + 'script/img-proxy.html#' + utils.quote_attr(href) + '"></iframe>';
}, },
@ -352,7 +352,7 @@ FFZ.prototype.setup_tokenization = function() {
// --------------------- // ---------------------
FFZ.prototype.load_twitch_emote_data = function(tries) { FFZ.prototype.load_twitch_emote_data = function(tries) {
jQuery.ajax(constants.SERVER + "script/twitch_emotes.json", {cache: false, context: this}) jQuery.ajax(constants.SERVER + "script/twitch_emotes.json", {context: this})
.done(function(data) { .done(function(data) {
for(var set_id in data) { for(var set_id in data) {
var set = data[set_id]; var set = data[set_id];

View file

@ -50,11 +50,11 @@ FFZ.basic_settings.minimalistic_chat = {
help: "Hide all of chat except messages and the input box and reduce chat margins.", help: "Hide all of chat except messages and the input box and reduce chat margins.",
get: function() { get: function() {
return this.settings.minimal_chat && this.settings.chat_padding; return this.settings.minimal_chat === 3 && this.settings.chat_padding;
}, },
set: function(val) { set: function(val) {
this.settings.set('minimal_chat', val); this.settings.set('minimal_chat', val ? 3 : 0);
this.settings.set('chat_padding', val); this.settings.set('chat_padding', val);
} }
}; };

View file

@ -2,6 +2,8 @@ var FFZ = window.FrankerFaceZ,
constants = require('../constants'); constants = require('../constants');
FFZ.prototype.setup_css = function() { FFZ.prototype.setup_css = function() {
document.body.classList.toggle('ffz-flip-dashboard', this.settings.flip_dashboard);
this.log("Injecting main FrankerFaceZ CSS."); this.log("Injecting main FrankerFaceZ CSS.");
var s = this._main_style = document.createElement('link'); var s = this._main_style = document.createElement('link');
@ -11,6 +13,7 @@ FFZ.prototype.setup_css = function() {
s.setAttribute('href', constants.SERVER + "script/style.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info)); s.setAttribute('href', constants.SERVER + "script/style.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info));
document.head.appendChild(s); document.head.appendChild(s);
if ( window.jQuery && jQuery.noty )
jQuery.noty.themes.ffzTheme = { jQuery.noty.themes.ffzTheme = {
name: "ffzTheme", name: "ffzTheme",
style: function() { style: function() {

View file

@ -15,6 +15,8 @@ var sanitize_el = document.createElement('span'),
R_LT = /</g, R_LT = /</g,
R_GT = />/g, R_GT = />/g,
DURATIONS = {},
quote_attr = function(msg) { quote_attr = function(msg) {
return msg.replace(R_AMP, "&amp;").replace(R_QUOTE, "&quot;").replace(R_SQUOTE, "&apos;").replace(R_LT, "&lt;").replace(R_GT, "&gt;"); return msg.replace(R_AMP, "&amp;").replace(R_QUOTE, "&quot;").replace(R_SQUOTE, "&apos;").replace(R_LT, "&lt;").replace(R_GT, "&gt;");
}, },
@ -256,7 +258,7 @@ module.exports = {
return 'less than a second'; return 'less than a second';
}, },
time_to_string: function(elapsed, separate_days, days_only, no_hours) { time_to_string: function(elapsed, separate_days, days_only, no_hours, no_seconds) {
var seconds = elapsed % 60, var seconds = elapsed % 60,
minutes = Math.floor(elapsed / 60), minutes = Math.floor(elapsed / 60),
hours = Math.floor(minutes / 60), hours = Math.floor(minutes / 60),
@ -273,7 +275,32 @@ module.exports = {
days = ( days > 0 ) ? days + " days, " : ""; days = ( days > 0 ) ? days + " days, " : "";
} }
return days + ((!no_hours || days || hours) ? ((hours < 10 ? "0" : "") + hours + ':') : '') + (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds; return days + ((!no_hours || days || hours) ? ((days && hours < 10 ? "0" : "") + hours + ':') : '') + (minutes < 10 ? "0" : "") + minutes + (no_seconds ? "" : (":" + (seconds < 10 ? "0" : "") + seconds));
},
duration_string: function(val) {
if ( val === 1 )
return 'Purge';
if ( DURATIONS[val] )
return DURATIONS[val];
var weeks, days, hours, minutes, seconds;
weeks = Math.floor(val / 604800);
seconds = val % 604800;
days = Math.floor(seconds / 86400);
seconds %= 86400;
hours = Math.floor(seconds / 3600);
seconds %= 3600;
minutes = Math.floor(seconds / 60);
seconds %= 60;
var out = DURATIONS[val] = (weeks ? weeks + 'w' : '') + ((days || (weeks && (hours || minutes || seconds))) ? days + 'd' : '') + ((hours || ((weeks || days) && (minutes || seconds))) ? hours + 'h' : '') + ((minutes || ((weeks || days || hours) && seconds)) ? minutes + 'm' : '') + (seconds ? seconds + 's' : '');
return out;
}, },
format_unread: function(count) { format_unread: function(count) {

182
style.css
View file

@ -21,20 +21,20 @@ body > div.tipsy .tipsy-arrow { opacity: 0.8; }
.ffz-hide-recent-past-broadcast .recent-past-broadcast, .ffz-hide-recent-past-broadcast .recent-past-broadcast,
.ffz-hide-view-count .stat.twitch-channel-views, .ffz-hide-view-count .stat.twitch-channel-views,
.ffz-minimal-chat .emoticon-selector-toggle, .ffz-minimal-chat-input .emoticon-selector-toggle,
.ffz-menu-replace .emoticon-selector-toggle { .ffz-menu-replace .emoticon-selector-toggle {
display: none !important; display: none !important;
} }
body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle svg, body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle svg,
body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle svg body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle svg
{ {
height: 14px; height: 14px;
width: 18px; width: 18px;
} }
body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle, body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle,
body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle { body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle {
height: 14px; height: 14px;
width: 18px; width: 18px;
top: 28px; top: 28px;
@ -43,6 +43,8 @@ body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + s
.ffz-ui-toggle svg.svg-emoticons path { fill: rgba(0,0,0,0.2); } .ffz-ui-toggle svg.svg-emoticons path { fill: rgba(0,0,0,0.2); }
.ffz-ui-toggle:hover svg.svg-emoticons path { fill: rgba(0,0,0,0.5); } .ffz-ui-toggle:hover svg.svg-emoticons path { fill: rgba(0,0,0,0.5); }
.streams .stream .content .overlay_info.live svg path,
.videos .video .content .overlay_info.live svg path { fill: #ff2020; }
.ember-chat-container.dark .ffz-ui-toggle svg.svg-emoticons path, .ember-chat-container.dark .ffz-ui-toggle svg.svg-emoticons path,
.chat-container.dark .ffz-ui-toggle svg.svg-emoticons path, .chat-container.dark .ffz-ui-toggle svg.svg-emoticons path,
@ -974,6 +976,16 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; }
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.ember-chat .mod-icons .custom {
text-indent: 0;
text-align: center;
text-decoration: none;
font-size: 18px;
font-weight: bold;
color: #888 !important;
}
/* Chat Rows */ /* Chat Rows */
.ffz-alias { font-style: italic; } .ffz-alias { font-style: italic; }
@ -1045,10 +1057,19 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; }
border-bottom: 1px solid #aaa; border-bottom: 1px solid #aaa;
} }
.ffz-chat-separator-wide .chat-line:before {
border-top: 1px solid #aaa;
}
.ffz-chat-separator-3d .chat-line:before { .ffz-chat-separator-3d .chat-line:before {
border-top: 1px solid rgba(255,255,255,0.5); border-top: 1px solid rgba(255,255,255,0.5);
} }
.ffz-chat-separator-3d-inset .chat-line:before {
border-bottom-color: rgba(255,255,255,0.5);
border-top: 1px solid #aaa;
}
.ffz-chat-separator-3d ul.chat-lines div:first-of-type .chat-line:before { .ffz-chat-separator-3d ul.chat-lines div:first-of-type .chat-line:before {
border-top: none; border-top: none;
} }
@ -1066,6 +1087,14 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; }
border-bottom-color: #000; border-bottom-color: #000;
} }
.ffz-chat-separator-wide .app-main.theatre .chat-line:before,
.ffz-chat-separator-wide .chat-container.dark .chat-line:before,
.ffz-chat-separator-wide .chat-container.force-dark .chat-line:before,
.ffz-chat-separator-wide .ember-chat-container.dark .chat-line:before,
.ffz-chat-separator-wide .ember-chat-container.force-dark .chat-line:before {
border-top-color: #000;
}
.ffz-chat-separator-3d .app-main.theatre .chat-line:before, .ffz-chat-separator-3d .app-main.theatre .chat-line:before,
.ffz-chat-separator-3d .chat-container.dark .chat-line:before, .ffz-chat-separator-3d .chat-container.dark .chat-line:before,
.ffz-chat-separator-3d .chat-container.force-dark .chat-line:before, .ffz-chat-separator-3d .chat-container.force-dark .chat-line:before,
@ -1074,6 +1103,15 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; }
border-top-color: rgba(255,255,255,0.1); border-top-color: rgba(255,255,255,0.1);
} }
.ffz-chat-separator-3d-inset .app-main.theatre .chat-line:before,
.ffz-chat-separator-3d-inset .chat-container.dark .chat-line:before,
.ffz-chat-separator-3d-inset .chat-container.force-dark .chat-line:before,
.ffz-chat-separator-3d-inset .ember-chat-container.dark .chat-line:before,
.ffz-chat-separator-3d-inset .ember-chat-container.force-dark .chat-line:before {
border-bottom-color: rgba(255,255,255,0.1);
border-top-color: #000;
}
.ffz-chat-background .chat-history .chat-line.ffz-alternate:before, .ffz-chat-background .chat-history .chat-line.ffz-alternate:before,
.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-alternate:before { .ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-alternate:before {
background-color: rgba(0,0,0, 0.1); background-color: rgba(0,0,0, 0.1);
@ -1213,6 +1251,7 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; }
display: block; display: block;
width: 80px; width: 80px;
height: 63px; height: 63px;
background-image: url("//cdn.frankerfacez.com/script/spinner-dark.png"); background-image: url("//cdn.frankerfacez.com/script/spinner-dark.png");
margin: 50px auto; margin: 50px auto;
@ -1514,9 +1553,9 @@ th.ffz-row-switch {
/* Minimalistic Chat */ /* Minimalistic Chat */
body.ffz-minimal-chat .ember-chat .chat-header, body.ffz-minimal-chat-head .ember-chat > .chat-header,
body.ffz-minimal-chat .ember-chat #ffz-group-tabs, body.ffz-minimal-chat-head .ember-chat #ffz-group-tabs,
body.ffz-minimal-chat .ember-chat .chat-buttons-container { body.ffz-minimal-chat-input .ember-chat .chat-buttons-container {
display: none !important; display: none !important;
} }
@ -1525,30 +1564,30 @@ body.ffz-minimal-chat .ember-chat .chat-interface .emoticon-selector {
bottom: 33px; bottom: 33px;
}*/ }*/
body.ffz-minimal-chat .ember-chat .chat-interface .emoticon-selector { body.ffz-minimal-chat-input .ember-chat .chat-interface .emoticon-selector {
right: 10px; right: 10px;
} }
body.ffz-minimal-chat .ember-chat .chat-interface .emoticon-selector .dropmenu { body.ffz-minimal-chat-input .ember-chat .chat-interface .emoticon-selector .dropmenu {
margin-bottom: 10px; margin-bottom: 10px;
} }
body.ffz-minimal-chat .ember-chat .chat-room { body.ffz-minimal-chat-head .ember-chat .chat-room {
top: 0 !important; top: 0 !important;
} }
body.ffz-minimal-chat .ember-chat .chat-interface { body.ffz-minimal-chat-input .ember-chat .chat-interface {
/*height: 33px !important;*/ /*height: 33px !important;*/
padding: 0; padding: 0;
} }
body.ffz-minimal-chat .ember-chat .chat-interface .textarea-contain { body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain {
top: 0 !important; top: 0 !important;
margin: 0 !important; margin: 0 !important;
height: auto; height: auto;
} }
body.ffz-minimal-chat .ember-chat .chat-interface .textarea-contain textarea { body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textarea {
/*height: 33px !important;*/ /*height: 33px !important;*/
overflow: hidden; overflow: hidden;
border-bottom: 0 !important; border-bottom: 0 !important;
@ -1983,3 +2022,118 @@ li[data-name="following"] a {
.ffz-yt-thumb { .ffz-yt-thumb {
max-height: 90px; max-height: 90px;
} }
/* Classic Player */
.ffz-classic-player .player .player-video {
position: absolute;
top: 0; bottom: 32px;
left: 0; right: 0;
}
.ffz-classic-player .player.player-isvod .player-video {
bottom: 36px;
}
.ffz-classic-player .player .player-controls-bottom {
opacity: 1;
padding-top: 0;
border-top: 1px solid #000;
border-bottom: 1px solid #000;
background: -webkit-linear-gradient(bottom, #252525, #666);
background: linear-gradient(to top, #252525, #666);
}
.ffz-classic-player .app-main.theatre .player .player-video,
.ffz-classic-player .player[data-fullscreen="true"] .player-video {
bottom: 0;
}
.ffz-classic-player .app-main.theatre .player .player-controls-bottom,
.ffz-classic-player .player[data-fullscreen="true"] .player-controls-bottom {
margin-bottom: -32px;
-webkit-transition: margin-bottom .2s ease-out;
transition: margin-bottom .2s ease-out;
}
.ffz-classic-player .app-main.theatre .player.player-isvod .player-controls-bottom,
.ffz-classic-player .player.player-isvod[data-fullscreen="true"] .player-controls-bottom {
margin-bottom: -36px;
}
.ffz-classic-player .app-main.theatre .player-column:hover .player .player-controls-bottom,
.ffz-classic-player .app-main.theatre .player-column:focus .player .player-controls-bottom,
.ffz-classic-player .player[data-fullscreen="true"][data-controls="true"] .player-controls-bottom {
margin-bottom: 0;
}
.ffz-classic-player .player .player-button {
padding-bottom: 0;
height: 30px;
}
.ffz-classic-player .player .player-slider:before,
.ffz-classic-player .player .player-button,
.ffz-classic-player .player .player-slider .ui-slider-handle,
.ffz-classic-player .player .player-seek .player-seek__time {
-webkit-filter: drop-shadow(0px 0px 1px #000);
filter: drop-shadow(0px 0px 1px #000);
}
.ffz-classic-player .player .player-slider .ui-slider-handle { background-color: #aeaeae; }
.ffz-classic-player .player .player-button svg { fill: #aeaeae; }
.ffz-classic-player .player .player-seek .player-seek__time { color: #ddd; }
.ffz-classic-player .player .player-volume__slider-container {
width: auto;
}
.ffz-classic-player .player .player-seek {
padding: 0;
}
.ffz-classic-player .player .player-seek .player-slider {
margin: -1em 0;
}
.ffz-classic-player .player .player-seek .player-seek__time-container {
position: absolute;
bottom: -12px;
left: 210px;
}
.ffz-classic-player .player .player-seek .player-seek__time + .player-seek__time:before {
content: "/";
padding: 0 5px;
opacity: 0.8;
}
/* Directory Logos */
.ffz-directory-logo .meta p { width: auto; }
.ffz-directory-logo .profile-photo {
float: left;
height: 46px;
width: 46px;
margin-right: 10px;
}
/* Flip Dashboard */
.ffz-flip-dashboard #dash_main #controls_column {
float: right;
margin-left: 20px;
margin-right: 0;
}
.ffz-flip-dashboard #dash_main .dash-chat-column {
right: inherit;
left: 0;
margin-right: 20px;
}