diff --git a/src/components/alert.js b/src/components/alert.js
index 3d967b55a9..f6339489f3 100644
--- a/src/components/alert.js
+++ b/src/components/alert.js
@@ -1,4 +1,4 @@
-
+import { appRouter } from './appRouter';
import browser from '../scripts/browser';
import dialog from './dialog/dialog';
import globalize from '../scripts/globalize';
@@ -10,7 +10,7 @@ import globalize from '../scripts/globalize';
return originalString.replace(reg, strWith);
}
- export default function (text, title) {
+ export default async function (text, title) {
let options;
if (typeof text === 'string') {
options = {
@@ -22,7 +22,9 @@ import globalize from '../scripts/globalize';
}
if (browser.tv && window.alert) {
+ await appRouter.ready();
alert(replaceAll(options.text || '', '
', '\n'));
+ return Promise.resolve();
} else {
const items = [];
@@ -35,8 +37,6 @@ import globalize from '../scripts/globalize';
options.buttons = items;
return dialog.show(options);
}
-
- return Promise.resolve();
}
/* eslint-enable indent */
diff --git a/src/components/appRouter.js b/src/components/appRouter.js
index 5a89deca54..aa869b7cc6 100644
--- a/src/components/appRouter.js
+++ b/src/components/appRouter.js
@@ -24,6 +24,7 @@ class AppRouter {
isDummyBackToHome;
msgTimeout;
popstateOccurred = false;
+ promiseShow;
resolveOnNextShow;
previousRoute = {};
/**
@@ -122,11 +123,24 @@ class AppRouter {
}
}
- back() {
- page.back();
+ ready() {
+ return this.promiseShow || Promise.resolve();
}
- show(path, options) {
+ async back() {
+ if (this.promiseShow) await this.promiseShow;
+
+ this.promiseShow = new Promise((resolve) => {
+ this.resolveOnNextShow = resolve;
+ page.back();
+ });
+
+ return this.promiseShow;
+ }
+
+ async show(path, options) {
+ if (this.promiseShow) await this.promiseShow;
+
// ensure the path does not start with '#!' since the router adds this
if (path.startsWith('#!')) {
path = path.substring(2);
@@ -146,17 +160,25 @@ class AppRouter {
}
}
- return new Promise((resolve) => {
+ this.promiseShow = new Promise((resolve) => {
this.resolveOnNextShow = resolve;
- page.show(path, options);
+ // Schedule a call to return the promise
+ setTimeout(() => page.show(path, options), 0);
});
+
+ return this.promiseShow;
}
- showDirect(path) {
- return new Promise(function(resolve) {
+ async showDirect(path) {
+ if (this.promiseShow) await this.promiseShow;
+
+ this.promiseShow = new Promise((resolve) => {
this.resolveOnNextShow = resolve;
- page.show(this.baseUrl() + path);
+ // Schedule a call to return the promise
+ setTimeout(() => page.show(this.baseUrl() + path), 0);
});
+
+ return this.promiseShow;
}
start(options) {
@@ -414,6 +436,7 @@ class AppRouter {
onViewShow() {
const resolve = this.resolveOnNextShow;
if (resolve) {
+ this.promiseShow = null;
this.resolveOnNextShow = null;
resolve();
}
diff --git a/src/components/confirm/confirm.js b/src/components/confirm/confirm.js
index 1978324e7c..7fe7fb9832 100644
--- a/src/components/confirm/confirm.js
+++ b/src/components/confirm/confirm.js
@@ -1,3 +1,4 @@
+import { appRouter } from '../appRouter';
import browser from '../../scripts/browser';
import dialog from '../dialog/dialog';
import globalize from '../../scripts/globalize';
@@ -6,7 +7,7 @@ function replaceAll(str, find, replace) {
return str.split(find).join(replace);
}
-function nativeConfirm(options) {
+async function nativeConfirm(options) {
if (typeof options === 'string') {
options = {
title: '',
@@ -15,6 +16,7 @@ function nativeConfirm(options) {
}
const text = replaceAll(options.text || '', '
', '\n');
+ await appRouter.ready();
const result = window.confirm(text);
if (result) {
diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js
index 8a6a22fd15..fbaf86a024 100644
--- a/src/components/dialogHelper/dialogHelper.js
+++ b/src/components/dialogHelper/dialogHelper.js
@@ -184,7 +184,9 @@ import '../../assets/css/scrollstyles.scss';
return dlg.getAttribute('data-history') === 'true';
}
- export function open(dlg) {
+ export async function open(dlg) {
+ await appRouter.ready();
+
if (globalOnOpenCallback) {
globalOnOpenCallback(dlg);
}
diff --git a/src/components/htmlMediaHelper.js b/src/components/htmlMediaHelper.js
index da53d6a063..82d6d790bc 100644
--- a/src/components/htmlMediaHelper.js
+++ b/src/components/htmlMediaHelper.js
@@ -185,6 +185,12 @@ import { Events } from 'jellyfin-apiclient';
return Promise.resolve();
}
+ export function resetSrc(elem) {
+ elem.src = '';
+ elem.innerHTML = '';
+ elem.removeAttribute('src');
+ }
+
function onSuccessfulPlay(elem, onErrorFn) {
elem.addEventListener('error', onErrorFn);
}
@@ -344,9 +350,7 @@ import { Events } from 'jellyfin-apiclient';
export function onEndedInternal(instance, elem, onErrorFn) {
elem.removeEventListener('error', onErrorFn);
- elem.src = '';
- elem.innerHTML = '';
- elem.removeAttribute('src');
+ resetSrc(elem);
destroyHlsPlayer(instance);
destroyFlvPlayer(instance);
diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js
index df84b072ae..85da076c5d 100644
--- a/src/components/playback/playbackmanager.js
+++ b/src/components/playback/playbackmanager.js
@@ -3064,7 +3064,9 @@ class PlaybackManager {
const data = getPlayerData(player);
const streamInfo = data.streamInfo;
- const nextItem = self._playNextAfterEnded ? self._playQueueManager.getNextItemInfo() : null;
+ const errorOccurred = displayErrorCode && typeof (displayErrorCode) === 'string';
+
+ const nextItem = self._playNextAfterEnded && !errorOccurred ? self._playQueueManager.getNextItemInfo() : null;
const nextMediaType = (nextItem ? nextItem.item.MediaType : null);
@@ -3101,17 +3103,15 @@ class PlaybackManager {
const newPlayer = nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null;
if (newPlayer !== player) {
+ data.streamInfo = null;
destroyPlayer(player);
removeCurrentPlayer(player);
}
- if (displayErrorCode && typeof (displayErrorCode) === 'string') {
+ if (errorOccurred) {
showPlaybackInfoErrorMessage(self, 'PlaybackError' + displayErrorCode);
} else if (nextItem) {
self.nextTrack();
- } else {
- // Nothing more to play - clear data
- data.streamInfo = null;
}
}
diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js
index 1e7d47f099..baa396dbb8 100644
--- a/src/plugins/htmlAudioPlayer/plugin.js
+++ b/src/plugins/htmlAudioPlayer/plugin.js
@@ -105,8 +105,6 @@ class HtmlAudioPlayer {
};
function setCurrentSrc(elem, options) {
- elem.removeEventListener('error', onError);
-
unBindEvents(elem);
bindEvents(elem);
@@ -184,6 +182,7 @@ class HtmlAudioPlayer {
elem.removeEventListener('playing', onPlaying);
elem.removeEventListener('play', onPlay);
elem.removeEventListener('waiting', onWaiting);
+ elem.removeEventListener('error', onError); // bound in htmlMediaHelper
}
self.stop = function (destroyPlayer) {
@@ -222,6 +221,7 @@ class HtmlAudioPlayer {
self.destroy = function () {
unBindEvents(self._mediaElement);
+ htmlMediaHelper.resetSrc(self._mediaElement);
};
function createMediaElement() {
diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js
index eeef1d5181..e4692e5971 100644
--- a/src/plugins/htmlVideoPlayer/plugin.js
+++ b/src/plugins/htmlVideoPlayer/plugin.js
@@ -13,6 +13,7 @@ import {
getCrossOriginValue,
enableHlsJsPlayer,
applySrc,
+ resetSrc,
playWithPromise,
onEndedInternal,
saveVolume,
@@ -708,6 +709,9 @@ function tryRemoveElement(elem) {
videoElement.removeEventListener('click', this.onClick);
videoElement.removeEventListener('dblclick', this.onDblClick);
videoElement.removeEventListener('waiting', this.onWaiting);
+ videoElement.removeEventListener('error', this.onError); // bound in htmlMediaHelper
+
+ resetSrc(videoElement);
videoElement.parentNode.removeChild(videoElement);
}