mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-04 11:44:00 +00:00
Address issues with Directory support (#342)
* Address issues with Directory support De-duplicate `modifyStreams` for Game and Community * More de-duplication! PogChamp * Early return for following.js * Rely on `props.directoryType` instead of the router * Move a method around to properly group them * Fix for game buttons not properly showing when switching tabs * More fixes!
This commit is contained in:
parent
fcc3cab35f
commit
60f86033e8
5 changed files with 263 additions and 597 deletions
|
@ -5,24 +5,12 @@
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
import {SiteModule} from 'utilities/module';
|
import {SiteModule} from 'utilities/module';
|
||||||
import {createElement as e} from 'utilities/dom';
|
|
||||||
import {duration_to_string} from 'utilities/time';
|
|
||||||
|
|
||||||
export default class Community extends SiteModule {
|
export default class Community extends SiteModule {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
this.inject('site.fine');
|
|
||||||
this.inject('site.router');
|
|
||||||
this.inject('site.apollo');
|
this.inject('site.apollo');
|
||||||
this.inject('site.css_tweaks');
|
|
||||||
|
|
||||||
this.inject('settings');
|
|
||||||
|
|
||||||
this.GameHeader = this.fine.define(
|
|
||||||
'game-header',
|
|
||||||
n => n.renderFollowButton && n.renderGameDetailsTab
|
|
||||||
);
|
|
||||||
|
|
||||||
this.apollo.registerModifier('GamePage_Game', `query {
|
this.apollo.registerModifier('GamePage_Game', `query {
|
||||||
directory {
|
directory {
|
||||||
|
@ -41,265 +29,5 @@ export default class Community extends SiteModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`);
|
}`);
|
||||||
|
|
||||||
this.ChannelCard = this.fine.define(
|
|
||||||
'community-channel-card',
|
|
||||||
n => n.props && n.props.streamNode
|
|
||||||
);
|
|
||||||
|
|
||||||
this.apollo.registerModifier('GamePage_Game', res => this.router.current.name === 'dir-community' && this.modifyStreams(res), false);
|
|
||||||
|
|
||||||
this.on('settings:changed:show-channel-avatar', value => {
|
|
||||||
this.css_tweaks.toggleHide('profile-hover-game', value === 2);
|
|
||||||
this.router.current.name === 'dir-community' && this.ChannelCard.forceUpdate();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('settings:changed:directory.following.uptime', () => this.router.current.name === 'dir-community' && this.ChannelCard.forceUpdate());
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyStreams(res) { // eslint-disable-line class-methods-use-this
|
|
||||||
const newStreams = [];
|
|
||||||
|
|
||||||
const edges = res.data.directory.streams.edges;
|
|
||||||
for (let i = 0; i < edges.length; i++) {
|
|
||||||
const edge = edges[i];
|
|
||||||
const node = edge.node;
|
|
||||||
|
|
||||||
const s = node.viewersCount = new Number(node.viewersCount || 0);
|
|
||||||
s.profileImageURL = node.broadcaster.profileImageURL;
|
|
||||||
s.createdAt = node.createdAt;
|
|
||||||
|
|
||||||
newStreams.push(edge);
|
|
||||||
}
|
|
||||||
res.data.directory.streams.edges = newStreams;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
onEnable() {
|
|
||||||
this.GameHeader.ready((cls, instances) => {
|
|
||||||
if (this.router.current.name === 'dir-community') {
|
|
||||||
for(const inst of instances) this.updateButtons(inst);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ChannelCard.ready((cls, instances) => {
|
|
||||||
if (this.router.current.name === 'dir-community') {
|
|
||||||
this.apollo.ensureQuery(
|
|
||||||
'GamePage_Game',
|
|
||||||
'data.directory.streams.edges.0.node.createdAt'
|
|
||||||
);
|
|
||||||
|
|
||||||
for(const inst of instances) this.updateChannelCard(inst);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ChannelCard.on('update', inst => this.router.current.name === 'dir-community' && this.updateChannelCard(inst), this);
|
|
||||||
|
|
||||||
this.ChannelCard.on('mount', inst => this.router.current.name === 'dir-community' && this.updateChannelCard(inst), this);
|
|
||||||
|
|
||||||
this.ChannelCard.on('unmount', inst => this.router.current.name === 'dir-community' && this.updateUptime(inst), this);
|
|
||||||
|
|
||||||
this.css_tweaks.toggleHide('profile-hover-game', this.settings.get('directory.following.show-channel-avatar') === 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateUptime(inst) {
|
|
||||||
const container = this.fine.getHostNode(inst);
|
|
||||||
const card = container && container.querySelector && container.querySelector('.tw-card');
|
|
||||||
|
|
||||||
if (container === null || card === null) {
|
|
||||||
if (inst.updateTimer !== undefined) {
|
|
||||||
clearInterval(inst.updateTimer);
|
|
||||||
inst.updateTimer = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.settings.get('directory.following.uptime') === 0) {
|
|
||||||
if (inst.updateTimer !== undefined) {
|
|
||||||
clearInterval(inst.updateTimer);
|
|
||||||
inst.updateTimer = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inst.uptimeElement !== undefined) {
|
|
||||||
inst.uptimeElement.remove();
|
|
||||||
inst.uptimeElementSpan = inst.uptimeElement = undefined;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (inst.updateTimer === undefined) {
|
|
||||||
inst.updateTimer = setInterval(
|
|
||||||
this.updateUptime.bind(this, inst),
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const up_since = new Date(inst.props.streamNode.viewersCount.createdAt);
|
|
||||||
const uptime = up_since && Math.floor((Date.now() - up_since) / 1000) || 0;
|
|
||||||
const uptimeText = duration_to_string(uptime, false, false, false, this.settings.get('directory.following.uptime') === 1);
|
|
||||||
|
|
||||||
if (uptime > 0) {
|
|
||||||
if (inst.uptimeElement === undefined) {
|
|
||||||
inst.uptimeElementSpan = e('span', 'tw-stat__value ffz-uptime', `${uptimeText}`);
|
|
||||||
inst.uptimeElement = e('div', {
|
|
||||||
className: 'c-background-overlay c-text-overlay font-size-6 top-0 right-0 z-default inline-flex absolute mg-05',
|
|
||||||
style: 'padding-left: 4px; padding-right: 4px;'
|
|
||||||
}, [
|
|
||||||
e('span', 'tw-stat__icon',
|
|
||||||
e('figure', 'ffz-i-clock')
|
|
||||||
),
|
|
||||||
inst.uptimeElementSpan
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (card.querySelector('.ffz-uptime') === null) card.appendChild(inst.uptimeElement);
|
|
||||||
} else {
|
|
||||||
inst.uptimeElementSpan.textContent = `${uptimeText}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateChannelCard(inst) {
|
|
||||||
this.updateUptime(inst);
|
|
||||||
|
|
||||||
const container = this.fine.getHostNode(inst);
|
|
||||||
const card = container && container.querySelector && container.querySelector('.tw-card');
|
|
||||||
|
|
||||||
if (container === null || card === null) return;
|
|
||||||
|
|
||||||
if (!inst.props.streamNode.viewersCount.createdAt) return;
|
|
||||||
|
|
||||||
// Remove old elements
|
|
||||||
const hiddenBodyCard = card.querySelector('.tw-card-body.hide');
|
|
||||||
if (hiddenBodyCard !== null) hiddenBodyCard.classList.remove('hide');
|
|
||||||
|
|
||||||
const ffzChannelData = card.querySelector('.ffz-channel-data');
|
|
||||||
if (ffzChannelData !== null) ffzChannelData.remove();
|
|
||||||
|
|
||||||
const channelAvatar = card.querySelector('.channel-avatar');
|
|
||||||
if (channelAvatar !== null) channelAvatar.remove();
|
|
||||||
|
|
||||||
if (inst.props.streamNode.viewersCount.profileImageURL) {
|
|
||||||
const avatarSetting = this.settings.get('directory.following.show-channel-avatar');
|
|
||||||
if (avatarSetting === 1) {
|
|
||||||
const cardDiv = card.querySelector('.tw-card-body');
|
|
||||||
const modifiedDiv = e('div', {
|
|
||||||
innerHTML: cardDiv.innerHTML
|
|
||||||
});
|
|
||||||
|
|
||||||
const avatarDiv = e('a', {
|
|
||||||
className: 'channel-avatar',
|
|
||||||
href: `/${inst.props.streamNode.broadcaster.login}`,
|
|
||||||
style: 'margin-right: 8px; min-width: 4rem; margin-top: 0.5rem;',
|
|
||||||
onclick: event => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
this.router.navigate('user', { userName: inst.props.streamNode.broadcaster.login});
|
|
||||||
}
|
|
||||||
}, e('img', {
|
|
||||||
title: inst.props.streamNode.broadcaster.displayName,
|
|
||||||
src: inst.props.streamNode.viewersCount.profileImageURL,
|
|
||||||
style: 'height: 4rem;'
|
|
||||||
}));
|
|
||||||
|
|
||||||
const cardDivParent = cardDiv.parentElement;
|
|
||||||
|
|
||||||
if (cardDivParent.querySelector('.ffz-channel-data') === null) {
|
|
||||||
cardDiv.classList.add('hide');
|
|
||||||
|
|
||||||
const newCardDiv = e('div', 'ffz-channel-data flex flex-nowrap', [
|
|
||||||
avatarDiv, modifiedDiv
|
|
||||||
]);
|
|
||||||
cardDivParent.appendChild(newCardDiv);
|
|
||||||
}
|
|
||||||
} else if (avatarSetting === 2 || avatarSetting === 3) {
|
|
||||||
const avatarElement = e('a', {
|
|
||||||
className: 'channel-avatar',
|
|
||||||
href: `/${inst.props.streamNode.broadcaster.login}`,
|
|
||||||
onclick: event => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
this.router.navigate('user', { userName: inst.props.streamNode.broadcaster.login});
|
|
||||||
}
|
|
||||||
}, e('div', 'live-channel-card__boxart bottom-0 absolute',
|
|
||||||
e('figure', 'tw-aspect tw-aspect--align-top',
|
|
||||||
e('img', {
|
|
||||||
title: inst.props.streamNode.broadcaster.displayName,
|
|
||||||
src: inst.props.streamNode.viewersCount.profileImageURL
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const divToAppend = card.querySelector('figure.tw-aspect');
|
|
||||||
if (divToAppend.querySelector('.channel-avatar') === null) divToAppend.appendChild(avatarElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateButtons(inst) {
|
|
||||||
const container = this.fine.getHostNode(inst);
|
|
||||||
// We can't get the buttons through querySelector('button ...') so this has to do for now...
|
|
||||||
const buttons = container && container.querySelector && container.querySelector('div > div.align-items-center');
|
|
||||||
|
|
||||||
const ffzButtons = buttons.querySelector('.ffz-buttons');
|
|
||||||
if (ffzButtons !== null) ffzButtons.remove();
|
|
||||||
|
|
||||||
if (buttons.querySelector('.ffz-buttons') === null) {
|
|
||||||
// Block / Unblock Games
|
|
||||||
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
|
||||||
const gameBlocked = blockedGames.includes(inst.props.directoryName);
|
|
||||||
|
|
||||||
const blockButton = e('button', {
|
|
||||||
className: 'mg-l-1 tw-button ffz-toggle-game-block',
|
|
||||||
style: `background-color: ${gameBlocked ? '#228B22' : '#B22222'};`
|
|
||||||
}, e('span', {
|
|
||||||
className: 'tw-button__text',
|
|
||||||
textContent: `${gameBlocked ? 'Unblock' : 'Block'}`
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
blockButton.addEventListener('click', () => {
|
|
||||||
const gameName = inst.props.directoryName;
|
|
||||||
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
|
||||||
if (blockedGames.includes(gameName)) blockedGames.splice(blockedGames.indexOf(gameName), 1);
|
|
||||||
else blockedGames.push(gameName);
|
|
||||||
|
|
||||||
this.settings.provider.set('directory.game.blocked-games', blockedGames);
|
|
||||||
|
|
||||||
this.updateButtons(inst);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Hide / Unhide Thumbnails
|
|
||||||
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
|
||||||
const thumbnailBlocked = hiddenThumbnails.includes(inst.props.directoryName);
|
|
||||||
|
|
||||||
const hideThumbnailButton = e('button', {
|
|
||||||
className: 'mg-l-1 tw-button ffz-toggle-thumbnail',
|
|
||||||
style: `background-color: ${thumbnailBlocked ? '#228B22' : '#B22222'};`
|
|
||||||
}, e('span', {
|
|
||||||
className: 'tw-button__text',
|
|
||||||
textContent: `${thumbnailBlocked ? 'Unhide Thumbnails' : 'Hide Thumbnails'}`
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
hideThumbnailButton.addEventListener('click', () => {
|
|
||||||
const gameName = inst.props.directoryName;
|
|
||||||
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
|
||||||
if (hiddenThumbnails.includes(gameName)) hiddenThumbnails.splice(hiddenThumbnails.indexOf(gameName), 1);
|
|
||||||
else hiddenThumbnails.push(gameName);
|
|
||||||
|
|
||||||
this.settings.provider.set('directory.game.hidden-thumbnails', hiddenThumbnails);
|
|
||||||
|
|
||||||
this.updateButtons(inst);
|
|
||||||
});
|
|
||||||
|
|
||||||
const ffzButtons = e('div', 'ffz-buttons', [
|
|
||||||
blockButton,
|
|
||||||
hideThumbnailButton
|
|
||||||
]);
|
|
||||||
|
|
||||||
buttons.appendChild(ffzButtons);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,7 +7,6 @@
|
||||||
import {SiteModule} from 'utilities/module';
|
import {SiteModule} from 'utilities/module';
|
||||||
import {createElement as e} from 'utilities/dom';
|
import {createElement as e} from 'utilities/dom';
|
||||||
import {get} from 'utilities/object';
|
import {get} from 'utilities/object';
|
||||||
import {duration_to_string} from 'utilities/time';
|
|
||||||
|
|
||||||
import Popper from 'popper.js';
|
import Popper from 'popper.js';
|
||||||
|
|
||||||
|
@ -178,29 +177,25 @@ export default class Following extends SiteModule {
|
||||||
}`);
|
}`);
|
||||||
|
|
||||||
this.ChannelCard = this.fine.define(
|
this.ChannelCard = this.fine.define(
|
||||||
'channel-card',
|
'following-channel-card',
|
||||||
n => n.renderGameBoxArt && n.renderContentType
|
n => n.renderGameBoxArt && n.renderContentType
|
||||||
);
|
);
|
||||||
|
|
||||||
this.apollo.registerModifier('FollowedIndex_CurrentUser', res => {
|
this.apollo.registerModifier('FollowedIndex_CurrentUser', res => {
|
||||||
res = this.modifyLiveUsers(res);
|
this.modifyLiveUsers(res);
|
||||||
res = this.modifyLiveHosts(res);
|
this.modifyLiveHosts(res);
|
||||||
return res;
|
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
this.apollo.registerModifier('FollowingLive_CurrentUser', res => this.modifyLiveUsers(res), false);
|
this.apollo.registerModifier('FollowingLive_CurrentUser', res => this.modifyLiveUsers(res), false);
|
||||||
|
|
||||||
this.apollo.registerModifier('FollowingHosts_CurrentUser', res => this.modifyLiveHosts(res), false);
|
this.apollo.registerModifier('FollowingHosts_CurrentUser', res => this.modifyLiveHosts(res), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
isRouteAcceptable() {
|
isRouteAcceptable() {
|
||||||
return this.router.current.name === 'dir-following-index'
|
return this.router.current.name === 'dir-following'
|
||||||
|| this.router.current.name === 'dir-category' && this.router.match[1] === 'following';
|
|| this.router.current.name === 'dir-category' && this.router.match[1] === 'following';
|
||||||
}
|
}
|
||||||
|
|
||||||
modifyLiveUsers(res) { // eslint-disable-line class-methods-use-this
|
modifyLiveUsers(res) {
|
||||||
if (!this.isRouteAcceptable()) return res;
|
|
||||||
|
|
||||||
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
||||||
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
||||||
|
|
||||||
|
@ -221,9 +216,7 @@ export default class Following extends SiteModule {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
modifyLiveHosts(res) { // eslint-disable-line class-methods-use-this
|
modifyLiveHosts(res) {
|
||||||
if (!this.isRouteAcceptable()) return res;
|
|
||||||
|
|
||||||
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
||||||
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
||||||
|
|
||||||
|
@ -266,8 +259,6 @@ export default class Following extends SiteModule {
|
||||||
this.css_tweaks.toggleHide('boxart-hide', this.settings.get('directory.following.hide-boxart') === 2);
|
this.css_tweaks.toggleHide('boxart-hide', this.settings.get('directory.following.hide-boxart') === 2);
|
||||||
this.css_tweaks.toggleHide('profile-hover-following', this.settings.get('directory.following.show-channel-avatar') === 2);
|
this.css_tweaks.toggleHide('profile-hover-following', this.settings.get('directory.following.show-channel-avatar') === 2);
|
||||||
|
|
||||||
this.ChannelCard.on('update', inst => this.updateChannelCard(inst), this);
|
|
||||||
|
|
||||||
this.ChannelCard.ready((cls, instances) => {
|
this.ChannelCard.ready((cls, instances) => {
|
||||||
if (this.router && this.router.match) {
|
if (this.router && this.router.match) {
|
||||||
if (this.router.match[1] === 'following') {
|
if (this.router.match[1] === 'following') {
|
||||||
|
@ -294,6 +285,7 @@ export default class Following extends SiteModule {
|
||||||
for(const inst of instances) this.updateChannelCard(inst);
|
for(const inst of instances) this.updateChannelCard(inst);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.ChannelCard.on('update', inst => this.updateChannelCard(inst), this);
|
||||||
this.ChannelCard.on('mount', inst => this.updateChannelCard(inst), this);
|
this.ChannelCard.on('mount', inst => this.updateChannelCard(inst), this);
|
||||||
this.ChannelCard.on('unmount', inst => this.parent.clearUptime(inst), this);
|
this.ChannelCard.on('unmount', inst => this.parent.clearUptime(inst), this);
|
||||||
|
|
||||||
|
@ -301,7 +293,7 @@ export default class Following extends SiteModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyHostMenu(event) {
|
destroyHostMenu(event) {
|
||||||
if (event.target.closest('.ffz-channel-selector-outer') === null && Date.now() > this.hostMenuBuffer) {
|
if (!event || event && event.target && event.target.closest('.ffz-channel-selector-outer') === null && Date.now() > this.hostMenuBuffer) {
|
||||||
this.hostMenuPopper && this.hostMenuPopper.destroy();
|
this.hostMenuPopper && this.hostMenuPopper.destroy();
|
||||||
this.hostMenu && this.hostMenu.remove();
|
this.hostMenu && this.hostMenu.remove();
|
||||||
this.hostMenuPopper = this.hostMenu = undefined;
|
this.hostMenuPopper = this.hostMenu = undefined;
|
||||||
|
@ -332,14 +324,9 @@ export default class Following extends SiteModule {
|
||||||
simplebarContentChildren.push(
|
simplebarContentChildren.push(
|
||||||
e('a', {
|
e('a', {
|
||||||
className: 'tw-interactable',
|
className: 'tw-interactable',
|
||||||
href: inst.props.linkTo.pathname,
|
href: `/${inst.props.viewerCount.hostData.channel}`,
|
||||||
style: 'padding-top: 0.1rem; padding-bottom: 0.1rem;',
|
style: 'padding-top: 0.1rem; padding-bottom: 0.1rem;',
|
||||||
onclick: event => {
|
onclick: event => this.parent.hijackUserClick(event, inst.props.viewerCount.hostData.channel, this.destroyHostMenu.bind(this))
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
this.router.navigate('user', { userName: inst.props.linkTo.pathname.substring(1)});
|
|
||||||
}
|
|
||||||
}, e('div', 'align-items-center flex flex-row flex-nowrap mg-x-1 mg-y-05',
|
}, e('div', 'align-items-center flex flex-row flex-nowrap mg-x-1 mg-y-05',
|
||||||
[
|
[
|
||||||
e('div', {
|
e('div', {
|
||||||
|
@ -374,6 +361,7 @@ export default class Following extends SiteModule {
|
||||||
className: 'tw-interactable',
|
className: 'tw-interactable',
|
||||||
href: `/${node.login}`,
|
href: `/${node.login}`,
|
||||||
style: 'padding-top: 0.1rem; padding-bottom: 0.1rem;',
|
style: 'padding-top: 0.1rem; padding-bottom: 0.1rem;',
|
||||||
|
onclick: event => this.parent.hijackUserClick(event, node.login, this.destroyHostMenu.bind(this))
|
||||||
}, e('div', 'align-items-center flex flex-row flex-nowrap mg-x-1 mg-y-05',
|
}, e('div', 'align-items-center flex flex-row flex-nowrap mg-x-1 mg-y-05',
|
||||||
[
|
[
|
||||||
e('div', {
|
e('div', {
|
||||||
|
@ -427,6 +415,8 @@ export default class Following extends SiteModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateChannelCard(inst) {
|
updateChannelCard(inst) {
|
||||||
|
if (!this.isRouteAcceptable()) return;
|
||||||
|
|
||||||
this.parent.updateUptime(inst, 'props.viewerCount.createdAt', '.tw-card .tw-aspect > div');
|
this.parent.updateUptime(inst, 'props.viewerCount.createdAt', '.tw-card .tw-aspect > div');
|
||||||
|
|
||||||
const container = this.fine.getHostNode(inst),
|
const container = this.fine.getHostNode(inst),
|
||||||
|
@ -435,11 +425,6 @@ export default class Following extends SiteModule {
|
||||||
if ( container === null || card === null )
|
if ( container === null || card === null )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const channelCardTitle = card.querySelector('.live-channel-card__title');
|
|
||||||
|
|
||||||
if ( channelCardTitle === null )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Remove old elements
|
// Remove old elements
|
||||||
const hiddenBodyCard = card.querySelector('.tw-card-body.hide');
|
const hiddenBodyCard = card.querySelector('.tw-card-body.hide');
|
||||||
if (hiddenBodyCard !== null) hiddenBodyCard.classList.remove('hide');
|
if (hiddenBodyCard !== null) hiddenBodyCard.classList.remove('hide');
|
||||||
|
@ -451,7 +436,7 @@ export default class Following extends SiteModule {
|
||||||
if (channelAvatar !== null) channelAvatar.remove();
|
if (channelAvatar !== null) channelAvatar.remove();
|
||||||
|
|
||||||
if (inst.props.viewerCount.profileImageURL) {
|
if (inst.props.viewerCount.profileImageURL) {
|
||||||
const hosting = inst.props.viewerCount.hostData;
|
const hosting = inst.props.channelNameLinkTo.state.content === 'live_host' && inst.props.viewerCount.hostData;
|
||||||
let channel, displayName;
|
let channel, displayName;
|
||||||
if (hosting) {
|
if (hosting) {
|
||||||
channel = inst.props.viewerCount.hostData.channel;
|
channel = inst.props.viewerCount.hostData.channel;
|
||||||
|
@ -479,12 +464,7 @@ export default class Following extends SiteModule {
|
||||||
const avatarElement = e('a', {
|
const avatarElement = e('a', {
|
||||||
className: 'channel-avatar',
|
className: 'channel-avatar',
|
||||||
href: hosting ? `/${channel}` : inst.props.linkTo.pathname,
|
href: hosting ? `/${channel}` : inst.props.linkTo.pathname,
|
||||||
onclick: event => {
|
onclick: event => this.parent.hijackUserClick(event, inst.props.streamNode.broadcaster.login)
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
this.router.navigate('user', { userName: inst.props.streamNode.broadcaster.login});
|
|
||||||
}
|
|
||||||
}, e('div', 'live-channel-card__boxart bottom-0 absolute',
|
}, e('div', 'live-channel-card__boxart bottom-0 absolute',
|
||||||
e('figure', 'tw-aspect tw-aspect--align-top',
|
e('figure', 'tw-aspect tw-aspect--align-top',
|
||||||
e('img', {
|
e('img', {
|
||||||
|
@ -515,16 +495,17 @@ export default class Following extends SiteModule {
|
||||||
if (this.settings.get('directory.following.group-hosts')) {
|
if (this.settings.get('directory.following.group-hosts')) {
|
||||||
const titleLink = card.querySelector('.ffz-channel-data a[data-a-target="live-channel-card-title-link"]');
|
const titleLink = card.querySelector('.ffz-channel-data a[data-a-target="live-channel-card-title-link"]');
|
||||||
const thumbnailLink = card.querySelector('a[data-a-target="live-channel-card-thumbnail-link"]');
|
const thumbnailLink = card.querySelector('a[data-a-target="live-channel-card-thumbnail-link"]');
|
||||||
|
const channelCardTitle = card.querySelector('.ffz-channel-data .live-channel-card__title');
|
||||||
|
|
||||||
if (hostObj.channels.length > 1) {
|
const textContent = hostObj.channels.length > 1 ? `${hostObj.channels.length} hosting ${displayName}` : inst.props.title;
|
||||||
const textContent = `${hostObj.channels.length} hosting ${displayName}`;
|
if (channelCardTitle !== null) {
|
||||||
channelCardTitle.textContent
|
channelCardTitle.textContent
|
||||||
= channelCardTitle.title
|
= channelCardTitle.title
|
||||||
= textContent;
|
= textContent;
|
||||||
|
|
||||||
if (thumbnailLink !== null) thumbnailLink.title = textContent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thumbnailLink !== null) thumbnailLink.title = textContent;
|
||||||
|
|
||||||
if (titleLink !== null) titleLink.onclick = this.showHostMenu.bind(this, inst, hostObj);
|
if (titleLink !== null) titleLink.onclick = this.showHostMenu.bind(this, inst, hostObj);
|
||||||
if (thumbnailLink !== null) thumbnailLink.onclick = this.showHostMenu.bind(this, inst, hostObj);
|
if (thumbnailLink !== null) thumbnailLink.onclick = this.showHostMenu.bind(this, inst, hostObj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,13 @@
|
||||||
|
|
||||||
import {SiteModule} from 'utilities/module';
|
import {SiteModule} from 'utilities/module';
|
||||||
import {createElement as e} from 'utilities/dom';
|
import {createElement as e} from 'utilities/dom';
|
||||||
import {duration_to_string} from 'utilities/time';
|
|
||||||
|
|
||||||
export default class Game extends SiteModule {
|
export default class Game extends SiteModule {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
this.inject('site.fine');
|
this.inject('site.fine');
|
||||||
this.inject('site.router');
|
|
||||||
this.inject('site.apollo');
|
this.inject('site.apollo');
|
||||||
this.inject('site.css_tweaks');
|
|
||||||
|
|
||||||
this.inject('settings');
|
this.inject('settings');
|
||||||
|
|
||||||
|
@ -41,223 +38,26 @@ export default class Game extends SiteModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`);
|
}`);
|
||||||
|
|
||||||
this.ChannelCard = this.fine.define(
|
|
||||||
'game-channel-card',
|
|
||||||
n => n.props && n.props.streamNode
|
|
||||||
);
|
|
||||||
|
|
||||||
this.apollo.registerModifier('GamePage_Game', res => this.router.current.name === 'dir-game-index' && this.modifyStreams(res), false);
|
|
||||||
|
|
||||||
this.on('site.directory.following:update-show-channel-avatar', value => {
|
|
||||||
this.css_tweaks.toggleHide('profile-hover-game', value === 2);
|
|
||||||
this.router.current.name === 'dir-game-index' && this.ChannelCard.forceUpdate();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('site.directory.following:update-uptime', () => this.router.current.name === 'dir-game-index' && this.ChannelCard.forceUpdate());
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyStreams(res) { // eslint-disable-line class-methods-use-this
|
|
||||||
const newStreams = [];
|
|
||||||
|
|
||||||
// const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
|
||||||
// const thumbnailBlocked = hiddenThumbnails.includes(res.data.directory.displayName);
|
|
||||||
|
|
||||||
const edges = res.data.directory.streams.edges;
|
|
||||||
for (let i = 0; i < edges.length; i++) {
|
|
||||||
const edge = edges[i];
|
|
||||||
const node = edge.node;
|
|
||||||
|
|
||||||
const s = node.viewersCount = new Number(node.viewersCount || 0);
|
|
||||||
s.profileImageURL = node.broadcaster.profileImageURL;
|
|
||||||
s.createdAt = node.createdAt;
|
|
||||||
|
|
||||||
// if (thumbnailBlocked) edge.node.previewImageURL = 'https://static-cdn.jtvnw.net/ttv-static/404_preview-320x180.jpg';
|
|
||||||
|
|
||||||
newStreams.push(edge);
|
|
||||||
}
|
|
||||||
res.data.directory.streams.edges = newStreams;
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
onEnable() {
|
||||||
this.GameHeader.ready((cls, instances) => {
|
this.GameHeader.ready((cls, instances) => {
|
||||||
if (this.router.current.name === 'dir-game-index') {
|
for(const inst of instances) this.updateButtons(inst);
|
||||||
for(const inst of instances) this.updateButtons(inst);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ChannelCard.ready((cls, instances) => {
|
this.GameHeader.on('update', inst => this.updateButtons(inst));
|
||||||
if (this.router.current.name === 'dir-game-index') {
|
|
||||||
this.apollo.ensureQuery(
|
|
||||||
'GamePage_Game',
|
|
||||||
'data.directory.streams.edges.0.node.createdAt'
|
|
||||||
);
|
|
||||||
|
|
||||||
for(const inst of instances) this.updateChannelCard(inst);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ChannelCard.on('update', inst => this.router.current.name === 'dir-game-index' && this.updateChannelCard(inst), this);
|
|
||||||
|
|
||||||
this.ChannelCard.on('mount', inst => this.router.current.name === 'dir-game-index' && this.updateChannelCard(inst), this);
|
|
||||||
|
|
||||||
this.ChannelCard.on('unmount', inst => this.router.current.name === 'dir-game-index' && this.updateUptime(inst), this);
|
|
||||||
|
|
||||||
this.css_tweaks.toggleHide('profile-hover-game', this.settings.get('directory.following.show-channel-avatar') === 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUptime(inst) {
|
updateButtons(inst, update = false) {
|
||||||
const container = this.fine.getHostNode(inst);
|
if (inst.props.directoryType !== 'GAMES') return;
|
||||||
const card = container && container.querySelector && container.querySelector('.tw-thumbnail-card');
|
|
||||||
|
|
||||||
if (container === null || card === null) {
|
|
||||||
if (inst.updateTimer !== undefined) {
|
|
||||||
clearInterval(inst.updateTimer);
|
|
||||||
inst.updateTimer = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.settings.get('directory.following.uptime') === 0) {
|
|
||||||
if (inst.updateTimer !== undefined) {
|
|
||||||
clearInterval(inst.updateTimer);
|
|
||||||
inst.updateTimer = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inst.uptimeElement !== undefined) {
|
|
||||||
inst.uptimeElement.remove();
|
|
||||||
inst.uptimeElementSpan = inst.uptimeElement = undefined;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (inst.updateTimer === undefined) {
|
|
||||||
inst.updateTimer = setInterval(
|
|
||||||
this.updateUptime.bind(this, inst),
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const up_since = new Date(inst.props.streamNode.viewersCount.createdAt);
|
|
||||||
const uptime = up_since && Math.floor((Date.now() - up_since) / 1000) || 0;
|
|
||||||
const uptimeText = duration_to_string(uptime, false, false, false, this.settings.get('directory.following.uptime') === 1);
|
|
||||||
|
|
||||||
if (uptime > 0) {
|
|
||||||
if (inst.uptimeElement === undefined) {
|
|
||||||
inst.uptimeElementSpan = e('span', 'tw-stat__value ffz-uptime', `${uptimeText}`);
|
|
||||||
inst.uptimeElement = e('div', {
|
|
||||||
className: 'c-background-overlay c-text-overlay font-size-6 top-0 right-0 z-default inline-flex absolute mg-05',
|
|
||||||
style: 'padding-left: 4px; padding-right: 4px;'
|
|
||||||
}, [
|
|
||||||
e('span', 'tw-stat__icon',
|
|
||||||
e('figure', 'ffz-i-clock')
|
|
||||||
),
|
|
||||||
inst.uptimeElementSpan
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (card.querySelector('.ffz-uptime') === null) card.appendChild(inst.uptimeElement);
|
|
||||||
} else {
|
|
||||||
inst.uptimeElementSpan.textContent = `${uptimeText}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateChannelCard(inst) {
|
|
||||||
this.updateUptime(inst);
|
|
||||||
|
|
||||||
const container = this.fine.getHostNode(inst);
|
|
||||||
const card = container && container.querySelector && container.querySelector('.tw-thumbnail-card');
|
|
||||||
|
|
||||||
if (container === null || card === null) return;
|
|
||||||
|
|
||||||
if (!inst.props.streamNode.viewersCount.createdAt || container === null || card === null) return;
|
|
||||||
|
|
||||||
// Remove old elements
|
|
||||||
const hiddenBodyCard = card.querySelector('.tw-card-body.hide');
|
|
||||||
if (hiddenBodyCard !== null) hiddenBodyCard.classList.remove('hide');
|
|
||||||
|
|
||||||
const ffzChannelData = card.querySelector('.ffz-channel-data');
|
|
||||||
if (ffzChannelData !== null) ffzChannelData.remove();
|
|
||||||
|
|
||||||
const channelAvatar = card.querySelector('.channel-avatar');
|
|
||||||
if (channelAvatar !== null) channelAvatar.remove();
|
|
||||||
|
|
||||||
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
|
||||||
const thumbnailBlocked = hiddenThumbnails.includes(inst.props.directoryName);
|
|
||||||
|
|
||||||
if (thumbnailBlocked) {
|
|
||||||
card.classList.add('ffz-thumbnail-hidden');
|
|
||||||
} else {
|
|
||||||
card.classList.remove('ffz-thumbnail-hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inst.props.streamNode.viewersCount.profileImageURL) {
|
|
||||||
const avatarSetting = this.settings.get('directory.following.show-channel-avatar');
|
|
||||||
if (avatarSetting === 1) {
|
|
||||||
const cardDiv = card.querySelector('.tw-card-body');
|
|
||||||
const modifiedDiv = e('div', {
|
|
||||||
innerHTML: cardDiv.innerHTML
|
|
||||||
});
|
|
||||||
|
|
||||||
const avatarDiv = e('a', {
|
|
||||||
className: 'channel-avatar',
|
|
||||||
href: `/${inst.props.streamNode.broadcaster.login}`,
|
|
||||||
style: 'margin-right: 8px; min-width: 4rem; margin-top: 0.5rem;',
|
|
||||||
onclick: event => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
this.router.navigate('user', { userName: inst.props.streamNode.broadcaster.login});
|
|
||||||
}
|
|
||||||
}, e('img', {
|
|
||||||
title: inst.props.streamNode.broadcaster.displayName,
|
|
||||||
src: inst.props.streamNode.viewersCount.profileImageURL,
|
|
||||||
style: 'height: 4rem;'
|
|
||||||
}));
|
|
||||||
|
|
||||||
const cardDivParent = cardDiv.parentElement;
|
|
||||||
|
|
||||||
if (cardDivParent.querySelector('.ffz-channel-data') === null) {
|
|
||||||
cardDiv.classList.add('hide');
|
|
||||||
|
|
||||||
const newCardDiv = e('div', 'ffz-channel-data flex flex-nowrap', [
|
|
||||||
avatarDiv, modifiedDiv
|
|
||||||
]);
|
|
||||||
cardDivParent.appendChild(newCardDiv);
|
|
||||||
}
|
|
||||||
} else if (avatarSetting === 2 || avatarSetting === 3) {
|
|
||||||
const avatarElement = e('a', {
|
|
||||||
className: 'channel-avatar',
|
|
||||||
href: `/${inst.props.streamNode.broadcaster.login}`,
|
|
||||||
onclick: event => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
this.router.navigate('user', { userName: inst.props.streamNode.broadcaster.login});
|
|
||||||
}
|
|
||||||
}, e('div', 'live-channel-card__boxart bottom-0 absolute',
|
|
||||||
e('figure', 'tw-aspect tw-aspect--align-top',
|
|
||||||
e('img', {
|
|
||||||
title: inst.props.streamNode.broadcaster.displayName,
|
|
||||||
src: inst.props.streamNode.viewersCount.profileImageURL
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const divToAppend = card.querySelector('figure.tw-aspect');
|
|
||||||
if (divToAppend.querySelector('.channel-avatar') === null) divToAppend.appendChild(avatarElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateButtons(inst) {
|
|
||||||
const container = this.fine.getHostNode(inst);
|
const container = this.fine.getHostNode(inst);
|
||||||
// We can't get the buttons through querySelector('button ...') so this has to do for now...
|
// We can't get the buttons through querySelector('button ...') so this has to do for now...
|
||||||
const buttons = container && container.querySelector && container.querySelector('div > div.align-items-center');
|
const buttons = container && container.querySelector && container.querySelector('div > div.align-items-center');
|
||||||
|
|
||||||
const ffzButtons = buttons.querySelector('.ffz-buttons');
|
const ffzButtons = buttons.querySelector('.ffz-buttons');
|
||||||
if (ffzButtons !== null) ffzButtons.remove();
|
if (ffzButtons !== null && !update) return;
|
||||||
|
else if (ffzButtons) ffzButtons.remove();
|
||||||
|
|
||||||
if (buttons.querySelector('.ffz-buttons') === null) {
|
if (buttons.querySelector('.ffz-buttons') === null) {
|
||||||
// Block / Unblock Games
|
// Block / Unblock Games
|
||||||
|
@ -281,7 +81,7 @@ export default class Game extends SiteModule {
|
||||||
|
|
||||||
this.settings.provider.set('directory.game.blocked-games', blockedGames);
|
this.settings.provider.set('directory.game.blocked-games', blockedGames);
|
||||||
|
|
||||||
this.updateButtons(inst);
|
this.updateButtons(inst, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hide / Unhide Thumbnails
|
// Hide / Unhide Thumbnails
|
||||||
|
@ -305,8 +105,8 @@ export default class Game extends SiteModule {
|
||||||
|
|
||||||
this.settings.provider.set('directory.game.hidden-thumbnails', hiddenThumbnails);
|
this.settings.provider.set('directory.game.hidden-thumbnails', hiddenThumbnails);
|
||||||
|
|
||||||
this.updateButtons(inst);
|
this.parent.ChannelCard.forceUpdate();
|
||||||
this.ChannelCard.forceUpdate();
|
this.updateButtons(inst, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
const ffzButtons = e('div', 'ffz-buttons', [
|
const ffzButtons = e('div', 'ffz-buttons', [
|
||||||
|
|
234
src/sites/twitch-twilight/modules/directory/index.js
Normal file
234
src/sites/twitch-twilight/modules/directory/index.js
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Directory
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
import {SiteModule} from 'utilities/module';
|
||||||
|
import {duration_to_string} from 'utilities/time';
|
||||||
|
import {createElement as e} from 'utilities/dom';
|
||||||
|
import {get} from 'utilities/object';
|
||||||
|
|
||||||
|
import Following from './following';
|
||||||
|
import Game from './game';
|
||||||
|
import Community from './community';
|
||||||
|
|
||||||
|
export default class Directory extends SiteModule {
|
||||||
|
constructor(...args) {
|
||||||
|
super(...args);
|
||||||
|
|
||||||
|
this.should_enable = true;
|
||||||
|
|
||||||
|
this.inject('site.fine');
|
||||||
|
this.inject('site.router');
|
||||||
|
this.inject('site.apollo');
|
||||||
|
this.inject('site.css_tweaks');
|
||||||
|
|
||||||
|
this.inject('settings');
|
||||||
|
|
||||||
|
this.inject(Following);
|
||||||
|
this.inject(Game);
|
||||||
|
this.inject(Community);
|
||||||
|
|
||||||
|
this.apollo.registerModifier('GamePage_Game', res => this.modifyStreams(res), false);
|
||||||
|
|
||||||
|
this.ChannelCard = this.fine.define(
|
||||||
|
'channel-card',
|
||||||
|
n => n.props && n.props.streamNode
|
||||||
|
);
|
||||||
|
|
||||||
|
this.on('settings:changed:directory.following.show-channel-avatar', value => {
|
||||||
|
this.css_tweaks.toggleHide('profile-hover-game', value === 2);
|
||||||
|
this.ChannelCard.forceUpdate();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('settings:changed:directory.following.uptime', () => this.ChannelCard.forceUpdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onEnable() {
|
||||||
|
this.css_tweaks.toggleHide('profile-hover-game', this.settings.get('directory.following.show-channel-avatar') === 2);
|
||||||
|
|
||||||
|
this.ChannelCard.ready((cls, instances) => {
|
||||||
|
this.apollo.ensureQuery(
|
||||||
|
'GamePage_Game',
|
||||||
|
'data.directory.streams.edges.0.node.createdAt'
|
||||||
|
);
|
||||||
|
|
||||||
|
for(const inst of instances) this.updateChannelCard(inst);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ChannelCard.on('update', inst => this.updateChannelCard(inst), this);
|
||||||
|
this.ChannelCard.on('mount', inst => this.updateChannelCard(inst), this);
|
||||||
|
this.ChannelCard.on('unmount', inst => this.clearUptime(inst), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateChannelCard(inst) {
|
||||||
|
const uptimeSel = inst.props.directoryType === 'GAMES' ? '.tw-thumbnail-card .tw-card-img' : '.tw-card .tw-aspect > div';
|
||||||
|
const avatarSel = inst.props.directoryType === 'GAMES' ? '.tw-thumbnail-card' : '.tw-card';
|
||||||
|
|
||||||
|
this.updateUptime(inst, 'props.streamNode.viewersCount.createdAt', uptimeSel);
|
||||||
|
this.addCardAvatar(inst, avatarSel);
|
||||||
|
|
||||||
|
const type = inst.props.directoryType;
|
||||||
|
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
||||||
|
const hiddenPreview = 'https://static-cdn.jtvnw.net/ttv-static/404_preview-320x180.jpg';
|
||||||
|
|
||||||
|
const container = this.fine.getHostNode(inst);
|
||||||
|
const img = container && container.querySelector && container.querySelector(`${uptimeSel} img`);
|
||||||
|
if (img === null) return;
|
||||||
|
|
||||||
|
if (type === 'GAMES' && hiddenThumbnails.includes(inst.props.directoryName) ||
|
||||||
|
type === 'COMMUNITIES' && hiddenThumbnails.includes(inst.props.streamNode.game.name)) {
|
||||||
|
img.src = hiddenPreview;
|
||||||
|
} else {
|
||||||
|
img.src = inst.props.streamNode.previewImageURL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
modifyStreams(res) { // eslint-disable-line class-methods-use-this
|
||||||
|
const newStreams = [];
|
||||||
|
|
||||||
|
const edges = res.data.directory.streams.edges;
|
||||||
|
for (let i = 0; i < edges.length; i++) {
|
||||||
|
const edge = edges[i];
|
||||||
|
const node = edge.node;
|
||||||
|
|
||||||
|
const s = node.viewersCount = new Number(node.viewersCount || 0);
|
||||||
|
s.profileImageURL = node.broadcaster.profileImageURL;
|
||||||
|
s.createdAt = node.createdAt;
|
||||||
|
|
||||||
|
newStreams.push(edge);
|
||||||
|
}
|
||||||
|
res.data.directory.streams.edges = newStreams;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
clearUptime(inst) { // eslint-disable-line class-methods-use-this
|
||||||
|
if ( inst.ffz_update_timer ) {
|
||||||
|
clearInterval(inst.ffz_update_timer);
|
||||||
|
inst.ffz_update_timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( inst.ffz_uptime_el ) {
|
||||||
|
inst.ffz_uptime_el.parentElement.removeChild(inst.ffz_uptime_el);
|
||||||
|
inst.ffz_uptime_el = null;
|
||||||
|
inst.ffz_uptime_span = null;
|
||||||
|
inst.ffz_uptime_tt = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateUptime(inst, created_path, selector) {
|
||||||
|
const container = this.fine.getHostNode(inst),
|
||||||
|
card = container && container.querySelector && container.querySelector(selector),
|
||||||
|
setting = this.settings.get('directory.following.uptime'),
|
||||||
|
created_at = get(created_path, inst),
|
||||||
|
up_since = created_at && new Date(created_at),
|
||||||
|
uptime = up_since && Math.floor((Date.now() - up_since) / 1000) || 0;
|
||||||
|
|
||||||
|
if ( ! card || setting === 0 || uptime < 1 )
|
||||||
|
return this.clearUptime(inst);
|
||||||
|
|
||||||
|
const up_text = duration_to_string(uptime, false, false, false, setting === 1);
|
||||||
|
|
||||||
|
if ( ! inst.ffz_uptime_el )
|
||||||
|
card.appendChild(inst.ffz_uptime_el = e('div',
|
||||||
|
'video-preview-card__preview-overlay-stat c-background-overlay c-text-overlay font-size-6 top-0 right-0 z-default inline-flex absolute mg-05',
|
||||||
|
e('div', 'tw-tooltip-wrapper inline-flex', [
|
||||||
|
e('div', 'tw-stat', [
|
||||||
|
e('span', 'c-text-live tw-stat__icon', e('figure', 'ffz-i-clock')),
|
||||||
|
inst.ffz_uptime_span = e('span', 'tw-stat__value')
|
||||||
|
]),
|
||||||
|
inst.ffz_uptime_tt = e('div', 'tw-tooltip tw-tooltip--down tw-tooltip--align-center')
|
||||||
|
])));
|
||||||
|
|
||||||
|
if ( ! inst.ffz_update_timer )
|
||||||
|
inst.ffz_update_timer = setInterval(this.updateUptime.bind(this, inst, created_path, selector), 1000);
|
||||||
|
|
||||||
|
inst.ffz_uptime_span.textContent = up_text;
|
||||||
|
inst.ffz_uptime_tt.textContent = up_since.toLocaleString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addCardAvatar(inst, selector) {
|
||||||
|
const container = this.fine.getHostNode(inst),
|
||||||
|
card = container && container.querySelector && container.querySelector(selector),
|
||||||
|
setting = this.settings.get('directory.following.show-channel-avatar');
|
||||||
|
|
||||||
|
// Remove old elements
|
||||||
|
const hiddenBodyCard = card.querySelector('.tw-card-body.hide');
|
||||||
|
if (hiddenBodyCard !== null) hiddenBodyCard.classList.remove('hide');
|
||||||
|
|
||||||
|
const ffzChannelData = card.querySelector('.ffz-channel-data');
|
||||||
|
if (ffzChannelData !== null) ffzChannelData.remove();
|
||||||
|
|
||||||
|
const channelAvatar = card.querySelector('.channel-avatar');
|
||||||
|
if (channelAvatar !== null) channelAvatar.remove();
|
||||||
|
|
||||||
|
if ( ! card || setting === 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (inst.props.streamNode.viewersCount.profileImageURL) {
|
||||||
|
if (setting === 1) {
|
||||||
|
const cardDiv = card.querySelector('.tw-card-body');
|
||||||
|
const modifiedDiv = e('div', {
|
||||||
|
innerHTML: cardDiv.innerHTML
|
||||||
|
});
|
||||||
|
|
||||||
|
const avatarDiv = e('a', {
|
||||||
|
className: 'channel-avatar',
|
||||||
|
href: `/${inst.props.streamNode.broadcaster.login}`,
|
||||||
|
style: 'margin-right: 8px; min-width: 4rem; margin-top: 0.5rem;',
|
||||||
|
onclick: event => this.hijackUserClick(event, inst.props.streamNode.broadcaster.login)
|
||||||
|
}, e('img', {
|
||||||
|
title: inst.props.streamNode.broadcaster.displayName,
|
||||||
|
src: inst.props.streamNode.viewersCount.profileImageURL,
|
||||||
|
style: 'height: 4rem;'
|
||||||
|
}));
|
||||||
|
|
||||||
|
const cardDivParent = cardDiv.parentElement;
|
||||||
|
|
||||||
|
if (cardDivParent.querySelector('.ffz-channel-data') === null) {
|
||||||
|
cardDiv.classList.add('hide');
|
||||||
|
|
||||||
|
const newCardDiv = e('div', 'ffz-channel-data flex flex-nowrap', [
|
||||||
|
avatarDiv, modifiedDiv
|
||||||
|
]);
|
||||||
|
cardDivParent.appendChild(newCardDiv);
|
||||||
|
}
|
||||||
|
} else if (setting === 2 || setting === 3) {
|
||||||
|
const avatarElement = e('a', {
|
||||||
|
className: 'channel-avatar',
|
||||||
|
href: `/${inst.props.streamNode.broadcaster.login}`,
|
||||||
|
onclick: event => this.hijackUserClick(event, inst.props.streamNode.broadcaster.login)
|
||||||
|
}, e('div', 'live-channel-card__boxart bottom-0 absolute',
|
||||||
|
e('figure', 'tw-aspect tw-aspect--align-top',
|
||||||
|
e('img', {
|
||||||
|
title: inst.props.streamNode.broadcaster.displayName,
|
||||||
|
src: inst.props.streamNode.viewersCount.profileImageURL
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const divToAppend = card.querySelector('figure.tw-aspect');
|
||||||
|
if (divToAppend.querySelector('.channel-avatar') === null) divToAppend.appendChild(avatarElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hijackUserClick(event, user, optionalFn = null) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if (optionalFn) optionalFn();
|
||||||
|
|
||||||
|
this.router.navigate('user', { userName: user });
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,77 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Directory
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
import {SiteModule} from 'utilities/module';
|
|
||||||
import {duration_to_string} from 'utilities/time';
|
|
||||||
import {createElement as e} from 'utilities/dom';
|
|
||||||
import {get} from 'utilities/object';
|
|
||||||
|
|
||||||
import Following from './following';
|
|
||||||
import Game from './game';
|
|
||||||
import Community from './community';
|
|
||||||
|
|
||||||
export default class Directory extends SiteModule {
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args);
|
|
||||||
|
|
||||||
this.should_enable = true;
|
|
||||||
|
|
||||||
this.inject('i18n');
|
|
||||||
this.inject('settings');
|
|
||||||
this.inject('site.fine');
|
|
||||||
|
|
||||||
this.inject(Following);
|
|
||||||
this.inject(Game);
|
|
||||||
this.inject(Community);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
clearUptime(inst) { // eslint-disable-line class-methods-use-this
|
|
||||||
if ( inst.ffz_update_timer ) {
|
|
||||||
clearInterval(inst.ffz_update_timer);
|
|
||||||
inst.ffz_update_timer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( inst.ffz_uptime_el ) {
|
|
||||||
inst.ffz_uptime_el.parentElement.removeChild(inst.ffz_uptime_el);
|
|
||||||
inst.ffz_uptime_el = null;
|
|
||||||
inst.ffz_uptime_span = null;
|
|
||||||
inst.ffz_uptime_tt = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
updateUptime(inst, created_path, selector) {
|
|
||||||
const container = this.fine.getHostNode(inst),
|
|
||||||
card = container && container.querySelector && container.querySelector(selector),
|
|
||||||
setting = this.settings.get('directory.following.uptime'),
|
|
||||||
created_at = get(created_path, inst),
|
|
||||||
up_since = created_at && new Date(created_at),
|
|
||||||
uptime = up_since && Math.floor((Date.now() - up_since) / 1000) || 0;
|
|
||||||
|
|
||||||
if ( ! card || setting === 0 || uptime < 1 )
|
|
||||||
return this.clearUptime(inst);
|
|
||||||
|
|
||||||
const up_text = duration_to_string(uptime, false, false, false, setting === 1);
|
|
||||||
|
|
||||||
if ( ! inst.ffz_uptime_el )
|
|
||||||
card.appendChild(inst.ffz_uptime_el = e('div',
|
|
||||||
'video-preview-card__preview-overlay-stat c-background-overlay c-text-overlay font-size-6 top-0 right-0 z-default inline-flex absolute mg-05',
|
|
||||||
e('div', 'tw-tooltip-wrapper inline-flex', [
|
|
||||||
e('div', 'tw-stat', [
|
|
||||||
e('span', 'c-text-live tw-stat__icon', e('figure', 'ffz-i-clock')),
|
|
||||||
inst.ffz_uptime_span = e('span', 'tw-stat__value')
|
|
||||||
]),
|
|
||||||
inst.ffz_uptime_tt = e('div', 'tw-tooltip tw-tooltip--down tw-tooltip--align-center')
|
|
||||||
])));
|
|
||||||
|
|
||||||
if ( ! inst.ffz_update_timer )
|
|
||||||
inst.ffz_update_timer = setInterval(this.updateUptime.bind(this, inst, created_path, selector), 1000);
|
|
||||||
|
|
||||||
inst.ffz_uptime_span.textContent = up_text;
|
|
||||||
inst.ffz_uptime_tt.textContent = up_since.toLocaleString();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue