1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-06 22:30:57 +00:00
* Added: Setting to apply username colors to chat mentions. (Closes #753)
* Changed: Stream links now use a darker color.
* Changed: Make the icon for FFZ's Alternative Viewer Count slightly larger.
* Fixed: Crazy flickering when disabling hosting.
* Fixed: Stream links showing up on the home page and not just the live page.
* Fixed: Better detection for channels where the Host button should appear.
* Fixed: FFZ's Alternative Viewer Count metadata not updating correctly when FS Chat is in use.
This commit is contained in:
SirStendec 2020-07-24 17:55:11 -04:00
parent 2f105eb3c4
commit fa3d73e05a
10 changed files with 158 additions and 14 deletions

15
package-lock.json generated
View file

@ -1,6 +1,6 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"version": "4.20.15", "version": "4.20.17",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -5615,6 +5615,14 @@
"minimist": "^1.2.5" "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": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "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": { "obuf": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",

View file

@ -1,7 +1,7 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"author": "Dan Salvato LLC", "author": "Dan Salvato LLC",
"version": "4.20.17", "version": "4.20.18",
"description": "FrankerFaceZ is a Twitch enhancement suite.", "description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {
@ -78,6 +78,7 @@
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"markdown-it": "^11.0.0", "markdown-it": "^11.0.0",
"markdown-it-link-attributes": "^3.0.0", "markdown-it-link-attributes": "^3.0.0",
"mnemonist": "^0.38.0",
"path-to-regexp": "^3.0.0", "path-to-regexp": "^3.0.0",
"popper.js": "^1.14.3", "popper.js": "^1.14.3",
"raven-js": "^3.24.2", "raven-js": "^3.24.2",

View file

@ -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', { this.settings.add('chat.filtering.bold-mentions', {
default: true, default: true,
ui: { ui: {
@ -853,6 +863,21 @@ export default class Chat extends Module {
for(const room of this.iterateRooms()) for(const room of this.iterateRooms())
room.buildBitsCSS(); 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() { onEnable() {
if ( this.context.get('chat.filtering.color-mentions') )
this.createColorCache().then(() => this.emit(':update-lines'));
for(const key in TOKENIZERS) for(const key in TOKENIZERS)
if ( has(TOKENIZERS, key) ) if ( has(TOKENIZERS, key) )
this.addTokenizer(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.displayName = user.displayName || user.userDisplayName || user.login || ext.displayName;
user.isIntl = user.login && user.displayName && user.displayName.trim().toLowerCase() !== user.login; 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 // Standardize Message Content
if ( ! msg.message && msg.messageParts ) if ( ! msg.message && msg.messageParts )
this.detokenizeMessage(msg); this.detokenizeMessage(msg);

View file

@ -209,8 +209,15 @@ export const Mentions = {
}, },
render(token, createElement) { render(token, createElement) {
let color = token.color;
if ( color ) {
const chat = this.resolve('site.chat');
color = chat ? chat.colors.process(color) : color;
}
return (<strong return (<strong
class={`chat-line__message-mention${token.me ? ' ffz--mention-me' : ''}`} class={`chat-line__message-mention${token.me ? ' ffz--mention-me' : ''}`}
style={{color}}
data-login={token.recipient} data-login={token.recipient}
onClick={this.handleMentionClick} onClick={this.handleMentionClick}
> >
@ -270,11 +277,15 @@ export const Mentions = {
mentioned = mentionable; mentioned = mentionable;
} }
const rlower = recipient ? recipient.toLowerCase() : '',
color = this.color_cache ? this.color_cache.get(rlower) : null;
out.push({ out.push({
type: 'mention', type: 'mention',
text: `${at}${recipient}`, text: `${at}${recipient}`,
me: mentioned, me: mentioned,
recipient: recipient ? recipient.toLowerCase() : '' color,
recipient: rlower
}); });
if ( mentioned ) { if ( mentioned ) {

View file

@ -0,0 +1,44 @@
<template>
<div>
<pre>{{ JSON.stringify(events, null, '\t') }}</pre>
</div>
</template>
<script>
import {deep_copy} from 'utilities/object';
export default {
props: ['item', 'context'],
data() {
return {
events: deep_copy(this.item.getEvents())
}
},
computed: {
initial_time() {
const event = this.events[0];
return event ? event.ts : 0;
}
},
created() {
this.onEvent = this.onEvent.bind(this);
this.item.setListener(this.onEvent);
},
destroyed() {
this.onEvent = null;
this.item.setListener(null);
},
methods: {
onEvent(event) {
this.events.push(deep_copy(event));
}
}
}
</script>

View file

@ -21,6 +21,7 @@ export default class Channel extends Module {
this.inject('i18n'); this.inject('i18n');
this.inject('settings'); this.inject('settings');
this.inject('site.apollo');
this.inject('site.css_tweaks'); this.inject('site.css_tweaks');
this.inject('site.elemental'); this.inject('site.elemental');
this.inject('site.subpump'); this.inject('site.subpump');
@ -71,6 +72,18 @@ export default class Channel extends Module {
USER_PAGES, USER_PAGES,
{childNodes: true, subtree: true}, 1 {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() { onEnable() {
@ -210,7 +223,8 @@ export default class Channel extends Module {
if ( ! el._ffz_links && want_links ) { if ( ! el._ffz_links && want_links ) {
const link = el.querySelector('a .tw-line-height-heading'), 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) ) { if ( cont && el.contains(cont) ) {
el._ffz_links = <div class="ffz--links tw-mg-l-1"></div>; el._ffz_links = <div class="ffz--links tw-mg-l-1"></div>;
@ -225,7 +239,7 @@ export default class Channel extends Module {
const login = el._ffz_link_login = props.channelLogin; const login = el._ffz_link_login = props.channelLogin;
if ( login ) { if ( login ) {
const make_link = (link, text) => { const make_link = (link, text) => {
const a = <a href={link} class="tw-c-text-inherit tw-interactive tw-pd-x-1 tw-font-size-5">{text}</a>; const a = <a href={link} class="tw-c-text-alt-2 tw-interactive tw-pd-x-1 tw-font-size-5">{text}</a>;
a.addEventListener('click', event => { a.addEventListener('click', event => {
if ( event.ctrlKey || event.shiftKey || event.altKey ) if ( event.ctrlKey || event.shiftKey || event.altKey )
return; return;
@ -240,11 +254,14 @@ export default class Channel extends Module {
return a; return a;
} }
setChildren(el._ffz_links, [ if ( el._ffz_links.closest('.home-header-sticky') )
make_link(`/${login}/schedule`, this.i18n.t('channel.links.schedule', 'Schedule')), el._ffz_links.innerHTML = '';
make_link(`/${login}/videos`, this.i18n.t('channel.links.videos', 'Videos')), else
make_link(`/${login}/clips`, this.i18n.t('channel.links.clips', 'Clips')) 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 } else
el._ffz_links.innerHTML = ''; el._ffz_links.innerHTML = '';
@ -310,6 +327,7 @@ export default class Channel extends Module {
login: props.channelLogin, login: props.channelLogin,
display_name: props.displayName, display_name: props.displayName,
live: props.isLive && ! props.videoID && ! props.clipSlug, live: props.isLive && ! props.videoID && ! props.clipSlug,
video: !!(props.videoID || props.clipSlug),
live_since: props.liveSince live_since: props.liveSince
}, },
props, props,
@ -319,7 +337,7 @@ export default class Channel extends Module {
}, },
el, el,
getViewerCount: () => { 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), r = thing && this.fine.getReactInstance(thing),
p = r?.memoizedProps?.children?.props; p = r?.memoizedProps?.children?.props;

View file

@ -55,6 +55,7 @@ export default class ChatLine extends Module {
async onEnable() { async onEnable() {
this.on('chat.overrides:changed', id => this.updateLinesByUser(id), this); 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.emoji.style', this.updateLines, this);
this.chat.context.on('changed:chat.bits.stack', this.updateLines, this); this.chat.context.on('changed:chat.bits.stack', this.updateLines, this);

View file

@ -83,14 +83,14 @@ export default class HostButton extends Module {
}, },
label: data => { label: data => {
if ( ! data.channel.live )
return;
const ffz_user = this.site.getUser(); const ffz_user = this.site.getUser();
if ( ! this.settings.get('metadata.host-button') || ! ffz_user || ! data.channel || data.channel.login === ffz_user.login ) if ( ! this.settings.get('metadata.host-button') || ! ffz_user || ! data.channel || data.channel.login === ffz_user.login )
return; return;
if ( data.channel.video && ! this.isChannelHosted(data.channel.login) )
return;
if ( this._host_updating ) if ( this._host_updating )
return this.i18n.t('metadata.host-button.updating', 'Updating...'); return this.i18n.t('metadata.host-button.updating', 'Updating...');

View file

@ -41,6 +41,15 @@
} }
} }
.ffz-stat[data-key="viewers"] figure {
font-size: 1.6rem;
&:before {
margin: 0 !important;
}
}
.ffz-stat-text { .ffz-stat-text {
font-size: 1.2rem; font-size: 1.2rem;
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;

View file

@ -13,6 +13,20 @@ export default class Timing extends Module {
super(...args); super(...args);
this.events = []; 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 __time() { /* no-op */ } // eslint-disable-line class-methods-use-this
@ -20,5 +34,7 @@ export default class Timing extends Module {
addEvent(event) { addEvent(event) {
event.ts = performance.now(); event.ts = performance.now();
this.events.push(event); this.events.push(event);
if ( this._listener )
this._listener(event);
} }
} }