diff --git a/package.json b/package.json index e9478491..9210f2de 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.76.3", + "version": "4.76.4", "description": "FrankerFaceZ is a Twitch enhancement suite.", "private": true, "license": "Apache-2.0", diff --git a/src/sites/twitch-twilight/modules/chat/index.js b/src/sites/twitch-twilight/modules/chat/index.js index fc00e69b..f80456f0 100644 --- a/src/sites/twitch-twilight/modules/chat/index.js +++ b/src/sites/twitch-twilight/modules/chat/index.js @@ -156,32 +156,37 @@ const NULL_TYPES = [ const INLINE_CALLOUT_TYPES = { - 'pinned_re_sub': 'share-resub' + 'pinned_re_sub': 'share-resub', + 'community_points_reward': 'community-points-rewards', + 'clip_live_nudge_chat_trigger': 'clip-live-nudge', + 'cheer_badge_grant': 'bits-badge-tier' }; const CALLOUT_TYPES = { "AppointedModerator": "appointed-moderator", "BitsBadgeTier": "bits-badge-tier", - "CommunityMoment": "community-moment", + "BitsPowerUps": "bits-power-ups", "ClipLiveNudge": "clip-live-nudge", - "ShareResub": "share-resub", - "ThankSubGifter": "thank-sub-gifter", + "CommunityMoment": "community-moment", "CommunityPointsRewards": "community-points-rewards", - "HypeTrainRewards": "hype-train-rewards", - "ReplyByKeyboard": "reply-by-keyboard", + "CosmicAbyss": "cosmic-abyss", + "CreatorAnniversaries": "creator-anniversaries", "Drop": "drop", "EarnedSubBadge": "earned-sub-badge", - "TurnOffAnimatedEmotes": "turn-off-animated-emotes", - "CreatorAnniversaries": "creator-anniversaries", - "RequestToJoinAccepted": "request-to-join-accepted", "FavoritedGuestCollab": "favorited-guest-collab", - "STPromo": "st-promo", - "LapsedBitsUser": "lapsed-bits-user", - "BitsPowerUps": "bits-power-ups", - "CosmicAbyss": "cosmic-abyss", - "PartnerPlusUpSellNudge": "partner-plus-up-sell-nudge", - "SubtemberPromoBits": "subtember-promo-bits", + "GiftBadgeExpiration": "gift-badge-expiration", + "GiftBadgeRestored": "gift-badge-restored", "GiftBundleUpSell": "gift-bundle-up-sell", + "HypeTrainRewards": "hype-train-rewards", + "LapsedBitsUser": "lapsed-bits-user", + "PartnerPlusUpSellNudge": "partner-plus-up-sell-nudge", + "ReplyByKeyboard": "reply-by-keyboard", + "RequestToJoinAccepted": "request-to-join-accepted", + "STPromo": "st-promo", + "ShareResub": "share-resub", + "SubtemberPromoBits": "subtember-promo-bits", + "ThankSubGifter": "thank-sub-gifter", + "TurnOffAnimatedEmotes": "turn-off-animated-emotes", "WalletDrop": "wallet-drop" }; @@ -288,11 +293,11 @@ export default class ChatHook extends Module { Twilight.CHAT_ROUTES ); - /*this.CalloutSelector = this.fine.define( + this.CalloutSelector = this.fine.define( 'callout-selector', n => n.selectCalloutComponent && n.props && has(n.props, 'callouts'), Twilight.CHAT_ROUTES - );*/ + ); this.PointsButton = this.fine.define( 'points-button', @@ -1669,7 +1674,7 @@ export default class ChatHook extends Module { this.ChatContainer.on('unmount', this.containerUnmounted, this); //removeRoom, this); this.ChatContainer.on('update', this.containerUpdated, this); - /*this.CalloutSelector.ready((cls, instances) => { + this.CalloutSelector.ready((cls, instances) => { const t = this, old_render = cls.prototype.render; @@ -1686,7 +1691,7 @@ export default class ChatHook extends Module { return out; } } catch(err) { - /* no-op * / + /* no-op */ } return old_render.call(this); @@ -1694,7 +1699,7 @@ export default class ChatHook extends Module { for(const inst of instances) inst.forceUpdate(); - });*/ + }); this.ChatContainer.ready((cls, instances) => { const t = this, @@ -1809,7 +1814,7 @@ export default class ChatHook extends Module { if ( ! type ) return; - type = INLINE_CALLOUT_TYPES[type] ?? type; + type = INLINE_CALLOUT_TYPES[type] ?? type.replace(/_/g, '-'); const ctm = this.callout_types ?? CALLOUT_TYPES, blocked = this.chat.context.get('chat.filtering.blocked-callouts'); @@ -2059,21 +2064,29 @@ export default class ChatHook extends Module { } } + cleanCallouts() { + const stack = this.callout_stack; + if (stack?.pinnedCallout?.event?.type && this.shouldHideCallout(stack.pinnedCallout.event.type)) + stack.unpinCallout(); + + if (stack?.callouts?.[0]?.event?.type && this.shouldHideCallout(stack.callouts[0].event.type)) + stack.clearCalloutType(stack.callouts[0].event.type); + } defineClasses() { - if ( this.CommunityStackHandler ) // && this.CalloutStackHandler ) + if ( this.CommunityStackHandler && this.CalloutStackHandler ) return true; const t = this, React = this.site.getReact(), createElement = React?.createElement, - StackMod = this.web_munch.getModule('highlightstack'); - //CalloutMod = this.web_munch.getModule('calloutstack'); + StackMod = this.web_munch.getModule('highlightstack'), + CalloutMod = this.web_munch.getModule('calloutstack'); if ( ! createElement ) return false; - /*if ( ! this.CalloutStackHandler && CalloutMod ) { + if ( ! this.CalloutStackHandler && CalloutMod ) { this.CalloutStackHandler = function() { const stack = React.useContext(CalloutMod.stack); @@ -2083,7 +2096,7 @@ export default class ChatHook extends Module { } this.CalloutSelector.forceUpdate(); - }*/ + } if ( ! this.CommunityStackHandler && StackMod ) { this.CommunityStackHandler = function() { diff --git a/src/sites/twitch-twilight/modules/chat/line.js b/src/sites/twitch-twilight/modules/chat/line.js index d4872d7d..c2382f74 100644 --- a/src/sites/twitch-twilight/modules/chat/line.js +++ b/src/sites/twitch-twilight/modules/chat/line.js @@ -240,7 +240,7 @@ export default class ChatLine extends Module { let has_message; if (setting === 1 && months > 1) { - const tokens = msg.ffz_tokens = msg.ffz_tokens || t.chat.tokenizeMessage(msg, current_user); + const tokens = msg.ffz_tokens = msg.ffz_tokens || this.chat.tokenizeMessage(msg, current_user); has_message = tokens.length > 0; } diff --git a/src/sites/twitch-twilight/modules/chat/scroller.js b/src/sites/twitch-twilight/modules/chat/scroller.js index 5b842fe2..28baa649 100644 --- a/src/sites/twitch-twilight/modules/chat/scroller.js +++ b/src/sites/twitch-twilight/modules/chat/scroller.js @@ -233,6 +233,29 @@ export default class Scroller extends Module { } } + cls.prototype.ffzInstallCleaner = function() { + if ( this._ffz_cleaner ) + return; + + this._ffz_cleaner = this.ffzOnClean.bind(this); + this._ffz_clean_timer = setInterval(this._ffz_cleaner, 60_000); + } + + cls.prototype.ffzOnClean = function() { + const el = t.fine.getChildNode(this); + if (!el) + return this.ffzRemoveCleaner(); + + requestAnimationFrame(() => t.cleanMessages(el.querySelector('.chat-scrollable-area__message-container'))); + } + + cls.prototype.ffzRemoveCleaner = function() { + if ( this._ffz_clean_timer ) + clearInterval(this._ffz_clean_timer); + + this._ffz_clean_timer = this._ffz_cleaner = null; + } + cls.prototype.ffzInstallHandler = function() { if ( this._ffz_installed ) return; @@ -681,6 +704,7 @@ export default class Scroller extends Module { onMount(inst) { inst.ffzSetSmoothScroll(this.smooth_scroll); inst.ffzInstallHandler(); + inst.ffzInstallCleaner(); } onUnmount(inst) { // eslint-disable-line class-methods-use-this @@ -697,7 +721,49 @@ export default class Scroller extends Module { inst._ffz_outside_timer = null; } + inst.ffzRemoveCleaner(); + window.removeEventListener('keydown', inst.ffzHandleKey); window.removeEventListener('keyup', inst.ffzHandleKey); } + + + cleanMessages(el) { + const react = ffz.site.fine.getReactInstance(el); + + // Make sure we have the right thing. + if (!react || !Array.isArray(react.child?.memoizedProps)) + return; + + // Find the first real child + let node = null, + r = react.child, + i = 0; + while(r && i < 10) { + if (r.stateNode instanceof HTMLDivElement) { + node = r.stateNode; + break; + } + r = r.child; + i++; + } + + if (!node || node.parentElement !== el) + return; + + let to_remove = node.previousElementSibling; + i = 0; + + while(to_remove) { + const removable = to_remove; + to_remove = to_remove.previousElementSibling; + removable.remove(); + i++; + } + + if (i > 0) + this.log.debug(`Removed ${i} dead chat lines from`, el); + } + + }