From d55527817ebee2f966a3a60fcdb8c2f6a6f9a78b Mon Sep 17 00:00:00 2001 From: absidue <48293849+absidue@users.noreply.github.com> Date: Thu, 21 Nov 2024 01:43:39 +0100 Subject: [PATCH] Better player error handling (#6180) * Better player error handling * Fix format switching * Fix legacy quality handling --- .../ft-shaka-video-player.js | 70 ++++++++++++++----- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js index 074739caf03a1..a361dd8eba051 100644 --- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js +++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js @@ -1252,24 +1252,21 @@ export default defineComponent({ } /** - * @param {'dash'|'audio'|null} previousFormat * @param {number|null} playbackPosition + * @param {number|undefined} previousQuality */ - async function setLegacyQuality(previousFormat = null, playbackPosition = null) { + async function setLegacyQuality(playbackPosition = null, previousQuality = undefined) { + if (typeof previousQuality === 'undefined') { + if (defaultQuality.value === 'auto') { + previousQuality = Infinity + } else { + previousQuality = defaultQuality.value + } + } + /** @type {object[]} */ const legacyFormats = props.legacyFormats - let previousQuality - if (previousFormat === 'dash') { - const previousTrack = player.getVariantTracks().find(track => track.active) - - previousQuality = previousTrack.height > previousTrack.width ? previousTrack.width : previousTrack.height - } else if (defaultQuality.value === 'auto') { - previousQuality = Infinity - } else { - previousQuality = defaultQuality.value - } - const isPortrait = legacyFormats[0].height > legacyFormats[0].width let matches = legacyFormats.filter(variant => { @@ -2147,17 +2144,28 @@ export default defineComponent({ // #endregion keyboard shortcuts + let ignoreErrors = false + /** * @param {shaka.util.Error} error * @param {string} context * @param {object?} details */ function handleError(error, context, details) { + // These two errors are just wrappers around another error, so use the original error instead + // As they can be nested (e.g. multiple googlevideo redirects because the Invidious server was far away from the user) we should pick the inner most one + while (error.code === shaka.util.Error.Code.REQUEST_FILTER_ERROR || error.code === shaka.util.Error.Code.RESPONSE_FILTER_ERROR) { + error = error.data[0] + } + logShakaError(error, context, props.videoId, details) // text related errors aren't serious (captions and seek bar thumbnails), so we should just log them // TODO: consider only emitting when the severity is crititcal? - if (error.category !== shaka.util.Error.Category.TEXT) { + if (!ignoreErrors && error.category !== shaka.util.Error.Category.TEXT) { + // don't react to multiple consecutive errors, otherwise we don't give the format fallback from the previous error a chance to work + ignoreErrors = true + emit('error', error) stopPowerSaveBlocker() @@ -2414,7 +2422,7 @@ export default defineComponent({ handleError(error, 'loading dash/audio manifest and setting default quality in mounted') } } else { - await setLegacyQuality(null, props.startTime) + await setLegacyQuality(props.startTime) } } @@ -2532,9 +2540,17 @@ export default defineComponent({ * @param {'dash'|'audio'|'legacy'} oldFormat */ async (newFormat, oldFormat) => { + ignoreErrors = true + // format switch happened before the player loaded, probably because of an error // as there are no previous player settings to restore, we should treat it like this was the original format if (!hasLoaded.value) { + try { + await player.unload() + } catch { } + + ignoreErrors = false + player.configure(getPlayerConfig(newFormat, defaultQuality.value === 'auto')) await performFirstLoad() @@ -2597,6 +2613,12 @@ export default defineComponent({ } } + try { + await player.unload() + } catch { } + + ignoreErrors = false + player.configure(getPlayerConfig(newFormat, useAutoQuality)) try { @@ -2634,7 +2656,21 @@ export default defineComponent({ } activeLegacyFormat.value = null } else { - await setLegacyQuality(oldFormat, playbackPosition) + let previousQuality + + if (oldFormat === 'dash') { + const previousTrack = player.getVariantTracks().find(track => track.active) + + previousQuality = previousTrack.height > previousTrack.width ? previousTrack.width : previousTrack.height + } + + try { + await player.unload() + } catch { } + + ignoreErrors = false + + await setLegacyQuality(playbackPosition, previousQuality) } if (wasPaused) { @@ -2702,6 +2738,8 @@ export default defineComponent({ * To workaround that we destroy the player first and wait for it to finish before we unmount this component. */ async function destroyPlayer() { + ignoreErrors = true + if (ui) { // destroying the ui also destroys the player await ui.destroy()