mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.20.64
* Added: Setting to make emotes twice as big in chat. * Added: Setting for hiding Prediction banners in chat. * Fixed: Current channel, category, and title not being detected correctly on the Stream Dashboard page. * Fixed: Tweak the clip URL regex again to support more possible characters. * Fixed: Cyclic dependency error with the CSS Tweaks module. * Fixed: Cyclic dependencies in modules not being detected due to how the enable/load/disable/unload promises work. * Changed: In Switchboard, try finding a route with no parameters first to minimize errors in the log. * Changed: Attempt to detect Firefox with `InstallTrigger` for users that change their User-Agent.
This commit is contained in:
parent
9cecab8dd4
commit
01e7a95cd8
13 changed files with 194 additions and 107 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.20.63",
|
"version": "4.20.64",
|
||||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
"name": "New Link Tokenization",
|
"name": "New Link Tokenization",
|
||||||
"description": "Update to Twitch's latest link regex. Experiment while this is checked for bugs.",
|
"description": "Update to Twitch's latest link regex. Experiment while this is checked for bugs.",
|
||||||
"groups": [
|
"groups": [
|
||||||
{"value": true, "weight": 50},
|
{"value": true, "weight": 100},
|
||||||
{"value": false, "weight": 50}
|
{"value": false, "weight": 0}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"api_load": {
|
"api_load": {
|
||||||
|
@ -19,8 +19,8 @@
|
||||||
"name": "API-Based Link Lookups",
|
"name": "API-Based Link Lookups",
|
||||||
"description": "Use the new API to look up links instead of the socket cluster.",
|
"description": "Use the new API to look up links instead of the socket cluster.",
|
||||||
"groups": [
|
"groups": [
|
||||||
{"value": true, "weight": 50},
|
{"value": true, "weight": 30},
|
||||||
{"value": false, "weight": 50}
|
{"value": false, "weight": 70}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -84,6 +84,16 @@ export default class Emotes extends Module {
|
||||||
this._set_refs = {};
|
this._set_refs = {};
|
||||||
this._set_timers = {};
|
this._set_timers = {};
|
||||||
|
|
||||||
|
this.settings.add('chat.emotes.2x', {
|
||||||
|
default: false,
|
||||||
|
ui: {
|
||||||
|
path: 'Chat > Appearance >> Emotes',
|
||||||
|
title: 'Larger Emotes',
|
||||||
|
description: 'This setting will make emotes appear twice as large in chat. It\'s good for use with larger fonts or just if you really like emotes.',
|
||||||
|
component: 'setting-check-box'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.settings.add('chat.fix-bad-emotes', {
|
this.settings.add('chat.fix-bad-emotes', {
|
||||||
default: true,
|
default: true,
|
||||||
ui: {
|
ui: {
|
||||||
|
@ -721,6 +731,14 @@ export default class Emotes extends Module {
|
||||||
if ( emote.urls[4] )
|
if ( emote.urls[4] )
|
||||||
emote.srcSet += `, ${emote.urls[4]} 4x`;
|
emote.srcSet += `, ${emote.urls[4]} 4x`;
|
||||||
|
|
||||||
|
if ( emote.urls[2] ) {
|
||||||
|
emote.can_big = true;
|
||||||
|
emote.src2 = emote.urls[2];
|
||||||
|
emote.srcSet2 = `${emote.urls[2]} 1x`;
|
||||||
|
if ( emote.urls[4] )
|
||||||
|
emote.srcSet2 += `, ${emote.urls[4]} 2x`;
|
||||||
|
}
|
||||||
|
|
||||||
emote.token = {
|
emote.token = {
|
||||||
type: 'emote',
|
type: 'emote',
|
||||||
id: emote.id,
|
id: emote.id,
|
||||||
|
@ -728,8 +746,12 @@ export default class Emotes extends Module {
|
||||||
provider: 'ffz',
|
provider: 'ffz',
|
||||||
src: emote.urls[1],
|
src: emote.urls[1],
|
||||||
srcSet: emote.srcSet,
|
srcSet: emote.srcSet,
|
||||||
|
can_big: !! emote.urls[2],
|
||||||
|
src2: emote.src2,
|
||||||
|
srcSet2: emote.srcSet2,
|
||||||
text: emote.hidden ? '???' : emote.name,
|
text: emote.hidden ? '???' : emote.name,
|
||||||
length: emote.name.length
|
length: emote.name.length,
|
||||||
|
height: emote.height
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( has(MODIFIERS, emote.id) )
|
if ( has(MODIFIERS, emote.id) )
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
//const CLIP_URL = /^(?:https?:\/\/)?clips\.twitch\.tv\/(\w+)(?:\/)?(\w+)?(?:\/edit)?/;
|
//const CLIP_URL = /^(?:https?:\/\/)?clips\.twitch\.tv\/(\w+)(?:\/)?(\w+)?(?:\/edit)?/;
|
||||||
//const NEW_CLIP_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/\w+\/clip\/(\w+)/;
|
//const NEW_CLIP_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/\w+\/clip\/(\w+)/;
|
||||||
const CLIP_URL = /^(?:https?:\/\/)?clips\.twitch\.tv\/([a-z0-9-]+)(?:\/)?(\w+)?(?:\/edit)?/i;
|
const CLIP_URL = /^(?:https?:\/\/)?clips\.twitch\.tv\/([a-z0-9-_=]+)(?:\/)?(\w+)?(?:\/edit)?/i;
|
||||||
const NEW_CLIP_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/\w+\/clip\/([a-z0-9-]+)/i;
|
const NEW_CLIP_URL = /^(?:https?:\/\/)?(?:(?:www|m)\.)?twitch\.tv\/\w+\/clip\/([a-z0-9-_=]+)/i;
|
||||||
const VIDEO_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/(?:\w+\/v|videos)\/(\w+)/;
|
const VIDEO_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/(?:\w+\/v|videos)\/(\w+)/;
|
||||||
const USER_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/([^/]+)$/;
|
const USER_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/([^/]+)$/;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {CATEGORIES} from './emoji';
|
||||||
|
|
||||||
|
|
||||||
const EMOTE_CLASS = 'chat-image chat-line__message--emote',
|
const EMOTE_CLASS = 'chat-image chat-line__message--emote',
|
||||||
|
WHITESPACE = /^\s*$/,
|
||||||
LINK_REGEX = /([^\w@#%\-+=:~])?((?:(https?:\/\/)?(?:[\w@#%\-+=:~]+\.)+[a-z]{2,6}(?:\/[\w./@#%&()\-+=:?~]*)?))([^\w./@#%&()\-+=:?~]|\s|$)/g,
|
LINK_REGEX = /([^\w@#%\-+=:~])?((?:(https?:\/\/)?(?:[\w@#%\-+=:~]+\.)+[a-z]{2,6}(?:\/[\w./@#%&()\-+=:?~]*)?))([^\w./@#%&()\-+=:?~]|\s|$)/g,
|
||||||
NEW_LINK_REGEX = /(?:(https?:\/\/)?((?:[\w#%\-+=:~]+\.)+[a-z]{2,10}(?:\/[\w./#%&@()\-+=:?~]*)?))/g,
|
NEW_LINK_REGEX = /(?:(https?:\/\/)?((?:[\w#%\-+=:~]+\.)+[a-z]{2,10}(?:\/[\w./#%&@()\-+=:?~]*)?))/g,
|
||||||
//MENTION_REGEX = /([^\w@#%\-+=:~])?(@([^\u0000-\u007F]+|\w+)+)([^\w./@#%&()\-+=:?~]|\s|$)/g; // eslint-disable-line no-control-regex
|
//MENTION_REGEX = /([^\w@#%\-+=:~])?(@([^\u0000-\u007F]+|\w+)+)([^\w./@#%&()\-+=:?~]|\s|$)/g; // eslint-disable-line no-control-regex
|
||||||
|
@ -1057,9 +1058,10 @@ const render_emote = (token, createElement, wrapped) => {
|
||||||
emote = createElement('img', {
|
emote = createElement('img', {
|
||||||
class: `${EMOTE_CLASS} ffz-tooltip${token.provider === 'ffz' ? ' ffz-emote' : token.provider === 'emoji' ? ' ffz-emoji' : ''}`,
|
class: `${EMOTE_CLASS} ffz-tooltip${token.provider === 'ffz' ? ' ffz-emote' : token.provider === 'emoji' ? ' ffz-emoji' : ''}`,
|
||||||
attrs: {
|
attrs: {
|
||||||
src: token.src,
|
src: token.big && token.src2 || token.src,
|
||||||
srcSet: token.srcSet,
|
srcSet: token.big && token.srcSet2 || token.srcSet,
|
||||||
alt: token.text,
|
alt: token.text,
|
||||||
|
height: (token.big && ! token.can_big && token.height) ? `${token.height * 2}px` : undefined,
|
||||||
'data-tooltip-type': 'emote',
|
'data-tooltip-type': 'emote',
|
||||||
'data-provider': token.provider,
|
'data-provider': token.provider,
|
||||||
'data-id': token.id,
|
'data-id': token.id,
|
||||||
|
@ -1111,8 +1113,9 @@ export const AddonEmotes = {
|
||||||
const mods = token.modifiers || [], ml = mods.length,
|
const mods = token.modifiers || [], ml = mods.length,
|
||||||
emote = (<img
|
emote = (<img
|
||||||
class={`${EMOTE_CLASS} ffz--pointer-events ffz-tooltip${token.provider === 'ffz' ? ' ffz-emote' : token.provider === 'emoji' ? ' ffz-emoji' : ''}`}
|
class={`${EMOTE_CLASS} ffz--pointer-events ffz-tooltip${token.provider === 'ffz' ? ' ffz-emote' : token.provider === 'emoji' ? ' ffz-emoji' : ''}`}
|
||||||
src={token.src}
|
src={token.big && token.src2 || token.src}
|
||||||
srcSet={token.srcSet}
|
srcSet={token.big && token.srcSet2 || token.srcSet}
|
||||||
|
height={(token.big && ! token.can_big && token.height) ? `${token.height * 2}px` : undefined}
|
||||||
alt={token.text}
|
alt={token.text}
|
||||||
data-tooltip-type="emote"
|
data-tooltip-type="emote"
|
||||||
data-provider={token.provider}
|
data-provider={token.provider}
|
||||||
|
@ -1291,24 +1294,28 @@ export const AddonEmotes = {
|
||||||
return tokens;
|
return tokens;
|
||||||
|
|
||||||
const emotes = this.emotes.getEmotes(
|
const emotes = this.emotes.getEmotes(
|
||||||
msg.user.id,
|
msg.user.id,
|
||||||
msg.user.login,
|
msg.user.login,
|
||||||
msg.roomID,
|
msg.roomID,
|
||||||
msg.roomLogin
|
msg.roomLogin
|
||||||
),
|
);
|
||||||
out = [];
|
|
||||||
|
|
||||||
if ( ! emotes )
|
if ( ! emotes )
|
||||||
return tokens;
|
return tokens;
|
||||||
|
|
||||||
|
const big = this.context.get('chat.emotes.2x'),
|
||||||
|
out = [];
|
||||||
|
|
||||||
let last_token, emote;
|
let last_token, emote;
|
||||||
for(const token of tokens) {
|
for(const token of tokens) {
|
||||||
if ( ! token )
|
if ( ! token )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( token.type !== 'text' ) {
|
if ( token.type !== 'text' ) {
|
||||||
if ( token.type === 'emote' && ! token.modifiers )
|
if ( token.type === 'emote' ) {
|
||||||
token.modifiers = [];
|
if ( ! token.modifiers )
|
||||||
|
token.modifiers = [];
|
||||||
|
}
|
||||||
|
|
||||||
out.push(token);
|
out.push(token);
|
||||||
last_token = token;
|
last_token = token;
|
||||||
|
@ -1323,8 +1330,14 @@ export const AddonEmotes = {
|
||||||
|
|
||||||
// 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 && 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 ) {
|
||||||
last_token.modifiers.push(emote.token);
|
if ( big )
|
||||||
|
last_token.modifiers.push(Object.assign({
|
||||||
|
big
|
||||||
|
}, emote.token));
|
||||||
|
else
|
||||||
|
last_token.modifiers.push(emote.token);
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1339,7 +1352,10 @@ export const AddonEmotes = {
|
||||||
text = [];
|
text = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const t = Object.assign({modifiers: []}, emote.token);
|
const t = Object.assign({
|
||||||
|
modifiers: [],
|
||||||
|
big
|
||||||
|
}, emote.token);
|
||||||
out.push(t);
|
out.push(t);
|
||||||
last_token = t;
|
last_token = t;
|
||||||
|
|
||||||
|
@ -1349,8 +1365,10 @@ export const AddonEmotes = {
|
||||||
text.push(segment);
|
text.push(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( text.length > 1 || (text.length === 1 && text[0] !== '') )
|
if ( text.length > 1 || (text.length === 1 && text[0] !== '') ) {
|
||||||
out.push({type: 'text', text: text.join(' ')});
|
const t = {type: 'text', text: text.join(' ')};
|
||||||
|
out.push(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
@ -1445,6 +1463,8 @@ export const TwitchEmotes = {
|
||||||
return tokens;
|
return tokens;
|
||||||
|
|
||||||
const data = msg.ffz_emotes,
|
const data = msg.ffz_emotes,
|
||||||
|
big = this.context.get('chat.emotes.2x'),
|
||||||
|
use_replacements = this.context.get('chat.fix-bad-emotes'),
|
||||||
emotes = [];
|
emotes = [];
|
||||||
|
|
||||||
for(const emote_id in data)
|
for(const emote_id in data)
|
||||||
|
@ -1516,15 +1536,21 @@ export const TwitchEmotes = {
|
||||||
});
|
});
|
||||||
|
|
||||||
let src, srcSet;
|
let src, srcSet;
|
||||||
|
let src2, srcSet2;
|
||||||
|
|
||||||
const replacement = REPLACEMENTS[e_id];
|
const replacement = REPLACEMENTS[e_id];
|
||||||
if ( replacement && this.context.get('chat.fix-bad-emotes') ) {
|
if ( replacement && use_replacements ) {
|
||||||
src = `${REPLACEMENT_BASE}${replacement}`;
|
src = `${REPLACEMENT_BASE}${replacement}`;
|
||||||
srcSet = '';
|
srcSet = '';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
src = `${TWITCH_EMOTE_BASE}${e_id}/1.0`;
|
src = `${TWITCH_EMOTE_BASE}${e_id}/1.0`;
|
||||||
srcSet = `${TWITCH_EMOTE_BASE}${e_id}/1.0 1x, ${TWITCH_EMOTE_BASE}${e_id}/2.0 2x`;
|
srcSet = `${TWITCH_EMOTE_BASE}${e_id}/1.0 1x, ${TWITCH_EMOTE_BASE}${e_id}/2.0 2x`;
|
||||||
|
|
||||||
|
if ( big ) {
|
||||||
|
src2 = `${TWITCH_EMOTE_BASE}${e_id}/2.0`;
|
||||||
|
srcSet2 = `${TWITCH_EMOTE_BASE}${e_id}/2.0 1x, ${TWITCH_EMOTE_BASE}${e_id}/3.0 2x`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.push({
|
out.push({
|
||||||
|
@ -1533,6 +1559,9 @@ export const TwitchEmotes = {
|
||||||
provider: 'twitch',
|
provider: 'twitch',
|
||||||
src,
|
src,
|
||||||
srcSet,
|
srcSet,
|
||||||
|
src2,
|
||||||
|
srcSet2,
|
||||||
|
big,
|
||||||
text: text.slice(e_start - t_start, e_end - t_start).join(''),
|
text: text.slice(e_start - t_start, e_end - t_start).join(''),
|
||||||
modifiers: []
|
modifiers: []
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default class Channel extends Module {
|
||||||
|
|
||||||
|
|
||||||
this.settings.add('channel.panel-tips', {
|
this.settings.add('channel.panel-tips', {
|
||||||
default: true,
|
default: false,
|
||||||
ui: {
|
ui: {
|
||||||
path: 'Channel > Behavior >> Panels',
|
path: 'Channel > Behavior >> Panels',
|
||||||
title: 'Display rich tool-tips for links in channel panels.',
|
title: 'Display rich tool-tips for links in channel panels.',
|
||||||
|
|
|
@ -354,6 +354,15 @@ export default class ChatHook extends Module {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.settings.add('chat.banners.prediction', {
|
||||||
|
default: true,
|
||||||
|
ui: {
|
||||||
|
path: 'Chat > Appearance >> Community',
|
||||||
|
title: 'Allow Predictions to be displayed in chat.',
|
||||||
|
component: 'setting-check-box'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.settings.add('chat.community-chest.show', {
|
this.settings.add('chat.community-chest.show', {
|
||||||
default: true,
|
default: true,
|
||||||
ui: {
|
ui: {
|
||||||
|
@ -773,6 +782,7 @@ export default class ChatHook extends Module {
|
||||||
this.chat.context.on('changed:chat.banners.hype-train', this.cleanHighlights, this);
|
this.chat.context.on('changed:chat.banners.hype-train', this.cleanHighlights, this);
|
||||||
this.chat.context.on('changed:chat.subs.gift-banner', this.cleanHighlights, this);
|
this.chat.context.on('changed:chat.subs.gift-banner', this.cleanHighlights, this);
|
||||||
this.chat.context.on('changed:chat.banners.polls', this.cleanHighlights, this);
|
this.chat.context.on('changed:chat.banners.polls', this.cleanHighlights, this);
|
||||||
|
this.chat.context.on('changed:chat.banners.prediction', this.cleanHighlights, this);
|
||||||
|
|
||||||
this.chat.context.on('changed:chat.subs.gift-banner', () => this.GiftBanner.forceUpdate(), this);
|
this.chat.context.on('changed:chat.subs.gift-banner', () => this.GiftBanner.forceUpdate(), this);
|
||||||
this.chat.context.on('changed:chat.width', this.updateChatCSS, this);
|
this.chat.context.on('changed:chat.width', this.updateChatCSS, this);
|
||||||
|
@ -1258,6 +1268,7 @@ export default class ChatHook extends Module {
|
||||||
'community_sub_gift': this.chat.context.get('chat.subs.gift-banner'),
|
'community_sub_gift': this.chat.context.get('chat.subs.gift-banner'),
|
||||||
'megacheer': this.chat.context.get('chat.bits.show'),
|
'megacheer': this.chat.context.get('chat.bits.show'),
|
||||||
'hype_train': this.chat.context.get('chat.banners.hype-train'),
|
'hype_train': this.chat.context.get('chat.banners.hype-train'),
|
||||||
|
'prediction': this.chat.context.get('chat.banners.prediction'),
|
||||||
'poll': this.chat.context.get('chat.banners.polls')
|
'poll': this.chat.context.get('chat.banners.polls')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ export default class ChatLine extends Module {
|
||||||
this.on('chat:update-lines', this.updateLines, this);
|
this.on('chat:update-lines', this.updateLines, this);
|
||||||
this.on('i18n:update', this.updateLines, this);
|
this.on('i18n:update', this.updateLines, this);
|
||||||
|
|
||||||
|
this.chat.context.on('changed:chat.emotes.2x', 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);
|
||||||
this.chat.context.on('changed:chat.badges.style', this.updateLines, this);
|
this.chat.context.on('changed:chat.badges.style', this.updateLines, this);
|
||||||
|
|
|
@ -53,8 +53,6 @@ export default class CSSTweaks extends Module {
|
||||||
this.should_enable = true;
|
this.should_enable = true;
|
||||||
|
|
||||||
this.inject('settings');
|
this.inject('settings');
|
||||||
this.inject('site.chat');
|
|
||||||
this.inject('site.theme');
|
|
||||||
|
|
||||||
this.style = new ManagedStyle;
|
this.style = new ManagedStyle;
|
||||||
this.chunks = {};
|
this.chunks = {};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
import Module from 'utilities/module';
|
import Module from 'utilities/module';
|
||||||
import { get } from 'utilities/object';
|
import { get, has } from 'utilities/object';
|
||||||
|
|
||||||
import Twilight from 'site';
|
import Twilight from 'site';
|
||||||
|
|
||||||
|
@ -19,83 +19,69 @@ export default class Dashboard extends Module {
|
||||||
this.inject('site.fine');
|
this.inject('site.fine');
|
||||||
this.inject('site.channel');
|
this.inject('site.channel');
|
||||||
|
|
||||||
this.HostBar = this.fine.define(
|
this.SunlightBroadcast = this.fine.define(
|
||||||
'sunlight-host-bar',
|
'sunlight-bcast',
|
||||||
n => n.props && n.props.channel && n.props.hostedChannel !== undefined,
|
n => n.getGame && n.getTitle && n.props?.data,
|
||||||
Twilight.SUNLIGHT_ROUTES
|
Twilight.SUNLIGHT_ROUTES
|
||||||
)
|
);
|
||||||
|
|
||||||
this.Dashboard = this.fine.define(
|
this.SunlightManager = this.fine.define(
|
||||||
'sunlight-dash',
|
'sunlight-manager',
|
||||||
n => n.getIsChannelEditor && n.getIsChannelModerator && n.getIsAdsEnabled && n.getIsSquadStreamsEnabled,
|
n => n.props?.channelID && n.handleChange && has(n, 'hasVisitedStreamManager'),
|
||||||
Twilight.SUNLIGHT_ROUTES
|
Twilight.SUNLIGHT_ROUTES
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
onEnable() {
|
||||||
this.Dashboard.on('mount', this.onDashUpdate, this);
|
this.SunlightManager.on('mount', this.updateSunlight, this);
|
||||||
this.Dashboard.on('update', this.onDashUpdate, this);
|
this.SunlightManager.on('update', this.updateSunlight, this);
|
||||||
this.Dashboard.on('unmount', this.onDashUnmount, this);
|
this.SunlightManager.on('unmount', this.removeSunlight, this);
|
||||||
|
this.SunlightManager.ready((cls, instances) => {
|
||||||
this.HostBar.on('mount', this.onHostBarUpdate, this);
|
|
||||||
this.HostBar.on('update', this.onHostBarUpdate, this);
|
|
||||||
this.HostBar.on('unmount', this.onHostBarUnmount, this);
|
|
||||||
|
|
||||||
this.Dashboard.ready((cls, instances) => {
|
|
||||||
for(const inst of instances)
|
for(const inst of instances)
|
||||||
this.onDashUpdate(inst);
|
this.updateSunlight(inst);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.HostBar.ready((cls, instances) => {
|
this.SunlightBroadcast.on('mount', this.updateBroadcast, this);
|
||||||
|
this.SunlightBroadcast.on('update', this.updateBroadcast, this);
|
||||||
|
this.SunlightBroadcast.on('unmount', this.removeBroadcast, this);
|
||||||
|
this.SunlightBroadcast.ready((cls, instances) => {
|
||||||
for(const inst of instances)
|
for(const inst of instances)
|
||||||
this.onHostBarUpdate(inst);
|
this.updateBroadcast(inst);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onDashUpdate(inst) {
|
updateSunlight(inst) {
|
||||||
this.settings.updateContext({
|
this.settings.updateContext({
|
||||||
channel: get('props.channelLogin', inst),
|
channel: get('props.channelLogin', inst),
|
||||||
channelID: get('props.channelID', inst)
|
channelID: get('props.channelID', inst),
|
||||||
|
hosting: !! inst.props?.hostedChannel?.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onDashUnmount() {
|
removeSunlight() {
|
||||||
this.settings.updateContext({
|
this.settings.updateContext({
|
||||||
channel: null,
|
channel: null,
|
||||||
channelID: null
|
channelID: null,
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onHostBarUpdate(inst) {
|
|
||||||
const channel = inst.props?.channel,
|
|
||||||
source = channel?.stream || channel?.broadcastSettings;
|
|
||||||
|
|
||||||
const game = source?.game,
|
|
||||||
title = source?.title || null,
|
|
||||||
color = channel?.primaryColorHex || null;
|
|
||||||
|
|
||||||
this.channel.updateChannelColor(color);
|
|
||||||
|
|
||||||
this.settings.updateContext({
|
|
||||||
/*channel: channel?.login,
|
|
||||||
channelID: channel?.id,*/
|
|
||||||
category: game?.name,
|
|
||||||
categoryID: game?.id,
|
|
||||||
title,
|
|
||||||
channelColor: color,
|
|
||||||
hosting: !! inst.props?.hostedChannel
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onHostBarUnmount() {
|
|
||||||
this.settings.updateContext({
|
|
||||||
/*channel: null,
|
|
||||||
channelID: null,*/
|
|
||||||
channelColor: null,
|
|
||||||
category: null,
|
|
||||||
categoryID: null,
|
|
||||||
title: null,
|
|
||||||
hosting: false
|
hosting: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateBroadcast(inst) {
|
||||||
|
const data = inst.props?.data?.user?.broadcastSettings,
|
||||||
|
game = data?.game;
|
||||||
|
|
||||||
|
this.settings.updateContext({
|
||||||
|
category: game?.name,
|
||||||
|
categoryID: game?.id,
|
||||||
|
title: data?.title
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBroadcast() {
|
||||||
|
this.settings.updateContext({
|
||||||
|
category: null,
|
||||||
|
categoryID: null,
|
||||||
|
title: null
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -66,10 +66,18 @@ export default class Switchboard extends Module {
|
||||||
this.log.info(`Found Route and Switch with ${da_switch.props.children.length} routes.`);
|
this.log.info(`Found Route and Switch with ${da_switch.props.children.length} routes.`);
|
||||||
const location = router.props.location.pathname;
|
const location = router.props.location.pathname;
|
||||||
|
|
||||||
|
if ( ! this.loadRoute(da_switch, location, false) )
|
||||||
|
this.loadRoute(da_switch, location, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadRoute(da_switch, location, with_params) {
|
||||||
for(const route of da_switch.props.children) {
|
for(const route of da_switch.props.children) {
|
||||||
if ( ! route.props || ! route.props.component )
|
if ( ! route.props || ! route.props.component )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if ( with_params !== null && with_params !== route.props.path.includes(':') )
|
||||||
|
continue;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const reg = pathToRegexp(route.props.path);
|
const reg = pathToRegexp(route.props.path);
|
||||||
if ( ! reg.exec || reg.exec(location) )
|
if ( ! reg.exec || reg.exec(location) )
|
||||||
|
@ -124,7 +132,9 @@ export default class Switchboard extends Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -106,7 +106,7 @@ export const WS_CLUSTERS = {
|
||||||
export const IS_OSX = navigator.platform ? navigator.platform.indexOf('Mac') !== -1 : /OS X/.test(navigator.userAgent);
|
export const IS_OSX = navigator.platform ? navigator.platform.indexOf('Mac') !== -1 : /OS X/.test(navigator.userAgent);
|
||||||
export const IS_WIN = navigator.platform ? navigator.platform.indexOf('Win') !== -1 : /Windows/.test(navigator.userAgent);
|
export const IS_WIN = navigator.platform ? navigator.platform.indexOf('Win') !== -1 : /Windows/.test(navigator.userAgent);
|
||||||
export const IS_WEBKIT = navigator.userAgent.indexOf('AppleWebKit/') !== -1 && navigator.userAgent.indexOf('Edge/') === -1;
|
export const IS_WEBKIT = navigator.userAgent.indexOf('AppleWebKit/') !== -1 && navigator.userAgent.indexOf('Edge/') === -1;
|
||||||
export const IS_FIREFOX = navigator.userAgent.indexOf('Firefox/') !== -1;
|
export const IS_FIREFOX = (navigator.userAgent.indexOf('Firefox/') !== -1) || (window.InstallTrigger !== undefined);
|
||||||
|
|
||||||
export const WEBKIT_CSS = IS_WEBKIT ? '-webkit-' : '';
|
export const WEBKIT_CSS = IS_WEBKIT ? '-webkit-' : '';
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,17 @@ export class Module extends EventEmitter {
|
||||||
const path = this.__path || this.name,
|
const path = this.__path || this.name,
|
||||||
state = this.__load_state;
|
state = this.__load_state;
|
||||||
|
|
||||||
|
if ( chain.includes(this) )
|
||||||
|
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when loading ${initial}`, [...chain, this]));
|
||||||
|
else if ( this.load_requires )
|
||||||
|
for(const name of this.load_requires) {
|
||||||
|
const module = this.resolve(name);
|
||||||
|
if ( module && chain.includes(module) )
|
||||||
|
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when loading ${initial}`, [...chain, this, module]));
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.push(this);
|
||||||
|
|
||||||
if ( state === State.LOADING )
|
if ( state === State.LOADING )
|
||||||
return this.__load_promise;
|
return this.__load_promise;
|
||||||
|
|
||||||
|
@ -125,11 +136,6 @@ export class Module extends EventEmitter {
|
||||||
else if ( state === State.UNLOADING )
|
else if ( state === State.UNLOADING )
|
||||||
return Promise.reject(new ModuleError(`attempted to load module ${path} while module is being unloaded`));
|
return Promise.reject(new ModuleError(`attempted to load module ${path} while module is being unloaded`));
|
||||||
|
|
||||||
else if ( chain.includes(this) )
|
|
||||||
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when loading ${initial}`, chain));
|
|
||||||
|
|
||||||
chain.push(this);
|
|
||||||
|
|
||||||
this.__time('load-start');
|
this.__time('load-start');
|
||||||
this.__load_state = State.LOADING;
|
this.__load_state = State.LOADING;
|
||||||
return this.__load_promise = (async () => {
|
return this.__load_promise = (async () => {
|
||||||
|
@ -170,6 +176,17 @@ export class Module extends EventEmitter {
|
||||||
const path = this.__path || this.name,
|
const path = this.__path || this.name,
|
||||||
state = this.__load_state;
|
state = this.__load_state;
|
||||||
|
|
||||||
|
if ( chain.includes(this) )
|
||||||
|
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when unloading ${initial}`, [...chain, this]));
|
||||||
|
else if ( this.load_dependents )
|
||||||
|
for(const dep of this.load_dependents) {
|
||||||
|
const module = this.resolve(dep);
|
||||||
|
if ( module && chain.includes(module) )
|
||||||
|
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when unloading ${initial}`, [...chain, this, module]));
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.push(this);
|
||||||
|
|
||||||
if ( state === State.UNLOADING )
|
if ( state === State.UNLOADING )
|
||||||
return this.__load_promise;
|
return this.__load_promise;
|
||||||
|
|
||||||
|
@ -182,10 +199,6 @@ export class Module extends EventEmitter {
|
||||||
else if ( state === State.LOADING )
|
else if ( state === State.LOADING )
|
||||||
return Promise.reject(new ModuleError(`attempted to unload module ${path} while module is being loaded`));
|
return Promise.reject(new ModuleError(`attempted to unload module ${path} while module is being loaded`));
|
||||||
|
|
||||||
else if ( chain.includes(this) )
|
|
||||||
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when unloading ${initial}`, chain));
|
|
||||||
|
|
||||||
chain.push(this);
|
|
||||||
this.__time('unload-start');
|
this.__time('unload-start');
|
||||||
this.__load_state = State.UNLOADING;
|
this.__load_state = State.UNLOADING;
|
||||||
return this.__load_promise = (async () => {
|
return this.__load_promise = (async () => {
|
||||||
|
@ -197,7 +210,8 @@ export class Module extends EventEmitter {
|
||||||
for(const name of this.load_dependents) {
|
for(const name of this.load_dependents) {
|
||||||
const module = this.resolve(name);
|
const module = this.resolve(name);
|
||||||
if ( ! module )
|
if ( ! module )
|
||||||
throw new ModuleError(`cannot find depending module ${name} when unloading ${path}`);
|
//throw new ModuleError(`cannot find depending module ${name} when unloading ${path}`);
|
||||||
|
continue;
|
||||||
|
|
||||||
promises.push(module.__unload([], initial, Array.from(chain)));
|
promises.push(module.__unload([], initial, Array.from(chain)));
|
||||||
}
|
}
|
||||||
|
@ -227,6 +241,17 @@ export class Module extends EventEmitter {
|
||||||
const path = this.__path || this.name,
|
const path = this.__path || this.name,
|
||||||
state = this.__state;
|
state = this.__state;
|
||||||
|
|
||||||
|
if ( chain.includes(this) )
|
||||||
|
return Promise.reject(new CyclicDependencyError(`cyclic requirements when enabling ${initial}`, [...chain, this]));
|
||||||
|
else if ( this.requires )
|
||||||
|
for(const name of this.requires) {
|
||||||
|
const module = this.resolve(name);
|
||||||
|
if ( module && chain.includes(module) )
|
||||||
|
return Promise.reject(new CyclicDependencyError(`cyclic requirements when enabling ${initial}`, [...chain, this, module]));
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.push(this);
|
||||||
|
|
||||||
if ( state === State.ENABLING )
|
if ( state === State.ENABLING )
|
||||||
return this.__state_promise;
|
return this.__state_promise;
|
||||||
|
|
||||||
|
@ -236,10 +261,6 @@ export class Module extends EventEmitter {
|
||||||
else if ( state === State.DISABLING )
|
else if ( state === State.DISABLING )
|
||||||
return Promise.reject(new ModuleError(`attempted to enable module ${path} while module is being disabled`));
|
return Promise.reject(new ModuleError(`attempted to enable module ${path} while module is being disabled`));
|
||||||
|
|
||||||
else if ( chain.includes(this) )
|
|
||||||
return Promise.reject(new CyclicDependencyError(`cyclic requirements when enabling ${initial}`, chain));
|
|
||||||
|
|
||||||
chain.push(this);
|
|
||||||
this.__time('enable-start');
|
this.__time('enable-start');
|
||||||
this.__state = State.ENABLING;
|
this.__state = State.ENABLING;
|
||||||
return this.__state_promise = (async () => {
|
return this.__state_promise = (async () => {
|
||||||
|
@ -290,6 +311,17 @@ export class Module extends EventEmitter {
|
||||||
const path = this.__path || this.name,
|
const path = this.__path || this.name,
|
||||||
state = this.__state;
|
state = this.__state;
|
||||||
|
|
||||||
|
if ( chain.includes(this) )
|
||||||
|
return Promise.reject(new CyclicDependencyError(`cyclic requirements when disabling ${initial}`, [...chain, this]));
|
||||||
|
else if ( this.dependents )
|
||||||
|
for(const dep of this.dependents) {
|
||||||
|
const module = this.resolve(dep);
|
||||||
|
if ( module && chain.includes(module) )
|
||||||
|
return Promise.reject(new CyclicDependencyError(`cyclic requirements when disabling ${initial}`, [...chain, this, dep]));
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.push(this);
|
||||||
|
|
||||||
if ( state === State.DISABLING )
|
if ( state === State.DISABLING )
|
||||||
return this.__state_promise;
|
return this.__state_promise;
|
||||||
|
|
||||||
|
@ -302,10 +334,6 @@ export class Module extends EventEmitter {
|
||||||
else if ( state === State.ENABLING )
|
else if ( state === State.ENABLING )
|
||||||
return Promise.reject(new ModuleError(`attempted to disable module ${path} but module is being enabled`));
|
return Promise.reject(new ModuleError(`attempted to disable module ${path} but module is being enabled`));
|
||||||
|
|
||||||
else if ( chain.includes(this) )
|
|
||||||
return Promise.reject(new CyclicDependencyError(`cyclic requirements when disabling ${initial}`, chain));
|
|
||||||
|
|
||||||
chain.push(this);
|
|
||||||
this.__time('disable-start');
|
this.__time('disable-start');
|
||||||
this.__state = State.DISABLING;
|
this.__state = State.DISABLING;
|
||||||
return this.__state_promise = (async () => {
|
return this.__state_promise = (async () => {
|
||||||
|
@ -319,7 +347,9 @@ export class Module extends EventEmitter {
|
||||||
for(const name of this.dependents) {
|
for(const name of this.dependents) {
|
||||||
const module = this.resolve(name);
|
const module = this.resolve(name);
|
||||||
if ( ! module )
|
if ( ! module )
|
||||||
throw new ModuleError(`cannot find depending module ${name} when disabling ${path}`);
|
// Assume a non-existent module isn't enabled.
|
||||||
|
//throw new ModuleError(`cannot find depending module ${name} when disabling ${path}`);
|
||||||
|
continue;
|
||||||
|
|
||||||
promises.push(module.__disable([], initial, Array.from(chain)));
|
promises.push(module.__disable([], initial, Array.from(chain)));
|
||||||
}
|
}
|
||||||
|
@ -665,7 +695,7 @@ export class ModuleError extends Error { }
|
||||||
|
|
||||||
export class CyclicDependencyError extends ModuleError {
|
export class CyclicDependencyError extends ModuleError {
|
||||||
constructor(message, modules) {
|
constructor(message, modules) {
|
||||||
super(message);
|
super(`${message} (${modules.map(x => x.path).join(' => ')})`);
|
||||||
this.modules = modules;
|
this.modules = modules;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue