1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 05:15:54 +00:00
* Added: Setting to hide the "Discover Luna" link in the top navigation.
* Changed: Hide blocked categories from the directory's category list.
* Fixed: Stream up-times not appearing in the directory.
* Fixed: Error in error handler for PubSub.
* API Added: `Dialog` now supports prepending its element to its container, rather than appending.
* API Added: `tip.add_class` for adding additional classes to rich tooltips that may now have had their element created yet.
This commit is contained in:
SirStendec 2021-11-05 18:01:28 -04:00
parent 032c8821df
commit 76b72b86c8
22 changed files with 219 additions and 156 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"author": "Dan Salvato LLC", "author": "Dan Salvato LLC",
"version": "4.29.2", "version": "4.29.3",
"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",

View file

@ -11,11 +11,13 @@ import SettingsManager from './settings/index';
class FFZBridge extends Module { class FFZBridge extends Module {
constructor() { constructor() {
super(); super();
const start_time = performance.now(), const start_time = performance.now();
VER = FFZBridge.version_info;
FFZBridge.instance = this; FFZBridge.instance = this;
this.host = 'null';
this.flavor = 'bridge';
this.name = 'ffz_bridge'; this.name = 'ffz_bridge';
this.__state = 0; this.__state = 0;
this.__modules.core = this; this.__modules.core = this;
@ -29,8 +31,7 @@ class FFZBridge extends Module {
this.log.init = true; this.log.init = true;
this.core_log = this.log.get('core'); this.core_log = this.log.get('core');
this.log.hi(this);
this.log.info(`FrankerFaceZ Settings Bridge v${VER} (build ${VER.build}${VER.commit ? ` - commit ${VER.commit}` : ''}) (initial ${location})`);
// ======================================================================== // ========================================================================

View file

@ -21,11 +21,11 @@ import Chat from 'src/modules/chat';
class FrankerFaceZ extends Module { class FrankerFaceZ extends Module {
constructor() { constructor() {
super(); super();
const start_time = performance.now(), const start_time = performance.now();
VER = FrankerFaceZ.version_info;
FrankerFaceZ.instance = this; FrankerFaceZ.instance = this;
this.host = 'twitch';
this.flavor = 'clips'; this.flavor = 'clips';
this.name = 'ffz_clips'; this.name = 'ffz_clips';
this.__state = 0; this.__state = 0;
@ -42,8 +42,7 @@ class FrankerFaceZ extends Module {
this.log.init = true; this.log.init = true;
this.core_log = this.log.get('core'); this.core_log = this.log.get('core');
this.log.hi(this);
this.log.info(`FrankerFaceZ Standalone Clips v${VER} (build ${VER.build}${VER.commit ? ` - commit ${VER.commit}` : ''}) (initial ${location})`);
// ======================================================================== // ========================================================================

View file

@ -22,11 +22,11 @@ import Vue from 'utilities/vue';
class FrankerFaceZ extends Module { class FrankerFaceZ extends Module {
constructor() { constructor() {
super(); super();
const start_time = performance.now(), const start_time = performance.now();
VER = FrankerFaceZ.version_info;
FrankerFaceZ.instance = this; FrankerFaceZ.instance = this;
this.host = 'twitch';
this.flavor = 'main'; this.flavor = 'main';
this.name = 'frankerfacez'; this.name = 'frankerfacez';
this.__state = 0; this.__state = 0;
@ -46,8 +46,7 @@ class FrankerFaceZ extends Module {
this.log.init = true; this.log.init = true;
this.core_log = this.log.get('core'); this.core_log = this.log.get('core');
this.log.hi(this);
this.log.info(`FrankerFaceZ v${VER} (build ${VER.build}${VER.commit ? ` - commit ${VER.commit}` : ''}) (initial ${location})`);
// ======================================================================== // ========================================================================
@ -190,6 +189,5 @@ FrankerFaceZ.utilities = {
} }
window.FrankerFaceZ = FrankerFaceZ; window.FrankerFaceZ = FrankerFaceZ;
window.ffz = new FrankerFaceZ(); window.ffz = new FrankerFaceZ();

View file

@ -0,0 +1,3 @@
<template functional>
<div :style="{marginTop: props.item.top}" />
</template>

View file

@ -18,11 +18,11 @@ import Site from './sites/player';
class FrankerFaceZ extends Module { class FrankerFaceZ extends Module {
constructor() { constructor() {
super(); super();
const start_time = performance.now(), const start_time = performance.now();
VER = FrankerFaceZ.version_info;
FrankerFaceZ.instance = this; FrankerFaceZ.instance = this;
this.host = 'twitch';
this.flavor = 'player'; this.flavor = 'player';
this.name = 'ffz_player'; this.name = 'ffz_player';
this.__state = 0; this.__state = 0;
@ -39,8 +39,7 @@ class FrankerFaceZ extends Module {
this.log.init = true; this.log.init = true;
this.core_log = this.log.get('core'); this.core_log = this.log.get('core');
this.log.hi(this);
this.log.info(`FrankerFaceZ Standalone Player v${VER} (build ${VER.build}${VER.commit ? ` - commit ${VER.commit}` : ''}) (initial ${location})`);
// ======================================================================== // ========================================================================

View file

@ -52,7 +52,7 @@ export default class SettingsManager extends Module {
for(const key in PROVIDERS) for(const key in PROVIDERS)
if ( has(PROVIDERS, key) ) { if ( has(PROVIDERS, key) ) {
const provider = PROVIDERS[key]; const provider = PROVIDERS[key];
if ( provider.key && provider.supported() ) if ( provider.key && provider.supported(this) )
this.providers[provider.key] = provider; this.providers[provider.key] = provider;
} }
@ -584,7 +584,7 @@ export default class SettingsManager extends Module {
providers.sort((a,b) => b.priority - a.priority); providers.sort((a,b) => b.priority - a.priority);
for(const provider of providers) { for(const provider of providers) {
if ( provider.supported() && provider.hasContent && await provider.hasContent() ) // eslint-disable-line no-await-in-loop if ( provider.supported(this) && provider.hasContent && await provider.hasContent(this) ) // eslint-disable-line no-await-in-loop
return provider.key; return provider.key;
} }
@ -602,7 +602,7 @@ export default class SettingsManager extends Module {
* from the current provider. * from the current provider.
*/ */
async changeProvider(key, transfer) { async changeProvider(key, transfer) {
if ( ! this.providers[key] || ! this.providers[key].supported() ) if ( ! this.providers[key] || ! this.providers[key].supported(this) )
throw new Error(`Invalid provider: ${key}`); throw new Error(`Invalid provider: ${key}`);
// If we're changing to the current provider... well, that doesn't make // If we're changing to the current provider... well, that doesn't make

View file

@ -9,7 +9,8 @@ import {EventEmitter} from 'utilities/events';
import {has} from 'utilities/object'; import {has} from 'utilities/object';
const DB_VERSION = 1, const DB_VERSION = 1,
NOT_WWW = window.location.host !== 'www.twitch.tv'; NOT_WWW_TWITCH = window.location.host !== 'www.twitch.tv',
NOT_WWW_YT = window.location.host !== 'www.youtube.com';
// ============================================================================ // ============================================================================
@ -1026,7 +1027,9 @@ export class CrossOriginStorageBridge extends SettingsProvider {
this._last_id = 0; this._last_id = 0;
const frame = this.frame = document.createElement('iframe'); const frame = this.frame = document.createElement('iframe');
frame.src = '//www.twitch.tv/p/ffz_bridge/'; frame.src = this.manager.root.host === 'twitch' ?
'//www.twitch.tv/p/ffz_bridge/' :
'//www.youtube.com/__ffz_bridge/';
frame.id = 'ffz-settings-bridge'; frame.id = 'ffz-settings-bridge';
frame.style.width = 0; frame.style.width = 0;
frame.style.height = 0; frame.style.height = 0;
@ -1038,8 +1041,8 @@ export class CrossOriginStorageBridge extends SettingsProvider {
// Static Properties // Static Properties
static supported() { return NOT_WWW; } static supported(manager) { return manager.root.host === 'twitch' ? NOT_WWW_TWITCH : NOT_WWW_YT; }
static hasContent() { return NOT_WWW; } static hasContent(manager) { return CrossOriginStorageBridge.supported(manager); }
static key = 'cosb'; static key = 'cosb';
static priority = 100; static priority = 100;

View file

@ -643,8 +643,8 @@ export default class PlayerBase extends Module {
this._ffz_installed = true; this._ffz_installed = true;
if ( ! this._ffzUpdateVolume ) //if ( ! this._ffzUpdateVolume )
this._ffzUpdateVolume = debounce(this.ffzUpdateVolume.bind(this)); // this._ffzUpdateVolume = debounce(this.ffzUpdateVolume.bind(this));
if ( ! this._ffzUpdateState ) if ( ! this._ffzUpdateState )
this._ffzUpdateState = this.ffzUpdateState.bind(this); this._ffzUpdateState = this.ffzUpdateState.bind(this);
@ -694,7 +694,7 @@ export default class PlayerBase extends Module {
this.ffzStopAutoplay(); this.ffzStopAutoplay();
} }
cls.prototype.ffzUpdateVolume = function() { /*cls.prototype.ffzUpdateVolume = function() {
if ( document.hidden ) if ( document.hidden )
return; return;
@ -708,7 +708,7 @@ export default class PlayerBase extends Module {
player.setMuted(muted); player.setMuted(muted);
} }
} }
} }*/
cls.prototype.ffzUninstall = function() { cls.prototype.ffzUninstall = function() {
if ( this._ffz_state_raf ) if ( this._ffz_state_raf )
@ -1136,8 +1136,8 @@ export default class PlayerBase extends Module {
this.addGainSlider(inst, false); this.addGainSlider(inst, false);
this.addMetadata(inst); this.addMetadata(inst);
if ( inst._ffzUpdateVolume ) //if ( inst._ffzUpdateVolume )
inst._ffzUpdateVolume(); // inst._ffzUpdateVolume();
this.emit(':update-gui', inst); this.emit(':update-gui', inst);
} }

View file

@ -40,6 +40,7 @@ export default class BTTVCompat extends Module {
const settings = await this.awaitSettings(), const settings = await this.awaitSettings(),
waiter = () => this.updateContext(settings); waiter = () => this.updateContext(settings);
settings.on('changed.clickTwitchEmotes', waiter);
settings.on('changed.bttvGIFEmotes', waiter); settings.on('changed.bttvGIFEmotes', waiter);
waiter(); waiter();
@ -62,6 +63,8 @@ export default class BTTVCompat extends Module {
updateContext(settings) { updateContext(settings) {
this.settings.updateContext({ this.settings.updateContext({
bttv: { bttv: {
loaded: true,
emote_menu: settings.get('clickTwitchEmotes'),
gifs: settings.get('bttvGIFEmotes') gifs: settings.get('bttvGIFEmotes')
} }
}); });

View file

@ -200,15 +200,19 @@ export default class EmoteMenu extends Module {
}); });
this.settings.add('chat.emote-menu.icon', { this.settings.add('chat.emote-menu.icon', {
requires: ['chat.emote-menu.enabled'], requires: ['chat.emote-menu.enabled', 'context.bttv.emote_menu'],
default: false, default: false,
process(ctx, val) { process(ctx, val) {
return ctx.get('chat.emote-menu.enabled') ? val : false if ( ! ctx.get('chat.emote-menu.enabled') )
return false;
return ctx.get('context.bttv.emote_menu') || val;
}, },
ui: { ui: {
path: 'Chat > Emote Menu >> Appearance', path: 'Chat > Emote Menu >> Appearance',
title: 'Replace the emote menu icon with the FFZ icon for that classic feel.', title: 'Replace the emote menu icon with the FFZ icon for that classic feel.',
description: '**Note:** This setting may be forcibly enabled if other emote menus are detected, to ensure you can visually identify the FFZ Emote Menu.',
component: 'setting-check-box' component: 'setting-check-box'
} }
}); });
@ -367,7 +371,6 @@ export default class EmoteMenu extends Module {
this.chat.context.on('changed:chat.emote-menu.enabled', () => this.chat.context.on('changed:chat.emote-menu.enabled', () =>
this.EmoteMenu.forceUpdate()); this.EmoteMenu.forceUpdate());
//const fup = () => this.MenuWrapper.forceUpdate();
const rebuild = () => { const rebuild = () => {
for(const inst of this.MenuWrapper.instances) for(const inst of this.MenuWrapper.instances)
inst.rebuildData(); inst.rebuildData();
@ -379,18 +382,12 @@ export default class EmoteMenu extends Module {
this.chat.context.on('changed:chat.fix-bad-emotes', rebuild); this.chat.context.on('changed:chat.fix-bad-emotes', rebuild);
this.chat.context.on('changed:chat.emote-menu.sort-emotes', rebuild); this.chat.context.on('changed:chat.emote-menu.sort-emotes', rebuild);
this.chat.context.on('changed:chat.emote-menu.sort-tiers-last', rebuild); this.chat.context.on('changed:chat.emote-menu.sort-tiers-last', rebuild);
//this.chat.context.on('changed:chat.emote-menu.show-heading', fup);
//this.chat.context.on('changed:chat.emote-menu.show-search', fup);
//this.chat.context.on('changed:chat.emote-menu.reduced-padding', fup);
//this.chat.context.on('changed:chat.emote-menu.combine-tabs', fup);
this.chat.context.on('changed:chat.emoji.style', this.updateEmojiVariables, this); this.chat.context.on('changed:chat.emoji.style', this.updateEmojiVariables, this);
this.chat.context.on('changed:chat.emote-menu.icon', val => this.chat.context.getChanges('chat.emote-menu.icon', val =>
this.css_tweaks.toggle('emote-menu', val)); this.css_tweaks.toggle('emote-menu', val));
this.css_tweaks.toggle('emote-menu', this.chat.context.get('chat.emote-menu.icon'));
this.updateEmojiVariables(); this.updateEmojiVariables();
this.css_tweaks.setVariable('emoji-menu--sheet', `//cdn.frankerfacez.com/static/emoji/images/sheet-twemoji-36.png`); this.css_tweaks.setVariable('emoji-menu--sheet', `//cdn.frankerfacez.com/static/emoji/images/sheet-twemoji-36.png`);

View file

@ -875,8 +875,6 @@ export default class ChatHook extends Module {
this.chat.context.on('changed:chat.filtering.highlight-mentions', this.updateMentionCSS, this); this.chat.context.on('changed:chat.filtering.highlight-mentions', this.updateMentionCSS, this);
this.chat.context.on('changed:chat.filtering.highlight-tokens', this.updateMentionCSS, this); this.chat.context.on('changed:chat.filtering.highlight-tokens', this.updateMentionCSS, this);
this.chat.context.on('changed:chat.filtering.mention-color', this.updateMentionCSS, this); this.chat.context.on('changed:chat.filtering.mention-color', this.updateMentionCSS, this);
this.chat.context.on('changed:chat.filtering.clickable-mentions', val => this.css_tweaks.toggle('clickable-mentions', val));
this.chat.context.on('changed:chat.filtering.bold-mentions', val => this.css_tweaks.toggle('chat-mention-no-bold', ! val));
this.chat.context.on('changed:chat.pin-resubs', val => { this.chat.context.on('changed:chat.pin-resubs', val => {
if ( val ) { if ( val ) {
this.updateInlineCallouts(); this.updateInlineCallouts();
@ -889,46 +887,74 @@ export default class ChatHook extends Module {
this.CalloutSelector.forceUpdate(); this.CalloutSelector.forceUpdate();
}, this); }, this);
this.chat.context.on('changed:chat.input.show-mod-view', val => this.css_tweaks.toggleHide('mod-view', ! val)); this.chat.context.getChanges('chat.input.show-mod-view', val =>
this.css_tweaks.toggleHide('mod-view', ! this.chat.context.get('chat.input.show-mod-view')); this.css_tweaks.toggleHide('mod-view', ! val));
this.chat.context.on('changed:chat.lines.alternate', val => { /*this.chat.context.on('changed:chat.input.show-mod-view', val => this.css_tweaks.toggleHide('mod-view', ! val));
this.css_tweaks.toggle('chat-rows', val); this.css_tweaks.toggleHide('mod-view', ! this.chat.context.get('chat.input.show-mod-view'));*/
this.updateMentionCSS();
});
this.chat.context.on('changed:chat.lines.padding', val => this.chat.context.getChanges('chat.lines.padding', val =>
this.css_tweaks.toggle('chat-padding', val)); this.css_tweaks.toggle('chat-padding', val));
this.chat.context.on('changed:chat.bits.show', val => /*this.chat.context.on('changed:chat.lines.padding', val =>
this.css_tweaks.toggle('chat-padding', val));
this.css_tweaks.toggle('chat-padding', this.chat.context.get('chat.lines.padding'));*/
this.chat.context.getChanges('chat.bits.show', val =>
this.css_tweaks.toggle('hide-bits', !val)); this.css_tweaks.toggle('hide-bits', !val));
this.chat.context.on('changed:chat.bits.show-pinned', val =>
/*this.chat.context.on('changed:chat.bits.show', val =>
this.css_tweaks.toggle('hide-bits', !val));
this.css_tweaks.toggle('hide-bits', !this.chat.context.get('chat.bits.show'));*/
this.chat.context.getChanges('chat.bits.show-pinned', val =>
this.css_tweaks.toggleHide('pinned-cheer', !val)); this.css_tweaks.toggleHide('pinned-cheer', !val));
this.chat.context.on('changed:chat.filtering.deleted-style', val => { /*this.chat.context.on('changed:chat.bits.show-pinned', val =>
this.css_tweaks.toggleHide('pinned-cheer', !val));
this.css_tweaks.toggleHide('pinned-cheer', !this.chat.context.get('chat.bits.show-pinned'));*/
this.chat.context.getChanges('chat.filtering.deleted-style', val => {
this.css_tweaks.toggle('chat-deleted-strike', val === 1 || val === 2); this.css_tweaks.toggle('chat-deleted-strike', val === 1 || val === 2);
this.css_tweaks.toggle('chat-deleted-fade', val < 2); this.css_tweaks.toggle('chat-deleted-fade', val < 2);
}); });
const val = this.chat.context.get('chat.filtering.deleted-style'); this.chat.context.getChanges('chat.filtering.clickable-mentions', val =>
this.css_tweaks.toggle('chat-deleted-strike', val === 1 || val === 2); this.css_tweaks.toggle('clickable-mentions', val));
this.css_tweaks.toggle('chat-deleted-fade', val < 2);
this.css_tweaks.toggle('clickable-mentions', this.chat.context.get('chat.filtering.clickable-mentions')); /*this.chat.context.on('changed:chat.filtering.clickable-mentions', val =>
this.css_tweaks.toggle('chat-mention-no-bold', ! this.chat.context.get('chat.filtering.bold-mentions')); this.css_tweaks.toggle('clickable-mentions', val));
this.css_tweaks.toggle('clickable-mentions', this.chat.context.get('chat.filtering.clickable-mentions'));*/
this.chat.context.on('changed:chat.hide-community-highlights', val => this.css_tweaks.toggleHide('community-highlights', val)); this.chat.context.getChanges('chat.filtering.bold-mentions', val =>
this.css_tweaks.toggle('chat-mention-no-bold', ! val));
this.css_tweaks.toggleHide('community-highlights', this.chat.context.get('chat.hide-community-highlights')); /*this.chat.context.on('changed:chat.filtering.bold-mentions', val =>
this.css_tweaks.toggleHide('pinned-cheer', !this.chat.context.get('chat.bits.show-pinned')); this.css_tweaks.toggle('chat-mention-no-bold', ! val));
this.css_tweaks.toggle('hide-bits', !this.chat.context.get('chat.bits.show')); this.css_tweaks.toggle('chat-mention-no-bold', ! this.chat.context.get('chat.filtering.bold-mentions'));*/
this.css_tweaks.toggle('chat-rows', this.chat.context.get('chat.lines.alternate'));
this.css_tweaks.toggle('chat-padding', this.chat.context.get('chat.lines.padding')); this.chat.context.getChanges('chat.hide-community-highlights', val =>
this.css_tweaks.toggleHide('community-highlights', val));
/*this.chat.context.on('changed:chat.hide-community-highlights', val =>
this.css_tweaks.toggleHide('community-highlights', val));
this.css_tweaks.toggleHide('community-highlights', this.chat.context.get('chat.hide-community-highlights'));*/
this.chat.context.getChanges('chat.lines.alternate', val => {
this.css_tweaks.toggle('chat-rows', val);
this.updateMentionCSS();
});
/*this.chat.context.on('changed:chat.lines.alternate', val => {
this.css_tweaks.toggle('chat-rows', val);
this.updateMentionCSS();
});
this.css_tweaks.toggle('chat-rows', this.chat.context.get('chat.lines.alternate'));*/
this.updateChatCSS(); this.updateChatCSS();
this.updateColors(); this.updateColors();
this.updateLineBorders(); this.updateLineBorders();
this.updateMentionCSS(); //this.updateMentionCSS();
this.RaidController.on('mount', this.wrapRaidController, this); this.RaidController.on('mount', this.wrapRaidController, this);
this.RaidController.on('update', this.noAutoRaids, this); this.RaidController.on('update', this.noAutoRaids, this);

View file

@ -16,11 +16,11 @@ const CLASSES = {
'top-discover': '.navigation-link[data-a-target="discover-link"]', 'top-discover': '.navigation-link[data-a-target="discover-link"]',
'side-nav': '.side-nav,#sideNav', 'side-nav': '.side-nav,#sideNav',
'side-nav-viewers': '.side-nav-card__live-status', 'side-nav-viewers': '.side-nav-card__live-status',
'side-rec-channels': '.side-nav .recommended-channels,.side-nav .side-nav-section + .side-nav-section:not(.online-friends)', 'side-rec-channels': '.side-nav .recommended-channels,.side-nav .side-nav-section + .side-nav-section:not(.online-friends):not(.bd--shelf)',
//'side-rec-friends': '.side-nav .recommended-friends', //'side-rec-friends': '.side-nav .recommended-friends',
'side-friends': '.side-nav .online-friends', 'side-friends': '.side-nav .online-friends',
'side-closed-friends': '.side-nav--collapsed .online-friends', 'side-closed-friends': '.side-nav--collapsed .online-friends',
'side-closed-rec-channels': '.side-nav--collapsed .recommended-channels,.side-nav--collapsed .side-nav-section + .side-nav-section:not(.online-friends)', 'side-closed-rec-channels': '.side-nav--collapsed .recommended-channels,.side-nav--collapsed .side-nav-section + .side-nav-section:not(.online-friends):not(.bd--shelf)',
'side-offline-channels': '.ffz--side-nav-card-offline', 'side-offline-channels': '.ffz--side-nav-card-offline',
'side-rerun-channels': '.side-nav .ffz--side-nav-card-rerun', 'side-rerun-channels': '.side-nav .ffz--side-nav-card-rerun',
'modview-hide-info': '.modview-player-widget__hide-stream-info', 'modview-hide-info': '.modview-player-widget__hide-stream-info',
@ -28,6 +28,7 @@ const CLASSES = {
'community-highlights': '.community-highlight-stack__card', 'community-highlights': '.community-highlight-stack__card',
'prime-offers': '.top-nav__prime', 'prime-offers': '.top-nav__prime',
'discover-luna': '.top-nav__external-link[data-a-target="try-presto-link"]',
'player-gain-volume': '.video-player__container[data-compressed="true"] .volume-slider__slider-container:not(.ffz--player-gain)', 'player-gain-volume': '.video-player__container[data-compressed="true"] .volume-slider__slider-container:not(.ffz--player-gain)',
@ -61,7 +62,6 @@ export default class CSSTweaks extends Module {
this.chunks = {}; this.chunks = {};
this.chunks_loaded = false; this.chunks_loaded = false;
// Layout // Layout
this.settings.add('metadata.modview.hide-info', { this.settings.add('metadata.modview.hide-info', {
@ -333,6 +333,15 @@ export default class CSSTweaks extends Module {
changed: val => this.toggleHide('prime-offers', !val) changed: val => this.toggleHide('prime-offers', !val)
}); });
this.settings.add('layout.hide-discover-luna', {
default: false,
ui: {
path: 'Appearance > Layout >> Top Navigation',
title: 'Hide the "Discover Luna" link.',
component: 'setting-check-box'
},
changed: val => this.toggleHide('discover-luna', val)
});
// Chat // Chat
@ -446,6 +455,7 @@ export default class CSSTweaks extends Module {
this.toggle('hide-side-nav', !this.settings.get('layout.side-nav.show')); this.toggle('hide-side-nav', !this.settings.get('layout.side-nav.show'));
//this.toggleHide('side-rec-friends', !this.settings.get('layout.side-nav.show-rec-friends')); //this.toggleHide('side-rec-friends', !this.settings.get('layout.side-nav.show-rec-friends'));
this.toggleHide('side-offline-channels', this.settings.get('layout.side-nav.hide-offline')); this.toggleHide('side-offline-channels', this.settings.get('layout.side-nav.hide-offline'));
this.toggleHide('discover-luna', this.settings.get('layout.hide-discover-luna'));
this.toggleHide('prime-offers', !this.settings.get('layout.prime-offers')); this.toggleHide('prime-offers', !this.settings.get('layout.prime-offers'));
this.toggleHide('top-discover', !this.settings.get('layout.discover')); this.toggleHide('top-discover', !this.settings.get('layout.discover'));
this.toggle('hide-unfollow-button', this.settings.get('channel.hide-unfollow')); this.toggle('hide-unfollow-button', this.settings.get('channel.hide-unfollow'));

View file

@ -70,7 +70,7 @@
.right-column { .right-column {
display: unset !important; display: unset !important;
position: fixed !important; position: fixed !important;
z-index: 4000; z-index: 2000;
bottom: 0 !important; bottom: 0 !important;
left: 0 !important; left: 0 !important;
right: 0 !important; right: 0 !important;

View file

@ -51,7 +51,7 @@ export default class Game extends SiteModule {
}); });
this.settings.provider.on('changed', key => { this.settings.provider.on('changed', key => {
if ( key === 'directory.game.blocked-games' || key === 'directory.game.hidden-thumbnails' ) { if ( key === 'directory.game.blocked-games' || key === 'directory.game.hidden-thumbnails' || key === 'directory.game.blocked-tags' ) {
this.parent.updateCards(); this.parent.updateCards();
for(const inst of this.GameHeader.instances) for(const inst of this.GameHeader.instances)

View file

@ -47,6 +47,11 @@ export default class Directory extends SiteModule {
DIR_ROUTES, null, 0, 0 DIR_ROUTES, null, 0, 0
); );
this.DirectoryGameCard = this.elemental.define(
'directory-game-card', '.game-card[data-a-id]',
DIR_ROUTES, null, 0, 0
);
this.DirectoryShelf = this.fine.define( this.DirectoryShelf = this.fine.define(
'directory-shelf', 'directory-shelf',
n => n.shouldRenderNode && n.props && n.props.shelf, n => n.shouldRenderNode && n.props && n.props.shelf,
@ -213,9 +218,34 @@ export default class Directory extends SiteModule {
this.DirectoryCard.on('unmount', this.clearCard, this); this.DirectoryCard.on('unmount', this.clearCard, this);
this.DirectoryCard.each(el => this.updateCard(el)); this.DirectoryCard.each(el => this.updateCard(el));
this.DirectoryGameCard.on('mount', this.updateGameCard, this);
this.DirectoryGameCard.on('mutate', this.updateGameCard, this);
//this.DirectoryGameCard.on('unmount', this.clearGameCard, this);
this.DirectoryGameCard.each(el => this.updateGameCard(el));
const t = this; const t = this;
this.DirectoryShelf.ready(cls => { this.DirectoryShelf.ready(cls => {
const old_should_render = cls.prototype.shouldRenderNode;
cls.prototype.shouldRenderNode = function(node, ...args) {
try {
let game;
if ( node.__typename === 'Game' )
game = node.name;
else if ( node.game )
game = node.game.name;
if ( game && t.settings.provider.get('directory.game.blocked-games', []).includes(game) )
return false;
} catch(err) {
t.log.capture(err);
t.log.error(err);
}
return old_should_render.call(this, node, ...args);
}
const old_render = cls.prototype.render; const old_render = cls.prototype.render;
cls.prototype.render = function() { cls.prototype.render = function() {
try { try {
@ -234,87 +264,45 @@ export default class Directory extends SiteModule {
this.DirectoryShelf.forceUpdate(); this.DirectoryShelf.forceUpdate();
}); });
/*this.DirectoryCard.ready((cls, instances) => {
//const old_render = cls.prototype.render,
const old_render_iconic = cls.prototype.renderIconicImage,
old_render_titles = cls.prototype.renderTitles;
/*cls.prototype.render = function() {
if ( get('props.streamType', this) === 'rerun' && t.settings.get('directory.hide-vodcasts') )
return null;
return old_render.call(this);
}*
cls.prototype.renderIconicImage = function() {
if ( this.props.context !== CARD_CONTEXTS.SingleChannelList &&
! t.settings.get('directory.show-channel-avatars') )
return;
return old_render_iconic.call(this);
}
cls.prototype.renderTitles = function() {
const nodes = get(get('props.channelLogin', this), t.following.hosts);
if ( this.props.hostedByChannelLogin == null || ! nodes || ! nodes.length )
return old_render_titles.call(this);
const channel = nodes[0].hosting,
stream = channel.stream,
game = stream && stream.game,
channel_url = `/${channel.login}`,
game_url = game && `/directory/game/${stream.game.name}`,
user_link = <a href={channel_url} data-href={channel_url} title={channel.displayName} class="ffz-link ffz-link--inherit" onClick={t.routeClick}>{channel.displayName}</a>,
game_link = game && <a href={game_url} data-href={game_url} title={game.name} class="ffz-link ffz-link--inherit" onClick={t.routeClick}>{game.name}</a>;
return (<div>
<a href={channel_url} data-href={channel_url} class="ffz-link ffz-link--inherit" data-test-selector="preview-card-titles__primary-link" onClick={t.routeClick}>
<h3 class="tw-ellipsis tw-font-size-5 tw-strong" title={stream.title}>{stream.title}</h3>
</a>
<div class="preview-card-titles__subtitle-wrapper">
<div data-test-selector="preview-card-titles__subtitle">
<p class="tw-c-text-alt tw-ellipsis">{
game ?
game.id == CREATIVE_ID ?
t.i18n.tList('directory.user-creative', '{user} being {game}', {
user: user_link,
game: game_link
}) :
t.i18n.tList('directory.user-playing', '{user} playing {game}', {
user: user_link,
game: game_link
})
: user_link
}</p>
</div>
<div data-test-selector="preview-card-titles__subtitle">
<p class="tw-c-text-alt tw-ellipsis">{
nodes.length > 1 ?
t.i18n.t('directory.hosted.by-many', 'Hosted by {count,number} channel{count,en_plural}', nodes.length) :
t.i18n.tList('directory.hosted.by-one', 'Hosted by {user}', {
user: <a href={`/${nodes[0].login}`} data-href={`/${nodes[0].login}`} title={nodes[0].displayName} class="ffz-link ffz-link--inherit" onClick={t.routeClick}>{nodes[0].displayName}</a>
})
}</p>
</div>
</div>
</div>);
}
this.DirectoryCard.forceUpdate();
for(const inst of instances)
this.updateCard(inst);
});
this.DirectoryCard.on('update', this.updateCard, this);
this.DirectoryCard.on('mount', this.updateCard, this);
this.DirectoryCard.on('unmount', this.clearCard, this);*/
} }
updateGameCard(el) {
const react = this.fine.getReactInstance(el);
if ( ! react )
return;
const props = react.return?.memoizedProps;
if ( ! props?.trackingProps?.category )
return;
const game = props.trackingProps.category,
tags = props.tagListProps?.tags;
let bad_tag = false;
if ( Array.isArray(tags) ) {
const bad_tags = this.settings.provider.get('directory.game.blocked-tags', []);
if ( bad_tags.length ) {
for(const tag of tags) {
if ( tag?.id && bad_tags.includes(tag.id) ) {
bad_tag = true;
break;
}
}
}
}
const should_hide = bad_tag || this.settings.provider.get('directory.game.blocked-games', []).includes(game);
let hide_container = el.closest('.tw-tower > div');
if ( ! hide_container )
hide_container = el;
if ( hide_container.querySelectorAll('a[data-a-target="tw-box-art-card-link"]').length < 2 )
hide_container.classList.toggle('tw-hide', should_hide);
}
updateCard(el) { updateCard(el) {
const react = this.fine.getReactInstance(el); const react = this.fine.getReactInstance(el);
@ -340,7 +328,7 @@ export default class Directory extends SiteModule {
el.dataset.ffzType = props.streamType; el.dataset.ffzType = props.streamType;
if ( Array.isArray(tags) ) { if ( Array.isArray(tags) ) {
const bad_tags = this.settings.provider.get('directory.game.hidden-tags', []); const bad_tags = this.settings.provider.get('directory.game.blocked-tags', []);
if ( bad_tags.length ) { if ( bad_tags.length ) {
for(const tag of tags) { for(const tag of tags) {
if ( tag?.id && bad_tags.includes(tag.id) ) { if ( tag?.id && bad_tags.includes(tag.id) ) {
@ -368,6 +356,8 @@ export default class Directory extends SiteModule {
updateCards() { updateCards() {
this.DirectoryCard.each(el => this.updateCard(el)); this.DirectoryCard.each(el => this.updateCard(el));
this.DirectoryGameCard.each(el => this.updateGameCard(el));
this.DirectoryShelf.forceUpdate();
this.emit(':update-cards'); this.emit(':update-cards');
} }
@ -381,7 +371,7 @@ export default class Directory extends SiteModule {
if ( ! document.contains(el) ) if ( ! document.contains(el) )
return this.clearUptime(el); return this.clearUptime(el);
const container = el.querySelector('.tw-media-card-image__corners'), const container = el.querySelector('a[data-a-target="preview-card-image-link"] > div'),
setting = this.settings.get('directory.uptime'); setting = this.settings.get('directory.uptime');
if ( ! container || setting === 0 || props.viewCount || props.animatedImageProps ) if ( ! container || setting === 0 || props.viewCount || props.animatedImageProps )

View file

@ -99,7 +99,7 @@ export default class Subpump extends Module {
} }
} catch(err) { } catch(err) {
this.log.error('Error processing PubSub event.', err); t.log.error('Error processing PubSub event.', err);
} }
return orig_message.call(this, e); return orig_message.call(this, e);

View file

@ -474,6 +474,9 @@ export default class WebMunch extends Module {
this._required_ids.add(id); this._required_ids.add(id);
if ( ! require.m[id] )
this.log.warn('Tried requiring module that isn\'t loaded', id);
const mod = require(id); const mod = require(id);
if ( mod ) { if ( mod ) {
const ret = predicate(mod); const ret = predicate(mod);

View file

@ -24,6 +24,8 @@ export class Dialog extends EventEmitter {
this._maximized = options.maximized || false; this._maximized = options.maximized || false;
this._exclusive = options.exclusive || false; this._exclusive = options.exclusive || false;
this.prepend = options.prepend || false;
this._element = null; this._element = null;
this._visible = false; this._visible = false;
@ -149,7 +151,10 @@ export class Dialog extends EventEmitter {
if ( el instanceof Promise ) { if ( el instanceof Promise ) {
el.then(e => { el.then(e => {
this._element = e; this._element = e;
container.appendChild(e); if ( this.prepend )
container.insertBefore(e, container.firstChild);
else
container.appendChild(e);
this.emit('show'); this.emit('show');
}).catch(err => { }).catch(err => {
this.emit('error', err); this.emit('error', err);
@ -161,7 +166,10 @@ export class Dialog extends EventEmitter {
this._element = el; this._element = el;
} }
container.appendChild(this._element); if ( this.prepend )
container.insertBefore(this._element, container.firstChild);
else
container.appendChild(this._element);
this.emit('show'); this.emit('show');
} }
@ -185,8 +193,12 @@ export class Dialog extends EventEmitter {
old_container.classList.remove('ffz-has-dialog'); old_container.classList.remove('ffz-has-dialog');
this._element.remove(); this._element.remove();
if ( container ) if ( container ) {
container.appendChild(this._element); if ( this.prepend )
container.insertBefore(this._element, container.firstChild);
else
container.appendChild(this._element);
}
this.emit('resize'); this.emit('resize');
} }

View file

@ -45,6 +45,19 @@ export class Logger {
this.children = {}; this.children = {};
} }
hi(core) {
const VER = core.constructor.version_info;
this.info(`FrankerFaceZ v${VER} (s:${core.host} f:${core.flavor} b:${VER.build} c:${VER.commit || 'null'})`);
try {
const loc = new URL(location);
loc.search = '';
this.info(`Initial URL: ${loc}`);
} catch(err) {
this.warn(`Unable to read location.`, err);
}
}
get(name, level) { get(name, level) {
if ( ! this.children[name] ) if ( ! this.children[name] )
this.children[name] = new Logger(this, (this.name ? `${this.name}.${name}` : name), level); this.children[name] = new Logger(this, (this.name ? `${this.name}.${name}` : name), level);

View file

@ -301,7 +301,8 @@ export class Tooltip {
inner.classList.add(`${opts.innerClass}--align-${tip.align}`); inner.classList.add(`${opts.innerClass}--align-${tip.align}`);
if ( tip.add_class ) { if ( tip.add_class ) {
inner.classList.add(tip.add_class); for(const cls of Array.isArray(tip.add_class) ? tip.add_class : [tip.add_class])
inner.classList.add(cls);
tip.add_class = undefined; tip.add_class = undefined;
} }

View file

@ -39,6 +39,11 @@
width: 1.6rem; width: 1.6rem;
} }
.ffz__tooltip & {
background: rgba(128,128,128,0.3);
color: var(--color-text-tooltip);
}
&--overlay { &--overlay {
background: rgba(0,0,0,0.3); background: rgba(0,0,0,0.3);
border: var(--border-width-tag) solid var(--color-border-input-overlay); border: var(--border-width-tag) solid var(--color-border-input-overlay);