1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00

3.5.398. Three updates in one, I'm bad. New dashboard stuff. AutoMod badge. API helper functions for channel metadata.

This commit is contained in:
SirStendec 2016-12-14 02:40:18 -05:00
parent 439f2c32ae
commit b253f1a4d1
15 changed files with 335 additions and 23 deletions

View file

@ -1,3 +1,27 @@
<div class="list-header">3.5.398 <time datetime="2016-12-14">(2016-12-14)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Standalone Dashboard mode. Append <code>?standalone</code> to the end of the URL for your dashboard to see it. (Thanks to Warchamp7 for this idea.)</li>
<li>Changed: Minor CSS tweaks for the dashboard.</li>
<li>Fixed: Correct Twitch's uptime string formatting on the dashboard to not be blatantly wrong.</li>
</ul>
<div class="list-header">3.5.397 <time datetime="2016-12-12">(2016-12-12)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Darken the new dashboard.</li>
<li>Fixed: Ensure the FFZ chat menu can't be wider than dashboard chat.</li>
<li>&nbsp;</li>
<li>Other dashboard features will be returning as I have time to fix them.</li>
</ul>
<div class="list-header">3.5.396 <time datetime="2016-12-12">(2016-12-12)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Support for AutoMod's badge.</li>
<li>Fixed: Darken the new AutoMod UI on the channel settings page.</li>
<li>Fixed: Use a chatter's display name rather than their username when tab-completing if the message starts with <code>/me> </code>.</li>
<li>API Added: <code>api.register_metadata</code> and <code>api.unregister_metadata</code> functions for registering custom channel metadata providers.</li>
</ul>
<div class="list-header">3.5.395 <time datetime="2016-12-10">(2016-12-10)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: <code>/renamegroup</code> chat command to rename the current group chat room.</li>
@ -57,10 +81,5 @@
<li>Added: Support high-DPI images for custom moderator badges.</li>
</ul>
<div class="list-header">3.5.385 <time datetime="2016-11-30">(2016-11-30)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Mod cards not properly initializing in channels where you're not a mod.</li>
</ul>
<div class="list-header" id="ffz-old-news-button"><a href="#">View Older</a></div>
<div id="ffz-old-news"></div>

View file

@ -170,8 +170,8 @@ body.ffz-dark:not([data-page="teams#show"]),
/* Popups */
.ffz-dark #commission_modal {
background-color: #101010 !important;
border-color: #32323e !important;
background-color: #101010 !important;
border-color: #32323e !important;
}
.ffz-dark .twitch_subwindow_container.two-factor-auth .card,
@ -1108,12 +1108,22 @@ body.ffz-dark:not([data-page="teams#show"]),
-webkit-filter: invert(100%);
}
.ffz-dark .form__input[type=text],
.ffz-dark .form__input[type=email],
.ffz-dark .form__input[type=search],
.ffz-dark textarea.form__input,
.ffz-dark select.form__input,
.ffz-dark .new-header-search input {
color: #fff;
background-color: rgba(255,255,255,0.05);
box-shadow: rgba(255,255,255,0.2) 0 0 0 1px inset;
}
.ffz-dark .form__input[type=text]:focus,
.ffz-dark .form__input[type=email]:focus,
.ffz-dark .form__input[type=search]:focus,
.ffz-dark textarea.form__input:focus,
.ffz-dark select.form__input:focus,
.ffz-dark .new-header-search input:focus {
box-shadow: rgba(255,255,255,0.4) 0 0 0 1px inset;
}
@ -1512,10 +1522,19 @@ body.ffz-dark:not([data-page="teams#show"]),
box-shadow: inset 0 -1px 0 #161616, -1px 1px rgba(255,255,255,0.065);
}
.ffz-dark .twitchbot-border-more,
.ffz-dark .border-t,
.ffz-dark .border-b,
.ffz-dark .cn-metabar__more {
border-color: rgba(255,255,255,0.2) !important;
}
.ffz-dark .twitchbot-hover-text-help,
.ffz-dark .twitchbot-rule-container:hover,
.ffz-dark .twitchbot-right-container {
background-color: #191919;
}
.ffz-dark .cn-bar__button--resubscribe,
.ffz-dark .button--icon.cn-bar__button--subscribed {
@ -1524,6 +1543,8 @@ body.ffz-dark:not([data-page="teams#show"]),
}
.ffz-dark .twitchbot-help,
.ffz-dark .twitchbot-level-context,
.ffz-dark .cn-bar__avatar-wrap {
background-color: #101010;
border-color: #101010;
@ -1573,4 +1594,22 @@ body.ffz-dark:not([data-page="teams#show"]),
.ffz-dark .balloon .filter-bar__balloon-link--active {
color: #fff !important;
background-color: #6441a5 !important;
}
/* New Dashboard */
.ffz-dark .gu-transit,
.ffz-dark .dash-widget {
background-color: #191919;
border-color: rgba(255,255,255,0.2);
box-shadow: 0 2px 2px 0 rgba(255,255,255,0.05);
color: #c3c3c3;
}
.ffz-dark .form__input[type=checkbox]:not(:checked)+label:before,
.ffz-dark .form__input[type=radio]:not(:checked)+label:before,
.ffz-dark .dash-widget__header {
background-color: #232323;
border-color: rgba(255,255,255,0.2);
}

View file

@ -1,3 +1,8 @@
<div class="list-header">3.5.385 <time datetime="2016-11-30">(2016-11-30)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Mod cards not properly initializing in channels where you're not a mod.</li>
</ul>
<div class="list-header">3.5.384 <time datetime="2016-11-29">(2016-11-29)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Issue causing empty chat lines when badge data has not yet loaded.</li>

View file

@ -11,6 +11,7 @@ var FFZ = window.FrankerFaceZ,
global_mod: { 1: { color: "#0c6f20", use_svg: true } },
broadcaster: { 1: { color: "#e71818", use_svg: true } },
moderator: { 1: { color: "#34ae0a", use_svg: true } },
twitchbot: { 1: { color: "#34ae0a" } },
turbo: { 1: { color: "#6441a5", use_svg: true } },
premium: { 1: { color: "#009cdc" } },
@ -41,6 +42,7 @@ var FFZ = window.FrankerFaceZ,
'global_mod': 0,
'mod': 1,
'moderator': 1,
'twitchbot': 1,
'subscriber': 10,
},

View file

@ -355,6 +355,25 @@ FFZ.chat_commands.fetch_link.label = '/fetch_link &lt;url&gt; <i>[template]</i>'
FFZ.chat_commands.fetch_link.info = 'Fetch URL and Display in Chat';
// --------------------------
// Message-Specific Deletion
// --------------------------
FFZ.chat_commands.timeout_message = function(room, args) {
var username = args.shift(),
target_message = args.shift(),
duration = args.shift(),
reason = args.join(' ');
if ( ! username || ! target_message )
return 'Usage: /timeout_message <username> <target-message-id> [duration=600] [reason]\nTimeout a user and provide the ID of a specific message to remove.';
room.room.sendTags('/timeout ' + username + ' ' + (duration || '600') + (reason ? ' ' + reason : ''), {
'target-message-id': target_message
});
}
// ---------------------
// Group Chat Renaming
// ---------------------

View file

@ -380,11 +380,11 @@ FFZ.prototype.modify_channel_live = function(view) {
_ffzUpdateStat: function(key, basic_info, timers, metabar, is_hosting) {
var t = this,
info = FFZ.channel_metadata[key];
if ( ! info )
return;
if ( timers[key] )
clearTimeout(timers[key]);
if ( ! info )
return;
// Build the data we use for function calls.
var data = info.setup ? info.setup.apply(f, basic_info) : basic_info,
@ -411,11 +411,12 @@ FFZ.prototype.modify_channel_live = function(view) {
} else if ( ! el ) {
var btn,
static_label = typeof info.static_label === "function" ? info.static_label.apply(f, data) : info.static_label;
static_label = typeof info.static_label === "function" ? info.static_label.apply(f, data) : info.static_label,
lbl_start = static_label && static_label.substr(0,4);
if ( ! static_label )
static_label = '';
else if ( static_label.substr(0,4) === '<svg' )
else if ( lbl_start === '<svg' || lbl_start === '<img' )
static_label = utils.createElement('figure', 'icon cn-metabar__icon', static_label + ' ');
if ( info.popup ) {

View file

@ -646,7 +646,7 @@ FFZ.prototype.modify_chat_input = function(component) {
text = this.get('textareaValue'),
first_char = text.charAt(0),
is_cmd = first_char === '/' || first_char === '.',
is_cmd = (first_char === '/' || first_char === '.') && text.substr(1,3).toLowerCase() !== 'me ',
trail, prefix;

75
src/ember/dashboard.js Normal file
View file

@ -0,0 +1,75 @@
var FFZ = window.FrankerFaceZ,
utils = require('../utils'),
constants = require('../constants');
// --------------------
// Settings
// --------------------
FFZ.settings_info.dash_widget_click_to_expand = {
type: "boolean",
value: true,
category: "Dashboard",
name: "Click-to-Expand Widgets",
help: "Expand and contract widgets when you click anywhere in their header, not just when you click the toggle button."
}
// --------------------
// Initialization
// --------------------
FFZ.prototype.setup_dashboard = function() {
// Standalone Mode
if ( location.search === '?standalone' )
utils.toggle_cls('ffz-minimal-dashboard')(true);
this.update_views('component:dashboards/live-widget', this.modify_dashboard_widget);
this.update_views('component:dashboards/live/stream-stats', this.make_uptime_great_again);
}
FFZ.prototype.make_uptime_great_again = function(component) {
var f = this;
utils.ember_reopen_view(component, {
ffz_update: function() {
this.ffzFixUptime();
},
ffzFixUptime: function() {
var online = this.get('channel.stream.createdAt'),
now = Date.now() - (f._ws_server_offset || 0),
uptime = online && Math.floor((now - online.getTime()) / 1000) || -1,
setting = f.settings.stream_uptime;
this.set('timeLive', uptime >= 0 ? utils.time_to_string(uptime, false, false, false, true) : 'Offline');
},
_reloadStream: function() {
var t = this;
this.get('channel.stream').then(function(stream) {
t.isDestroyed || stream.reload().then(function(stream) {
t.isDestroyed || t.ffzFixUptime();
});
})
}
});
}
FFZ.prototype.modify_dashboard_widget = function(component) {
var f = this;
utils.ember_reopen_view(component, {
ffz_init: function() {
var t = this;
this.$(".dash-widget__header").click(function(e) {
if ( ! f.settings.dash_widget_click_to_expand || e.target.tagName === 'button' || jQuery(e.target).parents('button').length )
return;
t.actions.collapseWidget.call(t);
});
}
});
}

View file

@ -2,9 +2,9 @@
utils = require("../utils"),
constants = require("../constants"),
TB_TOOLTIP = '<hr>This message was flagged by TwitchBot. Should it be allowed?',
TB_TOOLTIP = '<hr>This message was flagged by AutoMod. Should it be allowed?',
BAN_SPLIT = /[/\.](?:ban ([^ ]+)|timeout ([^ ]+)(?: (\d+))?)(?: (.*))?$/;
BAN_SPLIT = /[\/\.](?:ban ([^ ]+)|timeout ([^ ]+)(?: (\d+))?|timeout_message ([^ ]+) ([^ ]+)(?: (\d+))?)(?: (.*))?$/;
// ---------------------
@ -1031,9 +1031,12 @@ FFZ.prototype._modify_chat_subline = function(component) {
if ( ! match )
return;
cmd = match[1] ? "/ban " + match[1] : "/timeout " + match[2] + " " + (match[3] || "600");
if ( match[4] )
trail = match[4] + trail;
cmd = match[1] ? '/ban ' + match[1] :
match[2] ? '/timeout ' + match[2] + ' ' + (match[3] || '600') :
'/timeout_message ' + match[4] + ' ' + match[5] + ' ' + (match[6] || '600');
if ( match[7] )
trail = match[7] = trail;
}
var bl = utils.createElement('ul', 'balloon__list'),
@ -1042,9 +1045,10 @@ FFZ.prototype._modify_chat_subline = function(component) {
has_items = false,
is_ban = cmd.substr(1, 4) === 'ban ',
is_timeout = cmd.substr(1, 8) === 'timeout ',
title = utils.createElement('li', 'ffz-title');
title.textContent = (is_ban ? 'Ban ' : 'Timeout ') + from + ' for...';
title.textContent = (is_ban ? 'Ban ' : (is_timeout ? 'Timeout ' : 'Remove Message and Timeout ')) + from + ' for...';
bl.appendChild(title);
bl.appendChild(utils.createElement('li', 'balloon__stroke'));

View file

@ -142,7 +142,7 @@ FFZ.prototype.setup_room = function() {
renderRight: e.right,
isIgnored: this.get("tmiSession").isIgnored(e.sender),
isChannelOwner: this.get("login.userData.login") === e.sender,
profileHref: Twitch.uri.profile(e.sender),
profileHref: Twitch.uri.channel(e.sender),
isModeratorOrHigher: this.get("model.isModeratorOrHigher")
});
}
@ -2151,6 +2151,15 @@ FFZ.prototype._modify_room = function(room) {
}
},
sendTags: function(text, tags) {
var tmi = this.get('tmiRoom'),
conn = tmi && tmi._roomConn,
tag_string = utils.build_tags(tags || {});
if ( conn )
conn.send((tag_string ? '@' + tag_string + ' ' : '') + 'PRIVMSG ' + tmi.ircChannel + ' :' + text);
},
send: function(text, ignore_history, used_aliases) {
try {
this.ffz_last_input = Date.now();

View file

@ -147,6 +147,36 @@ FFZ.prototype.api_trigger = function(/*event, args...*/) {
}
// ---------------------
// Metadata~!
// ---------------------
API.prototype.register_metadata = function(key, data) {
var real_key = this.id + '-' + key;
data.source_ext = this.id;
data.source_id = key;
FFZ.channel_metadata[real_key] = data;
if ( this.ffz._cindex )
this.ffz._cindex.ffzUpdateMetadata(real_key);
}
API.prototype.unregister_metadata = function(key) {
var real_key = this.id + '-' + key;
delete FFZ.channel_metadata[real_key];
if ( this.ffz._cindex ) {
this.ffz._cindex.$('.cn-metabar__ffz[data-key="' + real_key + '"]').remove();
this.ffz._cindex.ffzUpdateMetadata(real_key);
}
}
API.prototype.update_metadata = function(key) {
if ( this.ffz._cindex )
this.ffz._cindex.ffzUpdateMetadata(this.id + '-' + real_key);
}
// ---------------------
// Set Loading
// ---------------------

View file

@ -61,7 +61,7 @@ FFZ.channel_metadata = {};
// Version
var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 395,
major: 3, minor: 5, revision: 398,
toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
}
@ -229,6 +229,7 @@ require('./ember/directory');
require('./ember/following');
require('./ember/feed-card');
require('./ember/sidebar');
require('./ember/dashboard');
require('./debug');
@ -537,6 +538,7 @@ FFZ.prototype.init_ember = function(delay) {
this.setup_profile_following();
this.setup_feed_cards();
this.setup_sidebar();
this.setup_dashboard();
//this.setup_teams();

View file

@ -314,7 +314,8 @@ FFZ.prototype._ui_change_subpage = function(view, inner, menu, container, subpag
else if ( page_data.hasOwnProperty('wide') )
is_wide = page_data.wide || (typeof page_data.wide === "function" && page_data.wide.call(this));
inner.style.maxWidth = is_wide ? (app.offsetWidth < 640 ? (app.offsetWidth-40) : 600) + "px" : "";
var is_dash = is_wide && jQuery(menu).parents('.chat-container').hasClass('dash-chat');
inner.style.maxWidth = is_wide ? (is_dash ? 380 : (app.offsetWidth < 640 ? (app.offsetWidth-40) : 600)) + "px" : "";
// Re-position if necessary.
var f = this;

View file

@ -164,7 +164,7 @@ var createElement = function(tag, className, content) {
default:
// Try to unescape the value.
try {
return value;
return unescape_tag_value(value);
} catch(err) {
return "";
}
@ -183,6 +183,75 @@ var createElement = function(tag, className, content) {
return tags;
},
ESCAPE_CHARS = {
';': '\\:',
' ': '\\s',
'\r': '\\r',
'\n': '\\n',
'\\': '\\\\'
},
UNESCAPE_CHARS = {
':': ';',
's': ' ',
'r': '\r',
'n': '\n'
},
unescape_tag_value = function(value) {
var result = '';
for(var i=0,l=value.length; i < l; i++) {
var c = value.charAt(i);
if ( c === '\\' ) {
if ( i === l - 1 )
throw "Improperly escaped tag";
i++;
c = value.charAt(i);
result += UNESCAPE_CHARS[c] || c;
} else
result += c;
}
return result;
},
escape_tag_value = function(value) {
var value_str = ''+value,
result = '';
for(var i=0,l=value_str.length; i < l; i++) {
var c = value_str.charAt(i);
result += ESCAPE_CHARS[c] || c;
}
return result;
},
format_tag = function(tag, value) {
switch(tag) {
case "subscriber":
case "mod":
case "turbo":
case "r9k":
case "subs-only":
case "historical":
return value ? '1' : '0';
default:
return escape_tag_value(value)
}
},
build_tags = function(tags) {
var raw_tags = [];
for(var key in tags) {
if ( ! tags.hasOwnProperty(key) )
continue;
raw_tags.push(key + '=' + format_tag(key, tags[key]));
}
return raw_tags.join(';');
},
parse_sender = function(prefix, tags) {
var ind = prefix.indexOf('!');
if ( ind !== -1 )
@ -591,6 +660,10 @@ module.exports = FFZ.utils = {
parse_irc_message: parse_irc_message,
parse_irc_privmsg: parse_irc_privmsg,
format_tag: format_tag,
escape_tag_value: escape_tag_value,
unescape_tag_value: unescape_tag_value,
build_tags: build_tags,
CMD_VAR_REGEX: CMD_VAR_REGEX,

View file

@ -18,6 +18,15 @@ body > div.tipsy .tipsy-arrow { opacity: 0.8; }
cursor: pointer;
}
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] #main_col { margin: 0 !important }
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] .dash-dragula { height: calc(100vh - 70px) }
.ffz-minimize-conversations.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] .dash-dragula { height: calc(100vh - 50px) }
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] #left_col,
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] #left_close,
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] #right_col,
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] #right_close,
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] .new-dashboard .directory_header,
.ffz-hide-directory-uploads .ffz-following-uploads,
.pinned-cheers__dismiss,
.ffz-hide-pinned-cheers .pinned-cheers,
@ -1201,6 +1210,7 @@ body:not(.ffz-bttv) .dropmenu.share { margin-bottom: 0; }
/* Menu Scrollbar */
.dash-column::-webkit-scrollbar,
#ffz-metadata-popup .scroller::-webkit-scrollbar,
.search-panel .collection-wrapper::-webkit-scrollbar,
.activity-react__all::-webkit-scrollbar,
@ -1219,6 +1229,7 @@ body:not(.ffz-bttv) .dropmenu.share { margin-bottom: 0; }
width: 6px;
}
.dash-column::-webkit-scrollbar-thumb,
#ffz-metadata-popup .scroller::-webkit-scrollbar-thumb,
.search-panel .collection-wrapper::-webkit-scrollbar-thumb,
.activity-react__all::-webkit-scrollbar-thumb,
@ -1238,6 +1249,9 @@ body:not(.ffz-bttv) .dropmenu.share { margin-bottom: 0; }
box-shadow: 0 0 1px 1px rgba(255,255,255,0.25);
}
.ffz-dark .dash-column::-webkit-scrollbar-thumb,
.theatre .dash-column::-webkit-scrollbar-thumb,
.ffz-dark #ffz-metadata-popup .scroller::-webkit-scrollbar-thumb,
.theatre #ffz-metadata-popup .scroller::-webkit-scrollbar-thumb,
@ -2950,7 +2964,7 @@ body:not(.ffz-top-conversations) .conversations-list-bottom-bar {
top: 40px;
}
.ffz-top-conversations #directory-list { padding-top: 50px; }
.ffz-top-conversations:not([data-current-path="user.dashboards.index"]) #directory-list { padding-top: 50px; }
/* Minimize Conversations */
@ -3862,4 +3876,23 @@ body.ffz-sidebar-swap .app-main.theatre #main_col:not(.expandRight) #player[data
.ffz-sidebar-swap .expandRight .player-mini {
left: 10px !important;
}
/* New Dashboard */
.dash-chat {
font-size: 1.2rem;
width: calc(100% - 2px);
height: calc(100% - 2px);
}
.dash-column {
margin-right: calc(1rem - 5px);
padding-right: 5px;
}
@media(min-width: 1200px) {
.dash-column {
margin-right: calc(1.5rem - 5px);
}
}