diff --git a/package.json b/package.json index 25f4eb37..89cb7bea 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.19.4", + "version": "4.19.5", "description": "FrankerFaceZ is a Twitch enhancement suite.", "license": "Apache-2.0", "scripts": { diff --git a/src/sites/twitch-twilight/index.js b/src/sites/twitch-twilight/index.js index 4a6ef086..b8701653 100644 --- a/src/sites/twitch-twilight/index.js +++ b/src/sites/twitch-twilight/index.js @@ -210,7 +210,8 @@ Twilight.CHAT_ROUTES = [ 'embed-chat', 'squad', 'command-center', - 'dash-stream-manager' + 'dash-stream-manager', + 'mod-view' ]; @@ -262,7 +263,7 @@ Twilight.DASH_ROUTES = { 'dash-settings-moderation': '/u/:userName/settings/moderation', 'dash-settings-channel': '/u/:userName/settings/channel', 'dash-settings-revenue': '/u/:userName/settings/revenue', - 'dash-extensions': '/u/:userName/extensions', + 'dash-extensions': '/u/:userName/extensions', 'dash-streaming-tools': '/u/:userName/broadcast', }; @@ -300,10 +301,11 @@ Twilight.ROUTES = { 'user': '/:userName', 'squad': '/:userName/squad', 'command-center': '/:userName/commandcenter', - 'embed-chat': '/embed/:userName/chat' + 'embed-chat': '/embed/:userName/chat', + 'mod-view': '/moderator/:userName' }; -Twilight.DIALOG_EXCLUSIVE = '.sunlight-root,.twilight-main,.twilight-minimal-root>div,#root>div>.tw-full-height,.clips-root'; -Twilight.DIALOG_MAXIMIZED = '.sunlight-page,.twilight-main,.twilight-minimal-root,#root .dashboard-side-nav+.tw-full-height,.clips-root>.tw-full-height .scrollable-area'; -Twilight.DIALOG_SELECTOR = '.sunlight-root,#root>div,.twilight-minimal-root>.tw-full-height,.clips-root>.tw-full-height .scrollable-area'; \ No newline at end of file +Twilight.DIALOG_EXCLUSIVE = '.moderation-root,.sunlight-root,.twilight-main,.twilight-minimal-root>div,#root>div>.tw-full-height,.clips-root'; +Twilight.DIALOG_MAXIMIZED = '.moderation-view-page > div[data-highlight-selector="main-grid"],.sunlight-page,.twilight-main,.twilight-minimal-root,#root .dashboard-side-nav+.tw-full-height,.clips-root>.tw-full-height .scrollable-area'; +Twilight.DIALOG_SELECTOR = '.moderation-root,.sunlight-root,#root>div,.twilight-minimal-root>.tw-full-height,.clips-root>.tw-full-height .scrollable-area'; \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/chat/index.js b/src/sites/twitch-twilight/modules/chat/index.js index a4e98544..b5b7980c 100644 --- a/src/sites/twitch-twilight/modules/chat/index.js +++ b/src/sites/twitch-twilight/modules/chat/index.js @@ -6,7 +6,7 @@ import {ColorAdjuster} from 'utilities/color'; import {setChildren} from 'utilities/dom'; -import {get, has, make_enum, split_chars, shallow_object_equals, set_equals} from 'utilities/object'; +import {get, has, make_enum, split_chars, shallow_object_equals, set_equals, deep_equals} from 'utilities/object'; import {WEBKIT_CSS as WEBKIT} from 'utilities/constants'; import {FFZEvent} from 'utilities/events'; @@ -892,6 +892,12 @@ export default class ChatHook extends Module { inst._ffzInstall(); + const channel = inst.joinedChannel, + state = inst.client?.session?.channelstate?.[`#${channel}`]?.roomState; + + if ( state ) + this.updateChatState(state); + inst.connectHandlers(); inst.props.setChatConnectionAPI({ @@ -914,20 +920,19 @@ export default class ChatHook extends Module { if ( handler ) handler.addMessageHandler(inst.handleMessage); - if ( Array.isArray(inst.buffer) ) { + // We grab this from the chat client now. + /*if ( Array.isArray(inst.buffer) ) { let i = inst.buffer.length; const ct = this.chat_types || CHAT_TYPES; while(i--) { const msg = inst.buffer[i]; if ( msg && msg.type === ct.RoomState && msg.state ) { - this.chat.context.updateContext({ - chat_state: msg.state - }); + this.updateChatState(msg.state); break; } } - } + }*/ inst.props.setMessageBufferAPI({ addUpdateHandler: inst.addUpdateHandler, @@ -1105,6 +1110,19 @@ export default class ChatHook extends Module { } + updateChatState(state) { + const old_state = this.chat.context.get('context.chat_state') || {}; + if ( deep_equals(state, old_state) ) + return; + + this.chat.context.updateContext({ + chat_state: state + }); + + this.input.updateInput(); + } + + updatePinnedCallouts() { for(const inst of this.PinnedCallout.instances) this.onPinnedCallout(inst); @@ -1708,9 +1726,7 @@ export default class ChatHook extends Module { current = t.chat.context.get('context.channel'); if ( channel && (channel === current || channel === `#${current}`) ) - t.chat.context.updateContext({ - chat_state: e.state - }); + t.updateChatState(e.state); } catch(err) { t.log.capture(err, {extra: e}); diff --git a/src/sites/twitch-twilight/modules/chat/input.jsx b/src/sites/twitch-twilight/modules/chat/input.jsx index ccf5e3ae..e7199ee8 100644 --- a/src/sites/twitch-twilight/modules/chat/input.jsx +++ b/src/sites/twitch-twilight/modules/chat/input.jsx @@ -226,6 +226,15 @@ export default class Input extends Module { this.on('site.css_tweaks:update-chat-css', this.resizeInput, this); } + updateInput() { + for(const inst of this.ChatInput.instances) { + if ( inst ) { + inst.forceUpdate(); + this.emit('site:dom-update', 'chat-input', inst); + } + } + } + resizeInput() { if ( this._resize_waiter ) cancelAnimationFrame(this._resize_waiter); diff --git a/src/sites/twitch-twilight/modules/chat/line.js b/src/sites/twitch-twilight/modules/chat/line.js index aa6b9363..c11554b1 100644 --- a/src/sites/twitch-twilight/modules/chat/line.js +++ b/src/sites/twitch-twilight/modules/chat/line.js @@ -49,7 +49,7 @@ export default class ChatLine extends Module { this.WhisperLine = this.fine.define( 'whisper-line', - n => n.props && n.props.message && n.props.reportOutgoingWhisperRendered + n => n.props && n.props.message && has(n.props, 'reportOutgoingWhisperRendered') ) } diff --git a/src/sites/twitch-twilight/modules/menu_button.jsx b/src/sites/twitch-twilight/modules/menu_button.jsx index b2d4c8fa..ca654e65 100644 --- a/src/sites/twitch-twilight/modules/menu_button.jsx +++ b/src/sites/twitch-twilight/modules/menu_button.jsx @@ -38,6 +38,12 @@ export default class MenuButton extends SiteModule { changed: () => this.update() }); + this.ModBar = this.fine.define( + 'mod-view-bar', + n => n.actions && n.updateRoot && n.childContext, + ['mod-view'] + ); + this.SunlightDash = this.fine.define( 'sunlight-dash', n => n.getIsChannelEditor && n.getIsChannelModerator && n.getIsAdsEnabled && n.getIsSquadStreamsEnabled, @@ -188,6 +194,9 @@ export default class MenuButton extends SiteModule { for(const inst of this.SunlightDash.instances) this.updateButton(inst); + + for(const inst of this.ModBar.instances) + this.updateButton(inst); } @@ -208,6 +217,10 @@ export default class MenuButton extends SiteModule { this.SunlightDash.on('mount', this.updateButton, this); this.SunlightDash.on('update', this.updateButton, this); + this.ModBar.ready(() => this.update()); + this.ModBar.on('mount', this.updateButton, this); + this.ModBar.on('update', this.updateButton, this); + this.on(':clicked', () => this.important_update = false); this.once(':clicked', this.loadMenu); @@ -222,6 +235,7 @@ export default class MenuButton extends SiteModule { const root = this.fine.getChildNode(inst); let is_squad = false, is_sunlight = false, + is_mod = false, container = root && root.querySelector('.top-nav__menu'); if ( ! container ) { @@ -246,10 +260,16 @@ export default class MenuButton extends SiteModule { is_sunlight = true; } + if ( ! container && inst.childContext ) { + container = root && root.querySelector('.modview-dock > div:last-child'); + if ( container ) + is_mod = true; + } + if ( ! container ) return; - if ( ! is_squad ) { + if ( ! is_squad && ! is_mod ) { let user_stuff = null; try { user_stuff = container.querySelector(':scope > .tw-justify-content-end:last-child'); @@ -270,7 +290,7 @@ export default class MenuButton extends SiteModule { extra_pill = this.formatExtraPill(); el = (