diff --git a/package.json b/package.json index 6dd3b081..cb852db6 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.17.14", + "version": "4.17.15", "description": "FrankerFaceZ is a Twitch enhancement suite.", "license": "Apache-2.0", "scripts": { diff --git a/src/modules/chat/badges.jsx b/src/modules/chat/badges.jsx index 58b23433..2bbfe32b 100644 --- a/src/modules/chat/badges.jsx +++ b/src/modules/chat/badges.jsx @@ -247,6 +247,8 @@ export default class Badges extends Module { getSettingsBadges(include_addons) { const twitch = [], + owl = [], + tcon = [], game = [], ffz = [], addon = []; @@ -258,7 +260,7 @@ export default class Badges extends Module { let v = badge && (badge[1] || badge[0]); for(const key in badge) - if ( has(badge, key) ) { + if ( key !== '__cat' && has(badge, key) ) { const version = badge[key]; if ( ! v ) v = version; @@ -272,8 +274,18 @@ export default class Badges extends Module { }); } - if ( v ) - (badge.__game ? game : twitch).push({ + if ( v ) { + let cat; + if ( badge.__cat === 'm-owl' ) + cat = owl; + else if ( badge.__cat === 'm-tcon' ) + cat = tcon; + else if ( badge.__cat === 'm-game' ) + cat = game; + else + cat = twitch; + + cat.push({ id: key, provider: 'twitch', name: v.title, @@ -282,6 +294,7 @@ export default class Badges extends Module { versions: vs, styleImage: `url("${v.image2x}")` }); + } } if ( include_addons ) @@ -302,6 +315,8 @@ export default class Badges extends Module { return [ {title: 'Twitch', id: 'm-twitch', badges: twitch}, + {title: 'Twitch: TwitchCon', id: 'm-tcon', badges: tcon}, + {title: 'Twitch: Overwatch League', id: 'm-owl', badges: owl}, {title: 'Twitch: Game', id: 'm-game', key: 'game', badges: game}, {title: 'FrankerFaceZ', id: 'm-ffz', badges: ffz}, {title: 'Add-on', id: 'm-addon', badges: addon} @@ -408,11 +423,11 @@ export default class Badges extends Module { is_colored = badge_style !== 5, has_image = badge_style !== 3 && badge_style !== 4, - twitch_hidden = hidden_badges['m-twitch'], - game_hidden = hidden_badges['m-game'], ffz_hidden = hidden_badges['m-ffz'], addon_hidden = hidden_badges['m-addon'], + tb = this.twitch_badges, + out = [], slotted = {}, twitch_badges = msg.badges || {}, @@ -433,9 +448,10 @@ export default class Badges extends Module { if ( has(twitch_badges, badge_id) ) { const version = twitch_badges[badge_id], is_hidden = hidden_badges[badge_id], - is_game = badge_id.endsWith('_1'); + bdata = tb && tb[badge_id], + cat = bdata && bdata.__cat || 'm-twitch'; - if ( is_hidden || (is_hidden == null && (is_game ? game_hidden : twitch_hidden))) + if ( is_hidden || (is_hidden == null && hidden_badges[cat]) ) continue; if ( has(BADGE_POSITIONS, badge_id) ) @@ -771,7 +787,9 @@ export default class Badges extends Module { b = {}; for(const data of badges) { const sid = data.setID, - bs = b[sid] = b[sid] || {__game: /_\d+$/.test(sid) && ! sid.includes('overwatch') }; + bs = b[sid] = b[sid] || { + __cat: getBadgeCategory(sid) + }; this.twitch_badge_count++; bs[data.version] = data; @@ -864,4 +882,16 @@ export default class Badges extends Module { else this.style.delete('twitch-badges'); } +} + + +function getBadgeCategory(key) { + if ( key.startsWith('overwatch-league') ) + return 'm-owl'; + else if ( key.startsWith('twitchcon') ) + return 'm-tcon'; + else if ( /_\d+$/.test(key) ) + return 'm-game'; + + return 'm-twitch'; } \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/css_tweaks/styles/minimal-navigation.scss b/src/sites/twitch-twilight/modules/css_tweaks/styles/minimal-navigation.scss index 6430088a..7ffcb75b 100644 --- a/src/sites/twitch-twilight/modules/css_tweaks/styles/minimal-navigation.scss +++ b/src/sites/twitch-twilight/modules/css_tweaks/styles/minimal-navigation.scss @@ -4,6 +4,7 @@ height: 5rem !important; } + position: relative; height: 1rem !important; top: -4rem !important; diff --git a/src/sites/twitch-twilight/modules/player.jsx b/src/sites/twitch-twilight/modules/player.jsx index 1e06b1f3..fc480cf0 100644 --- a/src/sites/twitch-twilight/modules/player.jsx +++ b/src/sites/twitch-twilight/modules/player.jsx @@ -759,10 +759,22 @@ export default class Player extends Module { installVisibilityHook() { if ( ! document.pictureInPictureEnabled ) { - this.log.info('Skipping visibility hook. Picture-in-Picture is not available.'); + this.log.info('Skipping visibility hooks. Picture-in-Picture is not available.'); return; } + document.addEventListener('fullscreenchange', () => { + const fs = document.fullscreenElement, + pip = document.pictureInPictureElement; + + if ( fs && pip && (fs === pip || fs.contains(pip)) ) + document.exitPictureInPicture(); + + // Update the UI since we can't enter PiP from Fullscreen + for(const inst of this.Player.instances) + this.addPiPButton(inst); + }); + try { Object.defineProperty(document, 'hidden', { configurable: true, @@ -796,6 +808,8 @@ export default class Player extends Module { addPiPButton(inst, tries = 0) { const outer = inst.props.containerRef || this.fine.getChildNode(inst), + video = inst.props.mediaPlayerInstance?.mediaSinkManager?.video, + is_fs = video && document.fullscreenElement && document.fullscreenElement.contains(video), container = outer && outer.querySelector('.player-controls__right-control-group'), has_pip = document.pictureInPictureEnabled && this.settings.get('player.button.pip'); @@ -846,12 +860,17 @@ export default class Player extends Module { } const pip_active = !!document.pictureInPictureElement, - label = pip_active ? - this.i18n.t('player.pip_button.off', 'Exit Picture-in-Picture') : - this.i18n.t('player.pip_button', 'Picture-in-Picture'); + pip_swap = false, //pip_active && document.pictureInPictureElement !== video, + label = is_fs ? + this.i18n.t('player.pip_button.fs', 'Cannot use Picture-in-Picture when Fullscreen') + : pip_swap ? + this.i18n.t('player.pip_button.swap', 'Switch Picture-in-Picture') + : pip_active ? + this.i18n.t('player.pip_button.off', 'Exit Picture-in-Picture') + : this.i18n.t('player.pip_button', 'Picture-in-Picture'); - icon.classList.toggle('ffz-i-t-pip-inactive', ! pip_active); - icon.classList.toggle('ffz-i-t-pip-active', pip_active); + icon.classList.toggle('ffz-i-t-pip-inactive', ! pip_active || pip_swap); + icon.classList.toggle('ffz-i-t-pip-active', pip_active && ! pip_swap); btn.setAttribute('aria-label', label); tip.textContent = label; @@ -866,6 +885,9 @@ export default class Player extends Module { if ( e ) e.preventDefault(); + if ( document.fullscreenElement && document.fullscreenElement.contains(video) ) + return; + if ( ! video._ffz_pip_enter ) { video.addEventListener('enterpictureinpicture', video._ffz_pip_enter = () => { this.addPiPButton(inst); @@ -876,9 +898,11 @@ export default class Player extends Module { }); } + //const is_this = document.pictureInPictureElement === video; if ( document.pictureInPictureElement ) document.exitPictureInPicture(); else + //if ( ! is_this ) video.requestPictureInPicture(); } diff --git a/src/sites/twitch-twilight/modules/video_chat/index.jsx b/src/sites/twitch-twilight/modules/video_chat/index.jsx index 93282f0a..9ef36672 100644 --- a/src/sites/twitch-twilight/modules/video_chat/index.jsx +++ b/src/sites/twitch-twilight/modules/video_chat/index.jsx @@ -50,6 +50,15 @@ export default class VideoChatHook extends Module { // Settings + this.settings.add('chat.video-chat.timestamps', { + default: true, + ui: { + path: 'Chat > Chat on Videos >> Appearance', + title: 'Display timestamps alongside chat messages.', + component: 'setting-check-box' + } + }); + this.settings.add('chat.video-chat.enabled', { default: true, ui: { @@ -64,6 +73,7 @@ export default class VideoChatHook extends Module { async onEnable() { this.chat.context.on('changed:chat.video-chat.enabled', this.updateLines, this); + this.chat.context.on('changed:chat.video-chat.timestamps', this.updateLines, this); this.on('chat:updated-lines', this.updateLines, this); this.VideoChatController.on('mount', this.chatMounted, this); @@ -275,6 +285,7 @@ export default class VideoChatHook extends Module { const context = this.props.messageContext, msg = t.standardizeMessage(context.comment, context.author), main_message = this.ffzRenderMessage(msg, context), + hide_timestamps = this.props.hideTimestamp || ! t.chat.context.get('chat.video-chat.timestamps'), bg_css = msg.mentioned && msg.mention_color ? t.site_chat.inverse_colors.process(msg.mention_color) : null; @@ -288,7 +299,7 @@ export default class VideoChatHook extends Module { class={`tw-align-items-start tw-flex tw-flex-nowrap tw-full-width tw-pd-l-05 tw-pd-y-05 vod-message${msg.is_sub ? ' ffz-notice-line ffz--subscribe-line' : ''}${msg.highlight ? ' ffz-notice-line ffz--points-line' : ''}${highlight ? ' ffz--points-highlight ffz-custom-color' : ''}${msg.mentioned ? ' ffz-mentioned' : ''}${bg_css ? ' ffz-custom-color' : ''}`} style={{backgroundColor: bg_css}} > - {this.props.hideTimestamp || (