diff --git a/package.json b/package.json
index f5a8e834..3febb587 100755
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "frankerfacez",
"author": "Dan Salvato LLC",
- "version": "4.14.7",
+ "version": "4.14.8",
"description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0",
"scripts": {
diff --git a/src/sites/twitch-twilight/modules/player.jsx b/src/sites/twitch-twilight/modules/player.jsx
index ded349d5..cd55ea74 100644
--- a/src/sites/twitch-twilight/modules/player.jsx
+++ b/src/sites/twitch-twilight/modules/player.jsx
@@ -11,6 +11,21 @@ export const PLAYER_ROUTES = ['front-page', 'user', 'video', 'user-video', 'user
const STYLE_VALIDATOR = createElement('span');
+function rotateButton(event) {
+ const target = event.currentTarget,
+ icon = target && target.querySelector('figure');
+ if ( ! icon || icon.classList.contains('ffz-i-t-reset-clicked') )
+ return;
+
+ icon.classList.toggle('ffz-i-t-reset', false);
+ icon.classList.toggle('ffz-i-t-reset-clicked', true);
+
+ setTimeout(() => {
+ icon.classList.toggle('ffz-i-t-reset', true);
+ icon.classList.toggle('ffz-i-t-reset-clicked', false);
+ }, 500);
+}
+
export default class Player extends Module {
constructor(...args) {
super(...args);
@@ -395,6 +410,9 @@ export default class Player extends Module {
if ( ! this._ffzErrorReset )
this._ffzErrorReset = t.addErrorResetButton.bind(t, this);
+ if ( ! this._ffzReady )
+ this._ffzReady = this.ffzReady.bind(this);
+
const inst = this,
old_active = this.setPlayerActive,
old_inactive = this.setPlayerInactive;
@@ -427,6 +445,7 @@ export default class Player extends Module {
on(events, 'PlayerError', this._ffzErrorReset);
on(events, 'Ended', this._ffzUpdateState);
on(events, 'Ended', this.ffzOnEnded);
+ on(events, 'Ready', this._ffzReady);
on(events, 'Idle', this._ffzUpdateState);
}
@@ -444,6 +463,7 @@ export default class Player extends Module {
off(events, 'PlayerError', this._ffzErrorReset);
off(events, 'Ended', this._ffzUpdateState);
off(events, 'Ended', this.ffzOnEnded);
+ off(events, 'Ready', this._ffzReady);
off(events, 'Idle', this._ffzUpdateState);
}
@@ -452,9 +472,26 @@ export default class Player extends Module {
this._ffz_state_raf = null;
this._ffzUpdateState = null;
this._ffzErrorReset = null;
+ this._ffzReady = null;
this.ffzOnEnded = null;
}
+ cls.prototype.ffzReady = function() {
+ const cont = this.props.containerRef;
+ if ( ! cont )
+ return;
+
+ requestAnimationFrame(() => {
+ const icons = cont.querySelectorAll('.ffz--player-reset figure');
+ for(const icon of icons) {
+ if ( icon._ffz_unspin )
+ clearTimeout(icon._ffz_unspin);
+
+ icon.classList.toggle('loading', false);
+ }
+ });
+ }
+
cls.prototype.ffzStopAutoplay = function() {
if ( t.settings.get('player.no-autoplay') || (! t.settings.get('player.home.autoplay') && t.router.current.name === 'front-page') ) {
const player = this.props.mediaPlayerInstance,
@@ -758,7 +795,7 @@ export default class Player extends Module {
>
- {icon = ()}
+ {icon = ()}
)}
@@ -777,20 +814,27 @@ export default class Player extends Module {
tip = cont.querySelector('.tw-tooltip');
}
- const pip_active = !!document.pictureInPictureElement
+ 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');
icon.classList.toggle('ffz-i-t-pip-inactive', ! pip_active);
icon.classList.toggle('ffz-i-t-pip-active', pip_active);
- btn.setAttribute('aria-label', tip.textContent = this.i18n.t('player.pip_button', 'Picture-in-Picture'));
+ btn.setAttribute('aria-label', label);
+ tip.textContent = label;
}
- pipPlayer(inst) {
+ pipPlayer(inst, e) {
const video = inst.props.mediaPlayerInstance?.mediaSinkManager?.video;
if ( ! video || ! document.pictureInPictureEnabled )
return;
+ if ( e )
+ e.preventDefault();
+
if ( ! video._ffz_pip_enter ) {
video.addEventListener('enterpictureinpicture', video._ffz_pip_enter = () => {
this.addPiPButton(inst);
@@ -836,11 +880,12 @@ export default class Player extends Module {
class="tw-align-items-center tw-align-middle tw-border-bottom-left-radius-medium tw-border-bottom-right-radius-medium tw-border-top-left-radius-medium tw-border-top-right-radius-medium tw-button-icon tw-button-icon--overlay tw-core-button tw-core-button--border tw-core-button--overlay tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative"
type="button"
data-a-target="ffz-player-reset-button"
+ onClick={rotateButton}
onDblClick={this.resetPlayer.bind(this, inst)} // eslint-disable-line react/jsx-no-bind
>
)}
@@ -903,11 +948,12 @@ export default class Player extends Module {
class="tw-align-items-center tw-align-middle tw-border-bottom-left-radius-medium tw-border-bottom-right-radius-medium tw-border-top-left-radius-medium tw-border-top-right-radius-medium tw-button-icon tw-button-icon--overlay tw-core-button tw-core-button--border tw-core-button--overlay tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative"
type="button"
data-a-target="ffz-player-reset-button"
+ onClick={rotateButton}
onDblClick={this.resetPlayer.bind(this, inst)} // eslint-disable-line react/jsx-no-bind
>
)}
@@ -929,9 +975,29 @@ export default class Player extends Module {
}
- resetPlayer(inst) {
+ resetPlayer(inst, e) {
const player = inst ? (inst.mediaSinkManager ? inst : inst?.props?.mediaPlayerInstance) : null;
+ if ( e ) {
+ e.preventDefault();
+ const target = e.currentTarget,
+ icon = target && target.querySelector('figure');
+
+ if ( icon ) {
+ if ( icon.classList.contains('loading') )
+ return;
+
+ icon.classList.toggle('ffz-i-t-reset', true);
+ icon.classList.toggle('ffz-i-t-reset-clicked', false);
+
+ icon.classList.toggle('loading', true);
+ icon._ffz_unspin = setTimeout(() => {
+ icon._ffz_unspin = null;
+ icon.classList.toggle('loading', false);
+ }, 10000);
+ }
+ }
+
this.PlayerSource.check();
for(const inst of this.PlayerSource.instances) {
if ( ! player || player === inst.props?.mediaPlayerInstance )
diff --git a/styles/icons.scss b/styles/icons.scss
index 1afce8e9..90816d62 100644
--- a/styles/icons.scss
+++ b/styles/icons.scss
@@ -44,6 +44,12 @@
}
+.ffz-player-icon {
+ font-size: 2rem !important;
+ margin: -.5rem -.4rem !important;
+}
+
+
.tw-button-icon__icon {
[class^="ffz-i-"], [class*=" ffz-i-"] {
font-size: 1.6rem
diff --git a/styles/main.scss b/styles/main.scss
index 594bb5b8..0d0d856e 100644
--- a/styles/main.scss
+++ b/styles/main.scss
@@ -13,6 +13,8 @@
}
+.ffz-i-t-reset.loading,
+.ffz-i-t-reset-clicked.loading,
.ffz-i-zreknarf.loading {
animation: ffz-rotateplane 1.2s infinite linear;
}