diff --git a/package-lock.json b/package-lock.json index a96a7061..a78696af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "frankerfacez", - "version": "4.20.15", + "version": "4.20.17", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -5615,6 +5615,14 @@ "minimist": "^1.2.5" } }, + "mnemonist": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.0.tgz", + "integrity": "sha512-OrqILDYOEGVFooAbGid3/P9jdjWuZONlGHVyjfZnvg65+ZQ/QM5dOms+yADY/WURd1NFhCqjf/VJGFlnJToLJQ==", + "requires": { + "obliterator": "^1.6.1" + } + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -6269,6 +6277,11 @@ } } }, + "obliterator": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", + "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==" + }, "obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", diff --git a/package.json b/package.json index 57695b02..2365a97c 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.20.17", + "version": "4.20.18", "description": "FrankerFaceZ is a Twitch enhancement suite.", "license": "Apache-2.0", "scripts": { @@ -78,6 +78,7 @@ "js-cookie": "^2.2.1", "markdown-it": "^11.0.0", "markdown-it-link-attributes": "^3.0.0", + "mnemonist": "^0.38.0", "path-to-regexp": "^3.0.0", "popper.js": "^1.14.3", "raven-js": "^3.24.2", diff --git a/src/modules/chat/index.js b/src/modules/chat/index.js index 33a50730..91048923 100644 --- a/src/modules/chat/index.js +++ b/src/modules/chat/index.js @@ -628,6 +628,16 @@ export default class Chat extends Module { } }); + this.settings.add('chat.filtering.color-mentions', { + default: false, + ui: { + component: 'setting-check-box', + path: 'Chat > Filtering >> Appearance', + title: 'Display mentions in chat with username colors.', + description: '**Note:** Not compatible with color overrides as mentions do not include user IDs.' + } + }); + this.settings.add('chat.filtering.bold-mentions', { default: true, ui: { @@ -853,6 +863,21 @@ export default class Chat extends Module { for(const room of this.iterateRooms()) room.buildBitsCSS(); }); + + this.context.on('changed:chat.filtering.color-mentions', async val => { + if ( val ) + await this.createColorCache(); + else + this.color_cache = null; + + this.emit(':update-lines'); + }); + } + + + async createColorCache() { + const LRUCache = await require(/* webpackChunkName: 'utils' */ 'mnemonist/lru-cache'); + this.color_cache = new LRUCache(150); } @@ -866,6 +891,9 @@ export default class Chat extends Module { onEnable() { + if ( this.context.get('chat.filtering.color-mentions') ) + this.createColorCache().then(() => this.emit(':update-lines')); + for(const key in TOKENIZERS) if ( has(TOKENIZERS, key) ) this.addTokenizer(TOKENIZERS[key]); @@ -1143,6 +1171,9 @@ export default class Chat extends Module { user.displayName = user.displayName || user.userDisplayName || user.login || ext.displayName; user.isIntl = user.login && user.displayName && user.displayName.trim().toLowerCase() !== user.login; + if ( this.color_cache && user.color ) + this.color_cache.set(user.login, user.color); + // Standardize Message Content if ( ! msg.message && msg.messageParts ) this.detokenizeMessage(msg); diff --git a/src/modules/chat/tokenizers.jsx b/src/modules/chat/tokenizers.jsx index 93a3974f..dad2cbf2 100644 --- a/src/modules/chat/tokenizers.jsx +++ b/src/modules/chat/tokenizers.jsx @@ -209,8 +209,15 @@ export const Mentions = { }, render(token, createElement) { + let color = token.color; + if ( color ) { + const chat = this.resolve('site.chat'); + color = chat ? chat.colors.process(color) : color; + } + return ( @@ -270,11 +277,15 @@ export const Mentions = { mentioned = mentionable; } + const rlower = recipient ? recipient.toLowerCase() : '', + color = this.color_cache ? this.color_cache.get(rlower) : null; + out.push({ type: 'mention', text: `${at}${recipient}`, me: mentioned, - recipient: recipient ? recipient.toLowerCase() : '' + color, + recipient: rlower }); if ( mentioned ) { diff --git a/src/modules/main_menu/components/performance.vue b/src/modules/main_menu/components/performance.vue new file mode 100644 index 00000000..27502df0 --- /dev/null +++ b/src/modules/main_menu/components/performance.vue @@ -0,0 +1,44 @@ + + + \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/channel.jsx b/src/sites/twitch-twilight/modules/channel.jsx index 75b9468f..2795f205 100644 --- a/src/sites/twitch-twilight/modules/channel.jsx +++ b/src/sites/twitch-twilight/modules/channel.jsx @@ -21,6 +21,7 @@ export default class Channel extends Module { this.inject('i18n'); this.inject('settings'); + this.inject('site.apollo'); this.inject('site.css_tweaks'); this.inject('site.elemental'); this.inject('site.subpump'); @@ -71,6 +72,18 @@ export default class Channel extends Module { USER_PAGES, {childNodes: true, subtree: true}, 1 ); + + const strip_host = resp => { + if ( this.settings.get('channel.hosting.enable') ) + return; + + const user = resp?.data?.user; + if ( user ) + user.hosting = null; + }; + + this.apollo.registerModifier('UseHosting', strip_host, false); + this.apollo.registerModifier('PlayerTrackingContextQuery', strip_host, false); } onEnable() { @@ -210,7 +223,8 @@ export default class Channel extends Module { if ( ! el._ffz_links && want_links ) { const link = el.querySelector('a .tw-line-height-heading'), - cont = link && link.closest('.tw-flex'); + anchor = link && link.closest('a'), + cont = anchor && anchor.closest('.tw-flex'); if ( cont && el.contains(cont) ) { el._ffz_links = ; @@ -225,7 +239,7 @@ export default class Channel extends Module { const login = el._ffz_link_login = props.channelLogin; if ( login ) { const make_link = (link, text) => { - const a = {text}; + const a = {text}; a.addEventListener('click', event => { if ( event.ctrlKey || event.shiftKey || event.altKey ) return; @@ -240,11 +254,14 @@ export default class Channel extends Module { return a; } - setChildren(el._ffz_links, [ - make_link(`/${login}/schedule`, this.i18n.t('channel.links.schedule', 'Schedule')), - make_link(`/${login}/videos`, this.i18n.t('channel.links.videos', 'Videos')), - make_link(`/${login}/clips`, this.i18n.t('channel.links.clips', 'Clips')) - ]); + if ( el._ffz_links.closest('.home-header-sticky') ) + el._ffz_links.innerHTML = ''; + else + setChildren(el._ffz_links, [ + make_link(`/${login}/schedule`, this.i18n.t('channel.links.schedule', 'Schedule')), + make_link(`/${login}/videos`, this.i18n.t('channel.links.videos', 'Videos')), + make_link(`/${login}/clips`, this.i18n.t('channel.links.clips', 'Clips')) + ]); } else el._ffz_links.innerHTML = ''; @@ -310,6 +327,7 @@ export default class Channel extends Module { login: props.channelLogin, display_name: props.displayName, live: props.isLive && ! props.videoID && ! props.clipSlug, + video: !!(props.videoID || props.clipSlug), live_since: props.liveSince }, props, @@ -319,7 +337,7 @@ export default class Channel extends Module { }, el, getViewerCount: () => { - const thing = el.querySelector('p[data-a-target="animated-channel-viewers-count"]'), + const thing = cont.querySelector('p[data-a-target="animated-channel-viewers-count"]'), r = thing && this.fine.getReactInstance(thing), p = r?.memoizedProps?.children?.props; diff --git a/src/sites/twitch-twilight/modules/chat/line.js b/src/sites/twitch-twilight/modules/chat/line.js index 9010d581..1eb6f39e 100644 --- a/src/sites/twitch-twilight/modules/chat/line.js +++ b/src/sites/twitch-twilight/modules/chat/line.js @@ -55,6 +55,7 @@ export default class ChatLine extends Module { async onEnable() { this.on('chat.overrides:changed', id => this.updateLinesByUser(id), this); + this.on('chat:update-lines', this.updateLines, this); this.chat.context.on('changed:chat.emoji.style', this.updateLines, this); this.chat.context.on('changed:chat.bits.stack', this.updateLines, this); diff --git a/src/sites/twitch-twilight/modules/host_button/index.js b/src/sites/twitch-twilight/modules/host_button/index.js index 7755d0bc..91a75593 100644 --- a/src/sites/twitch-twilight/modules/host_button/index.js +++ b/src/sites/twitch-twilight/modules/host_button/index.js @@ -83,14 +83,14 @@ export default class HostButton extends Module { }, label: data => { - if ( ! data.channel.live ) - return; - const ffz_user = this.site.getUser(); if ( ! this.settings.get('metadata.host-button') || ! ffz_user || ! data.channel || data.channel.login === ffz_user.login ) return; + if ( data.channel.video && ! this.isChannelHosted(data.channel.login) ) + return; + if ( this._host_updating ) return this.i18n.t('metadata.host-button.updating', 'Updating...'); diff --git a/src/sites/twitch-twilight/styles/channel.scss b/src/sites/twitch-twilight/styles/channel.scss index 351a6a74..b8b298b9 100644 --- a/src/sites/twitch-twilight/styles/channel.scss +++ b/src/sites/twitch-twilight/styles/channel.scss @@ -41,6 +41,15 @@ } } +.ffz-stat[data-key="viewers"] figure { + font-size: 1.6rem; + + &:before { + margin: 0 !important; + } + +} + .ffz-stat-text { font-size: 1.2rem; font-variant-numeric: tabular-nums; diff --git a/src/utilities/timing.js b/src/utilities/timing.js index a5abdd84..4e9689a2 100644 --- a/src/utilities/timing.js +++ b/src/utilities/timing.js @@ -13,6 +13,20 @@ export default class Timing extends Module { super(...args); this.events = []; + + this._listener = null; + + this.on('settings:enabled', () => { + this.resolve('settings').addUI('timing.info', { + path: 'Debugging > Performance >> Info @{"sort": -1000}', + force_seen: true, + component: 'performance', + + setListener: fn => this._listener = fn, + getEvents: () => this.events, + getTiming: () => this + }); + }); } __time() { /* no-op */ } // eslint-disable-line class-methods-use-this @@ -20,5 +34,7 @@ export default class Timing extends Module { addEvent(event) { event.ts = performance.now(); this.events.push(event); + if ( this._listener ) + this._listener(event); } } \ No newline at end of file