1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-09 07:40:53 +00:00

3.5.271 to 3.5.284. As usual, I only remember to commit when someone mentions it.

This commit is contained in:
SirStendec 2016-09-09 17:34:20 -04:00
parent 9592dc1c2c
commit 8db999a8a8
29 changed files with 1388 additions and 317 deletions

View file

@ -1,3 +1,86 @@
<div class="list-header">3.5.284</div>
<ul class="chat-menu-content menu-side-padding">
<li>Changed: Inject FFZ emotes into the BetterTTV tab completion list.</li>
</ul>
<div class="list-header">3.5.283</div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Support for moderation logging. When possible, messages are combined to avoid filling chat with nonsense.</li>
</ul>
<div class="list-header">3.5.282</div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Height of classic player theme controls when in theater mode.</li>
</ul>
<div class="list-header">3.5.281</div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Option to hide whispers on embedded chat.</li>
</ul>
<div class="list-header">3.5.280</div>
<ul class="chat-menu-content menu-side-padding">
<li>Changed: Use new display name formatting logic in more places.</li>
<li>Fixed: Aliases now appear for moderation cards again.</li>
</ul>
<div class="list-header">3.5.279</div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Dark CSS tweaks for non-Ember pages.</li>
</ul>
<div class="list-header">3.5.278</div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Darken Clips.</li>
<li>Fixed: Classic Player's CSS was broken because of a malformed comment.</li>
</ul>
<div class="list-header">3.5.277</div>
<ul class="chat-menu-content menu-side-padding">
<li>Changed: More tab completion tweaks for users with display names that don't match their username.</li>
</ul>
<div class="list-header">3.5.276</div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Highlight a user's display name if it's different than their username. (Well, more of an addition with how it works...)</li>
<li>Changed: Make FFZ's tab completion work nicer for users with non-matching usernames and display names.</li>
<li>Changed: CSS tweaks for mod cards when user information is displayed alongside a user's username.</li>
</ul>
<div class="list-header">3.5.275</div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Option to control the appearance of usernames in chat when the user's name and display name do not match.</li>
<li>Changed: Darken the Closed Captioning settings dialog.</li>
<li>Fixed: CSS tweaks for mod cards.</li>
<li>Fixed: User information was not being added to mod cards properly.</li>
</ul>
<div class="list-header">3.5.274</div>
<ul class="chat-menu-content menu-side-padding">
<li>Changed: Use the new badges code for conversation window header badges.</li>
<li>Fixed: Dark CSS tweaks for the modified conversation windows.</li>
</ul>
<div class="list-header">3.5.273</div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Support the Discover directory with stream uptime and channel logos.</li>
<li>Changed: Dark theme CSS tweaks for the Discover directory.</li>
<li>Fixed: Chat status labels were breaking stuff on navigation thanks to an undefined variable.</li>
</ul>
<div class="list-header">3.5.272</div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Ember error handlers to hopefully catch more useful logs in the future when there are issues.</li>
<li>Fixed: Bug in an API wrapper that would cause the Ember app to fail to navigate in certain conditions.</li>
<li>Fixed: CSS tweaks.</li>
</ul>
<div class="list-header">3.5.271</div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: FFZ menu icon would appear at an incorrect position with the Bits dialog open.</li>
<li>Changed: Properly darken the bits dialog and adjust its colors when no-blue is enabled.</li>
</ul>
<div class="list-header">3.5.270</div> <div class="list-header">3.5.270</div>
<ul class="chat-menu-content menu-side-padding"> <ul class="chat-menu-content menu-side-padding">
<li>Changed: Remove client-side permissions check from <code>/ffz following</code>.</li> <li>Changed: Remove client-side permissions check from <code>/ffz following</code>.</li>

View file

@ -197,7 +197,7 @@ body.ffz-dark:not([data-page="teams#show"]),
background-color: rgb(16,16,16); background-color: rgb(16,16,16);
color: rgb(195,195,195); /*#acacbf;*/ color: rgb(195,195,195); /*#acacbf;*/
border-color: #32323e; border-color: #32323e;
box-shadow: rgba(255,255,255,0.2) 0 0 0 1px inset; box-shadow: rgba(255,255,255,0.2) 0 0 0 1px inset;
} }
.ffz-dark #flyout .content, .ffz-dark #flyout .content,
@ -315,6 +315,7 @@ body.ffz-dark:not([data-page="teams#show"]),
.ffz-dark .st-autocomplete-small .list ul .result:not(.active) p, .ffz-dark .st-autocomplete-small .list ul .result:not(.active) p,
.ffz-dark .manager .videos-grid .video:hover .meta .actions li a, .ffz-dark .manager .videos-grid .video:hover .meta .actions li a,
.ffz-dark .ember-chat .chat-room-list .room:not(:hover) p.room-title, .ffz-dark .ember-chat .chat-room-list .room:not(:hover) p.room-title,
.ffz-dark .dropmenu_action:not(:hover),
.ffz-dark .dropmenu_action:not(:hover) span, .ffz-dark .dropmenu_action:not(:hover) span,
.ffz-dark a { .ffz-dark a {
/*.ffz-dark a:not(.profile-card__content):not(.filter-item):not(.ui-state-focus):not(.button):not(.switch):not(.follow):not(.fb_button):not(.what) {*/ /*.ffz-dark a:not(.profile-card__content):not(.filter-item):not(.ui-state-focus):not(.button):not(.switch):not(.follow):not(.fb_button):not(.what) {*/
@ -522,6 +523,7 @@ body.ffz-dark:not([data-page="teams#show"]),
color: #999; color: #999;
} }
.ffz-dark .card__boxpin,
.ffz-dark .streams .stream .content .thumb .boxart, .ffz-dark .streams .stream .content .thumb .boxart,
.ffz-dark .videos .video .content .thumb .boxart { .ffz-dark .videos .video .content .thumb .boxart {
border-color: rgb(16,16,16); border-color: rgb(16,16,16);
@ -532,6 +534,8 @@ body.ffz-dark:not([data-page="teams#show"]),
background-color: rgb(16,16,16); background-color: rgb(16,16,16);
} }
.ffz-dark .card .card__title a,
.ffz-dark .card .card__info a,
.ffz-dark .items-grid .meta .title, .ffz-dark .items-grid .meta .title,
.ffz-dark .items-grid .meta p a { .ffz-dark .items-grid .meta p a {
color: #9c9c9c !important; color: #9c9c9c !important;
@ -541,18 +545,21 @@ body.ffz-dark:not([data-page="teams#show"]),
color: #6c6c6c; color: #6c6c6c;
} }
.ffz-dark .mininav li > a,
.ffz-dark ul.tabs li > a, .ffz-dark ul.tabs li > a,
.ffz-dark .directory_header .nav li > a, .ffz-dark .directory_header .nav li > a,
.ffz-dark ul.tabs_fake li > a { .ffz-dark ul.tabs_fake li > a {
color: #a68ed2; color: #a68ed2;
} }
.ffz-dark .mininav,
.ffz-dark ul.tabs:before, .ffz-dark ul.tabs:before,
.ffz-dark .direcotry_header .nav:before, .ffz-dark .direcotry_header .nav:before,
.ffz-dark ul.tabs_fake:before { .ffz-dark ul.tabs_fake:before {
border-color: #32323e; border-color: #32323e;
} }
.ffz-dark .mininav li > a:hover,
.ffz-dark ul.mininav li.active, .ffz-dark ul.mininav li.active,
.ffz-dark ul.tabs li.selected a, .ffz-dark ul.tabs li.selected a,
.ffz-dark .directory_header .nav li.selected a, .ffz-dark .directory_header .nav li.selected a,
@ -793,13 +800,34 @@ body.ffz-dark:not([data-page="teams#show"]),
/* Dashboard */ /* Dashboard */
.ffz-dark .carousel__button {
background-color: #101010;
}
.ffz-dark .carousel__arrow:before {
border-color: #a68ed2;
}
.ffz-dark .carousel__button:hover .carousel__arrow:before {
border-color: #fff;
}
.ffz-dark .carousel__button:hover {
background-color: #191919;
}
.ffz-dark .brick { .ffz-dark .brick {
background-color: #121212; background-color: #121212;
}
.ffz-dark .brick--marked.brick--theme-white,
.ffz-dark .brick--marked.brick--theme-grey {
box-shadow: 3px 0 0 #9a7fcc inset,0 0 0 1px rgba(255,255,255,0.2) inset;
} }
.ffz-dark .brick--faint, .ffz-dark .brick--faint,
.ffz-dark .brick--block { .ffz-dark .brick--block {
background-color: rgb(25,25,25); background-color: rgb(25,25,25);
} }
.ffz-dark .brick, .ffz-dark .brick,
@ -807,7 +835,7 @@ body.ffz-dark:not([data-page="teams#show"]),
.ffz-dark .brick--block, .ffz-dark .brick--block,
.ffz-dark #action_feed .action, .ffz-dark #action_feed .action,
.ffz-dark .revHeader__item { .ffz-dark .revHeader__item {
border-color: rgba(255,255,255,0.2); border-color: rgba(255,255,255,0.2);
} }
.ffz-dark #mantle_skin .what { background-color: #6441a5; } .ffz-dark #mantle_skin .what { background-color: #6441a5; }
@ -955,7 +983,23 @@ body.ffz-dark:not([data-page="teams#show"]),
background-color: transparent; background-color: transparent;
} }
.ffz-dark #mantle_skin div[style^=" display:background:#ffffff"],
.ffz-dark #mantle_skin .social_links img {
background-color: #fff;
}
.ffz-dark #mantle_skin div[style^=" display:background:#ffffff"] .extraspace { color: #333 }
.ffz-dark #mantle_skin ul.vtabs li .not_linked, .ffz-dark #mantle_skin ul.vtabs li .not_linked,
.ffz-dark #mantle_skin ul.vtabs li a {
color: #acacbf;
}
.ffz-dark #partner_application .partner_reqs {
background-color: #191919;
border-color: #404040;
}
.ffz-dark #mantle_skin ul.vtabs li.selected a, .ffz-dark #mantle_skin ul.vtabs li.selected a,
.ffz-dark #mantle_skin ul.submenu li a:hover, .ffz-dark #mantle_skin ul.submenu li a:hover,
.ffz-dark .sort-contain .sort-options li a:hover, .ffz-dark .sort-contain .sort-options li a:hover,
@ -998,6 +1042,15 @@ body.ffz-dark:not([data-page="teams#show"]),
-webkit-filter: invert(100%); -webkit-filter: invert(100%);
} }
.ffz-dark .new-header-search input {
color: #fff;
box-shadow: rgba(255,255,255,0.2) 0 0 0 1px inset;
}
.ffz-dark .new-header-search input:focus {
box-shadow: rgba(255,255,255,0.4) 0 0 0 1px inset;
}
/* Playlist */ /* Playlist */
.ffz-dark .ember-chat .chat-header { .ffz-dark .ember-chat .chat-header {
@ -1088,7 +1141,7 @@ body.ffz-dark:not([data-page="teams#show"]),
} }
.ffz-dark .conversations-list .search-divider, .ffz-dark .conversations-list .search-divider,
.ffz-dark .conversation-header { .ffz-dark .convoHeader {
background-color: #121217; background-color: #121217;
box-shadow: none; box-shadow: none;
} }
@ -1099,11 +1152,11 @@ body.ffz-dark:not([data-page="teams#show"]),
background-color: #444; background-color: #444;
} }
.ffz-dark .conversation-window.has-focus .conversation-header { .ffz-dark .conversation-window.has-focus .convoHeader {
background-color: #121217; background-color: #121217;
} }
.ffz-dark .conversation-window.has-focus .conversation-header-name { .ffz-dark .conversation-window.has-focus .convoHeader .username {
color: #fff; color: #fff;
} }
@ -1169,7 +1222,7 @@ body.ffz-dark:not([data-page="teams#show"]),
border-top: none; border-top: none;
} }
.ffz-dark .conversation-window:not(.collapsed) .conversation-header { .ffz-dark .conversation-window:not(.collapsed) .convoHeader {
border-bottom: 1px solid rgba(255,255,255,0.2); border-bottom: 1px solid rgba(255,255,255,0.2);
} }
@ -1329,6 +1382,11 @@ body.ffz-dark:not([data-page="teams#show"]),
color: #C3C3C3; color: #C3C3C3;
} }
.ffz-dark .searchPanel--fly:before,
.ffz-dark .searchPanel--fly:after {
border-bottom-color: #404040;
}
.ffz-dark .titleBar { .ffz-dark .titleBar {
background-color: #090909; background-color: #090909;
} }
@ -1344,6 +1402,15 @@ body.ffz-dark:not([data-page="teams#show"]),
.ffz-dark .titleBar__back:hover, .ffz-dark .titleBar__back:hover,
.ffz-dark .resultView__titlesep.isActive { background-color: #222 } .ffz-dark .resultView__titlesep.isActive { background-color: #222 }
.ffz-dark .searchPanel .card__body--overlay .card__title {
text-shadow: 1px 1px #000, -1px 1px #000, -1px -1px #000, 1px -1px #000;
}
.ffz-dark .card__title a:hover,
.ffz-dark .card__info a:hover {
color: #ccd;
}
.ffz-dark .resultView__item .card__info span, .ffz-dark .resultView__item .card__info span,
.ffz-dark .resultView__item .card__title, .ffz-dark .resultView__item .card__title,
.ffz-dark .resultView__titlesep.isActive .resultView__titleMore { color: #a68ed2 } .ffz-dark .resultView__titlesep.isActive .resultView__titleMore { color: #a68ed2 }

View file

@ -14,7 +14,7 @@ var fs = require('fs'),
var jsEscape = require('gulp-js-escape'), var jsEscape = require('gulp-js-escape'),
wrap = require('gulp-wrap'), wrap = require('gulp-wrap'),
declare = require('gulp-declare'), declare = require('gulp-declare'),
minifyCss = require('gulp-minify-css'); cleanCSS = require('gulp-clean-css');
// LESS // LESS
@ -30,7 +30,7 @@ var ftp = require('vinyl-ftp'),
// Server Dependencies // Server Dependencies
var http = require("http"), var http = require("http"),
https = require("https"), https = require("https"),
net = require('net'), net = require('net'),
path = require("path"), path = require("path"),
request = require("request"), request = require("request"),
url = require("url"); url = require("url");
@ -69,8 +69,8 @@ gulp.task('prepare', ['clean'], function() {
//}); //});
gulp.task('styles', ['prepare'], function() { gulp.task('styles', ['prepare'], function() {
return; //return;
return gulp.src(['build/less/*.less']) return gulp.src(['build/less/*.less', '!build/less/style.less'])
.pipe(sourcemaps.init()) .pipe(sourcemaps.init())
.pipe(less()) .pipe(less())
.pipe(sourcemaps.write()) .pipe(sourcemaps.write())
@ -81,7 +81,7 @@ gulp.task('styles', ['prepare'], function() {
gulp.task('embedded_styles', ['prepare'], function() { gulp.task('embedded_styles', ['prepare'], function() {
return gulp.src(['build/styles/**/*.css']) return gulp.src(['build/styles/**/*.css'])
.pipe(minifyCss()) .pipe(cleanCSS())
.pipe(jsEscape()) .pipe(jsEscape())
.pipe(declare({ .pipe(declare({
root: 'exports', root: 'exports',
@ -126,8 +126,8 @@ gulp.task('minify_script', ['scripts'], function() {
}); });
gulp.task('minify_style', function() { gulp.task('minify_style', function() {
return gulp.src(['style.css', 'dark.css']) return gulp.src(['style.css', 'style-clips.css', 'dark.css', 'dark-clips.css'])
.pipe(minifyCss()) .pipe(cleanCSS())
.pipe(rename(function(path) { .pipe(rename(function(path) {
path.basename += '.min'; path.basename += '.min';
})) }))
@ -258,33 +258,33 @@ gulp.task('server', function() {
}; };
if ( fs.existsSync("dev_key.pem") ) { if ( fs.existsSync("dev_key.pem") ) {
var https_options = { var https_options = {
key: fs.readFileSync("dev_key.pem"), key: fs.readFileSync("dev_key.pem"),
cert: fs.readFileSync("dev_cert.pem") cert: fs.readFileSync("dev_cert.pem")
}; };
http.createServer(handle_req).listen(8001, "localhost"); http.createServer(handle_req).listen(8001, "localhost");
https.createServer(https_options, handle_req).listen(8002, "localhost"); https.createServer(https_options, handle_req).listen(8002, "localhost");
net.createServer(function(conn) { net.createServer(function(conn) {
conn.on('error', function(e) { conn.on('error', function(e) {
util.log("[" + util.colors.cyan("HTTP") + "] Connection Error: " + util.colors.magenta('' + e)); util.log("[" + util.colors.cyan("HTTP") + "] Connection Error: " + util.colors.magenta('' + e));
}); });
conn.once('data', function(buf) { conn.once('data', function(buf) {
var address = (buf[0] === 22) ? 8002 : 8001; var address = (buf[0] === 22) ? 8002 : 8001;
var proxy = net.createConnection(address, function() { var proxy = net.createConnection(address, function() {
proxy.write(buf); proxy.write(buf);
conn.pipe(proxy).pipe(conn); conn.pipe(proxy).pipe(conn);
}); });
}); });
}).listen(8000); }).listen(8000);
util.log("[" + util.colors.cyan("HTTPS") + "] Listening on Port: " + util.colors.magenta("8000")); util.log("[" + util.colors.cyan("HTTPS") + "] Listening on Port: " + util.colors.magenta("8000"));
} else { } else {
http.createServer(handle_req).listen(8000, "localhost"); http.createServer(handle_req).listen(8000, "localhost");
util.log("[" + util.colors.cyan("HTTP") + "] Listening on Port: " + util.colors.magenta("8000")); util.log("[" + util.colors.cyan("HTTP") + "] Listening on Port: " + util.colors.magenta("8000"));
} }
}); });

View file

@ -5,25 +5,25 @@
"description": "FrankerFaceZ gives Twitch users custom emoticons.", "description": "FrankerFaceZ gives Twitch users custom emoticons.",
"main": "script.js", "main": "script.js",
"devDependencies": { "devDependencies": {
"gulp": "^3.8.10", "gulp": "^3.9.1",
"gulp-browserify": "^0.5.1", "gulp-browserify": "^0.5.1",
"gulp-changed": "^1.1.0", "gulp-changed": "^1.3.2",
"gulp-clean": "^0.3.1", "gulp-clean": "^0.3.2",
"gulp-concat": "^2.4.3", "gulp-clean-css": "^2.0.12",
"gulp-concat": "^2.6.0",
"gulp-declare": "^0.3.0", "gulp-declare": "^0.3.0",
"gulp-filesize": "0.0.6", "gulp-filesize": "0.0.6",
"gulp-footer": "^1.0.5", "gulp-footer": "^1.0.5",
"gulp-header": "^1.2.2", "gulp-header": "^1.8.8",
"gulp-js-escape": "^1.0.1", "gulp-js-escape": "^1.0.1",
"gulp-less": "^3.1.0", "gulp-less": "^3.1.0",
"gulp-minify-css": "^1.2.1", "gulp-rename": "^1.2.2",
"gulp-rename": "^1.2.0",
"gulp-sourcemaps": "^1.6.0", "gulp-sourcemaps": "^1.6.0",
"gulp-uglify": "^1.0.2", "gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.2", "gulp-util": "^3.0.7",
"gulp-wrap": "^0.11.0", "gulp-wrap": "^0.13.0",
"request": "^2.65.0", "request": "^2.74.0",
"vinyl-ftp": "^0.4.5" "vinyl-ftp": "^0.5.0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -340,15 +340,25 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) {
FFZ.prototype.get_line_badges = function(msg) { FFZ.prototype.get_line_badges = function(msg) {
var room = msg.get && msg.get('room') || msg.room,
from = msg.get && msg.get('from') || msg.from,
tags = msg.get && msg.get('tags') || msg.tags || {},
badge_tag = tags.badges || {};
// Twitch Badges
var badges = this.get_twitch_badges(badge_tag);
// FFZ Badges
return this.get_badges(from, room, badges, msg);
}
FFZ.prototype.get_twitch_badges = function(badge_tag) {
var badges = {}, var badges = {},
hidden_badges = this.settings.hidden_badges, hidden_badges = this.settings.hidden_badges,
last_id = -1, last_id = -1,
had_last = false, had_last = false,
room = msg.get && msg.get('room') || msg.room,
from = msg.get && msg.get('from') || msg.from,
tags = msg.get && msg.get('tags') || msg.tags || {},
badge_tag = tags.badges || {},
service = utils.ember_lookup('service:badges'), service = utils.ember_lookup('service:badges'),
badgeCollection = service && service.badgeCollection, badgeCollection = service && service.badgeCollection,
@ -410,12 +420,11 @@ FFZ.prototype.get_line_badges = function(msg) {
} }
} }
// FFZ Badges return badges;
return this.get_badges(from, room, badges, msg);
} }
FFZ.prototype.get_other_badges = function(user_id, room_id, user_type, has_sub, has_turbo) { /*FFZ.prototype.get_other_badges = function(user_id, room_id, user_type, has_sub, has_turbo) {
var badges = {}; var badges = {};
if ( room_id && user_id === room_id ) if ( room_id && user_id === room_id )
@ -435,7 +444,7 @@ FFZ.prototype.get_other_badges = function(user_id, room_id, user_type, has_sub,
badges[15] = {klass: 'turbo', title: 'Turbo'} badges[15] = {klass: 'turbo', title: 'Turbo'}
return this.get_badges(user_id, room_id, badges, null); return this.get_badges(user_id, room_id, badges, null);
} }*/
// -------------------- // --------------------

View file

@ -175,6 +175,46 @@ FFZ.ffz_commands.massmod = function(room, args) {
FFZ.ffz_commands.massmod.help = "Usage: /ffz massmod <list, of, users>\nBroadcaster only. Mod all the users in the provided list."; FFZ.ffz_commands.massmod.help = "Usage: /ffz massmod <list, of, users>\nBroadcaster only. Mod all the users in the provided list.";
// -----------------
// Mass Unbanning
// -----------------
FFZ.prototype.get_banned_users = function() {
var f = this;
return new Promise(function(succeed, fail) {
var user = f.get_user();
if ( ! user )
return fail();
jQuery.get("/settings/channel").done(function(data) {
try {
var dom = new DOMParser().parseFromString(data, 'text/html'),
users = _.pluck(dom.querySelectorAll('.ban .obj'), 'textContent');
succeed(_.map(users, function(x) { return x.trim() }));
} catch(err) {
f.error("Failed to parse banned users", err);
fail();
}
}).fail(function(err) {
f.error("Failed to load banned users", err);
fail();
})
});
}
/*FFZ.ffz_commands.massunban = function(room, args) {
var user = this.get_user();
if ( ! user || (user.login !== room.id && ! user.is_admin && ! user.is_staff) )
return "You must be the broadcaster to use massunban.";
}*/
/*FFZ.ffz_commands.massunban = function(room, args) { /*FFZ.ffz_commands.massunban = function(room, args) {
args = args.join(" ").trim(); args = args.join(" ").trim();

View file

@ -312,7 +312,7 @@ FFZ.prototype.modify_chat_input = function(component) {
// Let the browser's paste be do as it do if there weren't any emoji. // Let the browser's paste be do as it do if there weren't any emoji.
if ( output.length === text.length ) if ( output.length === text.length )
return f.log("No emoji in paste"); return;
// Can we get the selection in our input box? // Can we get the selection in our input box?
var input = this.get('chatTextArea'), var input = this.get('chatTextArea'),
@ -321,7 +321,7 @@ FFZ.prototype.modify_chat_input = function(component) {
s_end = input && input.selectionEnd; s_end = input && input.selectionEnd;
if ( ! input || typeof s_start !== "number" || typeof s_end !== "number" ) if ( ! input || typeof s_start !== "number" || typeof s_end !== "number" )
return f.log("Can't get input"); return;
// Still here? We're clear to inject this ourselves then. // Still here? We're clear to inject this ourselves then.
event.stopPropagation(); event.stopPropagation();
@ -717,6 +717,8 @@ FFZ.prototype.modify_chat_input = function(component) {
for(var i=0; i < suggestions.length; i++) { for(var i=0; i < suggestions.length; i++) {
var suggestion = suggestions[i], var suggestion = suggestions[i],
name = suggestion.id, name = suggestion.id,
display_name = suggestion.displayName || (name && name.capitalize()),
username_match = display_name.trim().toLowerCase() === name,
alias = f.aliases[name]; alias = f.aliases[name];
if ( user_output[name] && ! user_output[name].is_alias ) { if ( user_output[name] && ! user_output[name].is_alias ) {
@ -724,22 +726,43 @@ FFZ.prototype.modify_chat_input = function(component) {
token.whispered |= suggestion.whispered; token.whispered |= suggestion.whispered;
if ( suggestion.timestamp > token.timestamp ) if ( suggestion.timestamp > token.timestamp )
token.timestamp = suggestion.timestamp; token.timestamp = suggestion.timestamp;
}
if ( user_output[display_name] && ! user_output[display_name].is_alias ) {
var token = user_output[display_name];
token.whispered |= suggestion.whispered;
if ( suggestion.timestamp > token.timestamp )
token.timestamp = suggestion.timestamp;
} else { } else {
if ( alias_setting !== 2 ) if ( alias_setting !== 2 ) {
output.push(user_output[name] = { output.push(user_output[display_name] = {
type: "user", type: "user",
command_content: name, command_content: name,
label: FFZ.get_capitalization(name), label: display_name,
alternate_match: username_match ? null : name,
whispered: suggestion.whispered, whispered: suggestion.whispered,
timestamp: suggestion.timestamp || new Date(0), timestamp: suggestion.timestamp || new Date(0),
info: 'User', info: 'User' + (username_match ? '' : ' (' + name + ')'),
is_display_name: ! username_match,
is_alias: false is_alias: false
}); });
if ( ! username_match )
output.push(user_output[name] = {
type: "user",
label: name,
alternate_match: display_name,
whispered: suggestion.whispered,
timestamp: suggestion.timestamp || new Date(0),
info: 'User (' + display_name + ')',
is_alias: false
});
}
if ( alias && alias_setting ) { if ( alias && alias_setting ) {
if ( user_output[alias] && user_output[alias].is_alias ) { if ( user_output[alias] && user_output[alias].is_alias ) {
var token = user_output[name]; var token = user_output[alias];
token.whispered |= suggestion.whispered; token.whispered |= suggestion.whispered;
token.timestamp = Math.max(token.timestamp, suggestion.timestamp); token.timestamp = Math.max(token.timestamp, suggestion.timestamp);
@ -750,7 +773,7 @@ FFZ.prototype.modify_chat_input = function(component) {
label: alias, label: alias,
whispered: suggestion.whispered, whispered: suggestion.whispered,
timestamp: suggestion.timestamp || new Date(0), timestamp: suggestion.timestamp || new Date(0),
info: 'User Alias', info: 'User Alias (' + name + ')',
is_alias: true is_alias: true
}); });
} }
@ -779,7 +802,10 @@ FFZ.prototype.modify_chat_input = function(component) {
// Names are case insensitive, and we have to ignore the leading @ of our // Names are case insensitive, and we have to ignore the leading @ of our
// partial word when matching. // partial word when matching.
name = name.toLowerCase(); name = name.toLowerCase();
return char === '@' ? name.indexOf(part2.toLowerCase()) === 0 : name.indexOf(partial.toLowerCase()) === 0; var part = (char === '@' ? part2 : partial).toLowerCase(),
alt_name = item.alternate_match;
return name.indexOf(part) === 0 || (alt_name && alt_name.indexOf(part) === 0);
} else if ( type === 'emoji' || ! f.settings.input_emoticons_case_sensitive ) { } else if ( type === 'emoji' || ! f.settings.input_emoticons_case_sensitive ) {
name = name.toLowerCase(); name = name.toLowerCase();
@ -794,7 +820,9 @@ FFZ.prototype.modify_chat_input = function(component) {
ffz_sorted_suggestions: Ember.computed("ffz_filtered_suggestions.[]", function() { ffz_sorted_suggestions: Ember.computed("ffz_filtered_suggestions.[]", function() {
var text = this.get('textareaValue'), var text = this.get('textareaValue'),
now = Date.now(), now = Date.now(),
is_whisper = text.substr(0,3) === '/w '; char = text.charAt(0),
is_command = char === '/' || char === '.',
is_whisper = is_command && text.substr(1, 2) === 'w ';
return this.get('ffz_filtered_suggestions').sort(function(a, b) { return this.get('ffz_filtered_suggestions').sort(function(a, b) {
// First off, sort users ahead of everything else. // First off, sort users ahead of everything else.
@ -809,6 +837,11 @@ FFZ.prototype.modify_chat_input = function(component) {
return 1; return 1;
} }
if ( a.is_display_name && ! b.is_display_name )
return -1;
else if ( ! a.is_display_name && b.is_display_name )
return 1;
if ( a.timestamp > b.timestamp ) return -1; if ( a.timestamp > b.timestamp ) return -1;
else if ( a.timestamp < b.timestamp ) return 1; else if ( a.timestamp < b.timestamp ) return 1;

View file

@ -622,7 +622,7 @@ FFZ.prototype.modify_chat_view = function(view) {
if ( room && room._ffz_tab ) { if ( room && room._ffz_tab ) {
room._ffz_tab.classList.remove('tab-mentioned'); room._ffz_tab.classList.remove('tab-mentioned');
room._ffz_tab.classList.add('active'); room._ffz_tab.classList.add('active');
var sp = room._ffz_tab.querySelector('span'); var sp = room._ffz_tab.querySelector('span:not(.intl-login)');
if ( sp ) if ( sp )
sp.innerHTML = ''; sp.innerHTML = '';
} }
@ -630,7 +630,7 @@ FFZ.prototype.modify_chat_view = function(view) {
if ( room && room._ffz_row ) { if ( room && room._ffz_row ) {
room._ffz_row.classList.remove('row-mentioned'); room._ffz_row.classList.remove('row-mentioned');
room._ffz_row.classList.add('active'); room._ffz_row.classList.add('active');
var sp = room._ffz_row.querySelector('span'); var sp = room._ffz_row.querySelector('span:not(.intl-login)');
if ( sp ) if ( sp )
sp.innerHTML = ''; sp.innerHTML = '';
} }
@ -740,7 +740,7 @@ FFZ.prototype.modify_chat_view = function(view) {
} }
if ( row ) { if ( row ) {
var sp = row.querySelector('span'); var sp = row.querySelector('span:not(.intl-login)');
if ( sp ) if ( sp )
sp.innerHTML = unread; sp.innerHTML = unread;
} }
@ -748,7 +748,7 @@ FFZ.prototype.modify_chat_view = function(view) {
if ( tab ) { if ( tab ) {
var was_hidden = tab.classList.contains('hidden'), var was_hidden = tab.classList.contains('hidden'),
is_hidden = ! this.ffzTabVisible(room_id), is_hidden = ! this.ffzTabVisible(room_id),
sp = tab.querySelector('span'); sp = tab.querySelector('span:not(.intl-login)');
if ( was_hidden !== is_hidden ) { if ( was_hidden !== is_hidden ) {
tab.classList.toggle('hidden', is_hidden); tab.classList.toggle('hidden', is_hidden);
@ -909,10 +909,13 @@ FFZ.prototype.modify_chat_view = function(view) {
active_channel = room === this.get('controller.currentRoom'), active_channel = room === this.get('controller.currentRoom'),
unread = utils.format_unread(active_channel ? 0 : room.get('unreadCount')), unread = utils.format_unread(active_channel ? 0 : room.get('unreadCount')),
name = room.get('tmiRoom.displayName') || (group ? room.get('tmiRoom.name') : FFZ.get_capitalization(room_id, function(name) { name = room.get('channel.display_name') || room.get('tmiRoom.displayName') || (group ? room.get('tmiRoom.name') : FFZ.get_capitalization(room_id, function(name) {
var active_channel = room === view.get('controller.currentRoom'); var active_channel = room === view.get('controller.currentRoom');
unread = utils.format_unread(active_channel ? 0 : room.get('unreadCount')); unread = utils.format_unread(active_channel ? 0 : room.get('unreadCount'));
name_el.innerHTML = utils.sanitize(name) + ' <span>' + unread + '</span>'; var results = group ? [name, undefined] : f.format_display_name(name, room_id, true);
name_el.innerHTML = results[0] + ' <span>' + unread + '</span>';
if ( results[1] )
row.title += '<br>' + results[1];
})); }));
@ -936,7 +939,11 @@ FFZ.prototype.modify_chat_view = function(view) {
} }
name_el.className = 'ffz-room'; name_el.className = 'ffz-room';
name_el.innerHTML = utils.sanitize(name) + ' <span>' + unread + '</span>';
var results = group ? [name, undefined] : f.format_display_name(name, room_id, true);
name_el.innerHTML = results[0] + ' <span>' + unread + '</span>';
if ( results[1] )
row.title += '<br>' + results[1];
row.appendChild(icon); row.appendChild(icon);
row.appendChild(name_el); row.appendChild(name_el);
@ -1044,7 +1051,7 @@ FFZ.prototype.modify_chat_view = function(view) {
link.title = "Chat Room Management"; link.title = "Chat Room Management";
link.innerHTML = '<figure class="icon">' + constants.ROOMS + '</figure><span class="notifications"></span>'; link.innerHTML = '<figure class="icon">' + constants.ROOMS + '</figure><span class="notifications"></span>';
jQuery(link).tipsy({gravity: "n", offset: 5}); jQuery(link).tipsy({gravity: "n", offset: 10});
link.addEventListener('click', function() { link.addEventListener('click', function() {
var controller = view.get('controller'); var controller = view.get('controller');
@ -1129,10 +1136,13 @@ FFZ.prototype.modify_chat_view = function(view) {
unread = utils.format_unread(active_channel ? 0 : room.get('unreadCount')); unread = utils.format_unread(active_channel ? 0 : room.get('unreadCount'));
name = room.get('tmiRoom.displayName') || (group ? room.get('tmiRoom.name') : FFZ.get_capitalization(room_id, function(name) { name = room.get('channel.display_name') || room.get('tmiRoom.displayName') || (group ? room.get('tmiRoom.name') : FFZ.get_capitalization(room_id, function(name) {
var active_channel = room === view.get('controller.currentRoom'); var active_channel = room === view.get('controller.currentRoom');
unread = utils.format_unread(active_channel ? 0 : room.get('unreadCount')); unread = utils.format_unread(active_channel ? 0 : room.get('unreadCount'));
tab.innerHTML = icon + utils.sanitize(name) + '<span>' + unread + '</span>'; var results = group ? [name, undefined] : f.format_display_name(name, room_id, true, true);
tab.innerHTML = icon + results[0] + '<span>' + unread + '</span>';
if ( results[1] )
tab.title += '<br>' + results[1];
})); }));
if ( current_channel ) { if ( current_channel ) {
@ -1146,7 +1156,10 @@ FFZ.prototype.modify_chat_view = function(view) {
else else
tab.title = "Pinned Channel"; tab.title = "Pinned Channel";
tab.innerHTML = icon + utils.sanitize(name) + '<span>' + unread + '</span>'; var results = group ? [name, undefined] : f.format_display_name(name, room_id, true, true);
tab.innerHTML = icon + results[0] + '<span>' + unread + '</span>';
if ( results[1] )
tab.title += '<br>' + results[1];
tab.addEventListener('click', function() { tab.addEventListener('click', function() {
var controller = view.get('controller'); var controller = view.get('controller');
@ -1336,6 +1349,8 @@ FFZ.chat_commands.join = function(room, args) {
return "You have already joined " + room_id + ". Please use \"/part " + room_id + "\" to leave it."; return "You have already joined " + room_id + ". Please use \"/part " + room_id + "\" to leave it.";
} }
FFZ.chat_commands.join.no_bttv = true;
FFZ.chat_commands.part = function(room, args) { FFZ.chat_commands.part = function(room, args) {
if ( this.has_bttv ) if ( this.has_bttv )
@ -1354,4 +1369,6 @@ FFZ.chat_commands.part = function(room, args) {
return "You do not have " + room_id + " pinned and you cannot leave the current channel or hosted channels via /part."; return "You do not have " + room_id + " pinned and you cannot leave the current channel or hosted channels via /part.";
else else
return "You are not in " + room_id + "."; return "You are not in " + room_id + ".";
} }
FFZ.chat_commands.part.no_bttv = true;

View file

@ -20,6 +20,7 @@ FFZ.settings_info.conv_focus_on_click = {
help: "Focus on a conversation's input box when you click it." help: "Focus on a conversation's input box when you click it."
}; };
FFZ.settings_info.top_conversations = { FFZ.settings_info.top_conversations = {
type: "boolean", type: "boolean",
value: false, value: false,
@ -34,6 +35,37 @@ FFZ.settings_info.top_conversations = {
}; };
FFZ.settings_info.hide_whispers_in_embedded_chat = {
type: "boolean",
value: false,
no_bttv: true,
category: "Whispers",
name: "Hide Whispers in Embedded Chat",
help: "Do not display whispers on the dashboard, in pop-out chat, or in chat embedded into other websites.",
on_update: function(val) {
if ( ! val || this.has_bttv )
return;
for(var room_id in this.rooms) {
var room = this.rooms[room_id].room;
if ( ! room )
continue;
var messages = room.get('messages'),
length = messages && messages.length || 0,
i = length;
while(--i >= 0) {
if ( messages[i] && messages[i].style === 'whisper' )
messages.removeAt(i);
}
}
}
};
FFZ.settings_info.hide_conversations_in_theatre = { FFZ.settings_info.hide_conversations_in_theatre = {
type: "boolean", type: "boolean",
value: false, value: false,
@ -117,7 +149,7 @@ FFZ.prototype.modify_conversation_window = function(component) {
ffzHeaderBadges: Ember.computed("thread.participants", "currentUsername", function() { ffzHeaderBadges: Ember.computed("thread.participants", "currentUsername", function() {
var e = this.get("otherUser"); var e = this.get("otherUser");
return f.get_other_badges(e.get('username'), null, e.get('userType'), false, e.get('hasTurbo')); return f.get_badges(e.get('username'), null, f.get_twitch_badges(e.get('badges')), null);
}), }),
ffzReplaceBadges: function() { ffzReplaceBadges: function() {
@ -125,13 +157,25 @@ FFZ.prototype.modify_conversation_window = function(component) {
badge_el = el && el.querySelector('.badges'), badge_el = el && el.querySelector('.badges'),
badges = this.get('ffzHeaderBadges'); badges = this.get('ffzHeaderBadges');
if ( ! el )
return;
if ( ! badge_el ) {
badge_el = createElement('span', 'badges');
var header = el && el.querySelector('.convoHeader .username');
if ( ! header )
return;
header.insertBefore(badge_el, header.firstChild);
}
badge_el.innerHTML = f.render_badges(badges); badge_el.innerHTML = f.render_badges(badges);
}.observes('ffzHeaderBadges'), }.observes('ffzHeaderBadges'),
ffz_init: function() { ffz_init: function() {
var el = this.get('element'), var el = this.get('element'),
header = el && el.querySelector('.conversation-header'), header = el && el.querySelector('.convoHeader'),
header_name = header && header.querySelector('.conversation-header-name'), header_name = header && header.querySelector('.username'),
raw_color = this.get('otherUser.color'), raw_color = this.get('otherUser.color'),
colors = raw_color && f._handle_color(raw_color), colors = raw_color && f._handle_color(raw_color),

View file

@ -225,6 +225,7 @@ FFZ.prototype.setup_directory = function() {
this.update_views('component:stream-preview', function(x) { this.modify_directory_live(x, false) }, true); this.update_views('component:stream-preview', function(x) { this.modify_directory_live(x, false) }, true);
this.update_views('component:creative-preview', function(x) { this.modify_directory_live(x, false) }, true); this.update_views('component:creative-preview', function(x) { this.modify_directory_live(x, false) }, true);
this.update_views('component:csgo-channel-preview', function(x) { this.modify_directory_live(x, true) }, true); this.update_views('component:csgo-channel-preview', function(x) { this.modify_directory_live(x, true) }, true);
this.update_views('component:twitch-carousel/stream-item', function(x) { this.modify_directory_live(x, false, true) }, true);
this.update_views('component:host-preview', this.modify_directory_host, true, true); this.update_views('component:host-preview', this.modify_directory_host, true, true);
this.update_views('component:video-preview', this.modify_video_preview, true); this.update_views('component:video-preview', this.modify_video_preview, true);
@ -418,16 +419,22 @@ FFZ.prototype.modify_game_follow_button = function(component) {
} }
FFZ.prototype.modify_directory_live = function(component, is_csgo) { FFZ.prototype.modify_directory_live = function(component, is_csgo, is_card) {
var f = this, var f = this,
pref = is_csgo ? 'channel.' : 'stream.'; pref = is_csgo ? 'channel.' : 'stream.',
meta_selector = is_card ? '.card__body' : '.meta',
thumb_selector = is_card ? '.card__img' : '.thumb',
cap_selector = is_card ? 'a:not(.card__boxpin)' : '.cap';
utils.ember_reopen_view(component, { utils.ember_reopen_view(component, {
ffz_init: function() { ffz_init: function() {
var el = this.get('element'), var el = this.get('element'),
meta = el && el.querySelector('.meta'), meta = el && el.querySelector(meta_selector),
thumb = el && el.querySelector('.thumb'), thumb = el && el.querySelector(thumb_selector),
cap = thumb && thumb.querySelector('.cap'), cap = thumb && thumb.querySelector(cap_selector),
uptime_parent = is_card ? thumb : cap,
channel_id = this.get(pref + 'channel.name'), channel_id = this.get(pref + 'channel.name'),
game = this.get(pref + 'game'); game = this.get(pref + 'game');
@ -438,13 +445,13 @@ FFZ.prototype.modify_directory_live = function(component, is_csgo) {
el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1); el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1);
el.classList.toggle('ffz-game-spoilered', f.settings.spoiler_games.indexOf(game && game.toLowerCase()) !== -1); el.classList.toggle('ffz-game-spoilered', f.settings.spoiler_games.indexOf(game && game.toLowerCase()) !== -1);
if (f.settings.stream_uptime && f.settings.stream_uptime < 3 && cap ) { if (f.settings.stream_uptime && f.settings.stream_uptime < 3 && uptime_parent ) {
var t_el = this._ffz_uptime = document.createElement('div'); var t_el = this._ffz_uptime = document.createElement('div');
t_el.className = 'overlay_info length live'; t_el.className = 'overlay_info length live';
jQuery(t_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')}); jQuery(t_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')});
cap.appendChild(t_el); uptime_parent.appendChild(t_el);
this._ffz_uptime_timer = setInterval(this.ffzUpdateUptime.bind(this), 1000); this._ffz_uptime_timer = setInterval(this.ffzUpdateUptime.bind(this), 1000);
this.ffzUpdateUptime(); this.ffzUpdateUptime();
} }
@ -463,7 +470,7 @@ FFZ.prototype.modify_directory_live = function(component, is_csgo) {
logo.classList.toggle('is-csgo', is_csgo); logo.classList.toggle('is-csgo', is_csgo);
logo.src = this.get(pref + 'channel.logo') || NO_LOGO; logo.src = this.get(pref + 'channel.logo') || NO_LOGO;
logo.alt = this.get(pref + 'channel.display_name'); logo.alt = f.format_display_name(this.get(pref + 'channel.display_name'), channel_id, true, true)[0];
link.href = '/' + channel_id; link.href = '/' + channel_id;
link.addEventListener('click', function(e) { link.addEventListener('click', function(e) {
@ -510,9 +517,16 @@ FFZ.prototype.modify_directory_live = function(component, is_csgo) {
}, },
ffzUpdateUptime: function() { ffzUpdateUptime: function() {
var raw_created = this.get(pref + 'created_at'), var up_since;
up_since = raw_created && utils.parse_date(raw_created),
now = Date.now() - (f._ws_server_offset || 0), if ( is_card )
up_since = this.get(pref + 'createdAt');
else {
var raw_created = this.get(pref + 'created_at');
up_since = raw_created && utils.parse_date(raw_created);
}
var now = Date.now() - (f._ws_server_offset || 0),
uptime = up_since && Math.floor((now - up_since.getTime()) / 1000) || 0; uptime = up_since && Math.floor((now - up_since.getTime()) / 1000) || 0;
if ( uptime > 0 ) { if ( uptime > 0 ) {
@ -620,11 +634,13 @@ FFZ.prototype.modify_directory_host = function(component) {
var menu = document.createElement('div'), hdr, var menu = document.createElement('div'), hdr,
make_link = function(target) { make_link = function(target) {
var link = document.createElement('a'); var link = document.createElement('a'),
results = f.format_display_name(target.display_name, target.name, true);
link.className = 'dropmenu_action'; link.className = 'dropmenu_action';
link.setAttribute('data-channel', target.name); link.setAttribute('data-channel', target.name);
link.href = '/' + target.name; link.href = '/' + target.name;
link.innerHTML = '<img class="image" src="' + utils.sanitize(target.logo || NO_LOGO) + '"><span class="title">' + utils.sanitize(target.display_name) + '</span>'; link.innerHTML = '<img class="image" src="' + utils.sanitize(target.logo || NO_LOGO) + '"><span class="title' + (results[1] ? ' html-tooltip" title="' + utils.quote_attr(results[1]) : '') + '">' + results[0] + '</span>';
link.addEventListener('click', t.ffzVisitChannel.bind(t, target.name)); link.addEventListener('click', t.ffzVisitChannel.bind(t, target.name));
menu.appendChild(link); menu.appendChild(link);
return link; return link;
@ -709,7 +725,7 @@ FFZ.prototype.modify_directory_host = function(component) {
logo.className = 'profile-photo'; logo.className = 'profile-photo';
logo.src = this.get('stream.target.channel.logo') || NO_LOGO; logo.src = this.get('stream.target.channel.logo') || NO_LOGO;
logo.alt = this.get('stream.target.channel.display_name'); logo.alt = f.format_display_name(target.display_name, target.name, true, true)[0];
link.href = '/' + target.name; link.href = '/' + target.name;
link.addEventListener('click', this.ffzVisitChannel.bind(this, target.name)); link.addEventListener('click', this.ffzVisitChannel.bind(this, target.name));

View file

@ -85,8 +85,9 @@ FFZ.prototype.setup_profile_following = function() {
} }
success(result); success(result);
}).catch(function(err) { }).catch(function(err) {
fail(result); fail(err);
}) })
}); });
} }
@ -131,15 +132,14 @@ FFZ.prototype.modify_display_followed_item = function(component) {
el.classList.add('ffz-processed'); el.classList.add('ffz-processed');
// TODO: REMOVE jQuery('.aspect', el).tipsy();
window._d = this;
if ( ! data ) if ( ! data )
return false; return false;
var now = Date.now() - (f._ws_server_offset || 0), var now = Date.now() - (f._ws_server_offset || 0),
age = data[0] ? Math.floor((now - data[0].getTime()) / 1000) : 0, age = data[0] ? Math.floor((now - data[0].getTime()) / 1000) : 0,
t_el = createElement('div', 'overlay_info length'), t_el = createElement('div', 'overlay_info length html-tooltip'),
update_time = function() { update_time = function() {
var now = Date.now() - (f._ws_server_offset || 0), var now = Date.now() - (f._ws_server_offset || 0),
@ -154,7 +154,6 @@ FFZ.prototype.modify_display_followed_item = function(component) {
}; };
update_time(); update_time();
jQuery(t_el).tipsy({html:true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')});
el.appendChild(t_el); el.appendChild(t_el);
if ( ! mine || ! is_following ) if ( ! mine || ! is_following )
@ -162,7 +161,7 @@ FFZ.prototype.modify_display_followed_item = function(component) {
var actions = createElement('div', 'actions'), var actions = createElement('div', 'actions'),
follow = createElement('button', 'button ffz-no-bg follow'), follow = createElement('button', 'button ffz-no-bg follow'),
notif = createElement('button', 'button ffz-no-bg notifications'), notif = createElement('button', 'button ffz-no-bg notifications html-tooltip'),
update_follow = function() { update_follow = function() {
data = user_cache[user_id]; data = user_cache[user_id];
@ -173,7 +172,9 @@ FFZ.prototype.modify_display_followed_item = function(component) {
update_notif = function() { update_notif = function() {
data = user_cache[user_id]; data = user_cache[user_id];
notif.classList.toggle('notifications-on', data && data[1]); notif.classList.toggle('notifications-on', data && data[1]);
notif.textContent = 'Notification ' + (data && data[1] ? 'On' : 'Off'); notif.textContent = 'Notifications'; // ' + (data && data[1] ? 'On' : 'Off');
notif.setAttribute('original-title', 'Email Notifications: ' + (data && data[1] ? 'En' : 'Dis') + 'abled');
jQuery(notif).trigger('mouseout');
}; };
update_follow(); update_follow();

View file

@ -22,6 +22,50 @@ FFZ.settings_info.alias_italics = {
} }
}; };
FFZ.settings_info.username_display = {
type: "select",
options: {
0: "Username Only",
1: "Capitalization Only",
2: "Display Name Only",
3: "Username in Parenthesis",
4: "Username in Tooltip"
},
category: "Chat Appearance",
no_bttv: true,
name: "Username Display",
help: "How a user's name should be rendered when their display name differs from the username.",
value: 3,
process_value: function(val) {
if ( typeof val === "string" ) {
val = parseInt(val);
if ( isNaN(val) || ! isFinite(val) )
val = 3;
}
return val;
},
on_update: function(val) {
var CL = utils.ember_resolve('component:chat/chat-line'),
views = CL ? utils.ember_views() : [];
for(var vid in views) {
var view = views[vid];
if ( view instanceof CL && view.buildFromHTML ) {
view.$('.from').replaceWith(view.buildFromHTML());
if ( view.get('msgObject.to') )
view.$('.to').replaceWith(view.buildFromHTML(true));
}
}
}
}
FFZ.settings_info.room_status = { FFZ.settings_info.room_status = {
type: "boolean", type: "boolean",
value: true, value: true,
@ -768,27 +812,27 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
return output + '</span>'; return output + '</span>';
}, },
buildSenderHTML: function() { buildFromHTML: function(is_recipient) {
var user = this.get('msgObject.from'), var username = this.get(is_recipient ? 'msgObject.to' : 'msgObject.from'),
room_id = this.get('msgObject.room'), raw_display = this.get(is_recipient ? 'msgObject.tags.recipient-display-name' : 'msgObject.tags.display-name'),
room = f.rooms && f.rooms[room_id], alias = f.aliases[username],
deleted = this.get('msgObject.deleted'), raw_color = this.get(is_recipient ? 'msgObject.toColor' : 'msgObject.color'),
r = this,
recipient = this.get('msgObject.to'),
is_whisper = recipient && recipient.length,
is_replay = this.get('ffz_is_replay'),
this_ul = this.get('ffzUserLevel'),
other_ul = room && room.room && room.room.get('ffzUserLevel') || 0,
raw_color = this.get('msgObject.color'),
colors = raw_color && f._handle_color(raw_color),
is_dark = (Layout && Layout.get('isTheatreMode')) || (is_replay ? f.settings.dark_twitch : (Settings && Settings.get('settings.darkMode'))), is_dark = (Layout && Layout.get('isTheatreMode')) || (is_replay ? f.settings.dark_twitch : (Settings && Settings.get('settings.darkMode'))),
is_replay = this.get('ffz_is_replay'),
system_msg = this.get('systemMsg'), colors = raw_color && f._handle_color(raw_color),
style = colors ? 'color:' + (is_dark ? colors[1] : colors[0]) : '',
colored = colors ? ' has-color' + (is_replay ? ' replay-color' : '') : '',
results = f.format_display_name(raw_display, username);
return '<span class="' + (is_recipient ? 'to' : 'from') + (alias ? ' ffz-alias' : '') + (results[1] ? ' html-tooltip' : '') + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + (results[1] ? '" title="' + utils.quote_attr(results[1]) : '') + '">' + results[0] + '</span>';
},
buildSenderHTML: function() {
var system_msg = this.get('systemMsg'),
output = ''; output = '';
output = '<div class="indicator"></div>'; output = '<div class="indicator"></div>';
@ -809,41 +853,15 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
// Badges // Badges
output += '<span class="badges">' + f.render_badges(f.get_line_badges(this.get('msgObject'))) + '</span>'; output += '<span class="badges">' + f.render_badges(f.get_line_badges(this.get('msgObject'))) + '</span>';
// Alias Support // From!
var alias = f.aliases[user], output += this.buildFromHTML();
name = this.get('msgObject.tags.display-name') || (user && user.capitalize()) || "unknown user",
style = colors && 'color:' + (is_dark ? colors[1] : colors[0]) || '',
colored = style ? ' has-color' + (is_replay ? ' replay-color' : '') : '';
output += '<span class="from' + (alias ? ' ffz-alias html-tooltip' : '') + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : ''); if ( this.get('msgObject.to') ) {
output += "<svg class='svg-whisper-arrow' height='10px' version='1.1' width='16px'><polyline points='6 2, 10 6, 6 10, 6 2' /></svg>";
if ( alias ) output += this.buildFromHTML(true);
output += '" title="' + utils.quote_san(name) + '">' + utils.sanitize(alias);
else
output += '">' + utils.sanitize(name);
// Whisper Legacy Sucks
if ( is_whisper ) {
var to_alias = f.aliases[recipient],
to_name = this.get('msgObject.tags.recipient-display-name') || (recipient && recipient.capitalize()) || "unknown user",
to_color = this.get('msgObject.toColor'),
to_colors = to_color && f._handle_color(to_color),
to_style = to_color ? 'color:' + (is_dark ? to_colors[1] : to_colors[0]) : '',
to_colored = to_style ? ' has-color' : '';
output += "</span><svg class='svg-whisper-arrow' height='10px' version='1.1' width='16px'><polyline points='6 2, 10 6, 6 10, 6 2' /></svg>";
output += '<span class="to' + (to_alias ? ' ffz-alias html-tooltip' : '') + to_colored + '" style="' + to_style + (to_colors ? '" data=color="' + to_color : '');
if ( to_alias )
output += '" title="' + utils.quote_san(to_name) + '">' + utils.sanitize(to_alias);
else
output += '">' + utils.sanitize(to_name);
} }
return output + '</span><span class="colon">:</span> '; return output + '<span class="colon">:</span> ';
}, },
buildDeletedMessageHTML: function() { buildDeletedMessageHTML: function() {
@ -917,7 +935,7 @@ FFZ.prototype._modify_chat_subline = function(component) {
this._modify_chat_line(component); this._modify_chat_line(component);
component.reopen({ component.reopen({
classNameBindings: ["msgObject.style", "msgObject.ffz_has_mention:ffz-mentioned", "ffzWasDeleted:ffz-deleted", "ffzHasOldMessages:clearfix", "ffzHasOldMessages:ffz-has-deleted"], classNameBindings: ["msgObject.style", "msgObject.isModerationMessage:moderation-message", "msgObject.ffz_has_mention:ffz-mentioned", "ffzWasDeleted:ffz-deleted", "ffzHasOldMessages:clearfix", "ffzHasOldMessages:ffz-has-deleted"],
attributeBindings: ["msgObject.tags.id:data-id", "msgObject.room:data-room", "msgObject.from:data-sender", "msgObject.deleted:data-deleted"], attributeBindings: ["msgObject.tags.id:data-id", "msgObject.room:data-room", "msgObject.from:data-sender", "msgObject.deleted:data-deleted"],
didInsertElement: function() { didInsertElement: function() {
@ -989,7 +1007,7 @@ FFZ.prototype._modify_chat_subline = function(component) {
} else if ( f._click_emote(e.target, e) ) } else if ( f._click_emote(e.target, e) )
return; return;
else if ( e.target.classList.contains('from') ) { else if ( e.target.classList.contains('from') || e.target.parentElement.classList.contains('from') ) {
var n = this.get('element'), var n = this.get('element'),
bounds = n && n.getBoundingClientRect() || document.body.getBoundingClientRect(), bounds = n && n.getBoundingClientRect() || document.body.getBoundingClientRect(),
x = 0, right; x = 0, right;
@ -1005,6 +1023,22 @@ FFZ.prototype._modify_chat_subline = function(component) {
sender: from sender: from
}); });
} else if ( e.target.classList.contains('to') || e.target.parentElement.classList.contains('to') ) {
var n = this.get('element'),
bounds = n && n.getBoundingClientRect() || document.body.getBoundingClientRect(),
x = 0, right;
if ( bounds.left > 400 )
right = bounds.left - 40;
this.sendAction("showModOverlay", {
left: bounds.left,
right: right,
top: bounds.top + bounds.height,
real_top: bounds.top,
sender: this.get('msgObject.to')
});
} else if ( e.target.classList.contains('undelete') ) { } else if ( e.target.classList.contains('undelete') ) {
e.preventDefault(); e.preventDefault();
this.set("msgObject.deleted", false); this.set("msgObject.deleted", false);

View file

@ -661,13 +661,6 @@ FFZ.prototype.modify_moderation_card = function(component) {
info.innerHTML = out; info.innerHTML = out;
}.observes("cardInfo.user.views"), }.observes("cardInfo.user.views"),
userName: Ember.computed("cardInfo.user.id", "cardInfo.user.display_name", function() {
var user_id = this.get("cardInfo.user.id"),
alias = f.aliases[user_id];
return alias || this.get("cardInfo.user.display_name") || user_id.capitalize();
}),
ffz_destroy: function() { ffz_destroy: function() {
if ( f._mod_card === this ) if ( f._mod_card === this )
f._mod_card = undefined; f._mod_card = undefined;
@ -724,15 +717,15 @@ FFZ.prototype.modify_moderation_card = function(component) {
// Alias Display // Alias Display
if ( alias ) { if ( alias ) {
var name = el.querySelector('h3.name'), var name = el.querySelector('h4.name a');
link = name && name.querySelector('a');
if ( link )
name = link;
if ( name ) { if ( name ) {
name.classList.add('ffz-alias'); name.classList.add('ffz-alias');
name.title = utils.sanitize(controller.get('cardInfo.user.display_name') || user_id.capitalize()); var results = f.format_display_name(controller.get('cardInfo.user.display_name'), user_id);
jQuery(name).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
name.innerHTML = results[0];
name.title = results[1] || '';
if ( results[1] )
jQuery(name).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
} }
} }
@ -742,7 +735,7 @@ FFZ.prototype.modify_moderation_card = function(component) {
// Info-tize it! // Info-tize it!
if ( f.settings.mod_card_info ) { if ( f.settings.mod_card_info ) {
var info = utils.createElement('div', 'info channel-stats'), var info = utils.createElement('div', 'info channel-stats'),
after = el.querySelector('h3.name'); after = el.querySelector('h4.name');
if ( after ) { if ( after ) {
el.classList.add('ffz-has-info'); el.classList.add('ffz-has-info');
after.parentElement.insertBefore(info, after.nextSibling); after.parentElement.insertBefore(info, after.nextSibling);
@ -995,10 +988,11 @@ FFZ.prototype.modify_moderation_card = function(component) {
alias_btn.addEventListener('click', function() { alias_btn.addEventListener('click', function() {
var user = controller.get('cardInfo.user.id'), var user = controller.get('cardInfo.user.id'),
alias = f.aliases[user]; alias = f.aliases[user],
results = f.format_display_name(controller.get('cardInfo.user.display_name'), user, true);
utils.prompt( utils.prompt(
"Alias for <b>" + utils.sanitize(controller.get('cardInfo.user.display_name') || user) + "</b>", "Alias for <b" + (results[1] ? ' class="html-tooltip" title="' + utils.quote_attr(results[1]) + '">' : '>') + results[0] + "</b>",
"Please enter an alias for the user. Leave it blank to remove the alias.", "Please enter an alias for the user. Leave it blank to remove the alias.",
alias, alias,
function(new_val) { function(new_val) {
@ -1015,10 +1009,16 @@ FFZ.prototype.modify_moderation_card = function(component) {
// Update UI // Update UI
f._update_alias(user); f._update_alias(user);
Ember.propertyDidChange(controller, 'cardInfo.user.display_name'); var name = el.querySelector('h4.name');
var name = el.querySelector('h3.name'); if ( name ) {
if ( name )
name.classList.toggle('ffz-alias', new_val); name.classList.toggle('ffz-alias', new_val);
var results = f.format_display_name(controller.get('cardInfo.user.display_name'), user_id);
name.innerHTML = results[0];
name.title = results[1] || '';
if ( results[1] )
jQuery(name).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
}
}); });
}); });
@ -1256,11 +1256,10 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
if ( helpers && helpers.getTime ) if ( helpers && helpers.getTime )
out.push('<span class="timestamp">' + helpers.getTime(msg.date) + '</span>'); out.push('<span class="timestamp">' + helpers.getTime(msg.date) + '</span>');
var alias = this.aliases[msg.from],
name = (msg.tags && msg.tags['display-name']) || (msg.from && msg.from.capitalize()) || "unknown user";
if ( show_from ) { if ( show_from ) {
var alias = this.aliases[msg.from],
results = this.format_display_name(msg.tags && msg.tags['display-name'], msg.from);
// Badges // Badges
out.push('<span class="badges">'); out.push('<span class="badges">');
out.push(this.render_badges(this.get_line_badges(msg, false))); out.push(this.render_badges(this.get_line_badges(msg, false)));
@ -1277,15 +1276,18 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode')); is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode'));
// Aliases and Styling // Styling
var style = colors && 'color:' + (is_dark ? colors[1] : colors[0]), var style = colors && 'color:' + (is_dark ? colors[1] : colors[0]),
colored = style ? ' has-color' : ''; colored = style ? ' has-color' : '';
out.push('<span class="from' +
if ( alias ) (alias ? ' ffz-alias' : '') +
out.push('<span class="from ffz-alias html-tooltip' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '" title="' + utils.quote_san(name) + '">' + utils.sanitize(alias) + '</span>'); (results[1] ? ' html-tooltip' : '') +
else (style ? ' has-color' : '') +
out.push('<span class="from' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '">' + utils.sanitize(name) + '</span>'); '" style="' + style + '"' +
(colors ? ' data-color="' + raw_color + '"' : '') +
(results[1] ? ' title="' + utils.quote_attr(results[1]) + '"' : '') + '>'
+ results[0] + '</span>');
out.push('<span class="colon">:</span> '); out.push('<span class="colon">:</span> ');
} }
@ -1367,8 +1369,8 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
FFZ.prototype._update_alias = function(user) { FFZ.prototype._update_alias = function(user) {
var alias = this.aliases && this.aliases[user], var alias = this.aliases && this.aliases[user],
cap_name = FFZ.get_capitalization(user), results = this.format_display_name(FFZ.get_capitalization(user), user),
display_name = alias || cap_name,
el = this._roomv && this._roomv.get('element'), el = this._roomv && this._roomv.get('element'),
lines = el && el.querySelectorAll('.chat-line[data-sender="' + user + '"]'); lines = el && el.querySelectorAll('.chat-line[data-sender="' + user + '"]');
@ -1383,8 +1385,9 @@ FFZ.prototype._update_alias = function(user) {
continue; continue;
el_from.classList.toggle('ffz-alias', alias); el_from.classList.toggle('ffz-alias', alias);
el_from.textContent = display_name; el_from.classList.toggle('html-tooltip', results[1] || false);
el_from.title = alias ? cap_name : ''; el_from.innerHTML = results[0];
el_from.title = results[1] || '';
} }
@ -1402,16 +1405,12 @@ FFZ.prototype._update_alias = function(user) {
FFZ.chat_commands.purge = function(room, args) { FFZ.chat_commands.purge = function(room, args) {
if ( ! args || ! args.length ) if ( ! args || ! args.length )
return "Purge Usage: /p username [more usernames separated by spaces]"; return "Purge Usage: /p username [ban reason]";
if ( args.length > 10 ) var name = args.shift(),
return "Please only purge up to 10 users at once."; reason = args.length ? args.join(" ") : "";
for(var i=0; i < args.length; i++) { room.room.send("/timeout " + name + " 1 " + reason, true);
var name = args[i];
if ( name )
room.room.send("/timeout " + name + " 1", true);
}
} }
FFZ.chat_commands.p = function(room, args) { FFZ.chat_commands.p = function(room, args) {
@ -1423,7 +1422,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] [ban reason]";
room.room.send("/timeout " + args.join(" "), true); room.room.send("/timeout " + args.join(" "), true);
} }
@ -1432,16 +1431,12 @@ FFZ.chat_commands.t.enabled = function() { return this.settings.short_commands;
FFZ.chat_commands.b = function(room, args) { FFZ.chat_commands.b = function(room, args) {
if ( ! args || ! args.length ) if ( ! args || ! args.length )
return "Ban Usage: /b username [more usernames separated by spaces]"; return "Ban Usage: /b username [ban reason]";
if ( args.length > 10 ) var name = args.shift(),
return "Please only ban up to 10 users at once."; reason = args.length ? args.join(" ") : "";
for(var i=0; i < args.length; i++) { room.room.send("/ban " + name + " " + reason, true);
var name = args[i];
if ( name )
room.room.send("/ban " + name, true);
}
} }
FFZ.chat_commands.b.enabled = function() { return this.settings.short_commands; } FFZ.chat_commands.b.enabled = function() { return this.settings.short_commands; }

View file

@ -165,6 +165,7 @@ FFZ.prototype.modify_twitch_player = function(player) {
this.$('#video-1').html(''); this.$('#video-1').html('');
Mousetrap.unbind(['alt+x', 'alt+t', 'esc']); Mousetrap.unbind(['alt+x', 'alt+t', 'esc']);
this.set('player', null); this.set('player', null);
this.set('ffz_post_player', false);
// Now, let Twitch create a new player as usual. // Now, let Twitch create a new player as usual.
Ember.run.next(this.insertPlayer.bind(this, true)); Ember.run.next(this.insertPlayer.bind(this, true));

View file

@ -4,13 +4,24 @@ var FFZ = window.FrankerFaceZ,
utils = require('../utils'), utils = require('../utils'),
helpers, helpers,
NOTICE_MAPPING = {
'slow': 'slow_on',
'slowoff': 'slow_off',
'r9kbeta': 'r9k_on',
'r9kbetaoff': 'r9k_off',
'subscribers': 'subs_on',
'subscribersoff': 'subs_off',
'emoteonly': 'emote_only_on',
'emoteonlyoff': 'emote_only_off'
},
STATUS_BADGES = [ STATUS_BADGES = [
["r9k", "r9k", "This room is in R9K-mode."], ["r9k", "r9k", "This room is in R9K-mode."],
["emote", "emoteOnly", "This room is in Twitch emoticons only mode. Emoticons added by extensions are not available in this mode."], ["emote", "emoteOnly", "This room is in Twitch emoticons only mode. Emoticons added by extensions are not available in this mode."],
["sub", "subsOnly", "This room is in subscribers-only mode."], ["sub", "subsOnly", "This room is in subscribers-only mode."],
["slow", "slow", function(room) { return "This room is in slow mode. You may send messages every " + utils.number_commas(room && room.get('slow') || 120) + " seconds." }], ["slow", "slow", function(room) { return "This room is in slow mode. You may send messages every " + utils.number_commas(room && room.get('slow') || 120) + " seconds." }],
["ban", "ffz_banned", "You have been banned from talking in this room."], ["ban", "ffz_banned", "You have been banned from talking in this room."],
["delay", function(room) { return room && room.get('ffz_chat_delay') !== 0 }, function(room) { return "Artificial chat delay is enabled. Messages are displayed after " + (room.get('ffz_chat_delay')/1000) + " seconds." }], ["delay", function(room) { return room && room.get('ffz_chat_delay') !== 0 }, function(room) { return "Artificial chat delay is enabled. Messages are displayed after " + (room ? room.get('ffz_chat_delay')/1000 : 0) + " seconds." }],
["batch", function() { return this.settings.chat_batching !== 0 }, function() { return "You have enabled chat message batching. Messages are displayed in " + (this.settings.chat_batching/1000) + " second increments." }] ["batch", function() { return this.settings.chat_batching !== 0 }, function() { return "You have enabled chat message batching. Messages are displayed in " + (this.settings.chat_batching/1000) + " second increments." }]
], ],
@ -38,15 +49,24 @@ FFZ.prototype.setup_room = function() {
this.rooms = {}; this.rooms = {};
this.log("Creating room style element."); this.log("Creating room style element.");
var s = this._room_style = document.createElement("style"); var f = this,
s = this._room_style = document.createElement("style");
s.id = "ffz-room-css"; s.id = "ffz-room-css";
document.head.appendChild(s); document.head.appendChild(s);
this.log("Hooking the Ember Chat PubSub service.");
var PubSub = utils.ember_lookup('service:chat-pubsub');
if ( PubSub )
this._modify_chat_pubsub(PubSub);
else
this.error("Cannot locate the Chat PubSub service.");
this.log("Hooking the Ember Room controller."); this.log("Hooking the Ember Room controller.");
// Responsive ban button. // Responsive ban button.
var f = this, var RC = utils.ember_lookup('controller:room');
RC = utils.ember_lookup('controller:room');
if ( RC ) { if ( RC ) {
var orig_ban = RC._actions.banUser, var orig_ban = RC._actions.banUser,
@ -119,6 +139,120 @@ FFZ.prototype.setup_room = function() {
} }
// --------------------
// PubSub is fucking awful
// --------------------
FFZ.prototype._modify_chat_pubsub = function(pubsub) {
var f = this;
pubsub.reopen({
setupService: function(room_id, t) {
var n = this;
this.get("session").withCurrentUser(function(user) {
if ( n.isDestroyed )
return;
var ps = n._pubsub(),
token = user.chat_oauth_token,
new_topics = [
"chat_message_updated." + room_id,
"chat_moderator_actions." + room_id];
for(var i=0; i < new_topics.length; i++)
ps.Listen({
topic: new_topics[i],
auth: token,
success: function() {},
failure: function() {},
message: Ember.run.bind(n, n._onPubsubMessage, new_topics[i])
});
if ( n.chatTopics )
n.chatTopics = n.chatTopics.concat(new_topics);
else
n.chatTopics = new_topics;
ps.on("connected", Ember.run.bind(n, n._onPubsubConnect));
ps.on("disconnected", Ember.run.bind(n, n._onPubsubDisconnect));
t();
});
},
tearDownService: function(room_id) {
if ( ! this.chatTopics )
return;
var ps = this._pubsub(),
old_topics;
if ( ! room_id )
room_id = this.get("ffz_teardown_target");
if ( room_id ) {
// Make sure it's a string.
room_id = '.' + room_id;
old_topics = this.chatTopics.filter(function(x) { return x.substr(-room_id.length) === room_id });
} else
old_topics = this.chatTopics;
for(var i=0; i < old_topics.length; i++) {
ps.Unlisten({
topic: old_topics[i],
success: function() {},
failure: function() {}
});
this.chatTopics.removeObject(old_topics[i]);
}
if ( ! this.chatTopics.length )
this.chatTopics = null;
},
_onPubsubMessage: function(topic, e) {
if ( this.isDestroyed )
return;
var msg = JSON.parse(e),
msg_data = msg.data,
msg_type = msg.type || msg_data.type;
if ( msg_data )
msg_data.topic = topic;
this.trigger(msg_type, msg_data);
}
});
if ( ! pubsub.chatTopics )
return;
// Now that we've modified that, we need to re-listen to everything.
pubsub.get("session").withCurrentUser(function(user) {
if ( pubsub.isDestroyed )
return;
var ps = pubsub._pubsub(),
token = user.chat_oauth_token;
for(var i=0; i < pubsub.chatTopics.length; i++) {
ps.Unlisten({
topic: pubsub.chatTopics[i],
success: function() {},
failure: function() {}
});
ps.Listen({
topic: pubsub.chatTopics[i],
auth: token,
success: function() {},
failure: function() {},
message: Ember.run.bind(pubsub, pubsub._onPubsubMessage, pubsub.chatTopics[i])
});
}
});
}
// -------------------- // --------------------
// View Customization // View Customization
// -------------------- // --------------------
@ -225,6 +359,7 @@ FFZ.prototype.modify_room_view = function(view) {
this.ffzDisableFreeze(); this.ffzDisableFreeze();
}, },
ffzOnKey: function(event) { ffzOnKey: function(event) {
this.ffz_ctrl = event.ctrlKey; this.ffz_ctrl = event.ctrlKey;
this.ffz_alt = event.altKey; this.ffz_alt = event.altKey;
@ -835,10 +970,17 @@ FFZ.prototype._insert_history = function(room_id, data, from_server) {
// Store the message ID for this message, of course. // Store the message ID for this message, of course.
var msg_id = msg.tags && msg.tags.id, var msg_id = msg.tags && msg.tags.id,
ids = r.ffz_ids = r.ffz_ids || {}; notice_type = msg.tags && msg.tags['msg-id'],
ids = r.ffz_ids = r.ffz_ids || {},
notices = r.ffz_last_notices = r.ffz_last_notices || {};
if ( msg_id && ! ids[msg_id] ) if ( msg_id && ! ids[msg_id] )
ids[msg_id] = msg; ids[msg_id] = msg;
if ( notice_type && ! notices[notice_type] )
notices[notice_type] = msg;
messages.unshiftObject(msg); messages.unshiftObject(msg);
inserted += 1; inserted += 1;
@ -876,9 +1018,15 @@ FFZ.prototype._insert_history = function(room_id, data, from_server) {
messages.insertAt(inserted, msg); messages.insertAt(inserted, msg);
while ( messages.length > buffer_size ) { while ( messages.length > buffer_size ) {
// Remove this message from the ID tracker. // Remove this message from the ID tracker.
var m = messages.get(0); var m = messages.get(0),
if ( m.tags && m.tags.id && r.ffz_ids && r.ffz_ids[m.tags.id] ) msg_id = m.tags && m.tags.id,
delete r.ffz_ids[m.tags.id]; notice_type = m.tags && m.tags['msg-id'];
if ( msg_id && r.ffz_ids && r.ffz_ids[msg_id] )
delete r.ffz_ids[msg_id];
if ( notice_type && r.ffz_last_notices && r.ffz_last_notices[notice_type] === m )
delete r.ffz_last_notices[notice_type];
messages.removeAt(0); messages.removeAt(0);
removed++; removed++;
@ -1052,13 +1200,16 @@ FFZ.prototype._modify_room = function(room) {
f.add_room(this.id, this); f.add_room(this.id, this);
this.set("ffz_chatters", {}); this.set("ffz_chatters", {});
this.set("ffz_ids", this.get('ffz_ids') || {}); this.set("ffz_ids", this.get('ffz_ids') || {});
this.set("ffz_last_notices", this.get('ffz_last_notices') || {});
} catch(err) { } catch(err) {
f.error("add_room: " + err); f.error("add_room: " + err);
} }
}, },
willDestroy: function() { willDestroy: function() {
this.get("pubsub").set("ffz_teardown_target", this.get('roomProperties._id'));
this._super(); this._super();
this.get("pubsub").set("ffz_teardown_target", null);
try { try {
f.remove_room(this.id); f.remove_room(this.id);
@ -1067,26 +1218,80 @@ FFZ.prototype._modify_room = function(room) {
} }
}, },
clearMessages: function(user, tags, disable_log) { addChannelModerationMessage: function(event) {
// Throw out messages that are for other rooms.
var room_id = '.' + this.get("roomProperties._id");
if ( event.topic && event.topic.substr(-room_id.length) !== room_id || event.created_by === this.get("session.userData.login") )
return;
var target_notice = NOTICE_MAPPING[event.moderation_action];
if ( target_notice ) {
var last_notice = this.ffz_last_notices && this.ffz_last_notices[target_notice];
if ( last_notice && ! last_notice.has_owner ) {
last_notice.message += ' (By: ' + event.created_by + ')';
last_notice.has_owner = true;
last_notice.cachedTokens = undefined;
if ( last_notice._line )
last_notice._line.ffzRender();
} else {
var waiting = this.ffz_waiting_notices = this.ffz_waiting_notices || {};
waiting[target_notice] = event.created_by;
}
} else if ( f.settings.get_twitch('showModerationActions') )
this._super(event);
},
addLoginModerationMessage: function(event) {
// Throw out messages that are for other rooms.
var room_id = '.' + this.get("roomProperties._id");
if ( event.topic && event.topic.substr(-room_id.length) !== room_id || event.created_by === this.get("session.userData.login") )
return;
// In case we get unexpected input, do the other thing.
if ( ["ban", "unban", "timeout"].indexOf(event.moderation_action) === -1 )
return this._super(event);
var tags = {
'ban-duration': event.moderation_action === 'unban' ? -Infinity : event.args[1],
'ban-reason': event.args[2],
'ban-moderator': event.created_by
};
this.clearMessages(event.args[0], tags, false, event.moderation_action !== 'unban');
},
clearMessages: function(user, tags, disable_log, report_only) {
var t = this; var t = this;
if ( user ) { if ( user ) {
var duration = Infinity, var duration = Infinity,
reason = undefined, reason = undefined,
moderator = undefined,
msg_id = undefined, msg_id = undefined,
current_user = f.get_user(), current_user = f.get_user(),
is_me = current_user && current_user.login === user; is_me = current_user && current_user.login === user;
// Read the ban duration and reason from the message tags. // Read the ban duration and reason from the message tags.
if ( tags && tags['ban-duration'] ) if ( tags && tags['ban-duration'] ) {
duration = parseInt(tags['ban-duration']); duration = tags['ban-duration'];
if ( typeof duration === 'string' )
duration = parseInt(duration);
if ( isNaN(duration) ) if ( isNaN(duration) )
duration = Infinity; duration = Infinity;
}
if ( tags && tags['ban-reason'] && (is_me || t.get('isModeratorOrHigher')) ) if ( tags && tags['ban-reason'] && (is_me || t.get('isModeratorOrHigher')) )
reason = tags['ban-reason']; reason = tags['ban-reason'];
if ( tags && tags['ban-moderator'] && (is_me || t.get('isModeratorOrHigher')) )
moderator = tags['ban-moderator'];
// Does anything really matter?
if ( ! report_only && duration !== -Infinity ) {
// Is there a UUID on the end of the ban reason? // Is there a UUID on the end of the ban reason?
if ( reason ) { if ( reason ) {
@ -1142,6 +1347,11 @@ FFZ.prototype._modify_room = function(room) {
if ( msg.tags && msg.tags.id === msg_id ) { if ( msg.tags && msg.tags.id === msg_id ) {
msgs.removeAt(i); msgs.removeAt(i);
delete this.ffz_ids[msg_id]; delete this.ffz_ids[msg_id];
var notice_type = msg.tags && msg.tags['msg-id'];
if ( notice_type && this.ffz_last_notices && this.ffz_last_notices[notice_type] === msg )
delete this.ffz_last_notices[notice_type];
break; break;
} }
} }
@ -1170,8 +1380,14 @@ FFZ.prototype._modify_room = function(room) {
if ( msg.from === user ) { if ( msg.from === user ) {
if ( f.settings.remove_deleted ) { if ( f.settings.remove_deleted ) {
// Remove this message from the ID tracker. // Remove this message from the ID tracker.
if ( msg.tags && msg.tags.id && this.ffz_ids && this.ffz_ids[msg.tags.id] ) var msg_id = msg.tags && msg.tags.id,
delete this.ffz_ids[msg.tags.id]; notice_type = msg.tags && msg.tags['msg-id'];
if ( msg_id && this.ffz_ids && this.ffz_ids[msg_id] )
delete this.ffz_ids[msg_id];
if ( notice_type && this.ffz_last_notices && this.ffz_last_notices[notice_type] === msg )
delete this.ffz_last_notices[notice_type];
msgs.removeAt(i); msgs.removeAt(i);
removed++; removed++;
@ -1199,6 +1415,9 @@ FFZ.prototype._modify_room = function(room) {
} }
} }
// End of report_only check.
}
// Now we need to see about displaying a ban notice. // Now we need to see about displaying a ban notice.
if ( ! disable_log ) { if ( ! disable_log ) {
@ -1220,7 +1439,11 @@ FFZ.prototype._modify_room = function(room) {
} }
// Display a notice in chat. // Display a notice in chat.
var message = (is_me ? "You have" : FFZ.get_capitalization(user) + " has") + " been " + (isFinite(duration) ? "timed out for " + utils.duration_string(duration, true) : "banned"); var message = (is_me ?
"You have" : ffz.format_display_name(FFZ.get_capitalization(user), user, true, false, true)[0] + " has") +
" been " + (duration === -Infinity ? 'unbanned' :
(duration === 1 ? 'purged' :
(isFinite(duration) ? "timed out for " + utils.duration_string(duration, true) : "banned")));
if ( show_notice ) { if ( show_notice ) {
if ( ! last_ban ) { if ( ! last_ban ) {
@ -1229,11 +1452,12 @@ FFZ.prototype._modify_room = function(room) {
date: now, date: now,
ffz_ban_target: user, ffz_ban_target: user,
reasons: reason ? [reason] : [], reasons: reason ? [reason] : [],
moderators: moderator ? [moderator] : [],
msg_ids: msg_id ? [msg_id] : [], msg_ids: msg_id ? [msg_id] : [],
durations: [duration], durations: [duration],
end_time: end_time, end_time: end_time,
timeouts: 1, timeouts: report_only ? 0 : 1,
message: message + (show_reason && reason ? ' with reason: ' + reason : '.') message: message + (show_reason && moderator ? ' by ' + moderator : '') + (show_reason && reason ? ' with reason: ' + reason : '.')
}; };
if ( ban_history ) if ( ban_history )
@ -1248,13 +1472,21 @@ FFZ.prototype._modify_room = function(room) {
if ( reason && last_ban.reasons.indexOf(reason) === -1 ) if ( reason && last_ban.reasons.indexOf(reason) === -1 )
last_ban.reasons.push(reason); last_ban.reasons.push(reason);
if ( moderator && last_ban.moderators.indexOf(moderator) === -1 )
last_ban.moderators.push(moderator);
if ( last_ban.durations.indexOf(duration) === -1 ) if ( last_ban.durations.indexOf(duration) === -1 )
last_ban.durations.push(duration); last_ban.durations.push(duration);
last_ban.end_time = end_time; last_ban.end_time = end_time;
last_ban.timeouts++;
last_ban.message = message + ' (' + utils.number_commas(last_ban.timeouts) + ' times)' + (!show_reason || last_ban.reasons.length === 0 ? '.' : ' with reason' + utils.pluralize(last_ban.reasons.length) + ': ' + last_ban.reasons.join(', ')); if ( ! report_only )
last_ban.timeouts++;
last_ban.message = message +
(last_ban.timeouts > 1 ? ' (' + utils.number_commas(last_ban.timeouts) + ' times)' : '') +
(!show_reason || last_ban.moderators.length === 0 ? '' : ' by ' + last_ban.moderators.join(', ') ) +
(!show_reason || last_ban.reasons.length === 0 ? '.' : ' with reason' + utils.pluralize(last_ban.reasons.length) + ': ' + last_ban.reasons.join(', '));
last_ban.cachedTokens = [{type: "text", text: last_ban.message}]; last_ban.cachedTokens = [{type: "text", text: last_ban.message}];
// Now that we've reset the tokens, if there's a line for this, // Now that we've reset the tokens, if there's a line for this,
@ -1333,9 +1565,15 @@ FFZ.prototype._modify_room = function(room) {
var to_remove = len - limit; var to_remove = len - limit;
for(var i = 0; i < to_remove; i++) { for(var i = 0; i < to_remove; i++) {
// Remove this message from the ID tracker. // Remove this message from the ID tracker.
var msg = messages.get(i); var msg = messages.get(i),
if ( msg.tags && msg.tags.id && this.ffz_ids && this.ffz_ids[msg.tags.id] ) msg_id = msg.tags && msg.tags.id,
delete this.ffz_ids[msg.tags.id]; notice_type = msg.tags && msg.tags['msg-id'];
if ( msg_id && this.ffz_ids && this.ffz_ids[msg_id] )
delete this.ffz_ids[msg_id];
if ( notice_type && this.ffz_last_notices && this.ffz_last_notices[notice_type] === msg )
delete this.ffz_last_notices[notice_type];
} }
messages.removeAt(0, to_remove); messages.removeAt(0, to_remove);
@ -1423,9 +1661,15 @@ FFZ.prototype._modify_room = function(room) {
var msg = this.ffzPending[i]; var msg = this.ffzPending[i];
if ( msg.removed ) { if ( msg.removed ) {
// Don't keep this message ID around. // Don't keep this message ID around.
var msg_id = msg && msg.tags && msg.tags.id; var msg_id = msg && msg.tags && msg.tags.id,
notice_type = msg && msg.tags && msg.tags['msg-id'];
if ( msg_id && this.ffz_ids && this.ffz_ids[msg_id] ) if ( msg_id && this.ffz_ids && this.ffz_ids[msg_id] )
delete this.ffz_ids[msg_id]; delete this.ffz_ids[msg_id];
if ( notice_type && this.ffz_last_notices && this.ffz_last_notices[notice_type] === msg )
delete this.ffz_last_notices[notice_type];
continue; continue;
} }
@ -1470,7 +1714,24 @@ FFZ.prototype._modify_room = function(room) {
if ( (msg.msgId === 'timeout_success' || msg.msgId === 'ban_success') && this.ffzShouldDisplayNotice() ) if ( (msg.msgId === 'timeout_success' || msg.msgId === 'ban_success') && this.ffzShouldDisplayNotice() )
return; return;
return this._super(msg); f.log("Notification", msg);
if ( ! msg.tags )
msg.tags = {};
if ( ! msg.tags['msg-id'] )
msg.tags['msg-id'] = msg.msgId;
if ( ! msg.style )
msg.style = 'admin';
if ( this.ffz_waiting_notices && this.ffz_waiting_notices[msg.msgId]) {
msg.has_owner = true;
msg.message += ' (By: ' + this.ffz_waiting_notices[msg.msgId] + ')';
delete this.ffz_waiting_notices[msg.msgId];
}
return this.addMessage(msg);
} }
}, },
@ -1481,7 +1742,8 @@ FFZ.prototype._modify_room = function(room) {
addMessage: function(msg) { addMessage: function(msg) {
if ( msg ) { if ( msg ) {
var is_resub = msg.tags && msg.tags['msg-id'] === 'resub', var notice_type = msg.tags && msg.tags['msg-id'],
is_resub = notice_type === 'resub',
room_id = this.get('id'), room_id = this.get('id'),
msg_id = msg.tags && msg.tags.id; msg_id = msg.tags && msg.tags.id;
@ -1510,8 +1772,11 @@ FFZ.prototype._modify_room = function(room) {
var is_whisper = msg.style === 'whisper'; var is_whisper = msg.style === 'whisper';
// Ignore whispers if conversations are enabled. // Ignore whispers if conversations are enabled.
if ( is_whisper && utils.ember_lookup('controller:application').get('isConversationsEnabled') ) if ( is_whisper ) {
return; var conv_enabled = utils.ember_lookup('controller:application').get('isConversationsEnabled');
if ( conv_enabled || (!conv_enabled && f.settings.hide_whispers_in_embedded_chat) )
return;
}
if ( ! is_whisper ) if ( ! is_whisper )
msg.room = room_id; msg.room = room_id;
@ -1638,6 +1903,12 @@ FFZ.prototype._modify_room = function(room) {
ids[msg_id] = msg; ids[msg_id] = msg;
} }
// If this is a notice, store that this is the last of its type.
if ( notice_type ) {
var ids = this.ffz_last_notices = this.ffz_last_notices || {};
ids[notice_type] = msg;
}
// Report this message to the dashboard. // Report this message to the dashboard.
if ( window !== window.parent && parent.postMessage && msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" ) if ( window !== window.parent && parent.postMessage && msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" )
parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, "*"); //location.protocol + "//www.twitch.tv/"); parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, "*"); //location.protocol + "//www.twitch.tv/");

View file

@ -185,8 +185,8 @@ FFZ.prototype.setup_sidebar = function() {
} }
// Sidebar Followed Games // Sidebar Followed Games
var GamesFollowing = utils.ember_lookup('controller:games-following'), var f = this,
f = this; GamesFollowing = utils.ember_lookup('controller:games-following');
if ( GamesFollowing ) { if ( GamesFollowing ) {
this.log("Hooking the Ember games-following controller."); this.log("Hooking the Ember games-following controller.");

View file

@ -86,7 +86,11 @@ FFZ.prototype.modify_viewer_list = function(component) {
first_user = false; first_user = false;
} }
viewers.push({chatter: FFZ.get_capitalization(data[x])}); var display_name = FFZ.get_capitalization(data[x]);
if ( display_name.trim().toLowerCase() !== data[x] )
display_name = data[x];
viewers.push({chatter: display_name});
} }
} }

View file

@ -239,6 +239,43 @@ FFZ.prototype.setup_bttv = function(delay) {
} }
}; };
// Tab Completion
var original_emotes = BC.emotes;
BC.emotes = function() {
var output = original_emotes(),
user = f.get_user(),
room_id = BetterTTV.getChannel(),
ffz_sets = f.getEmotes(user && user.login, room_id);
for(var i=0; i < ffz_sets.length; i++) {
var emote_set = f.emote_sets[ffz_sets[i]];
if ( ! emote_set )
continue;
var set_name = (emote_set.source || "FFZ") + " " + (emote_set.title || "Global") + " Emotes",
set_icon = emote_set.icon || (emote_set.hasOwnProperty('source_ext') && f._apis[emote_set.source_ext] && f._apis[emote_set.source_ext].icon) || '//cdn.frankerfacez.com/script/devicon.png';
for(var emote_id in emote_set.emoticons) {
var emote = emote_set.emoticons[emote_id];
if ( ! emote.hidden && emote.name ) {
output.push({
text: emote.name,
channel: set_name,
badge: set_icon,
url: emote.urls[1]
});
}
}
}
f.log("BTTV Emotes", output);
return output;
}
// Emoji! // Emoji!
var parse_emoji = function(token) { var parse_emoji = function(token) {
var setting = f.settings.parse_emoji, var setting = f.settings.parse_emoji,

240
src/less/dark-clips.less Normal file
View file

@ -0,0 +1,240 @@
/* Colors */
@fg-color: #a49ab5;
@bg-color: #101010;
@link-color: #a68ed2;
@remove-link-color: #fc3636;
@hollow-button-color: darken(@link-color, 5%); //#9d8dba;
@bright-bg: lighten(@bg-color, 15%);
@bright-fg: lighten(@fg-color, 15%);
@nav-bg-color: #191919;
.ffz-dark {
html&, body {
background-color: @bg-color;
color: @fg-color;
}
a {
color: @link-color;
&:hover, &:focus {
color: lighten(@link-color, 10%);
}
}
.sub-text { color: darken(@fg-color, 10%) }
// Navigation
.nav {
background-color: @nav-bg-color;
border-bottom-color: lighten(@nav-bg-color, 10%);
}
.svg-logo_twitch, .clips-nav__logo { fill: white }
// Buttons
.button {
&, &:hover, &:focus {
color: #fff;
}
figure img, figure svg {
fill: @link-color;
}
}
.button--hollow {
box-shadow: inset 0 0 0 1px fade(@link-color, 50%);
color: @hollow-button-color;
&:hover, &:focus {
background-color: fade(@link-color, 10%);
color: @hollow-button-color;
}
}
.button--hollow.button--dropmenu {
&:after {
}
}
// Balloons
.balloon {
background-color: lighten(@bg-color, 10%);
color: #ccc;
box-shadow: 0 0 0 1px fade(white, 20%), 0 1px 1px fade(white, 5%);
&:after {
background-color: lighten(@bg-color, 10%);
}
&--fancy {
color: lighten(@link-color, 5%);
box-shadow: 0 0 0 1px fade(white, 10%);
}
&--left:after { box-shadow: 1px -1px 0 fade(white, 20%) }
&--right:after { box-shadow: -1px 1px 0 fade(white, 20%) }
&--up:after { box-shadow: 1px 1px 0 fade(white, 20%) }
&--down:after { box-shadow: -1px -1px 0 fade(white, 20%) }
&--cols .balloon__list ~ .balloon__list { box-shadow: -1px 0 0 #202021 }
&__stroke { border-bottom-color: fade(white, 10%) }
.balloon__link {
color: @link-color !important;
&:hover {
background-color: @link-color !important;
color: @bg-color !important;
}
&.request-removal-link,
&.clip-remove-link {
color: @remove-link-color !important;
&:hover {
background-color: @remove-link-color !important;
color: white !important;
}
}
}
}
// Modal Content
.modal {
&__content {
background-color: @bg-color;
box-shadow: 0 1px 1px fade(white, 10%);
}
&-title {
color: @bright-fg;
}
&-body-text {
color: @fg-color;
}
}
// Table
.table {
background-color: @bg-color;
box-shadow: 0 2px 4px 0 fade(white, 20%);
&__row {
background-color: @bg-color;
color: @fg-color;
&:nth-child(even) {
background-color: lighten(@bg-color, 5%);
}
&:hover {
background-color: lighten(@bg-color, 10%);
}
&--no-hover:hover { background-color: @bg-color }
}
&__header {
background-color: lighten(@bg-color, 5%)
}
&__cell {
border-top-color: @bright-bg;
border-bottom-color: @bright-bg;
color: @fg-color;
}
&__cell--header {
border-bottom-color: @bright-bg;
color: @bright-fg;
}
&__zero-title {
color: @bright-fg;
}
&__zero-body {
color: @fg-color;
}
}
// Tabs
.tabs {
box-shadow: inset 0 -1px 0 #202021;
&__item {
box-shadow: inset 0 -1px 0 #202021;
& > a { color: @link-color }
&:hover, &--active {
box-shadow: inset 0 -1px 0 @link-color;
& > a {
color: @bright-fg;
}
}
}
}
.loading-spinner {
border-color: fade(white, 18%);
border-left-color: @bright-fg;
}
.expand-button__border,
.ldboard-head {
border-bottom-color: #3e3d40;
}
// Previewer
.ld-previewer__iframe, .previewer__pane {
background-color: @bg-color;
}
.previewer__close {
fill: @link-color;
&:hover, &:focus {
fill: lighten(@link-color, 10%);
}
}
// Labels
.label {
color: @bright-fg;
}
// Input
select,
.input--text {
background-color: @bg-color;
color: @bright-fg;
border-color: @bright-bg;
&:focus {
border-color: lighten(@bright-bg, 15%);
}
}
}

View file

@ -0,0 +1,5 @@
.ffz-darken-clips {
position: fixed;
bottom: 10px;
left: 10px;
}

View file

@ -34,7 +34,7 @@ FFZ.msg_commands = {};
// Version // Version
var VER = FFZ.version_info = { var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 270, major: 3, minor: 5, revision: 283,
toString: function() { toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
} }
@ -241,22 +241,20 @@ FFZ.prototype.initialize = function(increment, delay) {
return this.log("Found banned sub-domain. Not initializing."); return this.log("Found banned sub-domain. Not initializing.");
// Check for the player // Check for the player
if ( location.hostname === 'player.twitch.tv' ) { if ( location.hostname === 'player.twitch.tv' )
this.init_player(delay); return this.init_player(delay);
return;
} // Clips~
if ( location.hostname === 'clips.twitch.tv' )
return this.init_clips(delay);
// Check for special non-ember pages. // Check for special non-ember pages.
if ( /^\/(?:$|search$|team\/|user\/|p\/|settings|m\/|messages?\/)/.test(location.pathname) ) { if ( /^\/(?:$|search$|team\/|user\/|p\/|settings|m\/|messages?\/)/.test(location.pathname) )
this.init_normal(delay); return this.init_normal(delay);
return;
}
// Check for the dashboard. // Check for the dashboard.
if ( /\/[^\/]+\/dashboard/.test(location.pathname) && !/bookmarks$/.test(location.pathname) ) { if ( /\/[^\/]+\/dashboard/.test(location.pathname) && !/bookmarks$/.test(location.pathname) )
this.init_dashboard(delay); return this.init_dashboard(delay);
return;
}
var loaded = FFZ.utils.ember_resolve('model:room'); var loaded = FFZ.utils.ember_resolve('model:room');
if ( !loaded ) { if ( !loaded ) {
@ -273,6 +271,32 @@ FFZ.prototype.initialize = function(increment, delay) {
} }
FFZ.prototype.init_clips = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch Clips after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
this.users = {};
this.is_dashboard = false;
this.embed_in_dash = false;
this.is_clips = true;
try {
this.embed_in_clips = window.top !== window && window.top.location.hostname === 'clips.twitch.tv';
} catch(err) { this.embed_in_clips = false; }
this.load_settings();
this.setup_dark();
this.setup_css();
this.add_clips_darken_button();
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
duration = end - start;
this.log("Initialization complete in " + duration + "ms");
}
FFZ.prototype.init_player = function(delay) { FFZ.prototype.init_player = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now(); var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch Player after " + (delay||0) + " ms at: " + location); this.log("Found Twitch Player after " + (delay||0) + " ms at: " + location);
@ -415,8 +439,24 @@ FFZ.prototype.init_ember = function(delay) {
Settings.reopen({settings: Ember.computed.alias('model')}); Settings.reopen({settings: Ember.computed.alias('model')});
// Initialize all the modules. // Settings are important.
this.load_settings(); this.load_settings();
// Is debug mode enabled? Scratch that, everyone gets error handlers!
if ( true ) { //this.settings.developer_mode ) {
// Set up an error listener for RSVP.
var f = this;
if ( Ember.RSVP && Ember.RSVP.on )
Ember.RSVP.on('error', function(error) {
f.error("There was an error within an Ember RSVP.", error);
});
Ember.onerror = function(error) {
f.error("There was an unknown error within Ember.", error);
}
}
// Set up all the everything.
this.setup_ember_wrapper(); this.setup_ember_wrapper();
// Start this early, for quick loading. // Start this early, for quick loading.

View file

@ -67,6 +67,9 @@ FFZ.prototype.load_settings = function() {
this.settings.del = this._setting_del.bind(this); this.settings.del = this._setting_del.bind(this);
this.settings.load = this._setting_load.bind(this); this.settings.load = this._setting_load.bind(this);
this.settings.get_twitch = this._setting_get_twitch.bind(this);
var found_settings = false; var found_settings = false;
for(var key in FFZ.settings_info) { for(var key in FFZ.settings_info) {
@ -811,6 +814,11 @@ FFZ.prototype._setting_get = function(key) {
return this.settings[key]; return this.settings[key];
} }
FFZ.prototype._setting_get_twitch = function(key) {
var Settings = utils.ember_lookup('controller:settings');
return Settings && Settings.get('settings.' + key);
}
FFZ.prototype._setting_set = function(key, val, suppress_log) { FFZ.prototype._setting_set = function(key, val, suppress_log) {
var info = FFZ.settings_info[key], var info = FFZ.settings_info[key],

View file

@ -289,6 +289,46 @@ FFZ.prototype.setup_tokenization = function() {
} }
// ------------------------
// Display Name Formatting
// ------------------------
FFZ.prototype.format_display_name = function(display_name, user_id, disable_alias, disable_intl, disable_html) {
var setting = this.settings.username_display,
alias = this.aliases[user_id],
name_matches = ! display_name || display_name.trim().toLowerCase() === user_id,
tooltip,
display_name;
if ( setting === 0 )
display_name = user_id;
else if ( setting === 1 )
display_name = name_matches ? (display_name || (user_id && user_id.capitalize())) : user_id;
else {
display_name = utils.sanitize(display_name || (user_id && user_id.capitalize()));
if ( ! disable_intl && setting === 3 && ! name_matches )
display_name += disable_html ? '(' + user_id + ')' : ' <span class="intl-login">(' + user_id + ')</span>';
else if ( ((disable_intl && setting === 3) || setting === 4) && ! name_matches )
tooltip = user_id;
}
if ( ! disable_alias && alias ) {
if ( display_name )
tooltip = display_name + (tooltip ? ' (' + tooltip + ')' : '');
display_name = utils.sanitize(alias);
}
return [display_name, tooltip];
}
// --------------------- // ---------------------
// Twitch Emote Data // Twitch Emote Data
// --------------------- // ---------------------
@ -505,9 +545,14 @@ FFZ.prototype.tokenize_conversation_line = function(message, prevent_notificatio
if ( helpers && helpers.linkifyMessage ) if ( helpers && helpers.linkifyMessage )
tokens = helpers.linkifyMessage(tokens); tokens = helpers.linkifyMessage(tokens);
if ( user && user.login && helpers && helpers.mentionizeMessage ) if ( user && user.login && helpers && helpers.mentionizeMessage ) {
tokens = helpers.mentionizeMessage(tokens, user.login, from_me); tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
// Display names~~
if ( ! from_me && user.name && user.name.trim().toLowerCase() !== user.login )
tokens = helpers.mentionizeMessage(tokens, user.name, from_me);
}
if ( helpers && helpers.emoticonizeMessage && emotes && this.settings.parse_emoticons ) if ( helpers && helpers.emoticonizeMessage && emotes && this.settings.parse_emoticons )
tokens = helpers.emoticonizeMessage(tokens, emotes); tokens = helpers.emoticonizeMessage(tokens, emotes);
@ -546,14 +591,20 @@ FFZ.prototype.tokenize_vod_line = function(msgObject, delete_links) {
user = this.get_user(), user = this.get_user(),
from_me = user && from_user === user.login, from_me = user && from_user === user.login,
emotes = msgObject.get('tags.emotes'), emotes = msgObject.get('tags.emotes'),
tokens = [msg]; tokens = [msg];
if ( helpers && helpers.linkifyMessage ) if ( helpers && helpers.linkifyMessage )
tokens = helpers.linkifyMessage(tokens, delete_links); tokens = helpers.linkifyMessage(tokens, delete_links);
if ( user && user.login && helpers && helpers.mentionizeMessage ) if ( user && user.login && helpers && helpers.mentionizeMessage ) {
tokens = helpers.mentionizeMessage(tokens, user.login, from_me); tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
// Display names~~
if ( ! from_me && user.name && user.name.trim().toLowerCase() !== user.login )
tokens = helpers.mentionizeMessage(tokens, user.name, from_me);
}
if ( helpers && helpers.emoticonizeMessage && emotes && this.settings.parse_emoticons ) if ( helpers && helpers.emoticonizeMessage && emotes && this.settings.parse_emoticons )
tokens = helpers.emoticonizeMessage(tokens, emotes); tokens = helpers.emoticonizeMessage(tokens, emotes);
@ -620,9 +671,14 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
} }
if ( user && user.login && helpers && helpers.mentionizeMessage ) if ( user && user.login && helpers && helpers.mentionizeMessage ) {
tokens = helpers.mentionizeMessage(tokens, user.login, from_me); tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
// Display names~~
if ( ! from_me && user.name && user.name.trim().toLowerCase() !== user.login )
tokens = helpers.mentionizeMessage(tokens, user.name, from_me);
}
if ( helpers && helpers.emoticonizeMessage && this.settings.parse_emoticons ) if ( helpers && helpers.emoticonizeMessage && this.settings.parse_emoticons )
tokens = helpers.emoticonizeMessage(tokens, emotes); tokens = helpers.emoticonizeMessage(tokens, emotes);
@ -754,8 +810,13 @@ FFZ.prototype.tokenize_line = function(user, room, message, no_emotes, no_emoji)
if ( helpers && helpers.mentionizeMessage ) { if ( helpers && helpers.mentionizeMessage ) {
var u = this.get_user(); var u = this.get_user();
if ( u && u.login ) if ( u && u.login ) {
message = helpers.mentionizeMessage(message, u.login, user === u.login); message = helpers.mentionizeMessage(message, u.login, user === u.login);
// Display names~~
if ( ! user === u.login && u.name && u.name.trim().toLowerCase() !== u.login )
tokens = helpers.mentionizeMessage(tokens, u.name, from_me);
}
} }
if ( ! no_emotes && this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 ) if ( ! no_emotes && this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 )

View file

@ -135,7 +135,7 @@ FFZ.settings_info.dark_twitch = {
if ( this.has_bttv ) if ( this.has_bttv )
return; return;
document.body.classList.toggle("ffz-dark", val); (this.is_clips ? document.querySelector('html') : document.body).classList.toggle("ffz-dark", val);
var Settings = utils.ember_lookup('controller:settings'), var Settings = utils.ember_lookup('controller:settings'),
settings = Settings && Settings.get('settings'); settings = Settings && Settings.get('settings');
@ -148,7 +148,7 @@ FFZ.settings_info.dark_twitch = {
settings && settings.set('darkMode', this.settings.twitch_chat_dark); settings && settings.set('darkMode', this.settings.twitch_chat_dark);
// Try coloring chat replay // Try coloring chat replay
jQuery('.chatReplay').toggleClass('dark', val || false); window.jQuery && jQuery('.chatReplay').toggleClass('dark', val || false);
//jQuery('.rechat-chat-line').parents('.chat-container').toggleClass('dark', val || this.settings.twitch_chat_dark); //jQuery('.rechat-chat-line').parents('.chat-container').toggleClass('dark', val || this.settings.twitch_chat_dark);
} }
}; };
@ -198,7 +198,8 @@ FFZ.prototype.setup_dark = function() {
if ( this.has_bttv ) if ( this.has_bttv )
return; return;
document.body.classList.toggle("ffz-dark", this.settings.dark_twitch); (this.is_clips ? document.querySelector('html') : document.body).classList.toggle('ffz-dark', this.settings.dark_twitch);
if ( ! this.settings.dark_twitch ) if ( ! this.settings.dark_twitch )
return; return;
@ -226,6 +227,24 @@ FFZ.prototype._load_dark_css = function() {
s.id = "ffz-dark-css"; s.id = "ffz-dark-css";
s.setAttribute('rel', 'stylesheet'); s.setAttribute('rel', 'stylesheet');
s.setAttribute('href', constants.SERVER + "script/dark" + (constants.DEBUG ? "" : ".min") + ".css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info)); s.setAttribute('href', constants.SERVER + "script/dark" + (this.is_clips ? '-clips' : '') + (constants.DEBUG ? "" : ".min") + ".css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info));
document.head.appendChild(s); document.head.appendChild(s);
}
FFZ.prototype.add_clips_darken_button = function() {
if ( this.embed_in_clips )
return;
this.log("Adding Clips Darken button.");
var f = this,
btn = utils.createElement('a', 'button button--hollow ffz-darken-clips', f.settings.dark_twitch ? 'Light' : 'Dark');
btn.addEventListener('click', function() {
f.settings.set('dark_twitch', ! f.settings.dark_twitch);
btn.textContent = f.settings.dark_twitch ? 'Light' : 'Dark';
});
document.body.appendChild(btn);
} }

View file

@ -299,20 +299,22 @@ FFZ.prototype._build_following_button = function(cont, channel_id) {
return this.log("Ignoring Invalid Channel: " + utils.sanitize(channel_id)); return this.log("Ignoring Invalid Channel: " + utils.sanitize(channel_id));
var f = this, var f = this,
btn = utils.createElement('button', 'follow-button button'), btn = utils.createElement('button', 'follow-button button html-tooltip'),
noti = utils.createElement('a', 'toggle-notification-menu js-toggle-notification-menu'), noti = utils.createElement('a', 'toggle-notification-menu js-toggle-notification-menu'),
noti_c = utils.createElement('div', 'notification-controls v2 hidden', noti), noti_c = utils.createElement('div', 'notification-controls v2 hidden', noti),
display_name, display_name,
tooltip,
following = false, following = false,
notifications = false, notifications = false,
update = function() { update = function() {
btn.classList.toggle('is-following', following); btn.classList.toggle('is-following', following);
btn.classList.toggle('button--status', following); btn.classList.toggle('button--status', following);
btn.title = (following ? "Unf" : "F") + "ollow " + utils.sanitize(display_name); btn.title = tooltip ? (following ? "Unf" : "F") + "ollow " + tooltip : '';
btn.innerHTML = (following ? "" : "Follow ") + utils.sanitize(display_name); btn.innerHTML = (following ? "" : "Follow ") + display_name;
noti_c.classList.toggle('hidden', !following); noti_c.classList.toggle('hidden', !following);
}, },
@ -353,7 +355,9 @@ FFZ.prototype._build_following_button = function(cont, channel_id) {
}, },
on_name = function(cap_name) { on_name = function(cap_name) {
display_name = cap_name || channel_id; var results = f.format_display_name(cap_name, channel_id, true, true);
display_name = results[0];
tooltip = results[1];
update(); update();
}; };
@ -404,9 +408,7 @@ FFZ.prototype._build_following_button = function(cont, channel_id) {
return false; return false;
}); });
on_name(FFZ.get_capitalization(channel_id, on_name));
display_name = FFZ.get_capitalization(channel_id, on_name);
update();
setTimeout(check_following, Math.random()*5000); setTimeout(check_following, Math.random()*5000);
@ -429,7 +431,9 @@ FFZ.prototype._build_following_popup = function(container, channel_id, notificat
this._popup_allow_parent = true; this._popup_allow_parent = true;
this._popup_parent = container; this._popup_parent = container;
out = '<div class="header">You are following ' + FFZ.get_capitalization(channel_id) + '</div>'; var results = this.format_display_name(FFZ.get_capitalization(channel_id), channel_id, true);
out = '<div class="header">You are following <span' + (results[1] ? ' class="html-tooltip" title="' + utils.quote_attr(results[1]) + '"' : '') + '>' + results[0] + '</span></div>';
out += '<p class="clearfix">'; out += '<p class="clearfix">';
out += '<a class="switch' + (notifications ? ' active' : '') + '"><span></span></a>'; out += '<a class="switch' + (notifications ? ' active' : '') + '"><span></span></a>';
out += '<span class="switch-label">Notify me when the broadcaster goes live</span>'; out += '<span class="switch-label">Notify me when the broadcaster goes live</span>';

View file

@ -80,15 +80,10 @@ FFZ.prototype.setup_menu = function() {
if ( ! menu ) if ( ! menu )
return; return;
var header = document.createElement('div'), var header = utils.createElement('div', 'list-header', 'FrankerFaceZ'),
content = document.createElement('div'), content = utils.createElement('div', 'chat-menu-content'),
p, cb, a; p, cb, a;
header.className = 'list-header';
header.innerHTML = 'FrankerFaceZ';
content.className = 'chat-menu-content';
// Dark Twitch // Dark Twitch
p = document.createElement('p'); p = document.createElement('p');
p.className = 'no-bttv'; p.className = 'no-bttv';

View file

@ -504,7 +504,7 @@ FFZ.menu_pages.myemotes = {
menu_id = set.hasOwnProperty('source_ext') ? 'ffz-ext-' + set.source_ext + '-' + set.source_id : 'ffz-' + set.id, menu_id = set.hasOwnProperty('source_ext') ? 'ffz-ext-' + set.source_ext + '-' + set.source_id : 'ffz-' + set.id,
favorites = this.settings.favorite_emotes[menu_id] || [], favorites = this.settings.favorite_emotes[menu_id] || [],
c = 0, c = 0,
icon = set.icon || (set.hasOwnProperty('source_ext') && '//cdn.frankerfacez.com/emoji/tw-1f4ac.svg') || '//cdn.frankerfacez.com/script/devicon.png', icon = set.icon || (set.hasOwnProperty('source_ext') && this._apis[set.source_ext] && this._apis[set.source_ext].icon) || '//cdn.frankerfacez.com/script/devicon.png',
collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf(menu_id) === -1; collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf(menu_id) === -1;
menu.className = 'emoticon-grid'; menu.className = 'emoticon-grid';

View file

@ -11,7 +11,7 @@ FFZ.prototype.setup_css = function() {
var s = this._main_style = document.createElement('link'); var s = this._main_style = document.createElement('link');
s.id = "ffz-main-css"; s.id = "ffz-main-css";
s.setAttribute('rel', 'stylesheet'); s.setAttribute('rel', 'stylesheet');
s.setAttribute('href', constants.SERVER + "script/style" + (constants.DEBUG ? "" : ".min") + ".css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info)); s.setAttribute('href', constants.SERVER + "script/style" + (this.is_clips ? '-clips' : '') + (constants.DEBUG ? "" : ".min") + ".css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info));
document.head.appendChild(s); document.head.appendChild(s);
this.log("Readying toggleable styles."); this.log("Readying toggleable styles.");

127
style.css
View file

@ -39,22 +39,24 @@ body:not(.ffz-show-bits-tags) .ember-chat .chat-messages.bits-tags__offset {
} }
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + .ffz-ui-toggle svg, body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + .ffz-ui-toggle svg,
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + script + .ffz-ui-toggle svg body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + div + .ffz-ui-toggle svg
{ {
height: 14px; height: 14px;
width: 18px; width: 18px;
} }
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + .ffz-ui-toggle, body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + .ffz-ui-toggle,
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + script + .ffz-ui-toggle { body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + div + .ffz-ui-toggle {
height: 14px; height: 14px;
width: 18px; width: 18px;
top: 28px; top: 28px;
right: 6px;
} }
.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); }
.carousel__item .card__img .overlay_info.live svg path,
.streams .stream .content .overlay_info.live svg path, .streams .stream .content .overlay_info.live svg path,
.videos .video .content .overlay_info.live svg path { fill: #ff2020; } .videos .video .content .overlay_info.live svg path { fill: #ff2020; }
@ -1257,7 +1259,8 @@ img.channel_background[src="null"] { display: none; }
} }
.ember-chat .ffz-moderation-card .close-button { .ember-chat .ffz-moderation-card .close-button {
right: 7px; right: 7px;
width: 20px;
} }
.ember-chat .ffz-moderation-card .extra-interface { .ember-chat .ffz-moderation-card .extra-interface {
@ -1268,13 +1271,17 @@ img.channel_background[src="null"] { display: none; }
margin-top: -10px; margin-top: -10px;
} }
.ffz-moderation-card.ffz-has-info h3.name { .ffz-moderation-card.ffz-has-info h4.name {
margin-top: -2px; /*margin-top: -2px;*/
margin-bottom: 0; margin-bottom: 0;
padding-top: 0; padding-top: 0;
white-space: nowrap; white-space: nowrap;
} }
.ffz-moderation-card.ffz-has-info .name .intl-login {
margin: -2px 0 -4px;
}
.ffz-moderation-card .info { .ffz-moderation-card .info {
float: none; float: none;
position: relative; position: relative;
@ -1359,10 +1366,10 @@ img.channel_background[src="null"] { display: none; }
border-top: none; border-top: none;
} }
.ffz-moderation-card h3.name { display: inline-block; } .ffz-moderation-card h4.name { display: inline-block; }
.ffz-moderation-card .info, .ffz-moderation-card .info,
.ffz-moderation-card h3.name { .ffz-moderation-card h4.name {
text-shadow: black 0 0 5px; text-shadow: black 0 0 5px;
} }
@ -1403,7 +1410,7 @@ img.channel_background[src="null"] { display: none; }
background-color: #232323; background-color: #232323;
} }
.moderation-card h3.name a { color: #fff !important; } .moderation-card h4.name a { color: #fff !important; }
/* purge icon */ /* purge icon */
@ -1799,7 +1806,7 @@ th.ffz-row-switch {
.ffz-room-row td > span:empty, .ffz-room-row td > span:empty,
.ffz-chat-tab span:empty { display: none; } .ffz-chat-tab span:empty { display: none; }
.ffz-room-row td > span, .ffz-room-row td > span:not(.intl-login),
.ffz-chat-tab span { .ffz-chat-tab span {
padding: 0 4px; padding: 0 4px;
display: inline-block; display: inline-block;
@ -1815,7 +1822,7 @@ th.ffz-row-switch {
position: relative; position: relative;
} }
.ffz-room-row td > span { .ffz-room-row td > span:not(.intl-login) {
line-height: 16px; line-height: 16px;
margin: 5px 0; margin: 5px 0;
} }
@ -1860,7 +1867,7 @@ th.ffz-row-switch {
color: #B9A3E3; color: #B9A3E3;
} }
.ffz-dark .ffz-room-row td > span, .ffz-dark .ffz-room-row td > span:not(.intl-login),
.app-main.theatre .ffz-chat-tab span, .app-main.theatre .ffz-chat-tab span,
.chat-container.dark .ffz-chat-tab span, .chat-container.dark .ffz-chat-tab span,
.ember-chat-container.dark .ffz-chat-tab span { .ember-chat-container.dark .ffz-chat-tab span {
@ -2186,11 +2193,11 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter
.ffz-no-blue .theatre .conversation-system-message, .ffz-no-blue .theatre .conversation-system-message,
.ffz-no-blue.ffz-dark .conversation-system-message, .ffz-no-blue.ffz-dark .conversation-system-message,
.ffz-no-blue .theatre .bits-card, .ffz-no-blue .app-main.theatre .bits-card,
.ffz-no-blue .dark .bits-card, .ffz-no-blue .dark .bits-card,
.ffz-no-blue .force-dark .bits-card, .ffz-no-blue .force-dark .bits-card,
.ffz-no-blue .theatre .bits-card--standard, .ffz-no-blue .app-main.theatre .bits-card--standard,
.ffz-no-blue .dark .bits-card--standard, .ffz-no-blue .dark .bits-card--standard,
.ffz-no-blue .force-dark .bits-card--standard, .ffz-no-blue .force-dark .bits-card--standard,
@ -2256,6 +2263,10 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter
background-color: #191919; background-color: #191919;
} }
.ffz-no-blue .app-main.theatre .bits-footer,
.ffz-no-blue .dark .bits-footer,
.ffz-no-blue .force-dark .bits-footer,
.ffz-no-blue .theatre .conversation-input-bar textarea, .ffz-no-blue .theatre .conversation-input-bar textarea,
.ffz-no-blue .theatre input.text, .ffz-no-blue .theatre input.text,
.ffz-no-blue .theatre input.countries-input, .ffz-no-blue .theatre input.countries-input,
@ -2320,13 +2331,13 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter
border-bottom-color: #323232; border-bottom-color: #323232;
} }
.ffz-no-blue .theatre .conversation-header, .ffz-no-blue .theatre .convoHeader,
.ffz-no-blue.ffz-dark .conversation-header, .ffz-no-blue.ffz-dark .convoHeader,
.ffz-no-blue .theatre .conversations-list .search-divider, .ffz-no-blue .theatre .conversations-list .search-divider,
.ffz-no-blue.ffz-dark .conversations-list .search-divider, .ffz-no-blue.ffz-dark .conversations-list .search-divider,
.ffz-no-blue.ffz-dark .conversations-list .conversations-list-header, .ffz-no-blue.ffz-dark .conversations-list .conversations-list-header,
.ffz-no-blue .theatre .conversation-window.has-focus .conversation-header, .ffz-no-blue .theatre .conversation-window.has-focus .convoHeader,
.ffz-no-blue.ffz-dark .conversation-window.has-focus .conversation-header, .ffz-no-blue.ffz-dark .conversation-window.has-focus .convoHeader,
.ffz-no-blue .theatre .conversations-list .conversations-list-item:hover, .ffz-no-blue .theatre .conversations-list .conversations-list-item:hover,
.ffz-no-blue.ffz-dark .conversations-list .conversations-list-item:hover { .ffz-no-blue.ffz-dark .conversations-list .conversations-list-item:hover {
background-color: #121212; background-color: #121212;
@ -2418,7 +2429,7 @@ li[data-name="following"] a {
max-height: 90px; max-height: 90px;
} }
/* Player Captions *\/ /* Player Captions */
.ffz-dark .player-modal__content, .ffz-dark .player-modal__content,
.theatre .player-modal__content { .theatre .player-modal__content {
@ -2457,7 +2468,7 @@ li[data-name="following"] a {
} }
.ffz-dark label.cc-edge-palette__square, .ffz-dark label.cc-edge-palette__square,
.theatre label.cc-edge-palette__square { color: #fff }*/ .theatre label.cc-edge-palette__square { color: #fff }
/* Classic Player */ /* Classic Player */
@ -2484,12 +2495,12 @@ li[data-name="following"] a {
} }
.ffz-classic-player .app-main.theatre .player .player-video, .ffz-classic-player .app-main.theatre .player .player-video,
.ffz-classic-player .player[data-fullscreen="true"] .player-video { .ffz-classic-player .player[data-isfullscreen="true"] .player-video {
bottom: 0; bottom: 0;
} }
.ffz-classic-player .app-main.theatre .player .player-controls-bottom, .ffz-classic-player .app-main.theatre .player .player-controls-bottom,
.ffz-classic-player .player[data-fullscreen="true"] .player-controls-bottom { .ffz-classic-player .player[data-isfullscreen="true"] .player-controls-bottom {
margin-bottom: -32px; margin-bottom: -32px;
-webkit-transition: margin-bottom .2s ease-out, padding-bottom .2s ease-out; -webkit-transition: margin-bottom .2s ease-out, padding-bottom .2s ease-out;
transition: margin-bottom .2s ease-out, padding-bottom .2s ease-out; transition: margin-bottom .2s ease-out, padding-bottom .2s ease-out;
@ -2497,23 +2508,22 @@ li[data-name="following"] a {
.ffz-classic-player:not(.ffz-top-conversations):not(.ffz-theatre-conversations) .app-main.theatre .player .player-controls-bottom, .ffz-classic-player:not(.ffz-top-conversations):not(.ffz-theatre-conversations) .app-main.theatre .player .player-controls-bottom,
.ffz-classic-player:not(.ffz-top-conversations):not(.ffz-theatre-conversations) .app-main.theatre .player[data-controls=true] .player-controls-bottom, .ffz-classic-player:not(.ffz-top-conversations):not(.ffz-theatre-conversations) .app-main.theatre .player[data-controls=true] .player-controls-bottom,
.ffz-classic-player .app-main.theatre .player[data-fullscreen="true"] .player-controls-bottom, .ffz-classic-player .app-main.theatre .player[data-isfullscreen="true"] .player-controls-bottom,
.ffz-classic-player .app-main.theatre .player[data-fullscreen="true"][data-controls=true] .player-controls-bottom { .ffz-classic-player .app-main.theatre .player[data-isfullscreen="true"][data-controls=true] .player-controls-bottom {
padding-bottom: 0; padding-bottom: 0;
} }
.ffz-classic-player .app-main.theatre .player.player-isvod .player-controls-bottom, .ffz-classic-player .app-main.theatre .player.player-isvod .player-controls-bottom,
.ffz-classic-player .player.player-isvod[data-fullscreen="true"] .player-controls-bottom { .ffz-classic-player .player.player-isvod[data-isfullscreen="true"] .player-controls-bottom {
margin-bottom: -36px; margin-bottom: -36px;
} }
.ffz-classic-player .app-main.theatre .player-column:hover .player .player-controls-bottom, .ffz-classic-player .app-main.theatre .player-column .player[data-controls=true] .player-controls-bottom,
.ffz-classic-player .app-main.theatre .player-column:focus .player .player-controls-bottom, .ffz-classic-player .player[data-isfullscreen="true"][data-controls="true"] .player-controls-bottom {
.ffz-classic-player .player[data-fullscreen="true"][data-controls="true"] .player-controls-bottom {
margin-bottom: 0; margin-bottom: 0;
} }
.ffz-classic-player:not(.ffz-top-conversations):not(.ffz-theatre-conversations) .app-main.theatre .player-column:hover .player[data-fullscreen="false"] .player-controls-bottom { .ffz-classic-player:not(.ffz-top-conversations):not(.ffz-theatre-conversations) .app-main.theatre .player[data-isfullscreen=false][data-controls=true] .player-controls-bottom {
padding-bottom: 40px; padding-bottom: 40px;
} }
@ -2569,8 +2579,14 @@ li[data-name="following"] a {
.item .meta .title a a, .item .meta .title a a,
.item .meta .title a img { pointer-events: none } .item .meta .title a img { pointer-events: none }
.ffz-directory-logo .card__body,
.ffz-directory-logo .meta {
padding-top: 5px;
}
.ffz-directory-logo .card__title,
.ffz-directory-logo .meta p.title { .ffz-directory-logo .meta p.title {
padding-top: 4px; padding-top: 4px;
min-height: 24px; min-height: 24px;
} }
@ -2656,11 +2672,9 @@ body:not(.ffz-bttv) .conversation-window .ignore-cta:not(.hidden) + .conversatio
.conversation-window.collapsed .ignore-cta, .conversation-window.collapsed .ignore-cta,
.conversation-chat-line.action .colon, .conversation-chat-line.action .colon,
.conversation-input-bar .emoticon-selector .tabs, .conversation-input-bar .emoticon-selector .tabs,
.conversation-preview-line .badges, .conversation-preview-line .badges { display:none }
body.ffz-conv-title-clickable .conversation-header span.conversation-header-name,
body:not(.ffz-conv-title-clickable) .conversation-header a.conversation-header-name { display:none }
.conversation-window.has-unread .conversation-header .conversation-header-name { color: #fff !important; } .conversation-window.has-unread .convoHeader .username { color: #fff !important; }
/* Top Conversations */ /* Top Conversations */
@ -2680,7 +2694,7 @@ body:not(.ffz-top-conversations) .conversations-list-bottom-bar {
top: 0px; top: 0px;
} }
.ffz-top-conversations .conversation-window.collapsed .conversation-header { .ffz-top-conversations .conversation-window.collapsed .convoHeader {
box-shadow: none; box-shadow: none;
} }
@ -2758,13 +2772,15 @@ body:not(.ffz-top-conversations) .conversations-list-bottom-bar {
.user.item { position: relative; } .user.item { position: relative; }
.card__img .overlay_info.length,
.user.item .overlay_info.length { .user.item .overlay_info.length {
position: absolute; position: absolute;
top: 5px; top: 5px;
right: 25px; right: 15px;
z-index: 1; z-index: 1;
display: inline-block; display: inline-block;
cursor: pointer;
padding: 0 5px; padding: 0 5px;
font-size: 11px; font-size: 11px;
@ -2775,18 +2791,20 @@ body:not(.ffz-top-conversations) .conversations-list-bottom-bar {
opacity: 0.75; opacity: 0.75;
} }
.card__img .overlay_info.length { right: 5px }
.card__img .overlay_info.length svg,
.user.item .overlay_info.length svg { .user.item .overlay_info.length svg {
float: left; float: left;
margin: 3px 5px 3px 0; margin: 3px 5px 3px 0;
} }
.card__img .overlay_info.length svg path,
.user.item .actions .follow svg path, .user.item .actions .follow svg path,
.user.item .overlay_info.length svg path { fill: #fff; } .user.item .overlay_info.length svg path { fill: #fff; }
.user.item .actions { .user.item .actions {
margin-top: -15px; margin-top: 5px;
margin-bottom: 20px;
margin-right: 20px;
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
} }
@ -2901,10 +2919,12 @@ body:not(.ffz-creative-showcase) .ct-spotlight-container { display: none; }
/* Banned and Spoiler Games */ /* Banned and Spoiler Games */
body:not([data-current-path^="directory.csgo"]):not([data-current-path^="directory.game"]):not([data-current-path^="directory.creative"]) .ffz-game-banned { display: none } body:not([data-current-path^="directory.csgo"]):not([data-current-path^="directory.game"]):not([data-current-path^="directory.creative"]) .ffz-game-banned { display: none !important }
.ffz-game-spoilered .card__img a:not(.card__boxpin) img,
.ffz-game-spoilered .thumb .cap img { visibility: hidden } .ffz-game-spoilered .thumb .cap img { visibility: hidden }
.ffz-game-spoilered .card__img a:not(.card__boxpin):after,
.ffz-game-spoilered .thumb .cap:after { .ffz-game-spoilered .thumb .cap:after {
position: absolute; position: absolute;
top: 0; left: 0; top: 0; left: 0;
@ -2986,7 +3006,7 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
/* Hide Outlines */ /* Hide Outlines */
.conversation-header, .convoHeader,
.conversations-list-icon, .conversations-list-icon,
.toggle-notification-menu { .toggle-notification-menu {
outline: none !important outline: none !important
@ -2997,6 +3017,10 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
.badges .badge { background-size: 18px 18px } .badges .badge { background-size: 18px 18px }
.convoHeader .badges .badge {
background-size: 14px 14px;
}
/*.badges .badge { /*.badges .badge {
height: 18px; height: 18px;
min-width: 18px; min-width: 18px;
@ -3145,6 +3169,29 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
content: attr(data-amount); content: attr(data-amount);
} }
.theatre .bits-purchase__header,
.dark .bits-purchase__header,
.force-dark .bits-purchase__header {
color: #acacbf;
}
.theatre .bits-card,
.app-main.theatre .chat-container .bits-card, /* Twitch's CSS is retarded */
.dark .bits-card,
.force-dark .bits-card,
.theatre .bits-purchase__row,
.dark .bits-purchase__row,
.force-dark .bits-purchase__row,
.theatre .bits-footer,
.dark .bits-footer,
.force-dark .bits-footer {
border-color: rgba(255,255,255,0.2);
color: #ccc;
}
/* New Chat Formatting */ /* New Chat Formatting */
.ember-chat .chat-messages .timestamp { margin-right: 0; } .ember-chat .chat-messages .timestamp { margin-right: 0; }