From 270430f6a110a97de3f1ea7edc4210ae41394ba7 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Sat, 26 Feb 2022 13:28:16 +0300 Subject: [PATCH] Polyfill HTMLMediaElement.play Return a `Promise` to match the new standard. --- src/components/htmlMediaHelper.js | 35 +++++++++++++------------------ src/legacy/htmlMediaElement.js | 26 +++++++++++++++++++++++ src/scripts/site.js | 1 + 3 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 src/legacy/htmlMediaElement.js diff --git a/src/components/htmlMediaHelper.js b/src/components/htmlMediaHelper.js index 9a4140435..a7a9961e1 100644 --- a/src/components/htmlMediaHelper.js +++ b/src/components/htmlMediaHelper.js @@ -197,28 +197,21 @@ import { Events } from 'jellyfin-apiclient'; export function playWithPromise(elem, onErrorFn) { try { - const promise = elem.play(); - if (promise && promise.then) { - // Chrome now returns a promise - return promise - .catch((e) => { - const errorName = (e.name || '').toLowerCase(); - // safari uses aborterror - if (errorName === 'notallowederror' || - errorName === 'aborterror') { - // swallow this error because the user can still click the play button on the video element - return Promise.resolve(); - } - return Promise.reject(); - }) - .then(() => { - onSuccessfulPlay(elem, onErrorFn); + return elem.play() + .catch((e) => { + const errorName = (e.name || '').toLowerCase(); + // safari uses aborterror + if (errorName === 'notallowederror' || + errorName === 'aborterror') { + // swallow this error because the user can still click the play button on the video element return Promise.resolve(); - }); - } else { - onSuccessfulPlay(elem, onErrorFn); - return Promise.resolve(); - } + } + return Promise.reject(); + }) + .then(() => { + onSuccessfulPlay(elem, onErrorFn); + return Promise.resolve(); + }); } catch (err) { console.error('error calling video.play: ' + err); return Promise.reject(); diff --git a/src/legacy/htmlMediaElement.js b/src/legacy/htmlMediaElement.js new file mode 100644 index 000000000..b7a2c7082 --- /dev/null +++ b/src/legacy/htmlMediaElement.js @@ -0,0 +1,26 @@ +/** + * Polyfill for HTMLMediaElement + * - HTMLMediaElement.play + * Return a `Promise`. + */ + +(function (HTMLMediaElement) { + 'use strict'; + + const HTMLMediaElement_proto = HTMLMediaElement.prototype; + const real_play = HTMLMediaElement_proto.play; + + HTMLMediaElement_proto.play = function () { + try { + const promise = real_play.apply(this, arguments); + + if (typeof promise?.then === 'function') { + return promise; + } + + return Promise.resolve(); + } catch (err) { + return Promise.reject(err); + } + }; +}(HTMLMediaElement)); diff --git a/src/scripts/site.js b/src/scripts/site.js index 9a167ff5d..7b94f2b20 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -31,6 +31,7 @@ import './serverNotifications'; import '../components/playback/playerSelectionMenu'; import '../legacy/domParserTextHtml'; import '../legacy/focusPreventScroll'; +import '../legacy/htmlMediaElement'; import '../legacy/vendorStyles'; import SyncPlay from '../components/syncPlay/core'; import { playbackManager } from '../components/playback/playbackmanager';