diff --git a/src/sites/twitch-twilight/modules/directory/following.js b/src/sites/twitch-twilight/modules/directory/following.js index aeabd5a2..f01b2ba1 100644 --- a/src/sites/twitch-twilight/modules/directory/following.js +++ b/src/sites/twitch-twilight/modules/directory/following.js @@ -416,7 +416,7 @@ export default class Following extends SiteModule { updateChannelCard(inst) { if (!this.isRouteAcceptable()) return; - + this.parent.updateUptime(inst, 'props.viewerCount.createdAt', '.tw-card .tw-aspect > div'); const container = this.fine.getHostNode(inst), @@ -432,7 +432,7 @@ export default class Following extends SiteModule { const ffzChannelData = card.querySelector('.ffz-channel-data'); if (ffzChannelData !== null) ffzChannelData.remove(); - const channelAvatar = card.querySelector('.channel-avatar'); + const channelAvatar = card.querySelector('.ffz-channel-avatar'); if (channelAvatar !== null) channelAvatar.remove(); if (inst.props.viewerCount.profileImageURL) { @@ -452,17 +452,15 @@ export default class Following extends SiteModule { let avatarDiv; if (avatarSetting === 1) { avatarDiv = e('a', { - className: 'channel-avatar', + className: 'ffz-channel-avatar mg-r-05 mg-t-05', href: hosting ? `/${channel}` : inst.props.linkTo.pathname, - style: 'margin-right: 8px; min-width: 4rem; margin-top: 0.5rem;' }, e('img', { title: inst.props.channelName, - src: inst.props.viewerCount.profileImageURL, - style: 'height: 4rem;' + src: inst.props.viewerCount.profileImageURL })); } else if (avatarSetting === 2 || avatarSetting === 3) { const avatarElement = e('a', { - className: 'channel-avatar', + className: 'ffz-channel-avatar', href: hosting ? `/${channel}` : inst.props.linkTo.pathname, onclick: event => this.parent.hijackUserClick(event, inst.props.streamNode.broadcaster.login) }, e('div', 'live-channel-card__boxart bottom-0 absolute', @@ -476,7 +474,7 @@ export default class Following extends SiteModule { ); const divToAppend = card.querySelector('.tw-aspect > div'); - if (divToAppend.querySelector('.channel-avatar') === null) divToAppend.appendChild(avatarElement); + if (divToAppend.querySelector('.ffz-channel-avatar') === null) divToAppend.appendChild(avatarElement); } const cardDivParent = cardDiv.parentElement; diff --git a/src/sites/twitch-twilight/modules/directory/game.js b/src/sites/twitch-twilight/modules/directory/game.js index 86b556e9..19649bfb 100644 --- a/src/sites/twitch-twilight/modules/directory/game.js +++ b/src/sites/twitch-twilight/modules/directory/game.js @@ -14,6 +14,7 @@ export default class Game extends SiteModule { this.inject('site.fine'); this.inject('site.apollo'); + this.inject('i18n'); this.inject('settings'); this.GameHeader = this.fine.define( @@ -49,72 +50,82 @@ export default class Game extends SiteModule { } updateButtons(inst, update = false) { - if (inst.props.directoryType !== 'GAMES') return; - 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'); + if ( inst.props.directoryType !== 'GAMES' || ! container || ! container.querySelector ) + return; - const ffzButtons = buttons.querySelector('.ffz-buttons'); - if (ffzButtons !== null && !update) return; - else if (ffzButtons) ffzButtons.remove(); + const buttons = container.querySelector('div > div.align-items-center'), + ffz_buttons = buttons && buttons.querySelector('.ffz-buttons'); - 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); + if ( ! buttons || (ffz_buttons && ! update) ) + return; - 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'}` - }) - ); + if ( ffz_buttons ) + ffz_buttons.remove(); - 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); + // The Block / Unblock Button + let block_btn, block_label, + hidden_btn, hidden_label; - this.settings.provider.set('directory.game.blocked-games', blockedGames); + const game = inst.props.directoryName, + update_block = () => { + const blocked_games = this.settings.provider.get('directory.game.blocked-games') || [], + blocked = blocked_games.includes(game); - this.updateButtons(inst, true); - }); + block_btn.classList.toggle('active', blocked); + block_label.textContent = blocked ? + this.i18n.t('directory.unblock', 'Unblock') : + this.i18n.t('directory.block', 'Block'); + } - // 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'}` - }) - ); + block_btn = e('button', { + className: 'mg-l-1 tw-button ffz-directory-toggle-block', + onClick: this.generateClickHandler('directory.game.blocked-games', game, update_block) + }, block_label = e('span', 'tw-button__text')); - 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); + update_block(); - this.settings.provider.set('directory.game.hidden-thumbnails', hiddenThumbnails); - this.parent.ChannelCard.forceUpdate(); - this.updateButtons(inst, true); - }); + const update_hidden = () => { + const hidden_games = this.settings.provider.get('directory.game.hidden-thumbnails') || [], + hidden = hidden_games.includes(game); - const ffzButtons = e('div', 'ffz-buttons', [ - blockButton, - hideThumbnailButton - ]); + hidden_btn.classList.toggle('active', hidden); + hidden_label.textContent = hidden ? + this.i18n.t('directory.show-thumbnails', 'Show Thumbnails') : + this.i18n.t('directory.hide-thumbnails', 'Hide Thumbnails'); - buttons.appendChild(ffzButtons); + this.parent.ChannelCard.forceUpdate(); + } + + hidden_btn = e('button', { + className: 'mg-l-1 tw-button ffz-directory-toggle-thumbnail', + onClick: this.generateClickHandler('directory.game.hidden-thumbnails', game, update_hidden) + }, hidden_label = e('span', 'tw-button__text')); + + update_hidden(); + + buttons.appendChild(e('div', 'ffz-buttons', [ + block_btn, + hidden_btn + ])); + } + + generateClickHandler(setting, game, update_func) { + return e => { + e.preventDefault(); + const values = this.settings.provider.get(setting) || [], + idx = values.indexOf(game); + + if ( idx === -1 ) + values.push(game); + else + values.splice(idx, 1); + + this.settings.provider.set(setting, values); + update_func(); } } + } \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/directory/index.js b/src/sites/twitch-twilight/modules/directory/index.js index d4343028..f6f42fa4 100644 --- a/src/sites/twitch-twilight/modules/directory/index.js +++ b/src/sites/twitch-twilight/modules/directory/index.js @@ -24,6 +24,7 @@ export default class Directory extends SiteModule { this.inject('site.apollo'); this.inject('site.css_tweaks'); + this.inject('i18n'); this.inject('settings'); this.inject(Following); @@ -48,16 +49,16 @@ export default class Directory extends SiteModule { 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); @@ -74,11 +75,11 @@ export default class Directory extends SiteModule { 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; @@ -118,6 +119,7 @@ export default class Directory extends SiteModule { inst.ffz_uptime_el = null; inst.ffz_uptime_span = null; inst.ffz_uptime_tt = null; + inst.ffz_last_created_at = null; } } @@ -135,7 +137,7 @@ export default class Directory extends SiteModule { const up_text = duration_to_string(uptime, false, false, false, setting === 1); - if ( ! inst.ffz_uptime_el ) + 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', [ @@ -145,13 +147,25 @@ export default class Directory extends SiteModule { ]), 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(); + if ( inst.ffz_last_created_at !== created_at ) { + inst.ffz_uptime_tt.innerHTML = `${this.i18n.t( + 'metadata.uptime.tooltip', + 'Stream Uptime' + )}