mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.50.0
* Added: Setting to automatically uncheck the "Featured Clips Only" option when viewing a channel's clips. * Added: Chat actions can now use the `urlencode` formatter. Really this should have been available from the beginning, as it makes the Open URL action much more useful. * Fixed: An issue where certain emotes wouldn't appear in the list of available emotes during tab-completion. * Fixed: An error in the stream latency metadata handler when the video player cannot be accessed. * Fixed: An issue where a user's FFZ settings profiles may become corrupt and prevent the FFZ Control Center from functioning correctly. * Fixed: An issue where ephemeral settings profiles may not initialize correctly. * Fixed: The new Hype Chat up-sell at the top of chat not being hidden. Go away Hype Chat no one likes you. * Changed: Add support for an updated pubsub library. * API Added: Prefix modifier support, to make Lordmau5's life easier with the BTTV Emotes add-on. * API Changed: Attempting to alter settings profiles before the settings module has fully initialized will throw an exception. * Maintenance: Update the pnpm lockfile.
This commit is contained in:
parent
7455ec6a2b
commit
cef58241d4
10 changed files with 1337 additions and 1069 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.49.0",
|
"version": "4.50.0",
|
||||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
|
2097
pnpm-lock.yaml
generated
2097
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -35,7 +35,8 @@ const Flags = make_enum_flags(
|
||||||
'Shake',
|
'Shake',
|
||||||
'Cursed',
|
'Cursed',
|
||||||
'Jam',
|
'Jam',
|
||||||
'Bounce'
|
'Bounce',
|
||||||
|
'NoSpace'
|
||||||
);
|
);
|
||||||
|
|
||||||
export const MODIFIER_FLAGS = Flags;
|
export const MODIFIER_FLAGS = Flags;
|
||||||
|
@ -1707,6 +1708,8 @@ export default class Emotes extends Module {
|
||||||
animSrc2: emote.animSrc2,
|
animSrc2: emote.animSrc2,
|
||||||
animSrcSet2: emote.animSrcSet2,
|
animSrcSet2: emote.animSrcSet2,
|
||||||
masked: !! emote.mask,
|
masked: !! emote.mask,
|
||||||
|
mod: emote.modifier,
|
||||||
|
mod_prefix: emote.modifier_prefix,
|
||||||
mod_hidden: (emote.modifier_flags & 1) === 1,
|
mod_hidden: (emote.modifier_flags & 1) === 1,
|
||||||
text: emote.hidden ? '???' : emote.name,
|
text: emote.hidden ? '???' : emote.name,
|
||||||
length: emote.name.length,
|
length: emote.name.length,
|
||||||
|
|
|
@ -1716,7 +1716,12 @@ export const AddonEmotes = {
|
||||||
anim = this.context.get('chat.emotes.animated'),
|
anim = this.context.get('chat.emotes.animated'),
|
||||||
out = [];
|
out = [];
|
||||||
|
|
||||||
|
let had_prefix_mods = false;
|
||||||
|
let had_no_space = false;
|
||||||
let last_token, emote;
|
let last_token, emote;
|
||||||
|
|
||||||
|
const NoSpace = this.emotes.ModifierFlags?.NoSpace;
|
||||||
|
|
||||||
for(const token of tokens) {
|
for(const token of tokens) {
|
||||||
if ( ! token )
|
if ( ! token )
|
||||||
continue;
|
continue;
|
||||||
|
@ -1741,10 +1746,15 @@ export const AddonEmotes = {
|
||||||
emote = emotes[segment];
|
emote = emotes[segment];
|
||||||
|
|
||||||
// Is this emote a modifier?
|
// Is this emote a modifier?
|
||||||
if ( emote.modifier && last_token && last_token.modifiers && (!text.length || (text.length === 1 && text[0] === '')) ) {
|
if ( emote.modifier && emote.modifier_prefix )
|
||||||
|
had_prefix_mods = true;
|
||||||
|
else if ( emote.modifier && last_token && last_token.modifiers && (!text.length || (text.length === 1 && text[0] === '')) ) {
|
||||||
if ( last_token.modifiers.indexOf(emote.token) === -1 ) {
|
if ( last_token.modifiers.indexOf(emote.token) === -1 ) {
|
||||||
if ( emote.modifier_flags )
|
if ( emote.modifier_flags ) {
|
||||||
last_token.modifier_flags |= emote.modifier_flags;
|
last_token.modifier_flags |= emote.modifier_flags;
|
||||||
|
if ( NoSpace && (emote.modifier_flags & NoSpace) === NoSpace )
|
||||||
|
had_no_space = true;
|
||||||
|
}
|
||||||
|
|
||||||
last_token.modifiers.push(
|
last_token.modifiers.push(
|
||||||
Object.assign({
|
Object.assign({
|
||||||
|
@ -1790,6 +1800,66 @@ export const AddonEmotes = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( had_prefix_mods ) {
|
||||||
|
// We need to scan through and apply prefix modifiers as appropriate.
|
||||||
|
let last_emote,
|
||||||
|
had_text = false;
|
||||||
|
|
||||||
|
let i = out.length;
|
||||||
|
while(i--) {
|
||||||
|
const token = out[i];
|
||||||
|
|
||||||
|
// Is it a new emote?
|
||||||
|
if ( token.type === 'emote' && ! token.mod ) {
|
||||||
|
last_emote = token;
|
||||||
|
had_text = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it a prefix mod with a target emote?
|
||||||
|
else if ( last_emote && token.type === 'emote' && token.mod && token.mod_prefix ) {
|
||||||
|
last_emote.modifiers.push(token);
|
||||||
|
if ( token.source_modifier_flags ) {
|
||||||
|
last_emote.modifier_flags |= token.source_modifier_flags;
|
||||||
|
if ( NoSpace && (token.source_modifier_flags & NoSpace) === NoSpace )
|
||||||
|
had_no_space = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove one or two tokens, depending on if we had a space.
|
||||||
|
// (We should always have a space, but be flexible.)
|
||||||
|
out.splice(i, had_text ? 2 : 1);
|
||||||
|
had_text = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a note of at most one space.
|
||||||
|
else if ( last_emote && ! had_text && token.type === 'text' && token.text === ' ' ) {
|
||||||
|
had_text = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Absolutely anything else means it's a broken sequence.
|
||||||
|
else {
|
||||||
|
last_emote = null;
|
||||||
|
had_text = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( had_no_space ) {
|
||||||
|
// We need to remove prefix spaces before emotes with the no-space effect.
|
||||||
|
let no_space = false;
|
||||||
|
let i = out.length;
|
||||||
|
while(i--) {
|
||||||
|
const token = out[i];
|
||||||
|
if ( token.type === 'emote' && (token.modifier_flags & NoSpace) === NoSpace )
|
||||||
|
no_space = true;
|
||||||
|
else {
|
||||||
|
if ( no_space && token.type === 'text' && token.text === ' ' )
|
||||||
|
out.splice(i, 1);
|
||||||
|
|
||||||
|
no_space = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -362,7 +362,7 @@ export default class Metadata extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the video element.
|
// Get the video element.
|
||||||
const video = maybe_call(player.getHTMLVideoElement, player);
|
const video = player && maybe_call(player.getHTMLVideoElement, player);
|
||||||
stats.avOffset = 0;
|
stats.avOffset = 0;
|
||||||
if ( video?._ffz_context )
|
if ( video?._ffz_context )
|
||||||
stats.avOffset = (video._ffz_context_offset ?? 0) + video._ffz_context.currentTime - video.currentTime;
|
stats.avOffset = (video._ffz_context_offset ?? 0) + video._ffz_context.currentTime - video.currentTime;
|
||||||
|
|
|
@ -184,7 +184,6 @@ export default class SettingsManager extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
addFilter(key, data) {
|
addFilter(key, data) {
|
||||||
if ( this.filters[key] )
|
if ( this.filters[key] )
|
||||||
return this.log.warn('Tried to add already existing filter', key);
|
return this.log.warn('Tried to add already existing filter', key);
|
||||||
|
@ -763,13 +762,22 @@ export default class SettingsManager extends Module {
|
||||||
old_ids = new Set(old_profiles.map(x => x.id)),
|
old_ids = new Set(old_profiles.map(x => x.id)),
|
||||||
|
|
||||||
new_ids = new Set,
|
new_ids = new Set,
|
||||||
changed_ids = new Set,
|
changed_ids = new Set;
|
||||||
|
|
||||||
raw_profiles = this.provider.get('profiles', [
|
let raw_profiles = this.provider.get('profiles', [
|
||||||
SettingsProfile.Moderation,
|
SettingsProfile.Moderation,
|
||||||
SettingsProfile.Default
|
SettingsProfile.Default
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Sanity check. If we have no profiles, delete the old data.
|
||||||
|
if ( ! raw_profiles?.length ) {
|
||||||
|
this.provider.delete('profiles');
|
||||||
|
raw_profiles = [
|
||||||
|
SettingsProfile.Moderation,
|
||||||
|
SettingsProfile.Default
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
let reordered = false,
|
let reordered = false,
|
||||||
changed = false;
|
changed = false;
|
||||||
|
|
||||||
|
@ -851,6 +859,9 @@ export default class SettingsManager extends Module {
|
||||||
* @returns {SettingsProfile}
|
* @returns {SettingsProfile}
|
||||||
*/
|
*/
|
||||||
createProfile(options) {
|
createProfile(options) {
|
||||||
|
if ( ! this.enabled )
|
||||||
|
throw new Error('Unable to create profile before settings have initialized. Please await enable()');
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while( this.__profile_ids[i] )
|
while( this.__profile_ids[i] )
|
||||||
i++;
|
i++;
|
||||||
|
@ -878,6 +889,9 @@ export default class SettingsManager extends Module {
|
||||||
* @param {number|SettingsProfile} id - The profile to delete
|
* @param {number|SettingsProfile} id - The profile to delete
|
||||||
*/
|
*/
|
||||||
deleteProfile(id) {
|
deleteProfile(id) {
|
||||||
|
if ( ! this.enabled )
|
||||||
|
throw new Error('Unable to delete profile before settings have initialized. Please await enable()');
|
||||||
|
|
||||||
if ( typeof id === 'object' && id.id != null )
|
if ( typeof id === 'object' && id.id != null )
|
||||||
id = id.id;
|
id = id.id;
|
||||||
|
|
||||||
|
@ -905,6 +919,9 @@ export default class SettingsManager extends Module {
|
||||||
|
|
||||||
|
|
||||||
moveProfile(id, index) {
|
moveProfile(id, index) {
|
||||||
|
if ( ! this.enabled )
|
||||||
|
throw new Error('Unable to move profiles before settings have initialized. Please await enable()');
|
||||||
|
|
||||||
if ( typeof id === 'object' && id.id )
|
if ( typeof id === 'object' && id.id )
|
||||||
id = id.id;
|
id = id.id;
|
||||||
|
|
||||||
|
@ -925,6 +942,9 @@ export default class SettingsManager extends Module {
|
||||||
|
|
||||||
|
|
||||||
saveProfile(id) {
|
saveProfile(id) {
|
||||||
|
if ( ! this.enabled )
|
||||||
|
throw new Error('Unable to save profile before settings have initialized. Please await enable()');
|
||||||
|
|
||||||
if ( typeof id === 'object' && id.id )
|
if ( typeof id === 'object' && id.id )
|
||||||
id = id.id;
|
id = id.id;
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,10 @@ export default class SettingsProfile extends EventEmitter {
|
||||||
|
|
||||||
this.matcher = null;
|
this.matcher = null;
|
||||||
|
|
||||||
|
// Make sure ephemeral is set first.
|
||||||
|
if ( val.ephemeral )
|
||||||
|
this.ephemeral = true;
|
||||||
|
|
||||||
for(const key in val)
|
for(const key in val)
|
||||||
if ( has(val, key) )
|
if ( has(val, key) )
|
||||||
this[key] = val[key];
|
this[key] = val[key];
|
||||||
|
@ -203,7 +207,7 @@ export default class SettingsProfile extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
set toggled(val) {
|
set toggled(val) {
|
||||||
if ( val === this.toggleState )
|
if ( val === this.toggled )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( this.ephemeral )
|
if ( this.ephemeral )
|
||||||
|
|
|
@ -31,6 +31,14 @@ export default class Channel extends Module {
|
||||||
this.inject('metadata');
|
this.inject('metadata');
|
||||||
this.inject('socket');
|
this.inject('socket');
|
||||||
|
|
||||||
|
this.settings.add('channel.auto-click-off-featured', {
|
||||||
|
default: false,
|
||||||
|
ui: {
|
||||||
|
path: 'Channel > Behavior >> General',
|
||||||
|
title: 'Automatically un-check "Featured Clips Only" when viewing a channel\'s clips.',
|
||||||
|
component: 'setting-check-box'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.settings.add('channel.panel-tips', {
|
this.settings.add('channel.panel-tips', {
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -212,7 +220,26 @@ export default class Channel extends Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkFeaturedClips() {
|
||||||
|
if ( this.router.current_name !== 'user-clips' && this.router.current_name !== 'user-videos' )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( this._featured_waiting || ! this.settings.get('channel.auto-click-off-featured') )
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._featured_waiting = this.parent.awaitElement('input#featured-clips-toggle').then(el => {
|
||||||
|
if ( el.checked )
|
||||||
|
el.click();
|
||||||
|
|
||||||
|
this._featured_waiting = false;
|
||||||
|
}).catch(() => {
|
||||||
|
this._featured_waiting = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
checkNavigation() {
|
checkNavigation() {
|
||||||
|
this.checkFeaturedClips();
|
||||||
|
|
||||||
if ( ! this.settings.get('channel.auto-click-chat') || this.router.current_name !== 'user-home' )
|
if ( ! this.settings.get('channel.auto-click-chat') || this.router.current_name !== 'user-home' )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -708,12 +708,17 @@ export default class EmoteMenu extends Module {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check for magic.
|
// Check for magic.
|
||||||
let prefix = '';
|
let prefix = '', postfix = '';
|
||||||
const effects = event.currentTarget.dataset.effects;
|
const effects = event.currentTarget.dataset.effects,
|
||||||
if ( effects?.length > 0 && effects != '0' && t.emotes.target_emote )
|
is_prefix = event.currentTarget.dataset.effectPrefix === 'true';
|
||||||
prefix = `${t.emotes.target_emote.name} `;
|
if ( effects?.length > 0 && effects != '0' && t.emotes.target_emote ) {
|
||||||
|
if ( is_prefix )
|
||||||
|
postfix = ` ${t.emotes.target_emote.name}`;
|
||||||
|
else
|
||||||
|
prefix = `${t.emotes.target_emote.name} `;
|
||||||
|
}
|
||||||
|
|
||||||
this.props.onClickToken(`${prefix}${event.currentTarget.dataset.name}`);
|
this.props.onClickToken(`${prefix}${event.currentTarget.dataset.name}${postfix}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyHeading(event) {
|
keyHeading(event) {
|
||||||
|
@ -925,6 +930,7 @@ export default class EmoteMenu extends Module {
|
||||||
data-code={emote.code}
|
data-code={emote.code}
|
||||||
data-modifiers={modifiers}
|
data-modifiers={modifiers}
|
||||||
data-effects={emote.effects}
|
data-effects={emote.effects}
|
||||||
|
data-effect-prefix={emote.effect_prefix}
|
||||||
data-variant={emote.variant}
|
data-variant={emote.variant}
|
||||||
data-no-source={source}
|
data-no-source={source}
|
||||||
data-name={emote.name}
|
data-name={emote.name}
|
||||||
|
@ -2519,6 +2525,7 @@ export default class EmoteMenu extends Module {
|
||||||
animSrc: emote.animSrc,
|
animSrc: emote.animSrc,
|
||||||
animSrcSet: emote.animSrcSet,
|
animSrcSet: emote.animSrcSet,
|
||||||
effects: emote.modifier ? emote.modifier_flags : 0,
|
effects: emote.modifier ? emote.modifier_flags : 0,
|
||||||
|
effect_prefix: emote.modifier ? emote.modifier_prefix : false,
|
||||||
name: emote.name,
|
name: emote.name,
|
||||||
favorite: is_fav,
|
favorite: is_fav,
|
||||||
locked: locked,
|
locked: locked,
|
||||||
|
|
|
@ -45,8 +45,10 @@ export default class Subpump extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable(tries = 0) {
|
onEnable(tries = 0) {
|
||||||
const instances = window.__Twitch__pubsubInstances;
|
const instance = window.__twitch_pubsub_client,
|
||||||
if ( ! instances ) {
|
instances = window.__Twitch__pubsubInstances;
|
||||||
|
|
||||||
|
if ( ! instance && ! instances ) {
|
||||||
if ( tries > 10 )
|
if ( tries > 10 )
|
||||||
this.log.warn('Unable to find PubSub.');
|
this.log.warn('Unable to find PubSub.');
|
||||||
else
|
else
|
||||||
|
@ -55,52 +57,113 @@ export default class Subpump extends Module {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const val of Object.values(instances))
|
if ( instance ) {
|
||||||
if ( val?._client ) {
|
this.instance = instance;
|
||||||
if ( this.instance ) {
|
this.hookClient(instance);
|
||||||
this.log.warn('Multiple PubSub instances detected. Things might act weird.');
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.instance = val;
|
else if ( instances ) {
|
||||||
this.hookClient(val._client);
|
for(const val of Object.values(instances))
|
||||||
}
|
if ( val?._client ) {
|
||||||
|
if ( this.instance ) {
|
||||||
|
this.log.warn('Multiple PubSub instances detected. Things might act weird.');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.instance = val;
|
||||||
|
this.hookOldClient(val._client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! this.instance )
|
if ( ! this.instance )
|
||||||
this.log.warn('Unable to find a PubSub instance.');
|
this.log.warn('Unable to find a PubSub instance.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleMessage(msg) {
|
||||||
|
try {
|
||||||
|
if ( msg.type === 'MESSAGE' && msg.data?.topic ) {
|
||||||
|
const raw_topic = msg.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: msg.data
|
||||||
|
});
|
||||||
|
|
||||||
|
this.emit(':pubsub-message', event);
|
||||||
|
if ( event.defaultPrevented )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ( event._changed )
|
||||||
|
msg.data.message = JSON.stringify(event._obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
this.log.error('Error processing PubSub event.', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hookClient(client) {
|
hookClient(client) {
|
||||||
|
const t = this,
|
||||||
|
orig_message = client.onMessage;
|
||||||
|
|
||||||
|
this.is_old = false;
|
||||||
|
|
||||||
|
client.connection.removeAllListeners('message');
|
||||||
|
|
||||||
|
client.onMessage = function(e) {
|
||||||
|
if ( t.handleMessage(e) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
return orig_message.call(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.connection.addListener('message', client.onMessage);
|
||||||
|
|
||||||
|
const orig_on = client.listen,
|
||||||
|
orig_off = client.unlisten;
|
||||||
|
|
||||||
|
client.ffz_original_listen = orig_on;
|
||||||
|
client.ffz_original_unlisten = orig_off;
|
||||||
|
|
||||||
|
client.listen = function(opts, fn, ...args) {
|
||||||
|
const topic = opts.topic,
|
||||||
|
has_topic = topic && !! client.topicListeners?._events?.[topic],
|
||||||
|
out = orig_on.call(this, opts, fn, ...args);
|
||||||
|
|
||||||
|
if ( topic && ! has_topic )
|
||||||
|
t.emit(':add-topic', topic);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.unlisten = function(topic, fn, ...args) {
|
||||||
|
const has_topic = !! client.topicListeners?._events?.[topic],
|
||||||
|
out = orig_off.call(this, topic, fn, ...args);
|
||||||
|
|
||||||
|
if ( has_topic && ! client.topicListeners?._events?.[topic] )
|
||||||
|
t.emit(':remove-topic', topic);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hookOldClient(client) {
|
||||||
const t = this,
|
const t = this,
|
||||||
orig_message = client._onMessage;
|
orig_message = client._onMessage;
|
||||||
|
|
||||||
|
this.is_old = true;
|
||||||
|
|
||||||
client._unbindPrimary(client._primarySocket);
|
client._unbindPrimary(client._primarySocket);
|
||||||
|
|
||||||
client._onMessage = function(e) {
|
client._onMessage = function(e) {
|
||||||
try {
|
if ( t.handleMessage(e) )
|
||||||
if ( e.type === 'MESSAGE' && e.data?.topic ) {
|
return;
|
||||||
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) {
|
|
||||||
t.log.error('Error processing PubSub event.', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return orig_message.call(this, e);
|
return orig_message.call(this, e);
|
||||||
};
|
};
|
||||||
|
@ -133,15 +196,24 @@ export default class Subpump extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
inject(topic, message) {
|
inject(topic, message) {
|
||||||
const listens = this.instance?._client?._listens;
|
if ( ! this.instance )
|
||||||
if ( ! listens )
|
|
||||||
throw new Error('No PubSub instance available');
|
throw new Error('No PubSub instance available');
|
||||||
|
|
||||||
listens._trigger(topic, JSON.stringify(message));
|
if ( this.is_old ) {
|
||||||
|
const listens = this.instance._client?._listens;
|
||||||
|
listens._trigger(topic, JSON.stringify(message));
|
||||||
|
} else {
|
||||||
|
this.instance.simulateMessage(topic, JSON.stringify(message));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get topics() {
|
get topics() {
|
||||||
const events = this.instance?._client?._listens._events;
|
let events;
|
||||||
|
if ( this.is_old )
|
||||||
|
events = this.instance?._client?._listens._events;
|
||||||
|
else
|
||||||
|
events = this.instance?.topicListeners?._events;
|
||||||
|
|
||||||
if ( ! events )
|
if ( ! events )
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue