mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-28 18:41:20 -08:00
fix(multiple-subtitles): render overlapping cues on legacy hosts [PKG-MULTI-SUB-10]
This commit is contained in:
1 parent
31f9024bff
commit
8ae2762a23
24 files changed
+3465
-56
No files matched your search
@@ -1,11 +1,15 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Lifetime } from './types'
|
||||
import type { CaptionHost, Lifetime } from './types'
|
||||
import renderLegacyCaptions from './legacy-caption'
|
||||
import { TIMESTAMP_CLASS } from './merge'
|
||||
|
||||
export default function installCaptionView(art: Pick<Artplayer, 'on' | 'off' | 'template'>, lifetime: Lifetime): void {
|
||||
export default function installCaptionView(art: CaptionHost, lifetime: Lifetime): void {
|
||||
const legacy = !!art.subtitle && 'activeCue' in art.subtitle && !('activeCues' in art.subtitle)
|
||||
const event = legacy ? 'subtitleUpdate' : 'subtitleAfterUpdate'
|
||||
function update(): void {
|
||||
if (lifetime.closed)
|
||||
return
|
||||
if (legacy)
|
||||
renderLegacyCaptions(art)
|
||||
// HTML does not pair <c.class> with </c>; unwrap while preserving following caption nodes.
|
||||
for (const marker of Array.from(art.template.$subtitle.getElementsByTagName(`c.${TIMESTAMP_CLASS}`))) {
|
||||
const first = marker.firstChild
|
||||
@@ -16,6 +20,6 @@ export default function installCaptionView(art: Pick<Artplayer, 'on' | 'off' | '
|
||||
}
|
||||
if (lifetime.closed)
|
||||
return
|
||||
lifetime.own(() => art.off('subtitleAfterUpdate', update))
|
||||
art.on('subtitleAfterUpdate', update)
|
||||
lifetime.own(() => art.off(event, update))
|
||||
art.on(event, update)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { CaptionHost } from './types'
|
||||
|
||||
export default function renderLegacyCaptions(art: CaptionHost): void {
|
||||
const cues = art.subtitle?.textTrack?.activeCues
|
||||
if (!cues || cues.length < 2)
|
||||
return
|
||||
|
||||
const texts = Array.from(cues, cue => 'text' in cue && typeof cue.text === 'string' ? cue.text : '')
|
||||
const target = art.template.$subtitle
|
||||
if (art.option?.subtitle?.escape) {
|
||||
target.innerHTML = ''
|
||||
for (const text of texts) {
|
||||
for (const line of text.split(/\r?\n/)) {
|
||||
const element = target.ownerDocument.createElement('div')
|
||||
element.className = 'art-subtitle-line'
|
||||
element.textContent = line
|
||||
target.appendChild(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
target.innerHTML = texts.join('')
|
||||
}
|
||||
}
|
||||
@@ -34,13 +34,16 @@ export function serializeTracks(trees: readonly (Track | undefined)[]): string {
|
||||
for (const cue of tree.cues) {
|
||||
const children: CueNode[] = []
|
||||
for (const child of cue.tree.children) {
|
||||
if (child.type === 'timestamp')
|
||||
if (child.type === 'timestamp') {
|
||||
children.push(markTimestamp(child))
|
||||
else children.push(
|
||||
{ type: 'text', value: `<div class="art-subtitle-${tree.name}">` },
|
||||
prepareCueNode(child),
|
||||
{ type: 'text', value: '</div>' },
|
||||
)
|
||||
}
|
||||
else {
|
||||
children.push(
|
||||
{ type: 'text', value: `<div class="art-subtitle-${tree.name}">` },
|
||||
prepareCueNode(child),
|
||||
{ type: 'text', value: '</div>' },
|
||||
)
|
||||
}
|
||||
}
|
||||
cues.push({
|
||||
...cue,
|
||||
|
||||
@@ -18,6 +18,11 @@ export interface Lifetime {
|
||||
dispose: Cleanup
|
||||
}
|
||||
export type LifetimeHost = Pick<Artplayer, 'isDestroy' | 'on' | 'off'>
|
||||
export interface CaptionHost extends Pick<Artplayer, 'on' | 'off'> {
|
||||
template: { $subtitle: HTMLElement }
|
||||
option?: { subtitle?: { escape?: boolean } }
|
||||
subtitle?: { readonly textTrack?: TextTrack }
|
||||
}
|
||||
export interface RenderHost {
|
||||
option: { subtitle?: Subtitle }
|
||||
subtitle: { init: (option: Subtitle) => unknown }
|
||||
|
||||
Reference in new issue
Block a user