mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-26 17:01:20 -08:00
fix(multiple-subtitles): [PKG-MULTI-SUB-08] preserve entity text and semantic cue wrappers
This commit is contained in:
1 parent
4acf85ea69
commit
675b095b27
22 files changed
+744
-59
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import type { Cue, CueNode, TimestampNode, WrappedNode } from './parser'
|
||||
import type { Track, TrackOption } from './types'
|
||||
import { WebVTTParser, WebVTTSerializer } from './parser'
|
||||
import { cueEntities, escapeCueText } from './text'
|
||||
|
||||
export const TIMESTAMP_CLASS = 'artplayer-multiple-subtitles-timestamp'
|
||||
|
||||
@@ -8,16 +9,16 @@ function markTimestamp(node: TimestampNode): CueNode {
|
||||
return { type: 'object', name: 'c', classes: [TIMESTAMP_CLASS], children: [node] }
|
||||
}
|
||||
|
||||
function markNestedTimestamps(node: CueNode): CueNode {
|
||||
function prepareCueNode(node: CueNode): CueNode {
|
||||
if (node.type === 'timestamp')
|
||||
return markTimestamp(node)
|
||||
if (node.type === 'object')
|
||||
return { ...node, children: node.children.map(markNestedTimestamps) }
|
||||
return node
|
||||
return { ...node, children: node.children.map(prepareCueNode) }
|
||||
return { ...node, value: escapeCueText(node.value) }
|
||||
}
|
||||
|
||||
export function parseTracks(vtts: readonly string[], subtitles: readonly TrackOption[]): Track[] {
|
||||
const parser = new WebVTTParser()
|
||||
const parser = new WebVTTParser(cueEntities)
|
||||
return vtts.map((vtt, index) => {
|
||||
const tree = parser.parse(vtt, 'metadata')
|
||||
// Options and completed downloads share the same Promise.all index.
|
||||
@@ -31,18 +32,21 @@ export function serializeTracks(trees: readonly (Track | undefined)[]): string {
|
||||
// Unknown names retain the historical TypeError at the property access below.
|
||||
const tree = selected!
|
||||
for (const cue of tree.cues) {
|
||||
const children: CueNode[] = []
|
||||
for (const child of cue.tree.children) {
|
||||
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>' },
|
||||
)
|
||||
}
|
||||
cues.push({
|
||||
...cue,
|
||||
tree: {
|
||||
...cue.tree,
|
||||
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 }
|
||||
}),
|
||||
children,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Keep the vendor's lenient aliases while making complete named references exact.
|
||||
export const cueEntities = {
|
||||
'&': '&',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'>': '>',
|
||||
'&lrm': '\u200E',
|
||||
'‎': '\u200E',
|
||||
'&rlm': '\u200F',
|
||||
'‏': '\u200F',
|
||||
' ': '\u00A0',
|
||||
' ': '\u00A0',
|
||||
}
|
||||
|
||||
// Serialization protects the whole VTT once; this protects cue text after onVttLoad unescape.
|
||||
export function escapeCueText(value: string): string {
|
||||
return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
}
|
||||
Reference in new issue
Block a user