1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-07 14:50:56 +00:00
* Added: Option to hide timestamps from Chat on Videos.
* Added: TwitchCon and Overwatch League badges are now sorted into their own categories for controlling badge visibility.
* Fixed: Automatically exit Picture-in-Picture when entering fullscreen mode.
* Fixed: Do not let users enter Picture-in-Picture when already in fullscreen.
* Fixed: Minimal Navigation not actually sliding the top navigation bar out of view.
This commit is contained in:
SirStendec 2020-01-24 19:02:06 -05:00
parent 829ec35808
commit 2d14c359c9
5 changed files with 82 additions and 16 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"author": "Dan Salvato LLC", "author": "Dan Salvato LLC",
"version": "4.17.14", "version": "4.17.15",
"description": "FrankerFaceZ is a Twitch enhancement suite.", "description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {

View file

@ -247,6 +247,8 @@ export default class Badges extends Module {
getSettingsBadges(include_addons) { getSettingsBadges(include_addons) {
const twitch = [], const twitch = [],
owl = [],
tcon = [],
game = [], game = [],
ffz = [], ffz = [],
addon = []; addon = [];
@ -258,7 +260,7 @@ export default class Badges extends Module {
let v = badge && (badge[1] || badge[0]); let v = badge && (badge[1] || badge[0]);
for(const key in badge) for(const key in badge)
if ( has(badge, key) ) { if ( key !== '__cat' && has(badge, key) ) {
const version = badge[key]; const version = badge[key];
if ( ! v ) if ( ! v )
v = version; v = version;
@ -272,8 +274,18 @@ export default class Badges extends Module {
}); });
} }
if ( v ) if ( v ) {
(badge.__game ? game : twitch).push({ 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, id: key,
provider: 'twitch', provider: 'twitch',
name: v.title, name: v.title,
@ -282,6 +294,7 @@ export default class Badges extends Module {
versions: vs, versions: vs,
styleImage: `url("${v.image2x}")` styleImage: `url("${v.image2x}")`
}); });
}
} }
if ( include_addons ) if ( include_addons )
@ -302,6 +315,8 @@ export default class Badges extends Module {
return [ return [
{title: 'Twitch', id: 'm-twitch', badges: twitch}, {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: 'Twitch: Game', id: 'm-game', key: 'game', badges: game},
{title: 'FrankerFaceZ', id: 'm-ffz', badges: ffz}, {title: 'FrankerFaceZ', id: 'm-ffz', badges: ffz},
{title: 'Add-on', id: 'm-addon', badges: addon} {title: 'Add-on', id: 'm-addon', badges: addon}
@ -408,11 +423,11 @@ export default class Badges extends Module {
is_colored = badge_style !== 5, is_colored = badge_style !== 5,
has_image = badge_style !== 3 && badge_style !== 4, 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'], ffz_hidden = hidden_badges['m-ffz'],
addon_hidden = hidden_badges['m-addon'], addon_hidden = hidden_badges['m-addon'],
tb = this.twitch_badges,
out = [], out = [],
slotted = {}, slotted = {},
twitch_badges = msg.badges || {}, twitch_badges = msg.badges || {},
@ -433,9 +448,10 @@ export default class Badges extends Module {
if ( has(twitch_badges, badge_id) ) { if ( has(twitch_badges, badge_id) ) {
const version = twitch_badges[badge_id], const version = twitch_badges[badge_id],
is_hidden = hidden_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; continue;
if ( has(BADGE_POSITIONS, badge_id) ) if ( has(BADGE_POSITIONS, badge_id) )
@ -771,7 +787,9 @@ export default class Badges extends Module {
b = {}; b = {};
for(const data of badges) { for(const data of badges) {
const sid = data.setID, 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++; this.twitch_badge_count++;
bs[data.version] = data; bs[data.version] = data;
@ -864,4 +882,16 @@ export default class Badges extends Module {
else else
this.style.delete('twitch-badges'); 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';
} }

View file

@ -4,6 +4,7 @@
height: 5rem !important; height: 5rem !important;
} }
position: relative;
height: 1rem !important; height: 1rem !important;
top: -4rem !important; top: -4rem !important;

View file

@ -759,10 +759,22 @@ export default class Player extends Module {
installVisibilityHook() { installVisibilityHook() {
if ( ! document.pictureInPictureEnabled ) { 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; 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 { try {
Object.defineProperty(document, 'hidden', { Object.defineProperty(document, 'hidden', {
configurable: true, configurable: true,
@ -796,6 +808,8 @@ export default class Player extends Module {
addPiPButton(inst, tries = 0) { addPiPButton(inst, tries = 0) {
const outer = inst.props.containerRef || this.fine.getChildNode(inst), 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'), container = outer && outer.querySelector('.player-controls__right-control-group'),
has_pip = document.pictureInPictureEnabled && this.settings.get('player.button.pip'); 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, const pip_active = !!document.pictureInPictureElement,
label = pip_active ? pip_swap = false, //pip_active && document.pictureInPictureElement !== video,
this.i18n.t('player.pip_button.off', 'Exit Picture-in-Picture') : label = is_fs ?
this.i18n.t('player.pip_button', 'Picture-in-Picture'); 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-inactive', ! pip_active || pip_swap);
icon.classList.toggle('ffz-i-t-pip-active', pip_active); icon.classList.toggle('ffz-i-t-pip-active', pip_active && ! pip_swap);
btn.setAttribute('aria-label', label); btn.setAttribute('aria-label', label);
tip.textContent = label; tip.textContent = label;
@ -866,6 +885,9 @@ export default class Player extends Module {
if ( e ) if ( e )
e.preventDefault(); e.preventDefault();
if ( document.fullscreenElement && document.fullscreenElement.contains(video) )
return;
if ( ! video._ffz_pip_enter ) { if ( ! video._ffz_pip_enter ) {
video.addEventListener('enterpictureinpicture', video._ffz_pip_enter = () => { video.addEventListener('enterpictureinpicture', video._ffz_pip_enter = () => {
this.addPiPButton(inst); this.addPiPButton(inst);
@ -876,9 +898,11 @@ export default class Player extends Module {
}); });
} }
//const is_this = document.pictureInPictureElement === video;
if ( document.pictureInPictureElement ) if ( document.pictureInPictureElement )
document.exitPictureInPicture(); document.exitPictureInPicture();
else else
//if ( ! is_this )
video.requestPictureInPicture(); video.requestPictureInPicture();
} }

View file

@ -50,6 +50,15 @@ export default class VideoChatHook extends Module {
// Settings // 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', { this.settings.add('chat.video-chat.enabled', {
default: true, default: true,
ui: { ui: {
@ -64,6 +73,7 @@ export default class VideoChatHook extends Module {
async onEnable() { async onEnable() {
this.chat.context.on('changed:chat.video-chat.enabled', this.updateLines, this); 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.on('chat:updated-lines', this.updateLines, this);
this.VideoChatController.on('mount', this.chatMounted, this); this.VideoChatController.on('mount', this.chatMounted, this);
@ -275,6 +285,7 @@ export default class VideoChatHook extends Module {
const context = this.props.messageContext, const context = this.props.messageContext,
msg = t.standardizeMessage(context.comment, context.author), msg = t.standardizeMessage(context.comment, context.author),
main_message = this.ffzRenderMessage(msg, context), 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; 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' : ''}`} 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}} style={{backgroundColor: bg_css}}
> >
{this.props.hideTimestamp || (<div data-test-selector="message-timestamp" class="tw-align-right tw-flex tw-flex-shrink-0 vod-message__header"> {hide_timestamps || (<div data-test-selector="message-timestamp" class="tw-align-right tw-flex tw-flex-shrink-0 vod-message__header">
<div class="tw-mg-r-05"> <div class="tw-mg-r-05">
<div class="tw-inline-flex tw-relative tw-tooltip-wrapper"> <div class="tw-inline-flex tw-relative tw-tooltip-wrapper">
<button class="tw-block tw-full-width tw-interactable tw-interactable--hover-enabled tw-interactable--inverted tw-interactive" onClick={this.onTimestampClickHandler}> <button class="tw-block tw-full-width tw-interactable tw-interactable--hover-enabled tw-interactable--inverted tw-interactive" onClick={this.onTimestampClickHandler}>