diff --git a/package.json b/package.json index c1250e3f..b1e21012 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.31.4", + "version": "4.31.5", "description": "FrankerFaceZ is a Twitch enhancement suite.", "private": true, "license": "Apache-2.0", diff --git a/src/modules/chat/badges.jsx b/src/modules/chat/badges.jsx index 1ca672b4..a008a7f4 100644 --- a/src/modules/chat/badges.jsx +++ b/src/modules/chat/badges.jsx @@ -502,6 +502,12 @@ export default class Badges extends Module { message = container[fine.accessor]?.return?.stateNode?.props?.message; if ( ! message ) message = fine.searchParent(container, n => n.props?.message)?.props?.message; + if ( ! message && this.root.flavor === 'clips' ) { + const lines = this.resolve('site.chat.line'); + const node = fine.searchParent(container, n => n.props?.node)?.props?.node; + if ( lines && node ) + message = lines.messages.get(node); + } if ( ! message ) message = fine.searchParent(container, n => n.props?.node)?.props?.node?._ffz_message; if ( ! message ) diff --git a/src/modules/metadata.jsx b/src/modules/metadata.jsx index 6c061ff2..1168d76b 100644 --- a/src/modules/metadata.jsx +++ b/src/modules/metadata.jsx @@ -287,8 +287,14 @@ export default class Metadata extends Module { icon: 'ffz-i-download', click(src) { - const link = createElement('a', {target: '_blank', href: src}); + const title = this.settings.get('context.title'); + const name = title.replace(/[\\/:"*?<>|]+/, '_') + '.mp4'; + + const link = createElement('a', {target: '_blank', download: name, href: src, style: {display: 'none'}}); + + document.body.appendChild(link); link.click(); + link.remove(); } } @@ -398,6 +404,9 @@ export default class Metadata extends Module { if ( ! this.settings.get('metadata.player-stats') || ! data.delay ) return null; + if ( data.old ) + return null; + const delayed = data.drift > 5000 ? '(!) ' : ''; if ( data.old ) diff --git a/src/sites/clips/line.jsx b/src/sites/clips/line.jsx index 282283d4..115aa22d 100644 --- a/src/sites/clips/line.jsx +++ b/src/sites/clips/line.jsx @@ -18,6 +18,7 @@ export default class Line extends Module { this.inject('i18n'); this.inject('chat'); + this.inject('chat.overrides'); this.inject('site.fine'); this.ChatLine = this.fine.define( @@ -75,12 +76,37 @@ export default class Line extends Module { action_italic = action_style >= 2, action_color = action_style === 1 || action_style === 3, user = msg.user, - color = t.parent.colors.process(user.color), + raw_color = t.overrides.getColor(user.id) || user.color, + color = t.parent.colors.process(raw_color), u = t.site.getUser(); const tokens = msg.ffz_tokens = msg.ffz_tokens || t.chat.tokenizeMessage(msg, u); + const user_block = t.chat.formatUser(user, createElement); + const override_name = t.overrides.getName(user.id); + + const user_props = { + className: `clip-chat__message-author tw-font-size-5 ffz-link notranslate tw-strong${override_name ? ' ffz--name-override tw-relative ffz-il-tooltip__container' : ''} ${msg.ffz_user_class ?? ''}`, + href: `https://www.twitch.tv/${user.login}/clips`, + style: { color } + }; + + if ( msg.ffz_user_props ) + Object.assign(user_props, msg.ffz_user_props); + + if ( msg.ffz_user_style ) + Object.assign(user_props.style, msg.ffz_user_style); + + const user_bits = createElement('a', user_props, override_name ? [ + createElement('span', { + className: 'chat-author__display-name' + }, override_name), + createElement('div', { + className: 'ffz-il-tooltip ffz-il-tooltip--down ffz-il-tooltip--align-center' + }, user_block) + ] : user_block); + return (
{ t.chat.badges.render(msg, createElement) } - { t.chat.formatUser(user, createElement) } + {user_bits}
{ is_action ? '' : ':' }
diff --git a/src/sites/twitch-twilight/modules/chat/index.js b/src/sites/twitch-twilight/modules/chat/index.js index b3822187..d783aae0 100644 --- a/src/sites/twitch-twilight/modules/chat/index.js +++ b/src/sites/twitch-twilight/modules/chat/index.js @@ -2010,6 +2010,21 @@ export default class ChatHook extends Module { } + scheduleMystery(mystery) { // eslint-disable-line class-methods-use-this + if ( ! mystery.line ) + return; + + if ( mystery._timer ) + return; + + mystery._timer = setTimeout(() => requestAnimationFrame(() => { + mystery._timer = null; + if ( mystery.line ) + mystery.line.forceUpdate(); + }), 250); + } + + wrapChatService(cls) { const t = this, old_mount = cls.prototype.componentDidMount, @@ -2213,7 +2228,7 @@ export default class ChatHook extends Module { mysteries[key] = null; if ( mystery.line ) - mystery.line.forceUpdate(); + t.scheduleMystery(mystery); return; } @@ -2265,7 +2280,7 @@ export default class ChatHook extends Module { mysteries[key] = null; if ( mystery.line ) - mystery.line.forceUpdate(); + t.scheduleMystery(mystery); return; } diff --git a/src/sites/twitch-twilight/modules/chat/line.js b/src/sites/twitch-twilight/modules/chat/line.js index 055c8f81..4db3ec83 100644 --- a/src/sites/twitch-twilight/modules/chat/line.js +++ b/src/sites/twitch-twilight/modules/chat/line.js @@ -485,18 +485,26 @@ other {# messages were deleted by a moderator.} const user_block = t.chat.formatUser(user, e); const override_name = t.overrides.getName(user.id); + const user_props = { + className: `chat-line__username notranslate${override_name ? ' ffz--name-override tw-relative ffz-il-tooltip__container' : ''} ${msg.ffz_user_class ?? ''}`, + role: 'button', + style: { color }, + onClick: this.ffz_user_click_handler, + onContextMenu: t.actions.handleUserContext + }; + + if ( msg.ffz_user_props ) + Object.assign(user_props, msg.ffz_user_props); + + if ( msg.ffz_user_style ) + Object.assign(user_props.style, msg.ffz_user_style); + const user_bits = [ t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e), e('span', { className: 'chat-line__message--badges' }, t.chat.badges.render(msg, e)), - e('span', { - className: `chat-line__username notranslate${override_name ? ' ffz--name-override tw-relative ffz-il-tooltip__container' : ''}`, - role: 'button', - style: { color }, - onClick: this.ffz_user_click_handler, - onContextMenu: t.actions.handleUserContext - }, override_name ? [ + e('span', user_props, override_name ? [ e('span', { className: 'chat-author__display-name' }, override_name), diff --git a/src/sites/twitch-twilight/modules/video_chat/index.jsx b/src/sites/twitch-twilight/modules/video_chat/index.jsx index 1639a052..2be10899 100644 --- a/src/sites/twitch-twilight/modules/video_chat/index.jsx +++ b/src/sites/twitch-twilight/modules/video_chat/index.jsx @@ -47,6 +47,7 @@ export default class VideoChatHook extends Module { this.inject('site.web_munch'); this.inject('chat'); + this.inject('chat.overrides'); this.injectAs('site_chat', 'site.chat'); this.inject('site.chat.chat_line.rich_content'); @@ -248,7 +249,8 @@ export default class VideoChatHook extends Module { action_italic = action_style >= 2, action_color = action_style === 1 || action_style === 3, user = msg.user, - color = t.site_chat.colors.process(user.color), + raw_color = t.overrides.getColor(user.id) || user.color, + color = t.site_chat.colors.process(raw_color), u = t.site.getUser(); @@ -313,18 +315,38 @@ export default class VideoChatHook extends Module { const tokens = msg.ffz_tokens = msg.ffz_tokens || t.chat.tokenizeMessage(msg, u), rich_content = FFZRichContent && t.chat.pluckRichContent(tokens, msg); + const user_block = t.chat.formatUser(user, createElement); + const override_name = t.overrides.getName(user.id); + + const user_props = { + className: `video-chat__message-author notranslate${override_name ? ' ffz--name-override tw-relative ffz-il-tooltip__container' : ''} ${msg.ffz_user_class ?? ''}`, + 'data-test-selector': 'comment-author-selector', + href: `/${user.login}`, + rel: 'noopener noreferrer', + target: '_blank', + style: { color } + }; + + if ( msg.ffz_user_props ) + Object.assign(user_props, msg.ffz_user_props); + + if ( msg.ffz_user_style ) + Object.assign(user_props.style, msg.ffz_user_style); + + const user_bits = createElement('a', user_props, override_name ? [ + createElement('span', { + className: 'chat-author__display-name' + }, override_name), + createElement('div', { + className: 'ffz-il-tooltip ffz-il-tooltip--down ffz-il-tooltip--align-center' + }, user_block) + ] : user_block); + let out = (
{ t.chat.badges.render(msg, createElement) } - {t.chat.formatUser(user, createElement)} + {user_bits}
{is_action ? ' ' : ': '}