mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-07-05 02:28:31 +00:00
4.0.0-rc10
* Added: Support for rendering metadata for the new Twitch layout. * Fixed: The option to disable Hosts not working with the new Twitch layout.
This commit is contained in:
parent
44dd04de20
commit
6654fda11d
7 changed files with 495 additions and 88 deletions
|
@ -100,7 +100,7 @@ class FrankerFaceZ extends Module {
|
|||
FrankerFaceZ.Logger = Logger;
|
||||
|
||||
const VER = FrankerFaceZ.version_info = {
|
||||
major: 4, minor: 0, revision: 0, extra: '-rc9.3',
|
||||
major: 4, minor: 0, revision: 0, extra: '-rc10',
|
||||
commit: __git_commit__,
|
||||
build: __webpack_hash__,
|
||||
toString: () =>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Channel Metadata
|
||||
// ============================================================================
|
||||
|
||||
import {createElement, ClickOutside} from 'utilities/dom';
|
||||
import {createElement, ClickOutside, setChildren} from 'utilities/dom';
|
||||
import {maybe_call} from 'utilities/object';
|
||||
|
||||
import {duration_to_string} from 'utilities/time';
|
||||
|
@ -58,10 +58,10 @@ export default class Metadata extends Module {
|
|||
this.definitions.uptime = {
|
||||
refresh() { return this.settings.get('metadata.uptime') > 0 },
|
||||
|
||||
setup() {
|
||||
setup(data) {
|
||||
const socket = this.resolve('socket'),
|
||||
apollo = this.resolve('site.apollo'),
|
||||
created_at = apollo.getFromQuery('ChannelPage_ChannelHeader', 'data.user.stream.createdAt');
|
||||
created_at = apollo.getFromQuery(data.legacy ? 'ChannelPage_ChannelHeader' : 'ChannelPage_User', 'data.user.stream.createdAt');
|
||||
|
||||
if ( ! created_at )
|
||||
return {};
|
||||
|
@ -86,6 +86,8 @@ export default class Metadata extends Module {
|
|||
return duration_to_string(data.uptime, false, false, false, setting !== 2);
|
||||
},
|
||||
|
||||
subtitle: () => this.i18n.t('metadata.uptime.subtitle', 'Uptime'),
|
||||
|
||||
tooltip(data) {
|
||||
if ( ! data.created )
|
||||
return null;
|
||||
|
@ -135,7 +137,7 @@ export default class Metadata extends Module {
|
|||
}
|
||||
}
|
||||
|
||||
if ( ! stats )
|
||||
if ( ! stats || stats.hlsLatencyBroadcaster < -100 )
|
||||
return {stats};
|
||||
|
||||
let drift = 0;
|
||||
|
@ -154,6 +156,8 @@ export default class Metadata extends Module {
|
|||
order: 3,
|
||||
icon: 'ffz-i-gauge',
|
||||
|
||||
subtitle: () => this.i18n.t('metadata.player-stats.subtitle', 'Latency'),
|
||||
|
||||
label(data) {
|
||||
if ( ! this.settings.get('metadata.player-stats') || ! data.delay )
|
||||
return null;
|
||||
|
@ -226,9 +230,6 @@ export default class Metadata extends Module {
|
|||
if ( bar ) {
|
||||
for(const inst of bar.ChannelBar.instances)
|
||||
bar.updateMetadata(inst, keys);
|
||||
|
||||
for(const inst of bar.HostBar.instances)
|
||||
bar.updateMetadata(inst, keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,6 +240,264 @@ export default class Metadata extends Module {
|
|||
|
||||
let el = container.querySelector(`.ffz-stat[data-key="${key}"]`);
|
||||
|
||||
const def = this.definitions[key],
|
||||
destroy = () => {
|
||||
if ( el ) {
|
||||
if ( el.tooltip )
|
||||
el.tooltip.destroy();
|
||||
|
||||
if ( el.popper )
|
||||
el.popper.destroy();
|
||||
|
||||
if ( el._ffz_destroy )
|
||||
el._ffz_destroy();
|
||||
|
||||
el._ffz_destroy = el.tooltip = el.popper = null;
|
||||
el.remove();
|
||||
}
|
||||
};
|
||||
|
||||
if ( ! def )
|
||||
return destroy();
|
||||
|
||||
try {
|
||||
// Process the data if a setup method is defined.
|
||||
if ( def.setup )
|
||||
data = await def.setup.call(this, data);
|
||||
|
||||
// Let's get refresh logic out of the way now.
|
||||
const refresh = maybe_call(def.refresh, this, data);
|
||||
if ( refresh )
|
||||
timers[key] = setTimeout(
|
||||
() => refresh_fn(key),
|
||||
typeof refresh === 'number' ? refresh : 1000
|
||||
);
|
||||
|
||||
|
||||
// Grab the element again in case it changed, somehow.
|
||||
el = container.querySelector(`.ffz-sidebar-stat[data-key="${key}"]`);
|
||||
|
||||
let stat, old_color, sub_el;
|
||||
|
||||
const label = maybe_call(def.label, this, data);
|
||||
|
||||
if ( ! label )
|
||||
return destroy();
|
||||
|
||||
const tooltip = maybe_call(def.tooltip, this, data),
|
||||
subtitle = maybe_call(def.subtitle, this, data),
|
||||
order = maybe_call(def.order, this, data),
|
||||
color = maybe_call(def.color, this, data) || '';
|
||||
|
||||
if ( ! el ) {
|
||||
let icon = maybe_call(def.icon, this, data);
|
||||
let button = false;
|
||||
|
||||
el = (<div
|
||||
class="ffz-sidebar-stat tw-flex tw-flex-grow-1 tw-flex-column tw-justify-content-center"
|
||||
data-key={key}
|
||||
tip_content={tooltip}
|
||||
/>);
|
||||
|
||||
if ( def.popup || def.click ) {
|
||||
button = true;
|
||||
|
||||
let btn, popup;
|
||||
let cls = maybe_call(def.button, this, data);
|
||||
if ( typeof cls !== 'string' )
|
||||
cls = `tw-button--${cls ? 'hollow' : 'text'}`;
|
||||
|
||||
if ( typeof icon === 'string' )
|
||||
icon = (<span class="tw-button__icon tw-button__icon--left"><figure class={icon} /></span>);
|
||||
|
||||
if ( def.popup && def.click ) {
|
||||
el.appendChild(<div class="tw-flex tw--full-width tw-flex-no-wrap">
|
||||
{btn = (<button class={`tw-interactive tw-button tw-button--full-width ${cls} ffz-has-stat-arrow`}>
|
||||
{icon}
|
||||
{stat = <div class="tw-button__text ffz-sidebar-stat--label" />}
|
||||
</button>)}
|
||||
{popup = (<button class={`tw-button ${cls} ffz-stat-arrow`}>
|
||||
<span class="tw-button__icon tw-pd-x-0">
|
||||
<figure class="ffz-i-down-dir" />
|
||||
</span>
|
||||
</button>)}
|
||||
</div>);
|
||||
|
||||
} else {
|
||||
el.appendChild(btn = popup = (<button class={`tw-interactive tw-button tw-button--full-width ${cls}`}>
|
||||
{icon}
|
||||
{stat = <div class="tw-button__text ffz-sidebar-stat--label" />}
|
||||
{def.popup && <span class="tw-button__icon tw-button__icon--right">
|
||||
<figure class="ffz-i-down-dir" />
|
||||
</span>}
|
||||
</button>));
|
||||
}
|
||||
|
||||
if ( def.click )
|
||||
btn.addEventListener('click', e => {
|
||||
if ( btn.disabled || btn.classList.contains('disabled') || el.disabled || el.classList.contains('disabled') )
|
||||
return false;
|
||||
|
||||
def.click.call(this, el._ffz_data, e, () => refresh_fn(key));
|
||||
});
|
||||
|
||||
if ( def.popup )
|
||||
popup.addEventListener('click', () => {
|
||||
if ( popup.disabled || popup.classList.contains('disabled') || el.disabled || el.classList.contains('disabled') )
|
||||
return false;
|
||||
|
||||
if ( el._ffz_popup )
|
||||
return el._ffz_destroy();
|
||||
|
||||
const destroy = el._ffz_destroy = () => {
|
||||
if ( el._ffz_outside )
|
||||
el._ffz_outside.destroy();
|
||||
|
||||
if ( el._ffz_popup ) {
|
||||
const fp = el._ffz_popup;
|
||||
el._ffz_popup = null;
|
||||
fp.destroy();
|
||||
}
|
||||
|
||||
el._ffz_destroy = el._ffz_outside = null;
|
||||
};
|
||||
|
||||
const parent = document.body.querySelector('body #root,body'),
|
||||
tt = el._ffz_popup = new Tooltip(parent, el, {
|
||||
logger: this.log,
|
||||
manual: true,
|
||||
html: true,
|
||||
|
||||
tooltipClass: 'ffz-metadata-balloon tw-balloon tw-block tw-border tw-elevation-1 tw-border-radius-small tw-c-background',
|
||||
// Hide the arrow for now, until we re-do our CSS to make it render correctly.
|
||||
arrowClass: 'tw-balloon__tail tw-overflow-hidden tw-absolute',
|
||||
arrowInner: 'tw-balloon__tail-symbol tw-border-t tw-border-r tw-border-b tw-border-l tw-border-radius-small tw-c-background tw-absolute',
|
||||
innerClass: 'tw-pd-1',
|
||||
|
||||
popper: {
|
||||
placement: 'right-start',
|
||||
modifiers: {
|
||||
preventOverflow: {
|
||||
boundariesElement: parent
|
||||
},
|
||||
flip: {
|
||||
behavior: ['top', 'bottom', 'left', 'right']
|
||||
}
|
||||
}
|
||||
},
|
||||
content: (t, tip) => def.popup.call(this, el._ffz_data, tip, () => refresh_fn(key)),
|
||||
onShow: (t, tip) =>
|
||||
setTimeout(() => {
|
||||
el._ffz_outside = new ClickOutside(tip.outer, destroy);
|
||||
}),
|
||||
onHide: destroy
|
||||
});
|
||||
|
||||
tt._enter(el);
|
||||
});
|
||||
|
||||
} else {
|
||||
el.appendChild(<div class="tw-align-items-center tw-flex tw-justify-content-center tw-font-size-4">
|
||||
{stat = <div class="tw-strong ffz-sidebar-stat--label" />}
|
||||
</div>);
|
||||
}
|
||||
|
||||
el.appendChild(sub_el = <div class="tw-flex tw-justify-content-center tw-c-text-alt-2 tw-font-size-6 ffz-sidebar-stat--subtitle" />);
|
||||
|
||||
let subcontainer;
|
||||
|
||||
if ( button ) {
|
||||
subcontainer = container.querySelector('.ffz-sidebar-stats--buttons');
|
||||
if ( ! subcontainer )
|
||||
container.appendChild(subcontainer = (<div class="tw-flex tw-flex-wrap tw-justify-content-between ffz-sidebar-stats ffz-sidebar-stats--buttons" />));
|
||||
|
||||
} else {
|
||||
subcontainer = container.querySelector('.ffz-sidebar-stats--stats');
|
||||
if ( ! subcontainer ) {
|
||||
subcontainer = (<div class="tw-flex tw-flex-wrap tw-justify-content-between ffz-sidebar-stats ffz-sidebar-stats--stats" />);
|
||||
const btns = container.querySelector('.ffz-sidebar-stats--buttons');
|
||||
if ( btns )
|
||||
container.insertBefore(subcontainer, btns);
|
||||
else
|
||||
container.appendChild(subcontainer);
|
||||
}
|
||||
}
|
||||
|
||||
el._ffz_order = order;
|
||||
|
||||
if ( order != null )
|
||||
el.style.order = order;
|
||||
|
||||
subcontainer.appendChild(el);
|
||||
|
||||
if ( def.tooltip ) {
|
||||
const parent = document.body.querySelector('body #root,body');
|
||||
el.tooltip = new Tooltip(parent, el, {
|
||||
logger: this.log,
|
||||
live: false,
|
||||
html: true,
|
||||
content: () => el.tip_content,
|
||||
onShow: (t, tip) => el.tip = tip,
|
||||
onHide: () => el.tip = null,
|
||||
popper: {
|
||||
placement: 'top',
|
||||
modifiers: {
|
||||
flip: {
|
||||
behavior: ['bottom', 'top']
|
||||
},
|
||||
preventOverflow: {
|
||||
boundariesElement: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
stat = el.querySelector('.ffz-sidebar-stat--label');
|
||||
sub_el = el.querySelector('.ffz-sidebar-stat--subtitle')
|
||||
old_color = el.dataset.color || '';
|
||||
|
||||
if ( el._ffz_order !== order )
|
||||
el.style.order = el._ffz_order = order;
|
||||
|
||||
if ( el.tip_content !== tooltip ) {
|
||||
el.tip_content = tooltip;
|
||||
if ( el.tip )
|
||||
el.tip.element.innerHTML = tooltip;
|
||||
}
|
||||
}
|
||||
|
||||
if ( old_color !== color )
|
||||
el.dataset.color = el.style.color = color;
|
||||
|
||||
el._ffz_data = data;
|
||||
|
||||
setChildren(stat, label, true);
|
||||
setChildren(sub_el, subtitle, true);
|
||||
|
||||
if ( def.disabled !== undefined )
|
||||
el.disabled = maybe_call(def.disabled, this, data);
|
||||
|
||||
} catch(err) {
|
||||
this.log.capture(err, {
|
||||
tags: {
|
||||
metadata: key
|
||||
}
|
||||
});
|
||||
this.log.error(`Error rendering metadata for ${key}`, err);
|
||||
return destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async renderLegacy(key, data, container, timers, refresh_fn) {
|
||||
if ( timers[key] )
|
||||
clearTimeout(timers[key]);
|
||||
|
||||
let el = container.querySelector(`.ffz-stat[data-key="${key}"]`);
|
||||
|
||||
const def = this.definitions[key],
|
||||
destroy = () => {
|
||||
if ( el ) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
import { has } from 'utilities/object';
|
||||
import { get, has } from 'utilities/object';
|
||||
|
||||
import Twilight from 'site';
|
||||
|
||||
|
@ -44,9 +44,8 @@ export default class Channel extends Module {
|
|||
|
||||
this.ChannelPage = this.fine.define(
|
||||
'channel-page',
|
||||
n => n.getHostedChannelLogin && n.handleHostingChange,
|
||||
//n => n.hostModeFromGraphQL,
|
||||
['user']
|
||||
n => (n.getHostedChannelLogin && n.handleHostingChange) || n.hostModeFromGraphQL,
|
||||
['user', 'user-videos', 'user-clips', 'user-collections', 'user-events', 'user-followers', 'user-following']
|
||||
);
|
||||
|
||||
this.RaidController = this.fine.define(
|
||||
|
@ -68,17 +67,12 @@ export default class Channel extends Module {
|
|||
});
|
||||
|
||||
this.ChannelPage.on('update', inst => {
|
||||
if ( this.settings.get('channel.hosting.enable') )
|
||||
if ( this.settings.get('channel.hosting.enable') || has(inst.state, 'hostMode') )
|
||||
return;
|
||||
|
||||
// We can't do this immediately because the player state
|
||||
// occasionally screws up if we do.
|
||||
setTimeout(() => {
|
||||
/*if ( inst.state.hostMode ) {
|
||||
inst.ffzExpectedHost = inst.state.hostMode;
|
||||
inst.ffzOldSetState({hostMode: null});
|
||||
}*/
|
||||
|
||||
const current_channel = inst.props.data && inst.props.data.variables && inst.props.data.variables.currentChannelLogin;
|
||||
if ( current_channel && current_channel !== inst.state.videoPlayerSource ) {
|
||||
inst.ffzExpectedHost = inst.state.videoPlayerSource;
|
||||
|
@ -134,26 +128,40 @@ export default class Channel extends Module {
|
|||
if ( inst._ffz_hosting_wrapped )
|
||||
return;
|
||||
|
||||
const t = this;
|
||||
const t = this,
|
||||
new_style = has(inst.state, 'hostMode');
|
||||
|
||||
inst.ffzGetChannel = () => {
|
||||
const params = inst.props.match.params
|
||||
if ( ! params )
|
||||
return get('props.data.variables.currentChannelLogin', inst)
|
||||
|
||||
return params.channelName || params.channelLogin
|
||||
}
|
||||
|
||||
inst.ffzOldSetState = inst.setState;
|
||||
inst.setState = function(state, ...args) {
|
||||
try {
|
||||
if ( ! t.settings.get('channel.hosting.enable') ) {
|
||||
if ( has(state, 'isHosting') )
|
||||
state.isHosting = false;
|
||||
if ( new_style ) {
|
||||
if ( has(state, 'hostMode') ) {
|
||||
t.log.info('update-host', state.hostMode)
|
||||
|
||||
if ( has(state, 'videoPlayerSource') )
|
||||
state.videoPlayerSource = inst.props.match.params.channelName;
|
||||
}
|
||||
|
||||
/*if ( has(state, 'hostMode') ) {
|
||||
inst.ffzExpectedHost = state.hostMode;
|
||||
if ( state.hostMode && ! t.settings.get('channel.hosting.enable') ) {
|
||||
state.hostMode = null;
|
||||
state.videoPlayerSource = inst.props.match.params.channelName;
|
||||
inst.ffzExpectedHost = state.hostMode;
|
||||
if ( state.hostMode && ! t.settings.get('channel.hosting.enable') ) {
|
||||
state.hostMode = null;
|
||||
state.videoPlayerSource = inst.ffzGetChannel();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
} else {
|
||||
if ( ! t.settings.get('channel.hosting.enable') ) {
|
||||
if ( has(state, 'isHosting') )
|
||||
state.isHosting = false;
|
||||
|
||||
if ( has(state, 'videoPlayerSource') )
|
||||
state.videoPlayerSource = inst.ffzGetChannel();
|
||||
}
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
t.log.capture(err, {extra: {props: inst.props, state}});
|
||||
|
@ -164,34 +172,41 @@ export default class Channel extends Module {
|
|||
|
||||
inst._ffz_hosting_wrapped = true;
|
||||
|
||||
inst.ffzOldGetHostedLogin = inst.getHostedChannelLogin;
|
||||
inst.getHostedChannelLogin = function() {
|
||||
return t.settings.get('channel.hosting.enable') ?
|
||||
inst.ffzOldGetHostedLogin() : null;
|
||||
}
|
||||
if ( new_style ) {
|
||||
const hosted = inst.ffzExpectedHost = inst.state.hostMode;
|
||||
t.log.info('Expected Host', hosted);
|
||||
|
||||
inst.ffzOldHostHandler = inst.handleHostingChange;
|
||||
inst.handleHostingChange = function(channel) {
|
||||
inst.ffzExpectedHost = channel;
|
||||
if ( t.settings.get('channel.hosting.enable') )
|
||||
return inst.ffzOldHostHandler(channel);
|
||||
}
|
||||
if ( hosted && ! this.settings.get('channel.hosting.enable') )
|
||||
inst.ffzOldSetState({
|
||||
hostMode: null,
|
||||
videoPlayerSource: inst.props.match.params.channelName
|
||||
});
|
||||
|
||||
// Store the current state and disable the current host if needed.
|
||||
inst.ffzExpectedHost = inst.state.isHosting ? inst.state.videoPlayerSource : null;
|
||||
if ( ! this.settings.get('channel.hosting.enable') )
|
||||
inst.ffzOldHostHandler(null);
|
||||
} else {
|
||||
inst.ffzOldGetHostedLogin = inst.getHostedChannelLogin;
|
||||
inst.getHostedChannelLogin = function() {
|
||||
return t.settings.get('channel.hosting.enable') ?
|
||||
inst.ffzOldGetHostedLogin() : null;
|
||||
}
|
||||
|
||||
inst.ffzOldHostHandler = inst.handleHostingChange;
|
||||
inst.handleHostingChange = function(channel) {
|
||||
inst.ffzExpectedHost = channel;
|
||||
if ( t.settings.get('channel.hosting.enable') )
|
||||
return inst.ffzOldHostHandler(channel);
|
||||
}
|
||||
|
||||
// Store the current state and disable the current host if needed.
|
||||
inst.ffzExpectedHost = inst.state.isHosting ? inst.state.videoPlayerSource : null;
|
||||
if ( ! this.settings.get('channel.hosting.enable') )
|
||||
inst.ffzOldHostHandler(null);
|
||||
}
|
||||
|
||||
// Finally, we force an update so that any child components
|
||||
// receive our updated handler.
|
||||
inst.forceUpdate();
|
||||
|
||||
/*const hosted = inst.ffzExpectedHost = inst.state.hostMode;
|
||||
if ( hosted && ! this.settings.get('channel.hosting.enable') )
|
||||
inst.ffzOldSetState({
|
||||
hostMode: null,
|
||||
videoPlayerSource: inst.props.match.params.channelName
|
||||
});*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -200,15 +215,17 @@ export default class Channel extends Module {
|
|||
val = this.settings.get('channel.hosting.enable');
|
||||
|
||||
for(const inst of this.ChannelPage.instances) {
|
||||
inst.ffzOldHostHandler(val ? inst.ffzExpectedHost : null);
|
||||
if ( has(inst.state, 'hostMode') ) {
|
||||
const host = val ? inst.ffzExpectedHost : null,
|
||||
target = host && host.hostedChannel && host.hostedChannel.login || inst.ffzGetChannel();
|
||||
|
||||
/*const host = val ? inst.ffzExpectedHost : null,
|
||||
target = host && host.hostedChannel && host.hostedChannel.login || inst.props.match.params.channelName;
|
||||
inst.ffzOldSetState({
|
||||
hostMode: host,
|
||||
videoPlayerSource: target
|
||||
});
|
||||
|
||||
inst.ffzOldSetState({
|
||||
hostMode: host,
|
||||
videoPlayerSource: target
|
||||
});*/
|
||||
} else
|
||||
inst.ffzOldHostHandler(val ? inst.ffzExpectedHost : null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ import {deep_copy} from 'utilities/object';
|
|||
|
||||
import CHANNEL_QUERY from './channel_bar_query.gql';
|
||||
|
||||
|
||||
export default class ChannelBar extends Module {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
@ -21,27 +20,19 @@ export default class ChannelBar extends Module {
|
|||
this.inject('metadata');
|
||||
this.inject('socket');
|
||||
|
||||
this.apollo.registerModifier('ChannelPage_ChannelHeader', CHANNEL_QUERY);
|
||||
this.apollo.registerModifier('ChannelPage_ChannelHeader', data => {
|
||||
this.apollo.registerModifier('ChannelPage_User', CHANNEL_QUERY);
|
||||
/*this.apollo.registerModifier('ChannelPage_User', data => {
|
||||
const u = data && data.data && data.data.user;
|
||||
if ( u ) {
|
||||
const o = u.profileViewCount = new Number(u.profileViewCount || 0);
|
||||
o.data = deep_copy(u);
|
||||
}
|
||||
}, false);
|
||||
|
||||
}, false);*/
|
||||
|
||||
this.ChannelBar = this.fine.define(
|
||||
'channel-bar',
|
||||
n => n.getTitle && n.getGame && n.renderGame,
|
||||
['user']
|
||||
);
|
||||
|
||||
|
||||
this.HostBar = this.fine.define(
|
||||
'host-container',
|
||||
n => n.handleReportHosterClick,
|
||||
['user']
|
||||
n => n.renderChannelMetadata && n.renderTitleInfo,
|
||||
['user', 'video', 'user-videos', 'user-clips', 'user-collections', 'user-events', 'user-followers', 'user-following']
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -54,16 +45,6 @@ export default class ChannelBar extends Module {
|
|||
for(const inst of instances)
|
||||
this.updateChannelBar(inst);
|
||||
});
|
||||
|
||||
|
||||
/*this.HostBar.on('unmount', this.unmountHostBar, this);
|
||||
this.HostBar.on('mount', this.updateHostBar, this);
|
||||
this.HostBar.on('update', this.updateHostBar, this);
|
||||
|
||||
this.HostBar.ready((cls, instances) => {
|
||||
for(const inst of instances)
|
||||
this.updateHostBar(inst);
|
||||
});*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,11 +80,13 @@ export default class ChannelBar extends Module {
|
|||
|
||||
updateMetadata(inst, keys) {
|
||||
const container = this.fine.getChildNode(inst),
|
||||
metabar = container && container.querySelector && container.querySelector('.channel-info-bar__action-container > .tw-flex');
|
||||
wrapper = container && container.querySelector && container.querySelector('.side-nav-channel-info__info-wrapper > .tw-pd-t-05');
|
||||
|
||||
if ( ! inst._ffz_mounted || ! metabar )
|
||||
if ( ! inst._ffz_mounted || ! wrapper )
|
||||
return;
|
||||
|
||||
const metabar = wrapper;
|
||||
|
||||
if ( ! keys )
|
||||
keys = this.metadata.keys;
|
||||
else if ( ! Array.isArray(keys) )
|
||||
|
@ -112,7 +95,7 @@ export default class ChannelBar extends Module {
|
|||
const timers = inst._ffz_meta_timers = inst._ffz_meta_timers || {},
|
||||
refresh_func = key => this.updateMetadata(inst, key),
|
||||
data = {
|
||||
channel: inst.props.userData && inst.props.userData.user,
|
||||
channel: inst.props.data && inst.props.data.user,
|
||||
hosting: false,
|
||||
_inst: inst
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ body .channel-page__video-player--theatre-mode {
|
|||
}
|
||||
|
||||
body .video-watch-page__right-column,
|
||||
body .channel-page__right-column {
|
||||
body .channel-page__right-column,
|
||||
body .right-column,
|
||||
body .channel-root__right-column {
|
||||
width: var(--ffz-chat-width);
|
||||
}
|
||||
|
||||
|
|
124
src/sites/twitch-twilight/modules/legacy_channel_bar.js
Normal file
124
src/sites/twitch-twilight/modules/legacy_channel_bar.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
'use strict';
|
||||
|
||||
// ============================================================================
|
||||
// Channel Bar
|
||||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
import {deep_copy} from 'utilities/object';
|
||||
|
||||
import CHANNEL_QUERY from './channel_bar_query.gql';
|
||||
|
||||
|
||||
export default class LegacyChannelBar extends Module {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
this.should_enable = true;
|
||||
|
||||
this.inject('site.fine');
|
||||
this.inject('site.apollo');
|
||||
this.inject('metadata');
|
||||
this.inject('socket');
|
||||
|
||||
this.apollo.registerModifier('ChannelPage_ChannelHeader', CHANNEL_QUERY);
|
||||
this.apollo.registerModifier('ChannelPage_ChannelHeader', data => {
|
||||
const u = data && data.data && data.data.user;
|
||||
if ( u ) {
|
||||
const o = u.profileViewCount = new Number(u.profileViewCount || 0);
|
||||
o.data = deep_copy(u);
|
||||
}
|
||||
}, false);
|
||||
|
||||
|
||||
this.ChannelBar = this.fine.define(
|
||||
'legacy-channel-bar',
|
||||
n => n.getTitle && n.getGame && n.renderGame,
|
||||
['user']
|
||||
);
|
||||
|
||||
|
||||
this.HostBar = this.fine.define(
|
||||
'legacy-host-container',
|
||||
n => n.handleReportHosterClick,
|
||||
['user']
|
||||
)
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.ChannelBar.on('unmount', this.unmountChannelBar, this);
|
||||
this.ChannelBar.on('mount', this.updateChannelBar, this);
|
||||
this.ChannelBar.on('update', this.updateChannelBar, this);
|
||||
|
||||
this.ChannelBar.ready((cls, instances) => {
|
||||
for(const inst of instances)
|
||||
this.updateChannelBar(inst);
|
||||
});
|
||||
|
||||
|
||||
/*this.HostBar.on('unmount', this.unmountHostBar, this);
|
||||
this.HostBar.on('mount', this.updateHostBar, this);
|
||||
this.HostBar.on('update', this.updateHostBar, this);
|
||||
|
||||
this.HostBar.ready((cls, instances) => {
|
||||
for(const inst of instances)
|
||||
this.updateHostBar(inst);
|
||||
});*/
|
||||
}
|
||||
|
||||
|
||||
updateChannelBar(inst) {
|
||||
const login = inst.props.channelLogin;
|
||||
if ( login !== inst._ffz_old_login ) {
|
||||
if ( inst._ffz_old_login )
|
||||
this.socket.unsubscribe(inst, `channel.${inst._ffz_old_login}`);
|
||||
|
||||
if ( login )
|
||||
this.socket.subscribe(inst, `channel.${login}`);
|
||||
inst._ffz_old_login = login;
|
||||
}
|
||||
|
||||
this.updateMetadata(inst);
|
||||
}
|
||||
|
||||
unmountChannelBar(inst) {
|
||||
if ( inst._ffz_old_login ) {
|
||||
this.socket.unsubscribe(inst, `channel.${inst._ffz_old_login}`);
|
||||
inst._ffz_old_login = null;
|
||||
}
|
||||
|
||||
const timers = inst._ffz_meta_timers;
|
||||
if ( timers )
|
||||
for(const key in timers)
|
||||
if ( timers[key] )
|
||||
clearTimeout(timers[key]);
|
||||
|
||||
inst._ffz_meta_timers = null;
|
||||
}
|
||||
|
||||
|
||||
updateMetadata(inst, keys) {
|
||||
const container = this.fine.getChildNode(inst),
|
||||
metabar = container && container.querySelector && container.querySelector('.channel-info-bar__action-container > .tw-flex');
|
||||
|
||||
if ( ! inst._ffz_mounted || ! metabar )
|
||||
return;
|
||||
|
||||
if ( ! keys )
|
||||
keys = this.metadata.keys;
|
||||
else if ( ! Array.isArray(keys) )
|
||||
keys = [keys];
|
||||
|
||||
const timers = inst._ffz_meta_timers = inst._ffz_meta_timers || {},
|
||||
refresh_func = key => this.updateMetadata(inst, key),
|
||||
data = {
|
||||
channel: inst.props.userData && inst.props.userData.user,
|
||||
hosting: false,
|
||||
legacy: true,
|
||||
_inst: inst
|
||||
}
|
||||
|
||||
for(const key of keys)
|
||||
this.metadata.renderLegacy(key, data, metabar, timers, refresh_func);
|
||||
}
|
||||
}
|
|
@ -36,8 +36,30 @@
|
|||
}
|
||||
}
|
||||
|
||||
.ffz-sidebar-stats {
|
||||
margin-top: .5rem;
|
||||
margin-right: -1rem;
|
||||
|
||||
& + .ffz-sidebar-stats {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.ffz-sidebar-stat {
|
||||
min-width: calc(50% - 1rem);
|
||||
margin: 0 1rem 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ffz-has-stat-arrow {
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
.ffz-stat-arrow {
|
||||
border-left: none !important;
|
||||
border-top-left-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue