eirtube/html/static/js/custom-captions.js
2024-12-19 18:49:09 -06:00

140 lines
3.6 KiB
JavaScript
Executable File

const video = document.getElementsByClassName("video")[0]
video.classList.add("hasCustomCaptions")
// Elements
const customStyle = document.createElement("style")
customStyle.setAttribute("type", "text/css")
document.head.appendChild(customStyle)
const captionBox = document.createElement("div")
captionBox.className = "caption-box"
video.parentNode.appendChild(captionBox)
const captionInner = document.createElement("div")
captionInner.className = "caption-inner"
captionBox.appendChild(captionInner)
// Parseing
const regexVVTSource = /::cue\(([^\. \)])+([^\)]*)\)/g
const regexCueText = /<([^\. />]+)([^>]+?)>/g
function parseVVTSource(s) {
s = s.split("\nStyle:\n")[1].split("\n##\n")[0]
for (const match of s.matchAll(regexVVTSource)) {
const wholeSelector = match[0]
const className = match[1]
const details = match[2] || null
s = s.replace(wholeSelector, `.caption-box .cue-container ${className}${details ? `[data-details="${details}"]` : ""}`)
}
return s
}
function parseCueText(t) {
if (!t)
return t
for (const match of t.matchAll(regexCueText)) {
const wholeElement = match[0]
const className = match[1]
const details = match[2]
t = t.replace(wholeElement, `<${className} data-details="${details}">`)
}
return t
}
// Detect caption switching
let lastTrack = null
for (const track of video.textTracks) {
track.sourceElement = video.querySelector(`track[label="${track.label}"]`)
function parseCaptionStyle(raw) {
if (raw.indexOf("\nStyle:\n") > -1)
return parseVVTSource(raw)
return null
}
function applyCaptionStyle(track) {
customStyle.innerHTML = track.style
}
// Eugh
track.addEventListener("cuechange", () => {
lastTrack = track
if (track.raw == undefined) {
fetch(track.sourceElement.src)
.then(r => r.text()).then(r => {
track.style = parseCaptionStyle(r)
if (lastTrack == track && track.style)
applyCaptionStyle(track)
})
} else if (track.style)
applyCaptionStyle(track)
})
}
// Functionality
for (const track of video.textTracks)
track.addEventListener("cuechange", () => {
// Remove previous cues TODO: also do when captions turned off
captionInner.innerHTML = ""
let cues = []
for (const c of track.activeCues) {
const cueContainer = document.createElement("div")
cueContainer.className = "cue-container"
captionInner.appendChild(cueContainer)
cueContainer.innerHTML = parseCueText(c.text)
console.log(c)
// align: "center"
// line: "auto"
// lineAlign: "start"
// position: "auto" / 89
// positionAlign: "auto"
// size: 100
// snapToLines: true
//
// console.log(c.position)
// cueContainer.style.position = c.position == "auto" ? "auto" : `${c.position}%`
const asHTML = c.getCueAsHTML()
// console.log(track.sourceElement)
console.log(asHTML)
cueContainer.style.textAlign = c.align
/*
position: absolute;
writing-mode: horizontal-tb;
top: 86.2709%;
left: 78%;
width: 22%;
height: auto;
overflow-wrap: break-word;
white-space: pre-line;
font: 53.9px sans-serif;
color: rgb(255, 255, 255);
text-align: center;
unicode-bidi: plaintext;
*/
// for (const child of asHTML.children)
// cueContainer.appendChild(child.cloneNode(true))
// captionInner.innerHTML = c.getCueAsHTML()
// const cue = document.createElement("span")
// cue.className = "cue"
// cueContainer.appendChild(cue)
// console.log(`NEW CUE:\n${c.align}, ${c.line}, ${c.lineAlign}, ${c.position}, ${c.positionAlign}, ${c.region}, ${c.size}, ${c.snapToLines}, ${c.text}, ${c.vertical}`)
// console.log(c.getCueAsHTML())
}
// captionRow.innerText = "hi"
})