mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-20 04:01:20 -08:00
fix(core): [CORE-24] preserve source playback intent and explicit pauses
This commit is contained in:
1 parent
b5e96664ee
commit
0218196df9
22 files changed
+12895
-36
No files matched your search
@@ -6,6 +6,9 @@ export interface SourceOperation {
|
||||
scope: ResourceScope
|
||||
assigned: boolean
|
||||
acceptingEvents: boolean
|
||||
pauseRevision: number
|
||||
resumePlaying?: boolean
|
||||
internalPause?: boolean
|
||||
onAssigned?: () => void
|
||||
onError?: (error: unknown) => void
|
||||
active: () => boolean
|
||||
@@ -15,6 +18,25 @@ const current = new WeakMap<object, SourceOperation>()
|
||||
const assignments = new WeakMap<object, SourceOperation>()
|
||||
const sources = new WeakMap<object, ResourceScope>()
|
||||
|
||||
export function sourcePlaybackIntent(owner: object): boolean | undefined {
|
||||
const operation = current.get(owner)
|
||||
return operation?.active() ? operation.resumePlaying : undefined
|
||||
}
|
||||
|
||||
export function requestSourcePlayback(owner: object, playing: boolean): void {
|
||||
const operation = current.get(owner)
|
||||
if (!operation?.active() || operation.resumePlaying === undefined)
|
||||
return
|
||||
if (!playing && operation.internalPause) {
|
||||
operation.internalPause = false
|
||||
}
|
||||
else {
|
||||
operation.resumePlaying = playing
|
||||
if (!playing)
|
||||
operation.pauseRevision++
|
||||
}
|
||||
}
|
||||
|
||||
export function getSourceScope(owner: object): ResourceScope {
|
||||
return sources.get(owner) || getScope(owner)
|
||||
}
|
||||
@@ -26,6 +48,13 @@ export function captureSource(owner: object): () => boolean {
|
||||
&& sources.get(owner) === source && (!source || !source.closed)
|
||||
}
|
||||
|
||||
export function captureSourcePlayback(owner: object): () => boolean {
|
||||
const active = captureSource(owner)
|
||||
const operation = current.get(owner)
|
||||
const revision = operation?.pauseRevision
|
||||
return () => active() && operation?.pauseRevision === revision
|
||||
}
|
||||
|
||||
export function beginSource(owner: object): SourceOperation {
|
||||
const previous = sources.get(owner)
|
||||
const source = getScope(owner).child()
|
||||
@@ -39,6 +68,7 @@ export function beginSource(owner: object): SourceOperation {
|
||||
scope,
|
||||
assigned: false,
|
||||
acceptingEvents: false,
|
||||
pauseRevision: 0,
|
||||
active: () => !isClosing(owner) && !scope.closed && current.get(owner) === operation,
|
||||
}
|
||||
current.set(owner, operation)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { SourceEvent, SourceListener, SwitchHost } from './types'
|
||||
import type { SourceListener, SwitchHost } from './types'
|
||||
import { isClosing } from '../lifecycle/instance'
|
||||
import { listenSource } from './listen'
|
||||
import { assignUrl, beginSource } from './operation'
|
||||
import { assignUrl, beginSource, sourcePlaybackIntent } from './operation'
|
||||
import { positionRestoration } from './restore-position'
|
||||
|
||||
export function switchSource(art: SwitchHost, url: string, currentTime: number): Promise<void> {
|
||||
@@ -10,13 +10,16 @@ export function switchSource(art: SwitchHost, url: string, currentTime: number):
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
const playing = sourcePlaybackIntent(art) ?? art.playing
|
||||
const operation = beginSource(art)
|
||||
operation.resumePlaying = playing
|
||||
const scope = operation.scope.child()
|
||||
let settled = false
|
||||
const settle = (failed = false, error?: unknown) => {
|
||||
if (settled)
|
||||
return
|
||||
settled = true
|
||||
operation.resumePlaying = undefined
|
||||
operation.onError = undefined
|
||||
operation.onAssigned = undefined
|
||||
scope.dispose()
|
||||
@@ -34,8 +37,14 @@ export function switchSource(art: SwitchHost, url: string, currentTime: number):
|
||||
const fail = (error: unknown) => settle(true, error)
|
||||
operation.onError = fail
|
||||
try {
|
||||
const { playing, aspectRatio, playbackRate } = art
|
||||
art.pause()
|
||||
const { aspectRatio, playbackRate } = art
|
||||
operation.internalPause = true
|
||||
try {
|
||||
art.pause()
|
||||
}
|
||||
finally {
|
||||
operation.internalPause = false
|
||||
}
|
||||
if (!active())
|
||||
return
|
||||
|
||||
@@ -45,10 +54,11 @@ export function switchSource(art: SwitchHost, url: string, currentTime: number):
|
||||
let rateRestored = false
|
||||
const position = positionRestoration(art, currentTime, active)
|
||||
const resume = async () => {
|
||||
const pauseRevision = operation.pauseRevision
|
||||
art.aspectRatio = aspectRatio
|
||||
if (!active())
|
||||
return
|
||||
if (playing) {
|
||||
if (operation.resumePlaying) {
|
||||
// The public play promise still rejects; this internal resume is best effort.
|
||||
try {
|
||||
await art.play()
|
||||
@@ -57,7 +67,8 @@ export function switchSource(art: SwitchHost, url: string, currentTime: number):
|
||||
}
|
||||
if (!active())
|
||||
return
|
||||
art.notice.show = ''
|
||||
if (operation.pauseRevision === pauseRevision)
|
||||
art.notice.show = ''
|
||||
settle()
|
||||
}
|
||||
const resumeWhenReady = () => {
|
||||
@@ -103,8 +114,8 @@ export function switchSource(art: SwitchHost, url: string, currentTime: number):
|
||||
'seek': position.manual,
|
||||
}
|
||||
const capture = scope.child()
|
||||
const queued: [SourceEvent, unknown][] = []
|
||||
const names = Object.keys(handlers) as SourceEvent[]
|
||||
const queued: [keyof typeof handlers, unknown][] = []
|
||||
const names = Object.keys(handlers) as (keyof typeof handlers)[]
|
||||
for (const name of names) {
|
||||
listenSource(capture, art, name, (event) => {
|
||||
if (operation.acceptingEvents)
|
||||
@@ -123,7 +134,7 @@ export function switchSource(art: SwitchHost, url: string, currentTime: number):
|
||||
settle()
|
||||
return
|
||||
}
|
||||
const dispatch = {} as Record<SourceEvent, SourceListener>
|
||||
const dispatch = {} as Record<keyof typeof handlers, SourceListener>
|
||||
for (const name of names)
|
||||
dispatch[name] = listenSource(readiness, art, name, handlers[name], name !== 'video:seeked')
|
||||
for (const [name, event] of queued) {
|
||||
|
||||
Reference in new issue
Block a user