From b9cca1053d0af20f21e8b55cee75456ed7a13fb8 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Thu, 18 Apr 2019 21:07:11 -0400 Subject: [PATCH] 4.0.0-rc16.3 * Added: More settings under Chat > Behavior >> Deleted Messages to control the display of moderated messages. * Fixed: Deleted messages displaying for non-moderated users using the settings that would be applied were that user a moderator. * Changed: In-line Chat Actions that only display when you are a moderator now only display when you have moderation powers over that user. Moderators will no longer see those actions next to other moderators. --- src/main.js | 2 +- src/modules/chat/actions/index.jsx | 19 ++- src/modules/chat/index.js | 30 ++++ .../twitch-twilight/modules/chat/index.js | 156 ++++++++++++++---- .../twitch-twilight/modules/chat/line.js | 28 ++-- 5 files changed, 189 insertions(+), 46 deletions(-) diff --git a/src/main.js b/src/main.js index 8b996720..fb84b059 100644 --- a/src/main.js +++ b/src/main.js @@ -149,7 +149,7 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}` FrankerFaceZ.Logger = Logger; const VER = FrankerFaceZ.version_info = { - major: 4, minor: 0, revision: 0, extra: '-rc16.2', + major: 4, minor: 0, revision: 0, extra: '-rc16.3', commit: __git_commit__, build: __webpack_hash__, toString: () => diff --git a/src/modules/chat/actions/index.jsx b/src/modules/chat/actions/index.jsx index f66b56d8..c0fcd622 100644 --- a/src/modules/chat/actions/index.jsx +++ b/src/modules/chat/actions/index.jsx @@ -202,12 +202,29 @@ export default class Actions extends Module { } + getUserLevel(room, user) { // eslint-disable-line class-methods-use-this + if ( ! room || ! user ) + return 0; + + if ( room.id === user.id || room.login === user.login ) + return 5; + + else if ( user.moderator || user.type === 'mod' || (user.badges && user.badges.moderator) ) + return 3; + + return 0; + } + + renderInline(msg, mod_icons, current_user, current_room, createElement) { const actions = []; if ( msg.user && current_user && current_user.login === msg.user.login ) return; + const current_level = this.getUserLevel(current_room, current_user), + msg_level = this.getUserLevel(current_room, msg.user); + const chat = this.resolve('site.chat'); for(const data of this.parent.context.get('chat.actions.inline')) { @@ -221,7 +238,7 @@ export default class Actions extends Module { if ( ! def || disp.disabled || (disp.mod_icons != null && disp.mod_icons !== !!mod_icons) || - (disp.mod != null && disp.mod !== (current_user ? !!current_user.moderator : false)) || + (disp.mod != null && disp.mod !== (current_level > msg_level)) || (disp.staff != null && disp.staff !== (current_user ? !!current_user.staff : false)) || (disp.deleted != null && disp.deleted !== !!msg.deleted) ) continue; diff --git a/src/modules/chat/index.js b/src/modules/chat/index.js index 745945b1..1460b50f 100644 --- a/src/modules/chat/index.js +++ b/src/modules/chat/index.js @@ -196,6 +196,36 @@ export default class Chat extends Module { } }); + this.settings.add('chat.filtering.display-deleted', { + default: false, + ui: { + path: 'Chat > Behavior >> Deleted Messages', + title: 'Deleted Message Rendering', + description: 'This, when set, overrides the mode selected in Twitch Chat settings. We do this to allow non-moderators access to the setting.', + component: 'setting-select-box', + data: [ + {value: false, title: 'Do Not Override'}, + {value: 'BRIEF', title: 'Brief'}, + {value: 'DETAILED', title: 'Detailed'}, + {value: 'LEGACY', title: 'Legacy'} + ] + } + }); + + this.settings.add('chat.filtering.display-mod-action', { + default: 1, + ui: { + path: 'Chat > Behavior >> Deleted Messages', + title: 'Display Deletion Reason', + component: 'setting-select-box', + data: [ + {value: 0, title: 'Never'}, + {value: 1, title: 'In Detailed Mode'}, + {value: 2, title: 'Always'} + ] + } + }); + this.settings.add('chat.filtering.process-own', { default: false, ui: { diff --git a/src/sites/twitch-twilight/modules/chat/index.js b/src/sites/twitch-twilight/modules/chat/index.js index 687b6616..2f6fa339 100644 --- a/src/sites/twitch-twilight/modules/chat/index.js +++ b/src/sites/twitch-twilight/modules/chat/index.js @@ -431,6 +431,8 @@ export default class ChatHook extends Module { this.chat.context.on('changed:chat.filtering.highlight-mentions', this.updateMentionCSS, this); this.chat.context.on('changed:chat.filtering.highlight-tokens', this.updateMentionCSS, this); this.chat.context.on('changed:chat.fix-bad-emotes', this.updateChatLines, this); + this.chat.context.on('changed:chat.filtering.display-deleted', this.updateChatLines, this); + this.chat.context.on('changed:chat.filtering.display-mod-action', this.updateChatLines, this); this.chat.context.on('changed:chat.lines.alternate', val => { this.css_tweaks.toggle('chat-rows', val); @@ -669,52 +671,94 @@ export default class ChatHook extends Module { if ( event.defaultPrevented || m.ffz_removed ) return; - /*} else if ( msg.type === types.ModerationAction ) { - t.log.info('Moderation Action', msg); - - } else if ( msg.type === types.Moderation ) { - t.log.info('Moderation', msg); - - const login = msg.userLogin; - if ( inst.moderatedUsers.has(login) ) + } else if ( msg.type === types.ModerationAction ) { + //t.log.info('Moderation Action', msg); + if ( ! inst.props.isCurrentUserModerator ) return; - const do_remove = t.chat.context.get('chat.filtering.remove-deleted') === 3, - is_delete = msg.moderationType === mod_types.Delete, - do_update = m => { - if ( m.event ) - m = m.event; + const mod_action = msg.moderationActionType; + if ( mod_action === 'ban' || mod_action === 'timeout' || mod_action === 'delete' ) { + const user = msg.targetUserLogin; + if ( inst.moderatedUsers.has(user) ) + return; - if ( is_delete ) { - if ( m.id === msg.targetMessageID ) - m.deleted = true; + const do_remove = t.chat.context.get('chat.filtering.remove-deleted') === 3; + if ( do_remove ) { + const len = inst.buffer.length, + target_id = msg.messageID; + inst.buffer = inst.buffer.filter(m => + m.type !== types.Message || ! m.user || m.user.userLogin !== user || + (target_id && m.id !== target_id) + ); + if ( len !== inst.buffer.length && ! inst.props.isBackground ) + inst.notifySubscribers(); - } else if ( m.type === types.Message ) { - if ( m.user && m.user.userLogin === login ) { - m.banned = true; - m.deleted = true; - } - } else if ( m.type === types.Resubscription || m.type === types.Ritual ) { - if ( m.message && m.message.user && m.message.user.userLogin === login ) { - m.deleted = true; - m.banned = true; - } - } - }; + inst.ffzModerateBuffer([inst.delayedMessageBuffer], msg); + } else + inst.ffzModerateBuffer([inst.buffer, inst.delayedMessageBuffer], msg); + + inst.moderatedUsers.add(user); + setTimeout(inst.unsetModeratedUser(user), 1e3); + + inst.delayedMessageBuffer.push({ + event: msg, + time: Date.now(), + shouldDelay: false + }); + + return; + } + + } else if ( msg.type === types.Moderation ) { + //t.log.info('Moderation', msg); + if ( inst.props.isCurrentUserModerator ) + return; + + const user = msg.userLogin; + if ( inst.moderatedUsers.has(user) ) + return; + + const mod_action = msg.moderationType; + let new_action; + if ( mod_action === mod_types.Ban ) + new_action = 'ban'; + else if ( mod_action === mod_types.Delete ) + new_action = 'delete'; + else if ( mod_action === mod_types.Unban ) + new_action = 'unban'; + else if ( mod_action === mod_types.Timeout ) + new_action = 'timeout'; + + if ( new_action ) + msg.moderationActionType = new_action; + + const do_remove = t.chat.context.get('chat.filtering.remove-deleted') === 3; if ( do_remove ) { - const len = inst.buffer.length; - inst.buffer = inst.buffer.filter(m => m.type !== types.Message || ! m.user || m.user.userLogin !== login); + const len = inst.buffer.length, + target_id = msg.targetMessageID; + inst.buffer = inst.buffer.filter(m => + m.type !== types.Message || ! m.user || m.user.userLogin !== user || + (target_id && m.id !== target_id) + ); if ( len !== inst.buffer.length && ! inst.props.isBackground ) inst.notifySubscribers(); + inst.ffzModerateBuffer([inst.delayedMessageBuffer], msg); + } else - inst.buffer.forEach(do_update); + inst.ffzModerateBuffer([inst.buffer, inst.delayedMessageBuffer], msg); - inst.delayedMessageBuffer.forEach(do_update); + inst.moderatedUsers.add(user); + setTimeout(inst.unsetModeratedUser(user), 1e3); - inst.moderatedUsers.add(login); - setTimeout(inst.unsetModeratedUser(login), 1000);*/ + inst.delayedMessageBuffer.push({ + event: msg, + time: Date.now(), + shouldDelay: false + }); + + return; } else if ( msg.type === types.Clear ) { if ( t.chat.context.get('chat.filtering.ignore-clear') ) @@ -733,6 +777,50 @@ export default class ChatHook extends Module { return old_handle.call(inst, msg); } + inst.ffzModerateBuffer = function(buffers, event) { + const mod_types = t.mod_types || {}, + mod_type = event.moderationActionType, + user_login = event.targetUserLogin || event.userLogin, + mod_login = event.createdByLogin, + target_id = event.targetMessageID || event.messageID; + + let deleted_count = 0, last_msg; + + const is_delete = mod_type === mod_types.Delete, + updater = m => { + if ( m.event ) + m = m.event; + + if ( target_id && m.id !== target_id ) + return; + + const msg = inst.markUserEventDeleted(m, user_login); + if ( ! msg ) + return; + + last_msg = msg; + deleted_count++; + + msg.modLogin = mod_login; + msg.modActionType = mod_type; + msg.duration = event.duration; + + if ( is_delete ) + return true; + }; + + for(const buffer of buffers) + if ( buffer.some(updater) ) + break; + + //t.log.info('Moderate Buffer', mod_type, user_login, mod_login, target_id, deleted_count, last_msg); + + if ( last_msg ) + last_msg.deletedCount = deleted_count; + } + + + inst.getMessages = function() { const buf = inst.buffer, size = t.chat.context.get('chat.scrollback-length'), diff --git a/src/sites/twitch-twilight/modules/chat/line.js b/src/sites/twitch-twilight/modules/chat/line.js index 902797dd..fc024443 100644 --- a/src/sites/twitch-twilight/modules/chat/line.js +++ b/src/sites/twitch-twilight/modules/chat/line.js @@ -268,8 +268,8 @@ export default class ChatLine extends Module { cls.prototype.render = function() { try { const types = t.parent.message_types || {}, - mod_mode = this.props.deletedMessageDisplay, deleted_count = this.props.deletedCount, + override_mode = t.chat.context.get('chat.filtering.display-deleted'), msg = t.chat.standardizeMessage(this.props.message), is_action = msg.messageType === types.Action, @@ -277,7 +277,14 @@ export default class ChatLine extends Module { user = msg.user, color = t.parent.colors.process(user.color); - let show, show_class, mod_action; + let mod_mode = this.props.deletedMessageDisplay; + let show, show_class, mod_action = null; + + if ( ! this.props.isCurrentUserModerator && mod_mode == 'DETAILED' ) + mod_mode = 'LEGACY'; + + if ( override_mode ) + mod_mode = override_mode; if ( mod_mode === 'BRIEF' ) { if ( msg.deleted ) { @@ -296,13 +303,19 @@ export default class ChatLine extends Module { show = true; show_class = false; - mod_action = null; } else if ( mod_mode === 'DETAILED' ) { show = true; show_class = msg.deleted; - if ( msg.deleted ) { + } else { + show = this.state && this.state.alwaysShowMessage || ! msg.deleted; + show_class = false; + } + + if ( msg.deleted ) { + const show_mode = t.chat.context.get('chat.filtering.display-mod-action'); + if ( show_mode === 2 || (show_mode === 1 && mod_mode === 'DETAILED') ) { const action = msg.modActionType; if ( action === 'timeout' ) mod_action = t.i18n.t('chat.mod-action.timeout', @@ -327,11 +340,6 @@ export default class ChatLine extends Module { 'data-test-selector': 'chat-deleted-message-attribution' }, `(${mod_action})`); } - - } else { - show = this.state && this.state.alwaysShowMessage || ! msg.deleted; - show_class = false; - mod_action = null; } let room = msg.roomLogin ? msg.roomLogin : msg.channel ? msg.channel.slice(1) : undefined; @@ -419,7 +427,7 @@ export default class ChatLine extends Module { show && rich_content && e(FFZRichContent, rich_content), - show && mod_action, + mod_action, /*this.state.renderDebug === 2 && e('div', { className: 'border mg-t-05'