mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-10-11 13:41:57 +00:00
4.20.11
* Added: Setting to disable Channel Hosting. * Added: Setting to hide streams tagged as Promoted from the directory. * Fixed: Tool-tips not appearing when an element is open in fullscreen. * Fixed: Bug when destroying a tool-tip instance. * Fixed: Directory cards not updating with FFZ features on the front page. * API Added: `Subpump` module for manipulating Twitch PubSub events. * API Changed: Add-Ons can now define custom settings profile filters.
This commit is contained in:
parent
ced61d2bfc
commit
22c60050e0
17 changed files with 356 additions and 96 deletions
151
src/utilities/compat/subpump.js
Normal file
151
src/utilities/compat/subpump.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
'use strict';
|
||||
|
||||
// ============================================================================
|
||||
// Subpump
|
||||
// It controls Twitch PubSub.
|
||||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
import { FFZEvent } from 'utilities/events';
|
||||
|
||||
export class PubSubEvent extends FFZEvent {
|
||||
constructor(data) {
|
||||
super(data);
|
||||
|
||||
this._obj = undefined;
|
||||
this._changed = false;
|
||||
}
|
||||
|
||||
markChanged() {
|
||||
this._changed = true;
|
||||
}
|
||||
|
||||
get topic() {
|
||||
return this.event.topic;
|
||||
}
|
||||
|
||||
get message() {
|
||||
if ( this._obj === undefined )
|
||||
this._obj = JSON.parse(this.event.message);
|
||||
|
||||
return this._obj;
|
||||
}
|
||||
|
||||
set message(val) {
|
||||
this._obj = val;
|
||||
this._changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
export default class Subpump extends Module {
|
||||
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this.instance = null;
|
||||
}
|
||||
|
||||
onEnable(tries = 0) {
|
||||
const instances = window.__Twitch__pubsubInstances;
|
||||
if ( ! instances ) {
|
||||
if ( tries > 10 )
|
||||
this.log.warn('Unable to find PubSub.');
|
||||
else
|
||||
new Promise(r => setTimeout(r, 50)).then(() => this.onEnable(tries + 1));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for(const [key, val] of Object.entries(instances))
|
||||
if ( val?._client ) {
|
||||
if ( this.instance ) {
|
||||
this.log.warn('Multiple PubSub instances detected. Things might act weird.');
|
||||
continue;
|
||||
}
|
||||
|
||||
this.instance = val;
|
||||
this.hookClient(val._client);
|
||||
}
|
||||
|
||||
if ( ! this.instance )
|
||||
this.log.warn('Unable to find a PubSub instance.');
|
||||
}
|
||||
|
||||
hookClient(client) {
|
||||
const t = this,
|
||||
orig_message = client._onMessage;
|
||||
|
||||
client._unbindPrimary(client._primarySocket);
|
||||
|
||||
client._onMessage = function(e) {
|
||||
try {
|
||||
if ( e.type === 'MESSAGE' && e.data?.topic ) {
|
||||
const raw_topic = e.data.topic,
|
||||
idx = raw_topic.indexOf('.'),
|
||||
prefix = idx === -1 ? raw_topic : raw_topic.slice(0, idx),
|
||||
trail = idx === -1 ? '' : raw_topic.slice(idx + 1);
|
||||
|
||||
const event = new PubSubEvent({
|
||||
prefix,
|
||||
trail,
|
||||
event: e.data
|
||||
});
|
||||
|
||||
t.emit(':pubsub-message', event);
|
||||
if ( event.defaultPrevented )
|
||||
return;
|
||||
|
||||
if ( event._changed )
|
||||
e.data.message = JSON.stringify(event._obj);
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
this.log.error('Error processing PubSub event.', err);
|
||||
}
|
||||
|
||||
return orig_message.call(this, e);
|
||||
};
|
||||
|
||||
client._bindPrimary(client._primarySocket);
|
||||
|
||||
const listener = client._listens,
|
||||
orig_on = listener.on,
|
||||
orig_off = listener.off;
|
||||
|
||||
listener.on = function(topic, fn, ctx) {
|
||||
const has_topic = !! listener._events?.[topic],
|
||||
out = orig_on.call(this, topic, fn, ctx);
|
||||
|
||||
if ( ! has_topic )
|
||||
t.emit(':add-topic', topic)
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
listener.off = function(topic, fn) {
|
||||
const has_topic = !! listener._events?.[topic],
|
||||
out = orig_off.call(this, topic, fn);
|
||||
|
||||
if ( has_topic && ! listener._events?.[topic] )
|
||||
t.emit(':remove-topic', topic);
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
inject(topic, message) {
|
||||
const listens = this.instance?._client?._listens;
|
||||
if ( ! listens )
|
||||
throw new Error('No PubSub instance available');
|
||||
|
||||
listens._trigger(topic, JSON.stringify(message));
|
||||
}
|
||||
|
||||
get topics() {
|
||||
const events = this.instance?._client?._listens._events;
|
||||
if ( ! events )
|
||||
return [];
|
||||
|
||||
return Object.keys(events);
|
||||
}
|
||||
|
||||
}
|
|
@ -105,8 +105,8 @@ export class Tooltip {
|
|||
if ( this.options.manual ) {
|
||||
// Do nothing~!
|
||||
} else if ( this.live || this.elements.size > 5 ) {
|
||||
parent.removeEventListener('mouseover', this._onMouseOver);
|
||||
parent.removeEventListener('mouseout', this._onMouseOut);
|
||||
this.parent.removeEventListener('mouseover', this._onMouseOver);
|
||||
this.parent.removeEventListener('mouseout', this._onMouseOut);
|
||||
} else
|
||||
for(const el of this.elements) {
|
||||
el.removeEventListener('mouseenter', this._onMouseOver);
|
||||
|
@ -119,6 +119,7 @@ export class Tooltip {
|
|||
this.hide(tip);
|
||||
|
||||
el[this._accessor] = null;
|
||||
el._ffz_tooltip = null;
|
||||
}
|
||||
|
||||
this.elements = null;
|
||||
|
@ -205,12 +206,18 @@ export class Tooltip {
|
|||
target = tip.target;
|
||||
|
||||
this.elements.add(target);
|
||||
target._ffz_tooltip = tip;
|
||||
|
||||
// Set this early in case content uses it early.
|
||||
tip._promises = [];
|
||||
tip.waitForDom = () => tip.element ? Promise.resolve() : new Promise(s => {tip._promises.push(s)});
|
||||
tip.update = () => tip._update(); // tip.popper && tip.popper.scheduleUpdate();
|
||||
tip.show = () => this.show(tip);
|
||||
tip.show = () => {
|
||||
let tip = target[this._accessor];
|
||||
if ( ! tip )
|
||||
tip = target[this._accessor] = {target};
|
||||
this.show(tip);
|
||||
};
|
||||
tip.hide = () => this.hide(tip);
|
||||
tip.rerender = () => {
|
||||
if ( tip.visible ) {
|
||||
|
@ -385,6 +392,10 @@ export class Tooltip {
|
|||
if ( this.live && this.elements )
|
||||
this.elements.delete(tip.target);
|
||||
|
||||
if ( tip.target._ffz_tooltip === tip )
|
||||
tip.target._ffz_tooltip = null;
|
||||
|
||||
tip.target[this._accessor] = null;
|
||||
tip._update = tip.rerender = tip.update = noop;
|
||||
tip.element = null;
|
||||
tip.visible = false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue