mirror of
https://github.com/ThaUnknown/miru.git
synced 2026-04-12 22:40:20 +00:00
108 lines
No EOL
6.1 KiB
JavaScript
108 lines
No EOL
6.1 KiB
JavaScript
const { SubtitleStream } = MatroskaSubtitles
|
|
const { SubtitleParser } = MatroskaSubtitles
|
|
|
|
function subStream(stream) { // subtitle parsing with seeking support
|
|
if (playerData.subtitleStream) {
|
|
playerData.subtitleStream = new SubtitleStream(playerData.subtitleStream)
|
|
} else {
|
|
playerData.subtitleStream = new SubtitleStream()
|
|
playerData.subtitleStream.once('tracks', pTracks => {
|
|
bcap.removeAttribute("disabled")
|
|
playerData.headers = []
|
|
pTracks.forEach(track => {
|
|
if (track.type != "ass") { // overwrite webvtt header with custom one
|
|
track.header = `[V4+ Styles]
|
|
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
|
Style: Default,${Object.values(subtitle1list.options).filter(item => item.value == settings.subtitle1)[0].innerText}
|
|
`
|
|
}
|
|
playerData.headers[track.number] = track
|
|
playerData.subtitles[track.number] = new Set()
|
|
if (!playerData.selectedHeader) playerData.selectedHeader = track.number
|
|
})
|
|
})
|
|
}
|
|
playerData.subtitleStream.on('subtitle', (subtitle, trackNumber) => {
|
|
if (playerData.headers && !playerData.parsed) {
|
|
if (playerData.headers[trackNumber].type == "webvtt") convertSub(subtitle)
|
|
let formatSub = "Dialogue: " + (subtitle.layer || 0) + "," + new Date(subtitle.time).toISOString().slice(12, -1).slice(0, -1) + "," + new Date(subtitle.time + subtitle.duration).toISOString().slice(12, -1).slice(0, -1) + "," + (subtitle.style || "Default") + "," + (subtitle.name || "") + "," + (subtitle.marginL || "0") + "," + (subtitle.marginR || "0") + "," + (subtitle.marginV || "0") + "," + (subtitle.effect || "") + "," + subtitle.text
|
|
if (!playerData.subtitles[trackNumber].has(formatSub)) {
|
|
playerData.subtitles[trackNumber].add(formatSub)
|
|
if (playerData.selectedHeader == trackNumber)
|
|
renderSubs.call(null, trackNumber)
|
|
}
|
|
}
|
|
|
|
})
|
|
playerData.subtitleStream.on('file', file => {
|
|
if (file.mimetype == ("application/x-truetype-font" || "application/font-woff")) playerData.fonts.push(window.URL.createObjectURL(new Blob([file.data], { type: file.mimetype })))
|
|
})
|
|
stream.pipe(playerData.subtitleStream)
|
|
}
|
|
let octopusTimeout
|
|
function renderSubs(trackNumber) {
|
|
if (!playerData.octopusInstance) {
|
|
let options = {
|
|
video: video,
|
|
subContent: trackNumber ? playerData.headers[trackNumber].header.slice(0, -1) + Array.from(playerData.subtitles[trackNumber]).join("\n") : playerData.headers[3].header.slice(0, -1),
|
|
lossyRender: true,
|
|
fonts: playerData.fonts.length == 0 ? ["https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc4.woff2"] : playerData.fonts,
|
|
workerUrl: 'js/subtitles-octopus-worker.js',
|
|
debug: true,
|
|
timeOffset: 0
|
|
};
|
|
playerData.octopusInstance = new SubtitlesOctopus(options);
|
|
} else {
|
|
if (!octopusTimeout) {
|
|
octopusTimeout = setTimeout(() => {
|
|
octopusTimeout = undefined
|
|
if (playerData.octopusInstance) playerData.octopusInstance.setTrack(trackNumber ? playerData.headers[trackNumber].header.slice(0, -1) + Array.from(playerData.subtitles[trackNumber]).join("\n") : playerData.headers[3].header.slice(0, -1))
|
|
}, 1000)
|
|
}
|
|
}
|
|
}
|
|
function convertSub(subtitle) { // converts vtt subtitles to ssa ones
|
|
let matches = subtitle.text.match(/<[^>]+>/g); // create array of all tags
|
|
if (matches)
|
|
matches.forEach(match => {
|
|
if (/<\//.test(match)) { // check if its a closing tag
|
|
subtitle.text = subtitle.text.replace(match, match.replace("</", "{\\").replace(">", "0}"))
|
|
} else {
|
|
subtitle.text = subtitle.text.replace(match, match.replace("<", "{\\").replace(">", "1}"))
|
|
}
|
|
})
|
|
//replace all html special tags with normal ones
|
|
subtitle.text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/ /g, "\\h")
|
|
}
|
|
function postDownload(file) { // parse subtitles fully after a download is finished
|
|
if (file.name.endsWith(".mkv") || file.name.endsWith(".webm")) {
|
|
let parser = new SubtitleParser(),
|
|
subtitles = [],
|
|
headers = []
|
|
parser.once('tracks', pTracks => {
|
|
pTracks.forEach(track => {
|
|
if (track.type != "ass") { // overwrite webvtt header with custom one
|
|
track.header = `[V4+ Styles]
|
|
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
|
Style: Default,${Object.values(subtitle1list.options).filter(item => item.value == settings.subtitle1)[0].innerText}
|
|
`
|
|
}
|
|
headers[track.number] = track
|
|
subtitles[track.number] = new Set()
|
|
})
|
|
})
|
|
parser.on('subtitle', (subtitle, trackNumber) => {
|
|
if (headers[trackNumber].type == "webvtt") convertSub(subtitle)
|
|
subtitles[trackNumber].add("Dialogue: " + (subtitle.layer || 0) + "," + new Date(subtitle.time).toISOString().slice(12, -1).slice(0, -1) + "," + new Date(subtitle.time + subtitle.duration).toISOString().slice(12, -1).slice(0, -1) + "," + (subtitle.style || "Default") + "," + (subtitle.name || "") + "," + (subtitle.marginL || "0") + "," + (subtitle.marginR || "0") + "," + (subtitle.marginV || "0") + "," + (subtitle.effect || "") + "," + subtitle.text)
|
|
})
|
|
parser.on('finish', () => {
|
|
playerData.subtitles = subtitles
|
|
playerData.headers = headers
|
|
playerData.parsed = 1
|
|
playerData.subtitleStream = undefined
|
|
renderSubs.call(null, playerData.selectedHeader)
|
|
parser = undefined
|
|
});
|
|
file.createReadStream().pipe(parser)
|
|
}
|
|
} |