Fix download status handling and the blank page after download
- Never let a non-authoritative MeTube 'updated' event downgrade a terminal job (it refilled the progress bar after completion). - Self-heal stale active jobs against MeTube history on status polls, so a missed event no longer leaves a job stuck in 'queued'. - Build YT.Player on an imperatively created child div: React keeps owning the container, so switching to the local copy after a download no longer throws removeChild and blanks the page. - Autoplay on open and seek controls; subtitle experiment reverted.
This commit is contained in:
parent
b1faeb3729
commit
43adec5224
9 changed files with 758 additions and 5 deletions
|
|
@ -185,6 +185,7 @@ button, .button-primary, .button-secondary, .button-quiet, .button-danger { tran
|
|||
.player-wrapper iframe, .player-wrapper video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: #000; }
|
||||
.player-wrapper video { touch-action: manipulation; }
|
||||
.yt-player-host { position: absolute; inset: 0; }
|
||||
.yt-player-host > div { width: 100%; height: 100%; }
|
||||
.video-page-meta-row { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; margin: 11px 0 22px; }
|
||||
.video-page-meta-row .video-page-source { margin: 0; }
|
||||
.video-page-source { color: var(--muted); font-size: 12px; }
|
||||
|
|
|
|||
|
|
@ -153,12 +153,15 @@ function Player({ video }: Props) {
|
|||
}, [useLocal])
|
||||
|
||||
// YouTube-ветка: динамическая идемпотентная загрузка IFrame Player API,
|
||||
// создание YT.Player в host-div с nocookie-хостом, фолбэк на plain-iframe по таймауту.
|
||||
// создание YT.Player на императивном дочернем div в host-div (YT.Player заменяет
|
||||
// переданный элемент iframe'ом, React управляет только контейнером), nocookie-хост,
|
||||
// фолбэк на plain-iframe по таймауту.
|
||||
useEffect(() => {
|
||||
if (useLocal) return
|
||||
let cancelled = false
|
||||
let timedOut = false
|
||||
let timeoutId: number | null = null
|
||||
let child: HTMLDivElement | null = null
|
||||
ytPlayerRef.current?.destroy()
|
||||
ytPlayerRef.current = null
|
||||
|
||||
|
|
@ -167,6 +170,8 @@ function Player({ video }: Props) {
|
|||
timedOut = true
|
||||
ytPlayerRef.current?.destroy()
|
||||
ytPlayerRef.current = null
|
||||
if (child?.parentNode) child.remove()
|
||||
child = null
|
||||
if (!cancelled) setYtApiStatus('timeout')
|
||||
}, YT_API_TIMEOUT_MS)
|
||||
|
||||
|
|
@ -175,7 +180,9 @@ function Player({ video }: Props) {
|
|||
if (cancelled || timedOut || !window.YT?.Player) return
|
||||
const host = ytHostRef.current
|
||||
if (!host) return
|
||||
const player = new window.YT.Player(host, {
|
||||
child = document.createElement('div')
|
||||
host.appendChild(child)
|
||||
const player = new window.YT.Player(child, {
|
||||
videoId: video.youtube_video_id,
|
||||
host: 'https://www.youtube-nocookie.com',
|
||||
playerVars: { playsinline: 1, autoplay: 1 },
|
||||
|
|
@ -206,6 +213,8 @@ function Player({ video }: Props) {
|
|||
if (timeoutId !== null) window.clearTimeout(timeoutId)
|
||||
ytPlayerRef.current?.destroy()
|
||||
ytPlayerRef.current = null
|
||||
if (child?.parentNode) child.remove()
|
||||
child = null
|
||||
}
|
||||
}, [useLocal, video.youtube_video_id])
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue