mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-03 08:28:31 +00:00
4.17.15
* 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:
parent
829ec35808
commit
2d14c359c9
5 changed files with 82 additions and 16 deletions
|
@ -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": {
|
||||
|
|
|
@ -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';
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
height: 5rem !important;
|
||||
}
|
||||
|
||||
position: relative;
|
||||
height: 1rem !important;
|
||||
top: -4rem !important;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 || (<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-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}>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue