From f2e0c8b324fa18c2d542a2d3e21dceb54a8385da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Polakovi=C4=8D?= Date: Wed, 19 Jan 2022 07:30:50 +0100 Subject: [PATCH 1/7] DownloadManager should use custom events to signal the pause request. --- src/js/classes/DownloadManager.js | 6 +++++- src/js/classes/VideoDownloaderRegistry.js | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/js/classes/DownloadManager.js b/src/js/classes/DownloadManager.js index aa835e1..d6880ba 100644 --- a/src/js/classes/DownloadManager.js +++ b/src/js/classes/DownloadManager.js @@ -226,7 +226,11 @@ export default class DownloadManager { */ forcePause() { this.pause(); - this.internal.videoDownloader.downloading = false; + + if (document) { + const pauseEvent = new CustomEvent('pausedownload', { detail: this.videoId }); + document.dispatchEvent(pauseEvent); + } } /** diff --git a/src/js/classes/VideoDownloaderRegistry.js b/src/js/classes/VideoDownloaderRegistry.js index ee6d480..d03b7fa 100644 --- a/src/js/classes/VideoDownloaderRegistry.js +++ b/src/js/classes/VideoDownloaderRegistry.js @@ -27,6 +27,10 @@ export default class VideoDownloaderRegistry { constructor({ connectionStatus }) { this.instances = new Map(); this.connectionStatus = connectionStatus; + + if (document) { + document.addEventListener('pausedownload', this.onPauseDownload.bind(this)); + } } /** @@ -67,4 +71,18 @@ export default class VideoDownloaderRegistry { destroyAll() { this.instances.clear(); } + + /** + * When a pause request is received, we need to pause the download. + * + * @param {CustomEvent} e Pause event. + * @param {string} e.detail Video ID. + */ + onPauseDownload(e) { + const downloaderInstance = this.get(e.detail); + + if (downloaderInstance) { + downloaderInstance.downloading = false; + } + } } From b02f5aa78020270c2fd0f74338e297b92a001521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Polakovi=C4=8D?= Date: Mon, 31 Jan 2022 13:27:27 +0100 Subject: [PATCH 2/7] Only return the casting button when there are devices to cast to. --- src/index.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 1250067..e1a04ab 100644 --- a/src/index.js +++ b/src/index.js @@ -170,20 +170,40 @@ window.kinoInitGoogleCast = (function kinoInitGoogleCastIIFE() { return () => { if (!castButtonPromise) { castButtonPromise = new Promise((resolve) => { - const initCastApi = () => { - window.cast.framework.CastContext.getInstance().setOptions({ - receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID, - }); + let resolved = false; + const resolveWithButton = () => { const castButton = document.createElement('button'); const castCustomElement = document.createElement('google-cast-launcher'); castButton.setAttribute('aria-label', 'Cast this video'); castButton.appendChild(castCustomElement); + resolved = true; resolve(castButton); }; + const checkCastState = () => { + const castState = window.cast.framework.CastContext.getInstance().getCastState(); + + if (castState !== 'NO_DEVICES_AVAILABLE' && !resolved) { + resolveWithButton(); + } + }; + + const initCastApi = () => { + window.cast.framework.CastContext.getInstance().setOptions({ + receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID, + }); + + checkCastState(); + + window.cast.framework.CastContext.getInstance().addEventListener( + window.cast.framework.CastContextEventType.CAST_STATE_CHANGED, + checkCastState, + ); + }; + window.__onGCastApiAvailable = (isAvailable) => { if (isAvailable) { initCastApi(); From f451221edca0b115005261d56ac967580553fb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Polakovi=C4=8D?= Date: Mon, 31 Jan 2022 13:50:18 +0100 Subject: [PATCH 3/7] Only play one video in PiP at once. --- src/js/web-components/video-player/VideoPlayer.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/js/web-components/video-player/VideoPlayer.js b/src/js/web-components/video-player/VideoPlayer.js index d458e13..c73864a 100644 --- a/src/js/web-components/video-player/VideoPlayer.js +++ b/src/js/web-components/video-player/VideoPlayer.js @@ -27,7 +27,7 @@ import { PIP_CLASSNAME, } from '../../constants'; -export default class extends HTMLElement { +export default class VideoPlayer extends HTMLElement { /** * @param {VideoDownloader} downloader Video downloader associated with the current video. */ @@ -464,6 +464,11 @@ export default class extends HTMLElement { pipButton.disabled = true; try { if (this !== document.pictureInPictureElement) { + // If another video is already in PiP, pause it and exit PiP mode. + if (document.pictureInPictureElement instanceof VideoPlayer) { + document.pictureInPictureElement.videoElement.pause(); + await document.exitPictureInPicture(); + } await this.videoElement.requestPictureInPicture(); } else { await document.exitPictureInPicture(); From 599d9ab4c439d598146f69f60123996e993aee79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Polakovi=C4=8D?= Date: Mon, 31 Jan 2022 14:25:56 +0100 Subject: [PATCH 4/7] Remove the superfluous exitPictureInPicture call. --- src/js/web-components/video-player/VideoPlayer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/web-components/video-player/VideoPlayer.js b/src/js/web-components/video-player/VideoPlayer.js index c73864a..42420a7 100644 --- a/src/js/web-components/video-player/VideoPlayer.js +++ b/src/js/web-components/video-player/VideoPlayer.js @@ -467,7 +467,6 @@ export default class VideoPlayer extends HTMLElement { // If another video is already in PiP, pause it and exit PiP mode. if (document.pictureInPictureElement instanceof VideoPlayer) { document.pictureInPictureElement.videoElement.pause(); - await document.exitPictureInPicture(); } await this.videoElement.requestPictureInPicture(); } else { From ff908c3f62f944c3549ffd7a4131d19dbb288474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Polakovi=C4=8D?= Date: Mon, 31 Jan 2022 14:36:40 +0100 Subject: [PATCH 5/7] Update a misleading comment. --- src/js/web-components/video-player/VideoPlayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/web-components/video-player/VideoPlayer.js b/src/js/web-components/video-player/VideoPlayer.js index 42420a7..b7d7914 100644 --- a/src/js/web-components/video-player/VideoPlayer.js +++ b/src/js/web-components/video-player/VideoPlayer.js @@ -464,7 +464,7 @@ export default class VideoPlayer extends HTMLElement { pipButton.disabled = true; try { if (this !== document.pictureInPictureElement) { - // If another video is already in PiP, pause it and exit PiP mode. + // If another video is already in PiP, pause it. if (document.pictureInPictureElement instanceof VideoPlayer) { document.pictureInPictureElement.videoElement.pause(); } From 7cdfcdd5cce2e51a44e474fbe66f1c8abedf2966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Polakovi=C4=8D?= Date: Mon, 31 Jan 2022 15:08:33 +0100 Subject: [PATCH 6/7] Hide and show the cast button depending on cast state changes. --- src/index.js | 34 ++++++++----------- src/js/constants.js | 1 + .../video-player/VideoPlayer.css | 4 +++ 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/index.js b/src/index.js index e1a04ab..eb18033 100644 --- a/src/index.js +++ b/src/index.js @@ -46,7 +46,7 @@ import ErrorPage from './js/pages/Error'; * Settings */ import { loadSetting } from './js/utils/settings'; -import { SETTING_KEY_TOGGLE_OFFLINE, SETTING_KEY_DARK_MODE } from './js/constants'; +import { SETTING_KEY_TOGGLE_OFFLINE, SETTING_KEY_DARK_MODE, CAST_BUTTON_HIDDEN_CLASSNAME } from './js/constants'; /** * Custom Elements definition. @@ -170,25 +170,20 @@ window.kinoInitGoogleCast = (function kinoInitGoogleCastIIFE() { return () => { if (!castButtonPromise) { castButtonPromise = new Promise((resolve) => { - let resolved = false; + const castButton = document.createElement('button'); + const castCustomElement = document.createElement('google-cast-launcher'); - const resolveWithButton = () => { - const castButton = document.createElement('button'); - const castCustomElement = document.createElement('google-cast-launcher'); + castButton.setAttribute('aria-label', 'Cast this video'); + castButton.appendChild(castCustomElement); + castButton.classList.add(CAST_BUTTON_HIDDEN_CLASSNAME); - castButton.setAttribute('aria-label', 'Cast this video'); - castButton.appendChild(castCustomElement); - - resolved = true; - resolve(castButton); - }; - - const checkCastState = () => { + const applyCastState = () => { const castState = window.cast.framework.CastContext.getInstance().getCastState(); - if (castState !== 'NO_DEVICES_AVAILABLE' && !resolved) { - resolveWithButton(); - } + castButton.classList.toggle( + CAST_BUTTON_HIDDEN_CLASSNAME, + castState === 'NO_DEVICES_AVAILABLE', + ); }; const initCastApi = () => { @@ -196,12 +191,13 @@ window.kinoInitGoogleCast = (function kinoInitGoogleCastIIFE() { receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID, }); - checkCastState(); - window.cast.framework.CastContext.getInstance().addEventListener( window.cast.framework.CastContextEventType.CAST_STATE_CHANGED, - checkCastState, + applyCastState, ); + applyCastState(); + + resolve(castButton); }; window.__onGCastApiAvailable = (isAvailable) => { diff --git a/src/js/constants.js b/src/js/constants.js index 330e27f..7dd0a04 100644 --- a/src/js/constants.js +++ b/src/js/constants.js @@ -137,3 +137,4 @@ export const PIP_CLASSNAME = 'picture-in-picture'; export const CAST_CLASSNAME = 'cast'; export const CAST_HAS_TARGET_NAME = 'cast-has-target'; export const CAST_TARGET_NAME = 'cast-target-name'; +export const CAST_BUTTON_HIDDEN_CLASSNAME = 'hidden'; diff --git a/src/js/web-components/video-player/VideoPlayer.css b/src/js/web-components/video-player/VideoPlayer.css index 235f207..8ef7ffa 100644 --- a/src/js/web-components/video-player/VideoPlayer.css +++ b/src/js/web-components/video-player/VideoPlayer.css @@ -38,6 +38,10 @@ border: none; } +:host .floating-buttons > button.hidden { + display: none; +} + button google-cast-launcher { height: 24px; width: auto; From 3cc1ef6bc8aff37708e1c48c35a22e404691b64b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Polakovi=C4=8D?= Date: Mon, 31 Jan 2022 16:28:09 +0100 Subject: [PATCH 7/7] Not necessary to hide the cast button when it's created. --- src/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.js b/src/index.js index eb18033..bc9c67c 100644 --- a/src/index.js +++ b/src/index.js @@ -175,7 +175,6 @@ window.kinoInitGoogleCast = (function kinoInitGoogleCastIIFE() { castButton.setAttribute('aria-label', 'Cast this video'); castButton.appendChild(castCustomElement); - castButton.classList.add(CAST_BUTTON_HIDDEN_CLASSNAME); const applyCastState = () => { const castState = window.cast.framework.CastContext.getInstance().getCastState();