mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-27 01:21:20 -08:00
fix(multiple-subtitles): [PKG-MULTI-SUB-07] preserve inline timestamps and caption text
This commit is contained in:
1 parent
da64aae267
commit
7f226ff822
24 files changed
+8660
-132
No files matched your search
@@ -0,0 +1,21 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Lifetime } from './types'
|
||||
import { TIMESTAMP_CLASS } from './merge'
|
||||
|
||||
export default function installCaptionView(art: Pick<Artplayer, 'on' | 'off' | 'template'>, lifetime: Lifetime): void {
|
||||
function update(): void {
|
||||
if (lifetime.closed)
|
||||
return
|
||||
// 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
|
||||
if (first?.nodeType === 3)
|
||||
first.nodeValue = (first.nodeValue || '').replace(/^<(?:\d+:)?\d{2}:\d{2}\.\d{3}>/, '')
|
||||
marker.replaceWith(...Array.from(marker.childNodes))
|
||||
}
|
||||
}
|
||||
if (lifetime.closed)
|
||||
return
|
||||
lifetime.own(() => art.off('subtitleAfterUpdate', update))
|
||||
art.on('subtitleAfterUpdate', update)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Option, Result, Track } from './types'
|
||||
import installCaptionView from './caption'
|
||||
import createLifetime from './lifetime'
|
||||
import { parseTracks, serializeTracks } from './merge'
|
||||
import createRenderer from './render'
|
||||
@@ -33,6 +34,7 @@ export default function artplayerPluginMultipleSubtitles({ subtitles = [] }: Opt
|
||||
return result
|
||||
// A live completed request yields text; cancellation was checked above.
|
||||
trees = parseTracks(vtts as string[], subtitles)
|
||||
installCaptionView(art, lifetime)
|
||||
setTracks(trees)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
import type { Cue, WrappedNode } from './parser'
|
||||
import type { Cue, CueNode, TimestampNode, WrappedNode } from './parser'
|
||||
import type { Track, TrackOption } from './types'
|
||||
import { WebVTTParser, WebVTTSerializer } from './parser'
|
||||
|
||||
export const TIMESTAMP_CLASS = 'artplayer-multiple-subtitles-timestamp'
|
||||
|
||||
function markTimestamp(node: TimestampNode): CueNode {
|
||||
return { type: 'object', name: 'c', classes: [TIMESTAMP_CLASS], children: [node] }
|
||||
}
|
||||
|
||||
function markNestedTimestamps(node: CueNode): CueNode {
|
||||
if (node.type === 'timestamp')
|
||||
return markTimestamp(node)
|
||||
if (node.type === 'object')
|
||||
return { ...node, children: node.children.map(markNestedTimestamps) }
|
||||
return node
|
||||
}
|
||||
|
||||
export function parseTracks(vtts: readonly string[], subtitles: readonly TrackOption[]): Track[] {
|
||||
const parser = new WebVTTParser()
|
||||
return vtts.map((vtt, index) => {
|
||||
@@ -21,10 +35,14 @@ export function serializeTracks(trees: readonly (Track | undefined)[]): string {
|
||||
...cue,
|
||||
tree: {
|
||||
...cue.tree,
|
||||
children: cue.tree.children.map(child => ({
|
||||
...child,
|
||||
value: `<div class="art-subtitle-${tree.name}">${child.value}</div>`,
|
||||
})),
|
||||
children: cue.tree.children.map((child) => {
|
||||
if (child.type === 'timestamp')
|
||||
return markTimestamp(child)
|
||||
const value = `<div class="art-subtitle-${tree.name}">${child.value}</div>`
|
||||
return child.type === 'object'
|
||||
? { ...child, value, children: child.children.map(markNestedTimestamps) }
|
||||
: { ...child, value }
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ export interface TimestampNode {
|
||||
}
|
||||
|
||||
export type CueNode = TextNode | ObjectNode | TimestampNode
|
||||
// The historical plugin wraps every top-level value, including timestamp nodes.
|
||||
export type WrappedNode = TextNode | (Omit<ObjectNode, 'value'> & { value: string }) | { type: 'timestamp', value: string }
|
||||
export type WrappedNode = CueNode
|
||||
|
||||
export interface Cue<Node = CueNode> {
|
||||
id: string
|
||||
|
||||
Reference in new issue
Block a user