mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-09-16 18:06:55 +00:00
Add Browse -> Popular support for avatar and uptime (#359)
* Add Browse -> Popular support for avatar and uptime * Fix potential null-erroring * Fix Twitch's mess once again... Also add actual decent support for the popular page and various other fixes, such as hiding blocked games and whatnot * Fix...
This commit is contained in:
parent
cc1705c0c8
commit
bbf158aee1
3 changed files with 181 additions and 45 deletions
104
src/sites/twitch-twilight/modules/directory/browse_popular.js
Normal file
104
src/sites/twitch-twilight/modules/directory/browse_popular.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
'use strict';
|
||||
|
||||
// ============================================================================
|
||||
// Directory (Following, for now)
|
||||
// ============================================================================
|
||||
|
||||
import {SiteModule} from 'utilities/module';
|
||||
import {get} from 'utilities/object';
|
||||
|
||||
export default class BrowsePopular extends SiteModule {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
this.inject('site.apollo');
|
||||
this.inject('site.fine');
|
||||
this.inject('settings');
|
||||
|
||||
this.apollo.registerModifier('BrowsePage_Popular', `query {
|
||||
streams {
|
||||
edges {
|
||||
node {
|
||||
createdAt
|
||||
broadcaster {
|
||||
profileImageURL(width: 70)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
this.ChannelCard = this.fine.define(
|
||||
'browse-all-channel-card',
|
||||
n => n.props && n.props.channelName && n.props.linkTo && n.props.linkTo.state && n.props.linkTo.state.medium === 'twitch_browse_directory'
|
||||
);
|
||||
|
||||
this.apollo.registerModifier('BrowsePage_Popular', res => this.modifyStreams(res), false);
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.ChannelCard.ready((cls, instances) => {
|
||||
// Popular Directory Channel Cards
|
||||
this.apollo.ensureQuery(
|
||||
'BrowsePage_Popular',
|
||||
'data.streams.edges.node.0.createdAt'
|
||||
);
|
||||
|
||||
for(const inst of instances) this.updateChannelCard(inst);
|
||||
});
|
||||
|
||||
this.ChannelCard.on('update', this.updateChannelCard, this);
|
||||
this.ChannelCard.on('mount', this.updateChannelCard, this);
|
||||
this.ChannelCard.on('unmount', this.parent.clearUptime, this);
|
||||
}
|
||||
|
||||
modifyStreams(res) { // eslint-disable-line class-methods-use-this
|
||||
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
||||
|
||||
const newStreams = [];
|
||||
|
||||
const edges = get('data.streams.edges', res);
|
||||
if (!edges) return res;
|
||||
|
||||
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;
|
||||
s.login = node.broadcaster.login;
|
||||
s.displayName = node.broadcaster.displayName;
|
||||
|
||||
if (!node.game || node.game && !blockedGames.includes(node.game.name)) newStreams.push(edge);
|
||||
}
|
||||
res.data.streams.edges = newStreams;
|
||||
return res;
|
||||
}
|
||||
|
||||
updateChannelCard(inst) {
|
||||
const container = this.fine.getHostNode(inst);
|
||||
if (!container) return;
|
||||
|
||||
if (container.classList.contains('ffz-modified-channel-card')) return;
|
||||
container.classList.add('ffz-modified-channel-card');
|
||||
|
||||
this.parent.updateUptime(inst, 'props.viewerCount.createdAt', '.tw-card-img');
|
||||
this.parent.addCardAvatar(inst, 'props.viewerCount', '.tw-card');
|
||||
|
||||
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
||||
const hiddenPreview = 'https://static-cdn.jtvnw.net/ttv-static/404_preview-320x180.jpg';
|
||||
|
||||
if (inst.props.type === 'watch_party')
|
||||
container.classList.toggle('tw-hide', this.settings.get('directory.hide-vodcasts'));
|
||||
|
||||
const img = container.querySelector && container.querySelector('.tw-card-img img');
|
||||
if (img == null) return;
|
||||
|
||||
if (hiddenThumbnails.includes(inst.props.gameTitle)) {
|
||||
img.src = hiddenPreview;
|
||||
} else {
|
||||
img.src = inst.props.imageSrc;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -86,7 +86,8 @@ export default class Following extends SiteModule {
|
|||
this.apollo.registerModifier('FollowingLive_CurrentUser', `query {
|
||||
currentUser {
|
||||
followedLiveUsers {
|
||||
nodes {
|
||||
edges {
|
||||
node {
|
||||
profileImageURL(width: 70)
|
||||
stream {
|
||||
createdAt
|
||||
|
@ -94,6 +95,7 @@ export default class Following extends SiteModule {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`);
|
||||
|
||||
this.apollo.registerModifier('FollowingHosts_CurrentUser', `query {
|
||||
|
@ -155,20 +157,28 @@ export default class Following extends SiteModule {
|
|||
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
||||
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
||||
|
||||
const newLiveNodes = [];
|
||||
const newStreams = [];
|
||||
|
||||
const nodes = res.data.currentUser.followedLiveUsers.nodes;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
const followedLiveUsers = get('data.currentUser.followedLiveUsers', res);
|
||||
if (!followedLiveUsers)
|
||||
return res;
|
||||
|
||||
const oldMode = !!followedLiveUsers.nodes;
|
||||
const edgesOrNodes = followedLiveUsers.nodes || followedLiveUsers.edges;
|
||||
|
||||
for (let i = 0; i < edgesOrNodes.length; i++) {
|
||||
const edge = edgesOrNodes[i];
|
||||
const node = edge.node || edge;
|
||||
|
||||
const s = node.stream.viewersCount = new Number(node.stream.viewersCount || 0);
|
||||
s.profileImageURL = node.profileImageURL;
|
||||
s.createdAt = node.stream.createdAt;
|
||||
|
||||
if (node.stream.game && hiddenThumbnails.includes(node.stream.game.name)) node.stream.previewImageURL = 'https://static-cdn.jtvnw.net/ttv-static/404_preview-320x180.jpg';
|
||||
if (!node.stream.game || node.stream.game && !blockedGames.includes(node.stream.game.name)) newLiveNodes.push(node);
|
||||
if (!node.stream.game || node.stream.game && !blockedGames.includes(node.stream.game.name)) newStreams.push(edge);
|
||||
}
|
||||
res.data.currentUser.followedLiveUsers.nodes = newLiveNodes;
|
||||
res.data.currentUser.followedLiveUsers[oldMode ? 'nodes' : 'edges'] = newStreams;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -176,12 +186,19 @@ export default class Following extends SiteModule {
|
|||
const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || [];
|
||||
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
||||
|
||||
const nodes = res.data.currentUser.followedHosts.nodes;
|
||||
const followedHosts = get('data.currentUser.followedHosts', res);
|
||||
if (!followedHosts)
|
||||
return res;
|
||||
|
||||
this.hosts = {};
|
||||
const newHostNodes = [];
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
const oldMode = !!followedHosts.nodes;
|
||||
const edgesOrNodes = followedHosts.nodes || followedHosts.edges;
|
||||
|
||||
for (let i = 0; i < edgesOrNodes.length; i++) {
|
||||
const edge = edgesOrNodes[i];
|
||||
const node = edge.node || edge;
|
||||
|
||||
const s = node.hosting.stream.viewersCount = new Number(node.hosting.stream.viewersCount || 0);
|
||||
s.profileImageURL = node.hosting.profileImageURL;
|
||||
|
@ -194,7 +211,7 @@ export default class Following extends SiteModule {
|
|||
channels: [node.displayName]
|
||||
};
|
||||
if (node.hosting.stream.game && hiddenThumbnails.includes(node.hosting.stream.game.name)) node.hosting.stream.previewImageURL = 'https://static-cdn.jtvnw.net/ttv-static/404_preview-320x180.jpg';
|
||||
if (!node.hosting.stream.game || node.hosting.stream.game && !blockedGames.includes(node.hosting.stream.game.name)) newHostNodes.push(node);
|
||||
if (!node.hosting.stream.game || node.hosting.stream.game && !blockedGames.includes(node.hosting.stream.game.name)) newHostNodes.push(edge);
|
||||
} else {
|
||||
this.hosts[node.hosting.displayName].nodes.push(node);
|
||||
this.hosts[node.hosting.displayName].channels.push(node.displayName);
|
||||
|
@ -202,7 +219,7 @@ export default class Following extends SiteModule {
|
|||
}
|
||||
|
||||
if (this.settings.get('directory.following.group-hosts')) {
|
||||
res.data.currentUser.followedHosts.nodes = newHostNodes;
|
||||
res.data.currentUser.followedHosts[oldMode ? 'nodes' : 'edges'] = newHostNodes;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -220,12 +237,14 @@ export default class Following extends SiteModule {
|
|||
n =>
|
||||
get('data.currentUser.followedLiveUsers.nodes.0.profileImageURL', n) !== undefined
|
||||
||
|
||||
get('data.currentUser.followedLiveUsers.edges.0.node.profileImageURL', n) !== undefined
|
||||
||
|
||||
get('data.currentUser.followedHosts.nodes.0.hosting.profileImageURL', n) !== undefined
|
||||
);
|
||||
} else if (this.router.match[1] === 'live') {
|
||||
this.apollo.ensureQuery(
|
||||
'FollowingLive_CurrentUser',
|
||||
'data.currentUser.followedLiveUsers.nodes.0.profileImageURL'
|
||||
'data.currentUser.followedLiveUsers.nodes.0.profileImageURL' || 'data.currentUser.followedLiveUsers.edges.0.node.profileImageURL'
|
||||
);
|
||||
} else if (this.router.match[1] === 'hosts') {
|
||||
this.apollo.ensureQuery(
|
||||
|
@ -353,9 +372,10 @@ export default class Following extends SiteModule {
|
|||
)
|
||||
);
|
||||
|
||||
(document.body.querySelector('.twilight-root') || document.body).appendChild(this.hostMenu);
|
||||
const root = (document.body.querySelector('.twilight-root') || document.body);
|
||||
root.appendChild(this.hostMenu);
|
||||
|
||||
this.hostMenuPopper = new Popper(document.body, this.hostMenu, {
|
||||
this.hostMenuPopper = new Popper(root, this.hostMenu, {
|
||||
placement: 'bottom-start',
|
||||
modifiers: {
|
||||
flip: {
|
||||
|
|
|
@ -12,6 +12,7 @@ import {get} from 'utilities/object';
|
|||
import Following from './following';
|
||||
import Game from './game';
|
||||
import Community from './community';
|
||||
import BrowsePopular from './browse_popular';
|
||||
|
||||
export default class Directory extends SiteModule {
|
||||
constructor(...args) {
|
||||
|
@ -30,6 +31,7 @@ export default class Directory extends SiteModule {
|
|||
this.inject(Following);
|
||||
this.inject(Game);
|
||||
this.inject(Community);
|
||||
this.inject(BrowsePopular);
|
||||
|
||||
this.apollo.registerModifier('GamePage_Game', res => this.modifyStreams(res), false);
|
||||
|
||||
|
@ -134,6 +136,7 @@ export default class Directory extends SiteModule {
|
|||
this.css_tweaks.toggleHide('boxart-hover', boxart === 1);
|
||||
|
||||
this.ChannelCard.ready((cls, instances) => {
|
||||
// Game Directory Channel Cards
|
||||
this.apollo.ensureQuery(
|
||||
'GamePage_Game',
|
||||
'data.directory.streams.edges.0.node.createdAt'
|
||||
|
@ -149,37 +152,40 @@ export default class Directory extends SiteModule {
|
|||
|
||||
|
||||
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';
|
||||
const container = this.fine.getHostNode(inst);
|
||||
if (!container) return;
|
||||
|
||||
this.updateUptime(inst, 'props.streamNode.viewersCount.createdAt', uptimeSel);
|
||||
this.addCardAvatar(inst, avatarSel);
|
||||
this.updateUptime(inst, 'props.streamNode.viewersCount.createdAt', '.tw-card-img');
|
||||
this.addCardAvatar(inst, 'props.streamNode.viewersCount', '.tw-card');
|
||||
|
||||
const type = inst.props.directoryType;
|
||||
const type = get('props.directoryType', inst);
|
||||
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);
|
||||
|
||||
if (inst.props.streamNode.type === 'watch_party')
|
||||
if (get('props.streamNode.type', inst) === 'watch_party' || get('props.type', inst) === 'watch_party')
|
||||
container.classList.toggle('tw-hide', this.settings.get('directory.hide-vodcasts'));
|
||||
|
||||
const img = container && container.querySelector && container.querySelector(`${uptimeSel} img`);
|
||||
if (img === null) return;
|
||||
const img = container.querySelector && container.querySelector('.tw-card-img img');
|
||||
if (img == null) return;
|
||||
|
||||
if (type === 'GAMES' && hiddenThumbnails.includes(inst.props.directoryName) ||
|
||||
type === 'COMMUNITIES' && hiddenThumbnails.includes(inst.props.streamNode.game.name)) {
|
||||
if (type === 'GAMES' && hiddenThumbnails.includes(get('props.directoryName', inst)) ||
|
||||
type === 'COMMUNITIES' && hiddenThumbnails.includes(get('props.streamNode.game.name', inst))) {
|
||||
img.src = hiddenPreview;
|
||||
} else {
|
||||
img.src = inst.props.streamNode.previewImageURL;
|
||||
img.src = get('props.streamNode.previewImageURL', inst) || get('props.imageSrc', inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
modifyStreams(res) { // eslint-disable-line class-methods-use-this
|
||||
const blockedGames = this.settings.provider.get('directory.game.blocked-games') || [];
|
||||
const gamePage = get('data.directory.__typename', res) === 'Game';
|
||||
|
||||
const newStreams = [];
|
||||
|
||||
const edges = res.data.directory.streams.edges;
|
||||
const edges = get('data.directory.streams.edges', res);
|
||||
if (!edges) return res;
|
||||
|
||||
for (let i = 0; i < edges.length; i++) {
|
||||
const edge = edges[i];
|
||||
const node = edge.node;
|
||||
|
@ -187,8 +193,10 @@ export default class Directory extends SiteModule {
|
|||
const s = node.viewersCount = new Number(node.viewersCount || 0);
|
||||
s.profileImageURL = node.broadcaster.profileImageURL;
|
||||
s.createdAt = node.createdAt;
|
||||
s.login = node.broadcaster.login;
|
||||
s.displayName = node.broadcaster.displayName;
|
||||
|
||||
newStreams.push(edge);
|
||||
if (gamePage || (!node.game || node.game && !blockedGames.includes(node.game.name))) newStreams.push(edge);
|
||||
}
|
||||
res.data.directory.streams.edges = newStreams;
|
||||
return res;
|
||||
|
@ -256,10 +264,14 @@ export default class Directory extends SiteModule {
|
|||
}
|
||||
|
||||
|
||||
addCardAvatar(inst, selector) {
|
||||
addCardAvatar(inst, created_path, selector) {
|
||||
const container = this.fine.getHostNode(inst),
|
||||
card = container && container.querySelector && container.querySelector(selector),
|
||||
setting = this.settings.get('directory.show-channel-avatars');
|
||||
setting = this.settings.get('directory.show-channel-avatars'),
|
||||
data = get(created_path, inst);
|
||||
|
||||
if ( ! card )
|
||||
return;
|
||||
|
||||
// Remove old elements
|
||||
const hiddenBodyCard = card.querySelector('.tw-card-body.tw-hide');
|
||||
|
@ -274,10 +286,10 @@ export default class Directory extends SiteModule {
|
|||
if (channelAvatar !== null)
|
||||
channelAvatar.remove();
|
||||
|
||||
if ( ! card || setting === 0 )
|
||||
if ( setting === 0 )
|
||||
return;
|
||||
|
||||
if (inst.props.streamNode.viewersCount.profileImageURL) {
|
||||
if (data) {
|
||||
if (setting === 1) {
|
||||
const cardDiv = card.querySelector('.tw-card-body');
|
||||
const modifiedDiv = e('div', {
|
||||
|
@ -286,11 +298,11 @@ export default class Directory extends SiteModule {
|
|||
|
||||
const avatarDiv = e('a', {
|
||||
className: 'ffz-channel-avatar tw-mg-r-05 tw-mg-t-05',
|
||||
href: `/${inst.props.streamNode.broadcaster.login}`,
|
||||
onclick: event => this.hijackUserClick(event, inst.props.streamNode.broadcaster.login)
|
||||
href: `/${data.login}`,
|
||||
onclick: event => this.hijackUserClick(event, data.login)
|
||||
}, e('img', {
|
||||
title: inst.props.streamNode.broadcaster.displayName,
|
||||
src: inst.props.streamNode.viewersCount.profileImageURL
|
||||
title: data.displayName,
|
||||
src: data.profileImageURL
|
||||
}));
|
||||
|
||||
const cardDivParent = cardDiv.parentElement;
|
||||
|
@ -306,13 +318,13 @@ export default class Directory extends SiteModule {
|
|||
} else if (setting === 2 || setting === 3) {
|
||||
const avatarElement = e('a', {
|
||||
className: 'ffz-channel-avatar',
|
||||
href: `/${inst.props.streamNode.broadcaster.login}`,
|
||||
onclick: event => this.hijackUserClick(event, inst.props.streamNode.broadcaster.login)
|
||||
href: `/${data.login}`,
|
||||
onclick: event => this.hijackUserClick(event, data.login)
|
||||
}, e('div', 'live-channel-card__boxart tw-bottom-0 tw-absolute',
|
||||
e('figure', 'tw-aspect tw-aspect--align-top',
|
||||
e('img', {
|
||||
title: inst.props.streamNode.broadcaster.displayName,
|
||||
src: inst.props.streamNode.viewersCount.profileImageURL
|
||||
title: data.displayName,
|
||||
src: data.profileImageURL
|
||||
})
|
||||
)
|
||||
));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue