mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-28 08:50:55 +00:00
4.20.57
* Added: Setting to hide viewer counts from the side bar. * Changed: Allow use of time formats when creating a timeout action. (Closes #978) * Changed: Highlight My Message highlights can now be displayed in either Twitch style or FFZ style, in addition to disabling the highlight. FFZ Style remains the default. (Closes #972) * Fixed: Current Channel profile rules not functioning, either on normal channel pages or on mod view pages. (Closes #957) * Fixed: Current Category and Title profile rules not working on mod view. * Fixed: Channel color not being detected correctly. (Also Closes #972) * Fixed: Download Clip not displaying on clip pages. (Closes #960) * Fixed: Remove debug logging from `resizeInput` * Fixed: Popups, including channel rules, not rendering correctly in portrait mode. (Closes #979) * Fixed: Rendering for certain elements using `tw-pill` * Fixed: Vue balloon elements not rendering correctly.
This commit is contained in:
parent
9a2a6f2acf
commit
046de0bb8a
16 changed files with 365 additions and 31 deletions
235
src/sites/twitch-twilight/modules/mod-view.jsx
Normal file
235
src/sites/twitch-twilight/modules/mod-view.jsx
Normal file
|
@ -0,0 +1,235 @@
|
|||
'use strict';
|
||||
|
||||
// ============================================================================
|
||||
// Mod View Module
|
||||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
import { Color } from 'utilities/color';
|
||||
import {debounce} from 'utilities/object';
|
||||
import {createElement, ClickOutside, setChildren} from 'utilities/dom';
|
||||
|
||||
|
||||
export default class ModView extends Module {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
this.inject('i18n');
|
||||
this.inject('settings');
|
||||
this.inject('site.channel');
|
||||
this.inject('site.css_tweaks');
|
||||
this.inject('site.fine');
|
||||
this.inject('site.elemental');
|
||||
this.inject('site.router');
|
||||
this.inject('site.twitch_data');
|
||||
this.inject('metadata');
|
||||
this.inject('socket');
|
||||
|
||||
this.should_enable = true;
|
||||
|
||||
this._cached_channel = null;
|
||||
|
||||
this.Root = this.elemental.define(
|
||||
'mod-view-root', '.moderation-view-page',
|
||||
['mod-view'],
|
||||
{attributes: true}, 1
|
||||
);
|
||||
|
||||
this.ModInfoBar = this.elemental.define(
|
||||
'mod-info-bar', '.modview-player-widget__stream-info .simplebar-content',
|
||||
['mod-view'],
|
||||
{childNodes: true, subtree: true}, 1
|
||||
);
|
||||
|
||||
this.checkRoot = debounce(this.checkRoot, 250);
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.Root.on('mount', this.updateRoot, this);
|
||||
this.Root.on('mutate', this.updateRoot, this);
|
||||
this.Root.on('unmount', this.removeRoot, this);
|
||||
this.Root.each(el => this.updateRoot(el));
|
||||
|
||||
this.ModInfoBar.on('mount', this.updateBar, this);
|
||||
this.ModInfoBar.on('mutate', this.updateBar, this);
|
||||
this.ModInfoBar.on('unmount', this.removeBar, this);
|
||||
this.ModInfoBar.each(el => this.updateBar(el));
|
||||
|
||||
this.router.on(':route', this.checkNavigation, this);
|
||||
this.checkNavigation();
|
||||
}
|
||||
|
||||
updateSubscription(login) {
|
||||
if ( this._subbed_login === login )
|
||||
return;
|
||||
|
||||
if ( this._subbed_login ) {
|
||||
this.socket.unsubscribe(this, `channel.${this._subbed_login}`);
|
||||
this._subbed_login = null;
|
||||
}
|
||||
|
||||
if ( login ) {
|
||||
this.socket.subscribe(this, `channel.${login}`);
|
||||
this._subbed_login = login;
|
||||
}
|
||||
}
|
||||
|
||||
checkNavigation() {
|
||||
if ( this.router.current_name === 'mod-view' ) {
|
||||
this.channel.updateChannelColor();
|
||||
this.checkRoot();
|
||||
}
|
||||
}
|
||||
|
||||
checkRoot() {
|
||||
this.Root.each(el => this.updateRoot(el));
|
||||
}
|
||||
|
||||
updateRoot(el) {
|
||||
const root = this.fine.getReactInstance(el);
|
||||
|
||||
let channel = null, state = root?.child?.memoizedState, i = 0;
|
||||
while(state != null && channel == null && i < 50 ) {
|
||||
state = state?.next;
|
||||
channel = state?.memoizedState?.current?.previousData?.result?.data?.user;
|
||||
i++;
|
||||
}
|
||||
|
||||
if ( channel?.id && this._cached_channel != channel.id ) {
|
||||
this._cached_channel = channel.id;
|
||||
this.updateSubscription(channel.login);
|
||||
|
||||
this.getChannelColor(el, channel.id).then(color => {
|
||||
this.channel.updateChannelColor(color);
|
||||
this.settings.updateContext({
|
||||
channelColor: color
|
||||
});
|
||||
}).catch(() => {
|
||||
this.channel.updateChannelColor();
|
||||
this.settings.updateContext({
|
||||
channelColor: null
|
||||
});
|
||||
});
|
||||
|
||||
this.settings.updateContext({
|
||||
channel: channel.login,
|
||||
channelID: channel.id
|
||||
});
|
||||
|
||||
} else
|
||||
this.removeRoot();
|
||||
|
||||
}
|
||||
|
||||
getChannelColor(el, channel_id, no_promise) {
|
||||
const cache = el._ffz_color_cache = el._ffz_color_cache || {};
|
||||
if ( channel_id === cache.channel_id ) {
|
||||
if ( Date.now() - cache.saved < 60000 ) {
|
||||
if ( no_promise )
|
||||
return cache.data;
|
||||
return Promise.resolve(cache.data);
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise(async (s, f) => {
|
||||
if ( cache.updating ) {
|
||||
cache.updating.push([s, f]);
|
||||
return ;
|
||||
}
|
||||
|
||||
cache.channel_id = channel_id;
|
||||
cache.updating = [[s,f]];
|
||||
let data, err;
|
||||
|
||||
try {
|
||||
data = await this.twitch_data.getChannelColor(channel_id);
|
||||
} catch(error) {
|
||||
data = null;
|
||||
err = error;
|
||||
}
|
||||
|
||||
const waiters = cache.updating;
|
||||
cache.updating = null;
|
||||
|
||||
if ( cache.channel_id !== channel_id ) {
|
||||
err = new Error('Outdated');
|
||||
cache.channel_id = null;
|
||||
cache.data = null;
|
||||
cache.saved = 0;
|
||||
for(const pair of waiters)
|
||||
pair[1](err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cache.data = data;
|
||||
cache.saved = Date.now();
|
||||
|
||||
for(const pair of waiters)
|
||||
err ? pair[1](err) : pair[0](data);
|
||||
});
|
||||
}
|
||||
|
||||
removeRoot() {
|
||||
this._cached_channel = null;
|
||||
this.updateSubscription();
|
||||
this.channel.updateChannelColor();
|
||||
this.settings.updateContext({
|
||||
channel: null,
|
||||
channelID: null,
|
||||
channelColor: null
|
||||
});
|
||||
}
|
||||
|
||||
updateBar(el) {
|
||||
const container = el.closest('.modview-player-widget__stream-info'),
|
||||
root = container && this.fine.getReactInstance(container);
|
||||
|
||||
let channel = null, state = root?.return?.memoizedState, i = 0;
|
||||
while(state != null && channel == null && i < 50 ) {
|
||||
state = state?.next;
|
||||
channel = state?.memoizedState?.current?.previousData?.result?.data?.channel;
|
||||
i++;
|
||||
}
|
||||
|
||||
const bcast = channel?.lastBroadcast,
|
||||
title = bcast?.title,
|
||||
game = bcast?.game;
|
||||
|
||||
if ( channel?.id && channel.id != this._cached_channel )
|
||||
this.checkRoot();
|
||||
|
||||
if ( title != el._cached_title || game?.id != el._cached_game ) {
|
||||
el._cached_title = title;
|
||||
el._cached_game = game?.id;
|
||||
|
||||
this.settings.updateContext({
|
||||
category: game?.name,
|
||||
categoryID: game?.id,
|
||||
title
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeBar(el) {
|
||||
this.settings.updateContext({
|
||||
category: null,
|
||||
categoryID: null,
|
||||
title: null
|
||||
});
|
||||
|
||||
if ( el._ffz_cont )
|
||||
el._ffz_cont.classList.remove('ffz--meta-tray');
|
||||
|
||||
el._ffz_cont = null;
|
||||
if ( el._ffz_meta_timers ) {
|
||||
for(const val of Object.values(el._ffz_meta_timers))
|
||||
clearTimeout(val);
|
||||
|
||||
el._ffz_meta_timers = null;
|
||||
}
|
||||
|
||||
el._ffz_update = null;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue