From 7ba3098212e71d50a6677b5fd9e7356cb42c6a48 Mon Sep 17 00:00:00 2001 From: Harvey Zack Date: Fri, 24 Nov 2023 00:37:37 +0800 Subject: [PATCH] Fix subtitle merging issue --- docs/assets/example/multiple.subtitles.js | 6 +- .../index.js | 135 ++++++++++-------- .../index.js.map | 2 +- .../src/index.js | 42 +++--- .../artplayer-plugin-multiple-subtitles.d.ts | 1 + 5 files changed, 104 insertions(+), 82 deletions(-) diff --git a/docs/assets/example/multiple.subtitles.js b/docs/assets/example/multiple.subtitles.js index c6dc5d24d..3a9f1f5f0 100644 --- a/docs/assets/example/multiple.subtitles.js +++ b/docs/assets/example/multiple.subtitles.js @@ -12,12 +12,14 @@ var art = new Artplayer({ name: 'japanese', url: '/assets/sample/subtitle.jp.srt', } - ] + ], + onMerge(trees) { + console.log(trees) + } }) ] }); - // 自定义你自己的样式,请勿复制以下代码 // Customize your own style, please do not copy the following code const style = ` diff --git a/docs/uncompiled/artplayer-plugin-multiple-subtitles/index.js b/docs/uncompiled/artplayer-plugin-multiple-subtitles/index.js index caa91a662..6ebd31ffc 100644 --- a/docs/uncompiled/artplayer-plugin-multiple-subtitles/index.js +++ b/docs/uncompiled/artplayer-plugin-multiple-subtitles/index.js @@ -158,8 +158,8 @@ function unescape(str) { const reg = new RegExp(`(${Object.keys(map).join("|")})`, "g"); return str.replace(reg, (tag)=>map[tag] || tag); } -async function loadSubtitleAsVtt(option) { - const { getExt, srtToVtt, assToVtt } = Artplayer.utils; +async function loadSubtitleAsVtt(option, art) { + const { getExt, srtToVtt, assToVtt } = art.constructor.utils; const response = await fetch(option.url); const buffer = await response.arrayBuffer(); const decoder = new TextDecoder(option.encoding || "utf-8"); @@ -175,13 +175,12 @@ async function loadSubtitleAsVtt(option) { return ""; } } -function mergeVtts(vtts, subtitles) { +function mergeTrees(trees, subtitles) { const parser = new (0, _parser.WebVTTParser)(); - const seri = new (0, _parser.WebVTTSerializer)(); const result = parser.parse("", "metadata"); - for(let i = 0; i < vtts.length; i++){ + for(let i = 0; i < trees.length; i++){ + const tree = trees[i]; const option = subtitles[i]; - const tree = parser.parse(vtts[i], "metadata"); for(let j = 0; j < tree.cues.length; j++){ const cue = tree.cues[j]; for(let k = 0; k < cue.tree.children.length; k++){ @@ -192,66 +191,44 @@ function mergeVtts(vtts, subtitles) { if (result.cues.length === 0) result.cues = tree.cues; else for(let l = 0; l < result.cues.length; l++)result.cues[l].tree.children.push(...tree.cues[l]?.tree?.children || []); } - return seri.serialize(result.cues); + return result; } -function artplayerPluginMultipleSubtitles({ subtitles }) { +function artplayerPluginMultipleSubtitles({ subtitles, onMerge = ()=>null }) { return async (art)=>{ - const vtts = await Promise.all(subtitles.map(loadSubtitleAsVtt)); - const vtt = mergeVtts(vtts, subtitles); - const url = URL.createObjectURL(new Blob([ - vtt - ], { - type: "text/vtt" - })); - art.option.subtitle.escape = false; - art.subtitle.init({ - ...art.option.subtitle, - url, - type: "vtt", - onVttLoad: unescape - }); + const vtts = await Promise.all(subtitles.map((option)=>loadSubtitleAsVtt(option, art))); + const parser = new (0, _parser.WebVTTParser)(); + const trees = vtts.map((vtt)=>parser.parse(vtt, "metadata")); + const seri = new (0, _parser.WebVTTSerializer)(); + const tree = onMerge(trees, subtitles) || mergeTrees(trees, subtitles); + if (tree?.cues?.length) { + const vtt = seri.serialize(tree.cues); + const url = URL.createObjectURL(new Blob([ + vtt + ], { + type: "text/vtt" + })); + art.option.subtitle.escape = false; + art.subtitle.init({ + ...art.option.subtitle, + url, + type: "vtt", + onVttLoad: unescape + }); + } else throw new Error("No subtitle found"); }; } artplayerPluginMultipleSubtitles.env = "development"; artplayerPluginMultipleSubtitles.version = "1.0.0"; -artplayerPluginMultipleSubtitles.build = "2023-11-23 22:22:14"; +artplayerPluginMultipleSubtitles.build = "2023-11-24 00:15:21"; +artplayerPluginMultipleSubtitles.WebVTTParser = (0, _parser.WebVTTParser); +artplayerPluginMultipleSubtitles.WebVTTSerializer = (0, _parser.WebVTTSerializer); if (typeof window !== "undefined") window["artplayerPluginMultipleSubtitles"] = artplayerPluginMultipleSubtitles; -},{"@parcel/transformer-js/src/esmodule-helpers.js":"5dUr6","./parser":"eko7u"}],"5dUr6":[function(require,module,exports) { -exports.interopDefault = function(a) { - return a && a.__esModule ? a : { - default: a - }; -}; -exports.defineInteropFlag = function(a) { - Object.defineProperty(a, "__esModule", { - value: true - }); -}; -exports.exportAll = function(source, dest) { - Object.keys(source).forEach(function(key) { - if (key === "default" || key === "__esModule" || dest.hasOwnProperty(key)) return; - Object.defineProperty(dest, key, { - enumerable: true, - get: function() { - return source[key]; - } - }); - }); - return dest; -}; -exports.export = function(dest, destName, get) { - Object.defineProperty(dest, destName, { - enumerable: true, - get: get - }); -}; - -},{}],"eko7u":[function(require,module,exports) { +},{"./parser":"eko7u","@parcel/transformer-js/src/esmodule-helpers.js":"5dUr6"}],"eko7u":[function(require,module,exports) { // Any copyright is dedicated to the Public Domain. // http://creativecommons.org/publicdomain/zero/1.0/ // Not intended to be fast, but if you can make it faster, please help out! -(function() { +/* eslint-disable */ (function() { var defaultCueSettings = { direction: "horizontal", snapToLines: true, @@ -325,6 +302,7 @@ exports.export = function(dest, destName, get) { Not part of the specification's parser as these would just be ignored. However, we want them to be conforming and not get "Cue identifier cannot be standalone". */ if (/^NOTE($|[ \t])/.test(cue.id)) { + // .startsWith fails in Chrome linePos++; while(lines[linePos] != "" && lines[linePos] != undefined){ if (lines[linePos].indexOf("-->") != -1) err("Cannot have timestamp in a comment."); @@ -506,12 +484,14 @@ exports.export = function(dest, destName, get) { return; } if (setting == "vertical") { + // writing direction if (value != "rl" && value != "lr") { err("Writing direction can only be set to 'rl' or 'rl'."); continue; } cue.direction = value; } else if (setting == "line") { + // line position and optionally line alignment if (/,/.test(value)) { var comp = value.split(","); value = comp[0]; @@ -562,6 +542,7 @@ exports.export = function(dest, destName, get) { cue.linePosition = parseFloat(numVal); if (parseFloat(numVal).toString() !== numVal) cue.nonSerializable = true; } else if (setting == "position") { + // text position and optional positionAlign if (/,/.test(value)) { var comp = value.split(","); value = comp[0]; @@ -593,6 +574,7 @@ exports.export = function(dest, destName, get) { } cue.textPosition = parseFloat(numVal); } else if (setting == "size") { + // size if (value[value.length - 1] != "%") { err("Size must be a percentage."); continue; @@ -615,6 +597,7 @@ exports.export = function(dest, destName, get) { } cue.size = size; } else if (setting == "align") { + // alignment var alignValues = [ "start", "center", @@ -725,13 +708,11 @@ exports.export = function(dest, destName, get) { else if (name == "v") { if (inScope("v")) err(" cannot be nested inside itself."); attach(token); - current.value = token[3] // annotation - ; + current.value = token[3]; // annotation if (!token[3]) err(" requires an annotation."); } else if (name == "lang") { attach(token); - current.value = token[3] // language - ; + current.value = token[3]; // language } else err("Incorrect start tag."); } else if (token[0] == "end tag") { if (mode == "chapters") err("End tags not allowed in chapter title text."); @@ -795,7 +776,8 @@ exports.export = function(dest, destName, get) { if (m = buffer.match(/^&#(x?[0-9]+)$/)) // we prepend "0" so that x20 be interpreted as hexadecim (0x20) result += String.fromCharCode("0" + m[1]); else if (self.entities[buffer + c]) result += self.entities[buffer + c]; - else if (m = Object.keys(entities).find((n)=>buffer.startsWith(n))) result += self.entities[m] + buffer.slice(m.length) + c; + else if (m = Object.keys(entities).find((n)=>buffer.startsWith(n))) // partial match + result += self.entities[m] + buffer.slice(m.length) + c; else { err("Incorrect escape."); result += buffer + ";"; @@ -891,8 +873,7 @@ exports.export = function(dest, destName, get) { result ]; } else result += c; - } else err("Never happens.") // The joke is it might. - ; + } else err("Never happens."); // The joke is it might. // 8 pos++; } @@ -957,6 +938,36 @@ exports.export = function(dest, destName, get) { exportify(exports); })(); +},{}],"5dUr6":[function(require,module,exports) { +exports.interopDefault = function(a) { + return a && a.__esModule ? a : { + default: a + }; +}; +exports.defineInteropFlag = function(a) { + Object.defineProperty(a, "__esModule", { + value: true + }); +}; +exports.exportAll = function(source, dest) { + Object.keys(source).forEach(function(key) { + if (key === "default" || key === "__esModule" || dest.hasOwnProperty(key)) return; + Object.defineProperty(dest, key, { + enumerable: true, + get: function() { + return source[key]; + } + }); + }); + return dest; +}; +exports.export = function(dest, destName, get) { + Object.defineProperty(dest, destName, { + enumerable: true, + get: get + }); +}; + },{}]},["LGGZX"], "LGGZX", "parcelRequire4dc0") //# sourceMappingURL=index.js.map diff --git a/docs/uncompiled/artplayer-plugin-multiple-subtitles/index.js.map b/docs/uncompiled/artplayer-plugin-multiple-subtitles/index.js.map index 2e67f3758..afbdd39a1 100644 --- a/docs/uncompiled/artplayer-plugin-multiple-subtitles/index.js.map +++ b/docs/uncompiled/artplayer-plugin-multiple-subtitles/index.js.map @@ -1 +1 @@ -{"mappings":"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","sources":["packages/artplayer-plugin-multiple-subtitles/src/index.js","node_modules/@parcel/transformer-js/src/esmodule-helpers.js","packages/artplayer-plugin-multiple-subtitles/src/parser.js"],"sourcesContent":["import { WebVTTParser, WebVTTSerializer } from './parser';\n\nfunction unescape(str) {\n const map = {\n '&': '&',\n '<': '<',\n '>': '>',\n ''': \"'\",\n '"': '\"',\n };\n const reg = new RegExp(`(${Object.keys(map).join('|')})`, 'g');\n return str.replace(reg, (tag) => map[tag] || tag);\n}\n\nasync function loadSubtitleAsVtt(option) {\n const { getExt, srtToVtt, assToVtt } = Artplayer.utils;\n const response = await fetch(option.url);\n const buffer = await response.arrayBuffer();\n const decoder = new TextDecoder(option.encoding || 'utf-8');\n const text = decoder.decode(buffer);\n switch (option.type || getExt(option.url)) {\n case 'srt': {\n return srtToVtt(text);\n }\n case 'ass': {\n return assToVtt(text);\n }\n case 'vtt': {\n return text;\n }\n default:\n return '';\n }\n}\n\nfunction mergeVtts(vtts, subtitles) {\n const parser = new WebVTTParser();\n const seri = new WebVTTSerializer();\n const result = parser.parse('', 'metadata');\n\n for (let i = 0; i < vtts.length; i++) {\n const option = subtitles[i];\n const tree = parser.parse(vtts[i], 'metadata');\n\n for (let j = 0; j < tree.cues.length; j++) {\n const cue = tree.cues[j];\n for (let k = 0; k < cue.tree.children.length; k++) {\n const children = cue.tree.children[k];\n children.value = `
${children.value}
`;\n }\n }\n\n if (result.cues.length === 0) {\n result.cues = tree.cues;\n } else {\n for (let l = 0; l < result.cues.length; l++) {\n result.cues[l].tree.children.push(...(tree.cues[l]?.tree?.children || []));\n }\n }\n }\n\n return seri.serialize(result.cues);\n}\n\nexport default function artplayerPluginMultipleSubtitles({ subtitles }) {\n return async (art) => {\n const vtts = await Promise.all(subtitles.map(loadSubtitleAsVtt));\n const vtt = mergeVtts(vtts, subtitles);\n const url = URL.createObjectURL(new Blob([vtt], { type: 'text/vtt' }));\n\n art.option.subtitle.escape = false;\n\n art.subtitle.init({\n ...art.option.subtitle,\n url,\n type: 'vtt',\n onVttLoad: unescape,\n });\n };\n}\nartplayerPluginMultipleSubtitles.env = process.env.NODE_ENV;\nartplayerPluginMultipleSubtitles.version = process.env.APP_VER;\nartplayerPluginMultipleSubtitles.build = process.env.BUILD_DATE;\n\nif (typeof window !== 'undefined') {\n window['artplayerPluginMultipleSubtitles'] = artplayerPluginMultipleSubtitles;\n}\n","exports.interopDefault = function (a) {\n return a && a.__esModule ? a : {default: a};\n};\n\nexports.defineInteropFlag = function (a) {\n Object.defineProperty(a, '__esModule', {value: true});\n};\n\nexports.exportAll = function (source, dest) {\n Object.keys(source).forEach(function (key) {\n if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) {\n return;\n }\n\n Object.defineProperty(dest, key, {\n enumerable: true,\n get: function () {\n return source[key];\n },\n });\n });\n\n return dest;\n};\n\nexports.export = function (dest, destName, get) {\n Object.defineProperty(dest, destName, {\n enumerable: true,\n get: get,\n });\n};\n","// Any copyright is dedicated to the Public Domain.\n// http://creativecommons.org/publicdomain/zero/1.0/\n\n// Not intended to be fast, but if you can make it faster, please help out!\n\n(function () {\n var defaultCueSettings = {\n direction:\"horizontal\",\n snapToLines:true,\n linePosition:\"auto\",\n lineAlign:\"start\",\n textPosition:\"auto\",\n positionAlign:\"auto\",\n size:100,\n alignment:\"center\",\n };\n\n var WebVTTParser = function(entities) {\n if (!entities) {\n entities = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n \"&lrm\": \"\\u200e\",\n \"&rlm\": \"\\u200f\",\n \" \": \"\\u00A0\"\n }\n }\n this.entities = entities\n this.parse = function(input, mode) {\n // global search and replace for \\0\n input = input.replace(/\\0/g, '\\uFFFD');\n var NEWLINE = /\\r\\n|\\r|\\n/,\n startTime = Date.now(),\n linePos = 0,\n lines = input.split(NEWLINE),\n alreadyCollected = false,\n styles = [],\n cues = [],\n errors = []\n function err(message, col) {\n errors.push({message:message, line:linePos+1, col:col})\n }\n\n var line = lines[linePos],\n lineLength = line.length,\n signature = \"WEBVTT\",\n bom = 0,\n signature_length = signature.length\n\n /* Byte order mark */\n if (line[0] === \"\\ufeff\") {\n bom = 1\n signature_length += 1\n }\n /* SIGNATURE */\n if (\n lineLength < signature_length ||\n line.indexOf(signature) !== 0+bom ||\n lineLength > signature_length &&\n line[signature_length] !== \" \" &&\n line[signature_length] !== \"\\t\"\n ) {\n err(\"No valid signature. (File needs to start with \\\"WEBVTT\\\".)\")\n }\n\n linePos++\n\n /* HEADER */\n while(lines[linePos] != \"\" && lines[linePos] != undefined) {\n err(\"No blank line after the signature.\")\n if(lines[linePos].indexOf(\"-->\") != -1) {\n alreadyCollected = true\n break\n }\n linePos++\n }\n\n /* CUE LOOP */\n while(lines[linePos] != undefined) {\n var cue\n while(!alreadyCollected && lines[linePos] == \"\") {\n linePos++\n }\n if(!alreadyCollected && lines[linePos] == undefined)\n break\n\n /* CUE CREATION */\n cue = Object.assign({}, defaultCueSettings, {\n id:\"\",\n startTime:0,\n endTime:0,\n pauseOnExit:false,\n direction:\"horizontal\",\n snapToLines:true,\n linePosition:\"auto\",\n lineAlign:\"start\",\n textPosition:\"auto\",\n positionAlign:\"auto\",\n size:100,\n alignment:\"center\",\n text:\"\",\n tree:null\n })\n\n var parseTimings = true\n\n if(lines[linePos].indexOf(\"-->\") == -1) {\n cue.id = lines[linePos]\n\n /* COMMENTS\n Not part of the specification's parser as these would just be ignored. However,\n we want them to be conforming and not get \"Cue identifier cannot be standalone\".\n */\n if(/^NOTE($|[ \\t])/.test(cue.id)) { // .startsWith fails in Chrome\n linePos++\n while(lines[linePos] != \"\" && lines[linePos] != undefined) {\n if(lines[linePos].indexOf(\"-->\") != -1)\n err(\"Cannot have timestamp in a comment.\")\n linePos++\n }\n continue\n }\n\n /* STYLES */\n if(/^STYLE($|[ \\t])/.test(cue.id)) {\n var style = []\n var invalid = false\n linePos++\n while(lines[linePos] != \"\" && lines[linePos] != undefined) {\n if(lines[linePos].indexOf(\"-->\") != -1) {\n err(\"Cannot have timestamp in a style block.\")\n invalid = true\n }\n style.push(lines[linePos])\n linePos++\n }\n if(cues.length) {\n err(\"Style blocks cannot appear after the first cue.\")\n continue\n }\n if (!invalid) {\n styles.push(style.join('\\n'))\n }\n continue\n }\n\n linePos++\n\n if(lines[linePos] == \"\" || lines[linePos] == undefined) {\n err(\"Cue identifier cannot be standalone.\")\n continue\n }\n\n if(lines[linePos].indexOf(\"-->\") == -1) {\n parseTimings = false\n err(\"Cue identifier needs to be followed by timestamp.\")\n continue\n }\n }\n\n /* TIMINGS */\n alreadyCollected = false\n var timings = new WebVTTCueTimingsAndSettingsParser(lines[linePos], err)\n var previousCueStart = 0\n if(cues.length > 0) {\n previousCueStart = cues[cues.length-1].startTime\n }\n if(parseTimings && !timings.parse(cue, previousCueStart)) {\n /* BAD CUE */\n\n cue = null\n linePos++\n\n /* BAD CUE LOOP */\n while(lines[linePos] != \"\" && lines[linePos] != undefined) {\n if(lines[linePos].indexOf(\"-->\") != -1) {\n alreadyCollected = true\n break\n }\n linePos++\n }\n continue\n }\n linePos++\n\n /* CUE TEXT LOOP */\n while(lines[linePos] != \"\" && lines[linePos] != undefined) {\n if(lines[linePos].indexOf(\"-->\") != -1) {\n err(\"Blank line missing before cue.\")\n alreadyCollected = true\n break\n }\n if(cue.text != \"\")\n cue.text += \"\\n\"\n cue.text += lines[linePos]\n linePos++\n }\n\n /* CUE TEXT PROCESSING */\n var cuetextparser = new WebVTTCueTextParser(cue.text, err, mode, entities)\n cue.tree = cuetextparser.parse(cue.startTime, cue.endTime)\n cues.push(cue)\n }\n cues.sort(function(a, b) {\n if (a.startTime < b.startTime)\n return -1\n if (a.startTime > b.startTime)\n return 1\n if (a.endTime > b.endTime)\n return -1\n if (a.endTime < b.endTime)\n return 1\n return 0\n })\n /* END */\n return {cues:cues, errors:errors, time:Date.now()-startTime, styles: styles}\n }\n }\n\n var WebVTTCueTimingsAndSettingsParser = function(line, errorHandler) {\n var SPACE = /[\\u0020\\t\\f]/,\n NOSPACE = /[^\\u0020\\t\\f]/,\n line = line,\n pos = 0,\n err = function(message) {\n errorHandler(message, pos+1)\n },\n spaceBeforeSetting = true\n function skip(pattern) {\n while(\n line[pos] != undefined &&\n pattern.test(line[pos])\n ) {\n pos++\n }\n }\n function collect(pattern) {\n var str = \"\"\n while(\n line[pos] != undefined &&\n pattern.test(line[pos])\n ) {\n str += line[pos]\n pos++\n }\n return str\n }\n /* http://dev.w3.org/html5/webvtt/#collect-a-webvtt-timestamp */\n function timestamp() {\n var units = \"minutes\",\n val1,\n val2,\n val3,\n val4\n // 3\n if(line[pos] == undefined) {\n err(\"No timestamp found.\")\n return\n }\n // 4\n if(!/\\d/.test(line[pos])) {\n err(\"Timestamp must start with a character in the range 0-9.\")\n return\n }\n // 5-7\n val1 = collect(/\\d/)\n if(val1.length > 2 || parseInt(val1, 10) > 59) {\n units = \"hours\"\n }\n // 8\n if(line[pos] != \":\") {\n err(\"No time unit separator found.\")\n return\n }\n pos++\n // 9-11\n val2 = collect(/\\d/)\n if(val2.length != 2) {\n err(\"Must be exactly two digits.\")\n return\n }\n // 12\n if(units == \"hours\" || line[pos] == \":\") {\n if(line[pos] != \":\") {\n err(\"No seconds found or minutes is greater than 59.\")\n return\n }\n pos++\n val3 = collect(/\\d/)\n if(val3.length != 2) {\n err(\"Must be exactly two digits.\")\n return\n }\n } else {\n if (val1.length != 2) {\n err(\"Must be exactly two digits.\")\n return\n }\n val3 = val2\n val2 = val1\n val1 = \"0\"\n }\n // 13\n if(line[pos] != \".\") {\n err(\"No decimal separator (\\\".\\\") found.\")\n return\n }\n pos++\n // 14-16\n val4 = collect(/\\d/)\n if(val4.length != 3) {\n err(\"Milliseconds must be given in three digits.\")\n return\n }\n // 17\n if(parseInt(val2, 10) > 59) {\n err(\"You cannot have more than 59 minutes.\")\n return\n }\n if(parseInt(val3, 10) > 59) {\n err(\"You cannot have more than 59 seconds.\")\n return\n }\n return parseInt(val1, 10) * 60 * 60 + parseInt(val2, 10) * 60 + parseInt(val3, 10) + parseInt(val4, 10) / 1000\n }\n\n /* http://dev.w3.org/html5/webvtt/#parse-the-webvtt-settings */\n function parseSettings(input, cue) {\n var settings = input.split(SPACE),\n seen = []\n for(var i=0; i < settings.length; i++) {\n if(settings[i] == \"\")\n continue\n\n var index = settings[i].indexOf(':'),\n setting = settings[i].slice(0, index),\n value = settings[i].slice(index + 1)\n\n if(seen.indexOf(setting) != -1) {\n err(\"Duplicate setting.\")\n }\n seen.push(setting)\n\n if(value == \"\") {\n err(\"No value for setting defined.\")\n return\n }\n\n if(setting == \"vertical\") { // writing direction\n if(value != \"rl\" && value != \"lr\") {\n err(\"Writing direction can only be set to 'rl' or 'rl'.\")\n continue\n }\n cue.direction = value\n } else if(setting == \"line\") { // line position and optionally line alignment\n if (/,/.test(value)) {\n var comp = value.split(',')\n value = comp[0]\n var lineAlign = comp[1]\n }\n if(!/^[-\\d](\\d*)(\\.\\d+)?%?$/.test(value)) {\n err(\"Line position takes a number or percentage.\")\n continue\n }\n if(value.indexOf(\"-\", 1) != -1) {\n err(\"Line position can only have '-' at the start.\")\n continue\n }\n if(value.indexOf(\"%\") != -1 && value.indexOf(\"%\") != value.length-1) {\n err(\"Line position can only have '%' at the end.\")\n continue\n }\n if(value[0] == \"-\" && value[value.length-1] == \"%\") {\n err(\"Line position cannot be a negative percentage.\")\n continue\n }\n var numVal = value;\n var isPercent = false;\n if(value[value.length-1] == \"%\") {\n isPercent = true;\n numVal = value.slice(0, value.length-1)\n if(parseInt(value, 10) > 100) {\n err(\"Line position cannot be >100%.\")\n continue\n }\n }\n if (numVal === '' || isNaN(numVal) || !isFinite(numVal)) {\n err(\"Line position needs to be a number\")\n continue\n }\n if (lineAlign !== undefined) {\n if (![\"start\", \"center\", \"end\"].includes(lineAlign)) {\n err(\"Line alignment needs to be one of start, center or end\")\n continue\n }\n cue.lineAlign = lineAlign\n }\n cue.snapToLines = !isPercent;\n cue.linePosition = parseFloat(numVal)\n if (parseFloat(numVal).toString() !== numVal) {\n cue.nonSerializable = true;\n }\n } else if(setting == \"position\") { // text position and optional positionAlign\n if (/,/.test(value)) {\n var comp = value.split(',')\n value = comp[0]\n var positionAlign = comp[1]\n }\n if(value[value.length-1] != \"%\") {\n err(\"Text position must be a percentage.\")\n continue\n }\n if(parseInt(value, 10) > 100 || parseInt(value, 10) < 0) {\n err(\"Text position needs to be between 0 and 100%.\")\n continue\n }\n numVal = value.slice(0, value.length-1)\n if (numVal === '' || isNaN(numVal) || !isFinite(numVal)) {\n err(\"Line position needs to be a number\")\n continue\n }\n if (positionAlign !== undefined) {\n if (![\"line-left\", \"center\", \"line-right\"].includes(positionAlign)) {\n err(\"Position alignment needs to be one of line-left, center or line-right\")\n continue\n }\n cue.positionAlign = positionAlign\n }\n cue.textPosition = parseFloat(numVal)\n } else if(setting == \"size\") { // size\n if(value[value.length-1] != \"%\") {\n err(\"Size must be a percentage.\")\n continue\n }\n if(parseInt(value, 10) > 100) {\n err(\"Size cannot be >100%.\")\n continue\n }\n var size = value.slice(0, value.length -1)\n if (size === undefined || size === \"\" || isNaN(size)) {\n err(\"Size needs to be a number\")\n size = 100\n continue\n } else {\n size = parseFloat(size)\n if (size < 0 || size > 100) {\n err(\"Size needs to be between 0 and 100%.\")\n continue;\n }\n }\n cue.size = size\n } else if(setting == \"align\") { // alignment\n var alignValues = [\"start\", \"center\", \"end\", \"left\", \"right\"]\n if(alignValues.indexOf(value) == -1) {\n err(\"Alignment can only be set to one of \" + alignValues.join(\", \") + \".\")\n continue\n }\n cue.alignment = value\n } else {\n err(\"Invalid setting.\")\n }\n }\n }\n\n this.parse = function(cue, previousCueStart) {\n skip(SPACE)\n cue.startTime = timestamp()\n if(cue.startTime == undefined) {\n return\n }\n if(cue.startTime < previousCueStart) {\n err(\"Start timestamp is not greater than or equal to start timestamp of previous cue.\")\n }\n if(NOSPACE.test(line[pos])) {\n err(\"Timestamp not separated from '-->' by whitespace.\")\n }\n skip(SPACE)\n // 6-8\n if(line[pos] != \"-\") {\n err(\"No valid timestamp separator found.\")\n return\n }\n pos++\n if(line[pos] != \"-\") {\n err(\"No valid timestamp separator found.\")\n return\n }\n pos++\n if(line[pos] != \">\") {\n err(\"No valid timestamp separator found.\")\n return\n }\n pos++\n if(NOSPACE.test(line[pos])) {\n err(\"'-->' not separated from timestamp by whitespace.\")\n }\n skip(SPACE)\n cue.endTime = timestamp()\n if(cue.endTime == undefined) {\n return\n }\n if(cue.endTime <= cue.startTime) {\n err(\"End timestamp is not greater than start timestamp.\")\n }\n\n if(NOSPACE.test(line[pos])) {\n spaceBeforeSetting = false\n }\n skip(SPACE)\n parseSettings(line.substring(pos), cue)\n return true\n }\n this.parseTimestamp = function() {\n var ts = timestamp()\n if(line[pos] != undefined) {\n err(\"Timestamp must not have trailing characters.\")\n return\n }\n return ts\n }\n }\n\n var WebVTTCueTextParser = function(line, errorHandler, mode, entities) {\n this.entities = entities\n var self = this\n var line = line,\n pos = 0,\n err = function(message) {\n if(mode == \"metadata\")\n return\n errorHandler(message, pos+1)\n }\n\n this.parse = function(cueStart, cueEnd) {\n function removeCycles(tree) {\n const cyclelessTree = {...tree};\n if (tree.children) {\n cyclelessTree.children = tree.children.map(removeCycles);\n }\n if (cyclelessTree.parent) {\n delete cyclelessTree.parent;\n }\n return cyclelessTree;\n }\n\n var result = {children:[]},\n current = result,\n timestamps = []\n\n function attach(token) {\n current.children.push({type:\"object\", name:token[1], classes:token[2], children:[], parent:current})\n current = current.children[current.children.length-1]\n }\n function inScope(name) {\n var node = current\n while(node) {\n if(node.name == name)\n return true\n node = node.parent\n }\n return\n }\n\n while(line[pos] != undefined) {\n var token = nextToken()\n if(token[0] == \"text\") {\n current.children.push({type:\"text\", value:token[1], parent:current})\n } else if(token[0] == \"start tag\") {\n if(mode == \"chapters\")\n err(\"Start tags not allowed in chapter title text.\")\n var name = token[1]\n if(name != \"v\" && name != \"lang\" && token[3] != \"\") {\n err(\"Only and can have an annotation.\")\n }\n if(\n name == \"c\" ||\n name == \"i\" ||\n name == \"b\" ||\n name == \"u\" ||\n name == \"ruby\"\n ) {\n attach(token)\n } else if(name == \"rt\" && current.name == \"ruby\") {\n attach(token)\n } else if(name == \"v\") {\n if(inScope(\"v\")) {\n err(\" cannot be nested inside itself.\")\n }\n attach(token)\n current.value = token[3] // annotation\n if(!token[3]) {\n err(\" requires an annotation.\")\n }\n } else if(name == \"lang\") {\n attach(token)\n current.value = token[3] // language\n } else {\n err(\"Incorrect start tag.\")\n }\n } else if(token[0] == \"end tag\") {\n if(mode == \"chapters\")\n err(\"End tags not allowed in chapter title text.\")\n // XXX check content\n if(token[1] == current.name) {\n current = current.parent\n } else if(token[1] == \"ruby\" && current.name == \"rt\") {\n current = current.parent.parent\n } else {\n err(\"Incorrect end tag.\")\n }\n } else if(token[0] == \"timestamp\") {\n if(mode == \"chapters\")\n err(\"Timestamp not allowed in chapter title text.\")\n var timings = new WebVTTCueTimingsAndSettingsParser(token[1], err),\n timestamp = timings.parseTimestamp()\n if(timestamp != undefined) {\n if(timestamp <= cueStart || timestamp >= cueEnd) {\n err(\"Timestamp must be between start timestamp and end timestamp.\")\n }\n if(timestamps.length > 0 && timestamps[timestamps.length-1] >= timestamp) {\n err(\"Timestamp must be greater than any previous timestamp.\")\n }\n current.children.push({type:\"timestamp\", value:timestamp, parent:current})\n timestamps.push(timestamp)\n }\n }\n }\n while(current.parent) {\n if(current.name != \"v\") {\n err(\"Required end tag missing.\")\n }\n current = current.parent\n }\n return removeCycles(result)\n }\n\n function nextToken() {\n var state = \"data\",\n result = \"\",\n buffer = \"\",\n classes = []\n while(line[pos-1] != undefined || pos == 0) {\n var c = line[pos]\n if(state == \"data\") {\n if(c == \"&\") {\n buffer = c\n state = \"escape\"\n } else if(c == \"<\" && result == \"\") {\n state = \"tag\"\n } else if(c == \"<\" || c == undefined) {\n return [\"text\", result]\n } else {\n result += c\n }\n } else if(state == \"escape\") {\n if(c == \"<\" || c == undefined) {\n err(\"Incorrect escape.\")\n let m;\n if (m = buffer.match(/^&#([0-9]+)$/)) {\n result += String.fromCharCode(m[1])\n } else {\n if(self.entities[buffer]) {\n result += self.entities[buffer]\n } else {\n result += buffer\n }\n }\n return [\"text\", result]\n } else if(c == \"&\") {\n err(\"Incorrect escape.\")\n result += buffer\n buffer = c\n } else if(/[a-z#0-9]/i.test(c)) {\n buffer += c\n } else if(c == \";\") {\n let m;\n if (m = buffer.match(/^&#(x?[0-9]+)$/)) {\n // we prepend \"0\" so that x20 be interpreted as hexadecim (0x20)\n result += String.fromCharCode(\"0\" + m[1])\n } else if(self.entities[buffer + c]) {\n result += self.entities[buffer + c]\n } else if (m = Object.keys(entities).find(n => buffer.startsWith(n))) { // partial match\n result += self.entities[m] + buffer.slice(m.length) + c\n } else {\n err(\"Incorrect escape.\")\n result += buffer + \";\"\n }\n state = \"data\"\n } else {\n err(\"Incorrect escape.\")\n result += buffer + c\n state = \"data\"\n }\n } else if(state == \"tag\") {\n if(c == \"\\t\" || c == \"\\n\" || c == \"\\f\" || c == \" \") {\n state = \"start tag annotation\"\n } else if(c == \".\") {\n state = \"start tag class\"\n } else if(c == \"/\") {\n state = \"end tag\"\n } else if(/\\d/.test(c)) {\n result = c\n state = \"timestamp tag\"\n } else if(c == \">\" || c == undefined) {\n if(c == \">\") {\n pos++\n }\n return [\"start tag\", \"\", [], \"\"]\n } else {\n result = c\n state = \"start tag\"\n }\n } else if(state == \"start tag\") {\n if(c == \"\\t\" || c == \"\\f\" || c == \" \") {\n state = \"start tag annotation\"\n } else if(c == \"\\n\") {\n buffer = c\n state = \"start tag annotation\"\n } else if(c == \".\") {\n state = \"start tag class\"\n } else if(c == \">\" || c == undefined) {\n if(c == \">\") {\n pos++\n }\n return [\"start tag\", result, [], \"\"]\n } else {\n result += c\n }\n } else if(state == \"start tag class\") {\n if(c == \"\\t\" || c == \"\\f\" || c == \" \") {\n if (buffer) {\n classes.push(buffer)\n }\n buffer = \"\"\n state = \"start tag annotation\"\n } else if(c == \"\\n\") {\n if (buffer) {\n classes.push(buffer)\n }\n buffer = c\n state = \"start tag annotation\"\n } else if(c == \".\") {\n if (buffer) {\n classes.push(buffer)\n }\n buffer = \"\"\n } else if(c == \">\" || c == undefined) {\n if(c == \">\") {\n pos++\n }\n if (buffer) {\n classes.push(buffer)\n }\n return [\"start tag\", result, classes, \"\"]\n } else {\n buffer += c\n }\n } else if(state == \"start tag annotation\") {\n if(c == \">\" || c == undefined) {\n if(c == \">\") {\n pos++\n }\n buffer = buffer.split(/[\\u0020\\t\\f\\r\\n]+/).filter(function(item) { if(item) return true }).join(\" \")\n return [\"start tag\", result, classes, buffer]\n } else {\n buffer +=c\n }\n } else if(state == \"end tag\") {\n if(c == \">\" || c == undefined) {\n if(c == \">\") {\n pos++\n }\n return [\"end tag\", result]\n } else {\n result += c\n }\n } else if(state == \"timestamp tag\") {\n if(c == \">\" || c == undefined) {\n if(c == \">\") {\n pos++\n }\n return [\"timestamp\", result]\n } else {\n result += c\n }\n } else {\n err(\"Never happens.\") // The joke is it might.\n }\n // 8\n pos++\n }\n }\n }\n\n var WebVTTSerializer = function() {\n function serializeTimestamp(seconds) {\n const ms = (\"00\" + (seconds - Math.floor(seconds)).toFixed(3)*1000).slice(-3);\n let h = 0, m = 0, s = 0;\n if (seconds >= 3600) {\n h = Math.floor(seconds/3600);\n }\n m = Math.floor((seconds - 3600*h) / 60);\n s = Math.floor(seconds - 3600*h - 60*m);\n return (h ? h + \":\" : \"\") + (\"\" + m).padStart(2, \"0\") + \":\" + (\"\" + s).padStart(2, \"0\") + \".\" + ms;\n }\n function serializeCueSettings(cue) {\n var result = \"\"\n const nonDefaultSettings = Object.keys(defaultCueSettings).filter(s => cue[s] !== defaultCueSettings[s]);\n if (nonDefaultSettings.includes(\"direction\")) {\n result+= \" vertical:\" + cue.direction\n }\n if (nonDefaultSettings.includes(\"alignment\")) {\n result+= \" align:\" + cue.alignment\n }\n if (nonDefaultSettings.includes(\"size\")) {\n result+= \" size:\" + cue.size + \"%\"\n }\n if (nonDefaultSettings.includes(\"lineAlign\") || nonDefaultSettings.includes(\"linePosition\")) {\n result += \" line:\" + cue.linePosition + (cue.snapToLines ? \"\" : \"%\") + (cue.lineAlign && cue.lineAlign != defaultCueSettings.lineAlign ? \",\" + cue.lineAlign : \"\")\n }\n if (nonDefaultSettings.includes(\"textPosition\") || nonDefaultSettings.includes(\"positionAlign\")) {\n result += \" position:\" + cue.textPosition + \"%\" + (cue.positionAlign && cue.positionAlign !== defaultCueSettings.positionAlign ? \",\" + cue.positionAlign : \"\")\n }\n return result\n }\n function serializeTree(tree) {\n var result = \"\"\n for (var i = 0; i < tree.length; i++) {\n var node = tree[i]\n if(node.type == \"text\") {\n result += node.value.replace(/&/g, '&').replace(//g, '>');\n } else if(node.type == \"object\") {\n result += \"<\" + node.name\n if(node.classes) {\n for(var y = 0; y < node.classes.length; y++) {\n result += \".\" + node.classes[y]\n }\n }\n if(node.value) {\n result += \" \" + node.value\n }\n result += \">\"\n if(node.children)\n result += serializeTree(node.children)\n result += \"\"\n } else if(node.type == \"timestamp\") {\n result += \"<\" + serializeTimestamp(node.value) + \">\"\n } else {\n result += \"<\" + node.value + \">\"\n }\n }\n return result\n }\n function serializeCue(cue) {\n return (cue.id !== undefined ? cue.id + \"\\n\" : \"\")\n + serializeTimestamp(cue.startTime)\n + \" --> \"\n + serializeTimestamp(cue.endTime)\n + serializeCueSettings(cue)\n + \"\\n\" + serializeTree(cue.tree.children) + \"\\n\\n\"\n }\n function serializeStyle(style) {\n return \"STYLE\\n\" + style + \"\\n\\n\"\n }\n this.serialize = function(cues, styles) {\n var result = \"WEBVTT\\n\\n\"\n if (styles) {\n for(var i=0;i',\n ''': \"'\",\n '"': '\"',\n };\n const reg = new RegExp(`(${Object.keys(map).join('|')})`, 'g');\n return str.replace(reg, (tag) => map[tag] || tag);\n}\n\nasync function loadSubtitleAsVtt(option, art) {\n const { getExt, srtToVtt, assToVtt } = art.constructor.utils;\n const response = await fetch(option.url);\n const buffer = await response.arrayBuffer();\n const decoder = new TextDecoder(option.encoding || 'utf-8');\n const text = decoder.decode(buffer);\n switch (option.type || getExt(option.url)) {\n case 'srt': {\n return srtToVtt(text);\n }\n case 'ass': {\n return assToVtt(text);\n }\n case 'vtt': {\n return text;\n }\n default:\n return '';\n }\n}\n\nfunction mergeTrees(trees, subtitles) {\n const parser = new WebVTTParser();\n const result = parser.parse('', 'metadata');\n\n for (let i = 0; i < trees.length; i++) {\n const tree = trees[i];\n const option = subtitles[i];\n\n for (let j = 0; j < tree.cues.length; j++) {\n const cue = tree.cues[j];\n for (let k = 0; k < cue.tree.children.length; k++) {\n const children = cue.tree.children[k];\n children.value = `
${children.value}
`;\n }\n }\n\n if (result.cues.length === 0) {\n result.cues = tree.cues;\n } else {\n for (let l = 0; l < result.cues.length; l++) {\n result.cues[l].tree.children.push(...(tree.cues[l]?.tree?.children || []));\n }\n }\n }\n\n return result;\n}\n\nexport default function artplayerPluginMultipleSubtitles({ subtitles, onMerge = () => null }) {\n return async (art) => {\n const vtts = await Promise.all(subtitles.map((option) => loadSubtitleAsVtt(option, art)));\n const parser = new WebVTTParser();\n const trees = vtts.map((vtt) => parser.parse(vtt, 'metadata'));\n const seri = new WebVTTSerializer();\n const tree = onMerge(trees, subtitles) || mergeTrees(trees, subtitles);\n if (tree?.cues?.length) {\n const vtt = seri.serialize(tree.cues);\n const url = URL.createObjectURL(new Blob([vtt], { type: 'text/vtt' }));\n art.option.subtitle.escape = false;\n art.subtitle.init({\n ...art.option.subtitle,\n url,\n type: 'vtt',\n onVttLoad: unescape,\n });\n } else {\n throw new Error('No subtitle found');\n }\n };\n}\n\nartplayerPluginMultipleSubtitles.env = process.env.NODE_ENV;\nartplayerPluginMultipleSubtitles.version = process.env.APP_VER;\nartplayerPluginMultipleSubtitles.build = process.env.BUILD_DATE;\nartplayerPluginMultipleSubtitles.WebVTTParser = WebVTTParser;\nartplayerPluginMultipleSubtitles.WebVTTSerializer = WebVTTSerializer;\n\nif (typeof window !== 'undefined') {\n window['artplayerPluginMultipleSubtitles'] = artplayerPluginMultipleSubtitles;\n}\n","// Any copyright is dedicated to the Public Domain.\n// http://creativecommons.org/publicdomain/zero/1.0/\n\n// Not intended to be fast, but if you can make it faster, please help out!\n\n/* eslint-disable */\n(function () {\n var defaultCueSettings = {\n direction: 'horizontal',\n snapToLines: true,\n linePosition: 'auto',\n lineAlign: 'start',\n textPosition: 'auto',\n positionAlign: 'auto',\n size: 100,\n alignment: 'center',\n };\n\n var WebVTTParser = function (entities) {\n if (!entities) {\n entities = {\n '&': '&',\n '<': '<',\n '>': '>',\n '&lrm': '\\u200e',\n '&rlm': '\\u200f',\n ' ': '\\u00A0',\n };\n }\n this.entities = entities;\n this.parse = function (input, mode) {\n // global search and replace for \\0\n input = input.replace(/\\0/g, '\\uFFFD');\n var NEWLINE = /\\r\\n|\\r|\\n/,\n startTime = Date.now(),\n linePos = 0,\n lines = input.split(NEWLINE),\n alreadyCollected = false,\n styles = [],\n cues = [],\n errors = [];\n function err(message, col) {\n errors.push({ message: message, line: linePos + 1, col: col });\n }\n\n var line = lines[linePos],\n lineLength = line.length,\n signature = 'WEBVTT',\n bom = 0,\n signature_length = signature.length;\n\n /* Byte order mark */\n if (line[0] === '\\ufeff') {\n bom = 1;\n signature_length += 1;\n }\n /* SIGNATURE */\n if (\n lineLength < signature_length ||\n line.indexOf(signature) !== 0 + bom ||\n (lineLength > signature_length && line[signature_length] !== ' ' && line[signature_length] !== '\\t')\n ) {\n err('No valid signature. (File needs to start with \"WEBVTT\".)');\n }\n\n linePos++;\n\n /* HEADER */\n while (lines[linePos] != '' && lines[linePos] != undefined) {\n err('No blank line after the signature.');\n if (lines[linePos].indexOf('-->') != -1) {\n alreadyCollected = true;\n break;\n }\n linePos++;\n }\n\n /* CUE LOOP */\n while (lines[linePos] != undefined) {\n var cue;\n while (!alreadyCollected && lines[linePos] == '') {\n linePos++;\n }\n if (!alreadyCollected && lines[linePos] == undefined) break;\n\n /* CUE CREATION */\n cue = Object.assign({}, defaultCueSettings, {\n id: '',\n startTime: 0,\n endTime: 0,\n pauseOnExit: false,\n direction: 'horizontal',\n snapToLines: true,\n linePosition: 'auto',\n lineAlign: 'start',\n textPosition: 'auto',\n positionAlign: 'auto',\n size: 100,\n alignment: 'center',\n text: '',\n tree: null,\n });\n\n var parseTimings = true;\n\n if (lines[linePos].indexOf('-->') == -1) {\n cue.id = lines[linePos];\n\n /* COMMENTS\n Not part of the specification's parser as these would just be ignored. However,\n we want them to be conforming and not get \"Cue identifier cannot be standalone\".\n */\n if (/^NOTE($|[ \\t])/.test(cue.id)) {\n // .startsWith fails in Chrome\n linePos++;\n while (lines[linePos] != '' && lines[linePos] != undefined) {\n if (lines[linePos].indexOf('-->') != -1) err('Cannot have timestamp in a comment.');\n linePos++;\n }\n continue;\n }\n\n /* STYLES */\n if (/^STYLE($|[ \\t])/.test(cue.id)) {\n var style = [];\n var invalid = false;\n linePos++;\n while (lines[linePos] != '' && lines[linePos] != undefined) {\n if (lines[linePos].indexOf('-->') != -1) {\n err('Cannot have timestamp in a style block.');\n invalid = true;\n }\n style.push(lines[linePos]);\n linePos++;\n }\n if (cues.length) {\n err('Style blocks cannot appear after the first cue.');\n continue;\n }\n if (!invalid) {\n styles.push(style.join('\\n'));\n }\n continue;\n }\n\n linePos++;\n\n if (lines[linePos] == '' || lines[linePos] == undefined) {\n err('Cue identifier cannot be standalone.');\n continue;\n }\n\n if (lines[linePos].indexOf('-->') == -1) {\n parseTimings = false;\n err('Cue identifier needs to be followed by timestamp.');\n continue;\n }\n }\n\n /* TIMINGS */\n alreadyCollected = false;\n var timings = new WebVTTCueTimingsAndSettingsParser(lines[linePos], err);\n var previousCueStart = 0;\n if (cues.length > 0) {\n previousCueStart = cues[cues.length - 1].startTime;\n }\n if (parseTimings && !timings.parse(cue, previousCueStart)) {\n /* BAD CUE */\n\n cue = null;\n linePos++;\n\n /* BAD CUE LOOP */\n while (lines[linePos] != '' && lines[linePos] != undefined) {\n if (lines[linePos].indexOf('-->') != -1) {\n alreadyCollected = true;\n break;\n }\n linePos++;\n }\n continue;\n }\n linePos++;\n\n /* CUE TEXT LOOP */\n while (lines[linePos] != '' && lines[linePos] != undefined) {\n if (lines[linePos].indexOf('-->') != -1) {\n err('Blank line missing before cue.');\n alreadyCollected = true;\n break;\n }\n if (cue.text != '') cue.text += '\\n';\n cue.text += lines[linePos];\n linePos++;\n }\n\n /* CUE TEXT PROCESSING */\n var cuetextparser = new WebVTTCueTextParser(cue.text, err, mode, entities);\n cue.tree = cuetextparser.parse(cue.startTime, cue.endTime);\n cues.push(cue);\n }\n cues.sort(function (a, b) {\n if (a.startTime < b.startTime) return -1;\n if (a.startTime > b.startTime) return 1;\n if (a.endTime > b.endTime) return -1;\n if (a.endTime < b.endTime) return 1;\n return 0;\n });\n /* END */\n return { cues: cues, errors: errors, time: Date.now() - startTime, styles: styles };\n };\n };\n\n var WebVTTCueTimingsAndSettingsParser = function (line, errorHandler) {\n var SPACE = /[\\u0020\\t\\f]/,\n NOSPACE = /[^\\u0020\\t\\f]/,\n line = line,\n pos = 0,\n err = function (message) {\n errorHandler(message, pos + 1);\n },\n spaceBeforeSetting = true;\n function skip(pattern) {\n while (line[pos] != undefined && pattern.test(line[pos])) {\n pos++;\n }\n }\n function collect(pattern) {\n var str = '';\n while (line[pos] != undefined && pattern.test(line[pos])) {\n str += line[pos];\n pos++;\n }\n return str;\n }\n /* http://dev.w3.org/html5/webvtt/#collect-a-webvtt-timestamp */\n function timestamp() {\n var units = 'minutes',\n val1,\n val2,\n val3,\n val4;\n // 3\n if (line[pos] == undefined) {\n err('No timestamp found.');\n return;\n }\n // 4\n if (!/\\d/.test(line[pos])) {\n err('Timestamp must start with a character in the range 0-9.');\n return;\n }\n // 5-7\n val1 = collect(/\\d/);\n if (val1.length > 2 || parseInt(val1, 10) > 59) {\n units = 'hours';\n }\n // 8\n if (line[pos] != ':') {\n err('No time unit separator found.');\n return;\n }\n pos++;\n // 9-11\n val2 = collect(/\\d/);\n if (val2.length != 2) {\n err('Must be exactly two digits.');\n return;\n }\n // 12\n if (units == 'hours' || line[pos] == ':') {\n if (line[pos] != ':') {\n err('No seconds found or minutes is greater than 59.');\n return;\n }\n pos++;\n val3 = collect(/\\d/);\n if (val3.length != 2) {\n err('Must be exactly two digits.');\n return;\n }\n } else {\n if (val1.length != 2) {\n err('Must be exactly two digits.');\n return;\n }\n val3 = val2;\n val2 = val1;\n val1 = '0';\n }\n // 13\n if (line[pos] != '.') {\n err('No decimal separator (\".\") found.');\n return;\n }\n pos++;\n // 14-16\n val4 = collect(/\\d/);\n if (val4.length != 3) {\n err('Milliseconds must be given in three digits.');\n return;\n }\n // 17\n if (parseInt(val2, 10) > 59) {\n err('You cannot have more than 59 minutes.');\n return;\n }\n if (parseInt(val3, 10) > 59) {\n err('You cannot have more than 59 seconds.');\n return;\n }\n return (\n parseInt(val1, 10) * 60 * 60 + parseInt(val2, 10) * 60 + parseInt(val3, 10) + parseInt(val4, 10) / 1000\n );\n }\n\n /* http://dev.w3.org/html5/webvtt/#parse-the-webvtt-settings */\n function parseSettings(input, cue) {\n var settings = input.split(SPACE),\n seen = [];\n for (var i = 0; i < settings.length; i++) {\n if (settings[i] == '') continue;\n\n var index = settings[i].indexOf(':'),\n setting = settings[i].slice(0, index),\n value = settings[i].slice(index + 1);\n\n if (seen.indexOf(setting) != -1) {\n err('Duplicate setting.');\n }\n seen.push(setting);\n\n if (value == '') {\n err('No value for setting defined.');\n return;\n }\n\n if (setting == 'vertical') {\n // writing direction\n if (value != 'rl' && value != 'lr') {\n err(\"Writing direction can only be set to 'rl' or 'rl'.\");\n continue;\n }\n cue.direction = value;\n } else if (setting == 'line') {\n // line position and optionally line alignment\n if (/,/.test(value)) {\n var comp = value.split(',');\n value = comp[0];\n var lineAlign = comp[1];\n }\n if (!/^[-\\d](\\d*)(\\.\\d+)?%?$/.test(value)) {\n err('Line position takes a number or percentage.');\n continue;\n }\n if (value.indexOf('-', 1) != -1) {\n err(\"Line position can only have '-' at the start.\");\n continue;\n }\n if (value.indexOf('%') != -1 && value.indexOf('%') != value.length - 1) {\n err(\"Line position can only have '%' at the end.\");\n continue;\n }\n if (value[0] == '-' && value[value.length - 1] == '%') {\n err('Line position cannot be a negative percentage.');\n continue;\n }\n var numVal = value;\n var isPercent = false;\n if (value[value.length - 1] == '%') {\n isPercent = true;\n numVal = value.slice(0, value.length - 1);\n if (parseInt(value, 10) > 100) {\n err('Line position cannot be >100%.');\n continue;\n }\n }\n if (numVal === '' || isNaN(numVal) || !isFinite(numVal)) {\n err('Line position needs to be a number');\n continue;\n }\n if (lineAlign !== undefined) {\n if (!['start', 'center', 'end'].includes(lineAlign)) {\n err('Line alignment needs to be one of start, center or end');\n continue;\n }\n cue.lineAlign = lineAlign;\n }\n cue.snapToLines = !isPercent;\n cue.linePosition = parseFloat(numVal);\n if (parseFloat(numVal).toString() !== numVal) {\n cue.nonSerializable = true;\n }\n } else if (setting == 'position') {\n // text position and optional positionAlign\n if (/,/.test(value)) {\n var comp = value.split(',');\n value = comp[0];\n var positionAlign = comp[1];\n }\n if (value[value.length - 1] != '%') {\n err('Text position must be a percentage.');\n continue;\n }\n if (parseInt(value, 10) > 100 || parseInt(value, 10) < 0) {\n err('Text position needs to be between 0 and 100%.');\n continue;\n }\n numVal = value.slice(0, value.length - 1);\n if (numVal === '' || isNaN(numVal) || !isFinite(numVal)) {\n err('Line position needs to be a number');\n continue;\n }\n if (positionAlign !== undefined) {\n if (!['line-left', 'center', 'line-right'].includes(positionAlign)) {\n err('Position alignment needs to be one of line-left, center or line-right');\n continue;\n }\n cue.positionAlign = positionAlign;\n }\n cue.textPosition = parseFloat(numVal);\n } else if (setting == 'size') {\n // size\n if (value[value.length - 1] != '%') {\n err('Size must be a percentage.');\n continue;\n }\n if (parseInt(value, 10) > 100) {\n err('Size cannot be >100%.');\n continue;\n }\n var size = value.slice(0, value.length - 1);\n if (size === undefined || size === '' || isNaN(size)) {\n err('Size needs to be a number');\n size = 100;\n continue;\n } else {\n size = parseFloat(size);\n if (size < 0 || size > 100) {\n err('Size needs to be between 0 and 100%.');\n continue;\n }\n }\n cue.size = size;\n } else if (setting == 'align') {\n // alignment\n var alignValues = ['start', 'center', 'end', 'left', 'right'];\n if (alignValues.indexOf(value) == -1) {\n err('Alignment can only be set to one of ' + alignValues.join(', ') + '.');\n continue;\n }\n cue.alignment = value;\n } else {\n err('Invalid setting.');\n }\n }\n }\n\n this.parse = function (cue, previousCueStart) {\n skip(SPACE);\n cue.startTime = timestamp();\n if (cue.startTime == undefined) {\n return;\n }\n if (cue.startTime < previousCueStart) {\n err('Start timestamp is not greater than or equal to start timestamp of previous cue.');\n }\n if (NOSPACE.test(line[pos])) {\n err(\"Timestamp not separated from '-->' by whitespace.\");\n }\n skip(SPACE);\n // 6-8\n if (line[pos] != '-') {\n err('No valid timestamp separator found.');\n return;\n }\n pos++;\n if (line[pos] != '-') {\n err('No valid timestamp separator found.');\n return;\n }\n pos++;\n if (line[pos] != '>') {\n err('No valid timestamp separator found.');\n return;\n }\n pos++;\n if (NOSPACE.test(line[pos])) {\n err(\"'-->' not separated from timestamp by whitespace.\");\n }\n skip(SPACE);\n cue.endTime = timestamp();\n if (cue.endTime == undefined) {\n return;\n }\n if (cue.endTime <= cue.startTime) {\n err('End timestamp is not greater than start timestamp.');\n }\n\n if (NOSPACE.test(line[pos])) {\n spaceBeforeSetting = false;\n }\n skip(SPACE);\n parseSettings(line.substring(pos), cue);\n return true;\n };\n this.parseTimestamp = function () {\n var ts = timestamp();\n if (line[pos] != undefined) {\n err('Timestamp must not have trailing characters.');\n return;\n }\n return ts;\n };\n };\n\n var WebVTTCueTextParser = function (line, errorHandler, mode, entities) {\n this.entities = entities;\n var self = this;\n var line = line,\n pos = 0,\n err = function (message) {\n if (mode == 'metadata') return;\n errorHandler(message, pos + 1);\n };\n\n this.parse = function (cueStart, cueEnd) {\n function removeCycles(tree) {\n const cyclelessTree = { ...tree };\n if (tree.children) {\n cyclelessTree.children = tree.children.map(removeCycles);\n }\n if (cyclelessTree.parent) {\n delete cyclelessTree.parent;\n }\n return cyclelessTree;\n }\n\n var result = { children: [] },\n current = result,\n timestamps = [];\n\n function attach(token) {\n current.children.push({\n type: 'object',\n name: token[1],\n classes: token[2],\n children: [],\n parent: current,\n });\n current = current.children[current.children.length - 1];\n }\n function inScope(name) {\n var node = current;\n while (node) {\n if (node.name == name) return true;\n node = node.parent;\n }\n return;\n }\n\n while (line[pos] != undefined) {\n var token = nextToken();\n if (token[0] == 'text') {\n current.children.push({ type: 'text', value: token[1], parent: current });\n } else if (token[0] == 'start tag') {\n if (mode == 'chapters') err('Start tags not allowed in chapter title text.');\n var name = token[1];\n if (name != 'v' && name != 'lang' && token[3] != '') {\n err('Only and can have an annotation.');\n }\n if (name == 'c' || name == 'i' || name == 'b' || name == 'u' || name == 'ruby') {\n attach(token);\n } else if (name == 'rt' && current.name == 'ruby') {\n attach(token);\n } else if (name == 'v') {\n if (inScope('v')) {\n err(' cannot be nested inside itself.');\n }\n attach(token);\n current.value = token[3]; // annotation\n if (!token[3]) {\n err(' requires an annotation.');\n }\n } else if (name == 'lang') {\n attach(token);\n current.value = token[3]; // language\n } else {\n err('Incorrect start tag.');\n }\n } else if (token[0] == 'end tag') {\n if (mode == 'chapters') err('End tags not allowed in chapter title text.');\n // XXX check content\n if (token[1] == current.name) {\n current = current.parent;\n } else if (token[1] == 'ruby' && current.name == 'rt') {\n current = current.parent.parent;\n } else {\n err('Incorrect end tag.');\n }\n } else if (token[0] == 'timestamp') {\n if (mode == 'chapters') err('Timestamp not allowed in chapter title text.');\n var timings = new WebVTTCueTimingsAndSettingsParser(token[1], err),\n timestamp = timings.parseTimestamp();\n if (timestamp != undefined) {\n if (timestamp <= cueStart || timestamp >= cueEnd) {\n err('Timestamp must be between start timestamp and end timestamp.');\n }\n if (timestamps.length > 0 && timestamps[timestamps.length - 1] >= timestamp) {\n err('Timestamp must be greater than any previous timestamp.');\n }\n current.children.push({ type: 'timestamp', value: timestamp, parent: current });\n timestamps.push(timestamp);\n }\n }\n }\n while (current.parent) {\n if (current.name != 'v') {\n err('Required end tag missing.');\n }\n current = current.parent;\n }\n return removeCycles(result);\n };\n\n function nextToken() {\n var state = 'data',\n result = '',\n buffer = '',\n classes = [];\n while (line[pos - 1] != undefined || pos == 0) {\n var c = line[pos];\n if (state == 'data') {\n if (c == '&') {\n buffer = c;\n state = 'escape';\n } else if (c == '<' && result == '') {\n state = 'tag';\n } else if (c == '<' || c == undefined) {\n return ['text', result];\n } else {\n result += c;\n }\n } else if (state == 'escape') {\n if (c == '<' || c == undefined) {\n err('Incorrect escape.');\n let m;\n if ((m = buffer.match(/^&#([0-9]+)$/))) {\n result += String.fromCharCode(m[1]);\n } else {\n if (self.entities[buffer]) {\n result += self.entities[buffer];\n } else {\n result += buffer;\n }\n }\n return ['text', result];\n } else if (c == '&') {\n err('Incorrect escape.');\n result += buffer;\n buffer = c;\n } else if (/[a-z#0-9]/i.test(c)) {\n buffer += c;\n } else if (c == ';') {\n let m;\n if ((m = buffer.match(/^&#(x?[0-9]+)$/))) {\n // we prepend \"0\" so that x20 be interpreted as hexadecim (0x20)\n result += String.fromCharCode('0' + m[1]);\n } else if (self.entities[buffer + c]) {\n result += self.entities[buffer + c];\n } else if ((m = Object.keys(entities).find((n) => buffer.startsWith(n)))) {\n // partial match\n result += self.entities[m] + buffer.slice(m.length) + c;\n } else {\n err('Incorrect escape.');\n result += buffer + ';';\n }\n state = 'data';\n } else {\n err('Incorrect escape.');\n result += buffer + c;\n state = 'data';\n }\n } else if (state == 'tag') {\n if (c == '\\t' || c == '\\n' || c == '\\f' || c == ' ') {\n state = 'start tag annotation';\n } else if (c == '.') {\n state = 'start tag class';\n } else if (c == '/') {\n state = 'end tag';\n } else if (/\\d/.test(c)) {\n result = c;\n state = 'timestamp tag';\n } else if (c == '>' || c == undefined) {\n if (c == '>') {\n pos++;\n }\n return ['start tag', '', [], ''];\n } else {\n result = c;\n state = 'start tag';\n }\n } else if (state == 'start tag') {\n if (c == '\\t' || c == '\\f' || c == ' ') {\n state = 'start tag annotation';\n } else if (c == '\\n') {\n buffer = c;\n state = 'start tag annotation';\n } else if (c == '.') {\n state = 'start tag class';\n } else if (c == '>' || c == undefined) {\n if (c == '>') {\n pos++;\n }\n return ['start tag', result, [], ''];\n } else {\n result += c;\n }\n } else if (state == 'start tag class') {\n if (c == '\\t' || c == '\\f' || c == ' ') {\n if (buffer) {\n classes.push(buffer);\n }\n buffer = '';\n state = 'start tag annotation';\n } else if (c == '\\n') {\n if (buffer) {\n classes.push(buffer);\n }\n buffer = c;\n state = 'start tag annotation';\n } else if (c == '.') {\n if (buffer) {\n classes.push(buffer);\n }\n buffer = '';\n } else if (c == '>' || c == undefined) {\n if (c == '>') {\n pos++;\n }\n if (buffer) {\n classes.push(buffer);\n }\n return ['start tag', result, classes, ''];\n } else {\n buffer += c;\n }\n } else if (state == 'start tag annotation') {\n if (c == '>' || c == undefined) {\n if (c == '>') {\n pos++;\n }\n buffer = buffer\n .split(/[\\u0020\\t\\f\\r\\n]+/)\n .filter(function (item) {\n if (item) return true;\n })\n .join(' ');\n return ['start tag', result, classes, buffer];\n } else {\n buffer += c;\n }\n } else if (state == 'end tag') {\n if (c == '>' || c == undefined) {\n if (c == '>') {\n pos++;\n }\n return ['end tag', result];\n } else {\n result += c;\n }\n } else if (state == 'timestamp tag') {\n if (c == '>' || c == undefined) {\n if (c == '>') {\n pos++;\n }\n return ['timestamp', result];\n } else {\n result += c;\n }\n } else {\n err('Never happens.'); // The joke is it might.\n }\n // 8\n pos++;\n }\n }\n };\n\n var WebVTTSerializer = function () {\n function serializeTimestamp(seconds) {\n const ms = ('00' + (seconds - Math.floor(seconds)).toFixed(3) * 1000).slice(-3);\n let h = 0,\n m = 0,\n s = 0;\n if (seconds >= 3600) {\n h = Math.floor(seconds / 3600);\n }\n m = Math.floor((seconds - 3600 * h) / 60);\n s = Math.floor(seconds - 3600 * h - 60 * m);\n return (h ? h + ':' : '') + ('' + m).padStart(2, '0') + ':' + ('' + s).padStart(2, '0') + '.' + ms;\n }\n function serializeCueSettings(cue) {\n var result = '';\n const nonDefaultSettings = Object.keys(defaultCueSettings).filter((s) => cue[s] !== defaultCueSettings[s]);\n if (nonDefaultSettings.includes('direction')) {\n result += ' vertical:' + cue.direction;\n }\n if (nonDefaultSettings.includes('alignment')) {\n result += ' align:' + cue.alignment;\n }\n if (nonDefaultSettings.includes('size')) {\n result += ' size:' + cue.size + '%';\n }\n if (nonDefaultSettings.includes('lineAlign') || nonDefaultSettings.includes('linePosition')) {\n result +=\n ' line:' +\n cue.linePosition +\n (cue.snapToLines ? '' : '%') +\n (cue.lineAlign && cue.lineAlign != defaultCueSettings.lineAlign ? ',' + cue.lineAlign : '');\n }\n if (nonDefaultSettings.includes('textPosition') || nonDefaultSettings.includes('positionAlign')) {\n result +=\n ' position:' +\n cue.textPosition +\n '%' +\n (cue.positionAlign && cue.positionAlign !== defaultCueSettings.positionAlign\n ? ',' + cue.positionAlign\n : '');\n }\n return result;\n }\n function serializeTree(tree) {\n var result = '';\n for (var i = 0; i < tree.length; i++) {\n var node = tree[i];\n if (node.type == 'text') {\n result += node.value.replace(/&/g, '&').replace(//g, '>');\n } else if (node.type == 'object') {\n result += '<' + node.name;\n if (node.classes) {\n for (var y = 0; y < node.classes.length; y++) {\n result += '.' + node.classes[y];\n }\n }\n if (node.value) {\n result += ' ' + node.value;\n }\n result += '>';\n if (node.children) result += serializeTree(node.children);\n result += '';\n } else if (node.type == 'timestamp') {\n result += '<' + serializeTimestamp(node.value) + '>';\n } else {\n result += '<' + node.value + '>';\n }\n }\n return result;\n }\n function serializeCue(cue) {\n return (\n (cue.id !== undefined ? cue.id + '\\n' : '') +\n serializeTimestamp(cue.startTime) +\n ' --> ' +\n serializeTimestamp(cue.endTime) +\n serializeCueSettings(cue) +\n '\\n' +\n serializeTree(cue.tree.children) +\n '\\n\\n'\n );\n }\n function serializeStyle(style) {\n return 'STYLE\\n' + style + '\\n\\n';\n }\n this.serialize = function (cues, styles) {\n var result = 'WEBVTT\\n\\n';\n if (styles) {\n for (var i = 0; i < styles.length; i++) {\n result += serializeStyle(styles[i]);\n }\n }\n for (var i = 0; i < cues.length; i++) {\n result += serializeCue(cues[i]);\n }\n return result;\n };\n };\n\n function exportify(object) {\n object.WebVTTParser = WebVTTParser;\n object.WebVTTCueTimingsAndSettingsParser = WebVTTCueTimingsAndSettingsParser;\n object.WebVTTCueTextParser = WebVTTCueTextParser;\n object.WebVTTSerializer = WebVTTSerializer;\n }\n if (typeof window !== 'undefined') exportify(window);\n if (typeof exports !== 'undefined') exportify(exports);\n})();\n","exports.interopDefault = function (a) {\n return a && a.__esModule ? a : {default: a};\n};\n\nexports.defineInteropFlag = function (a) {\n Object.defineProperty(a, '__esModule', {value: true});\n};\n\nexports.exportAll = function (source, dest) {\n Object.keys(source).forEach(function (key) {\n if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) {\n return;\n }\n\n Object.defineProperty(dest, key, {\n enumerable: true,\n get: function () {\n return source[key];\n },\n });\n });\n\n return dest;\n};\n\nexports.export = function (dest, destName, get) {\n Object.defineProperty(dest, destName, {\n enumerable: true,\n get: get,\n });\n};\n"],"names":[],"version":3,"file":"index.js.map","sourceRoot":"../../../"} \ No newline at end of file diff --git a/packages/artplayer-plugin-multiple-subtitles/src/index.js b/packages/artplayer-plugin-multiple-subtitles/src/index.js index db7e0de24..3039b818b 100644 --- a/packages/artplayer-plugin-multiple-subtitles/src/index.js +++ b/packages/artplayer-plugin-multiple-subtitles/src/index.js @@ -33,14 +33,13 @@ async function loadSubtitleAsVtt(option, art) { } } -function mergeVtts(vtts, subtitles) { +function mergeTrees(trees, subtitles) { const parser = new WebVTTParser(); - const seri = new WebVTTSerializer(); const result = parser.parse('', 'metadata'); - for (let i = 0; i < vtts.length; i++) { + for (let i = 0; i < trees.length; i++) { + const tree = trees[i]; const option = subtitles[i]; - const tree = parser.parse(vtts[i], 'metadata'); for (let j = 0; j < tree.cues.length; j++) { const cue = tree.cues[j]; @@ -59,28 +58,37 @@ function mergeVtts(vtts, subtitles) { } } - return seri.serialize(result.cues); + return result; } -export default function artplayerPluginMultipleSubtitles({ subtitles }) { +export default function artplayerPluginMultipleSubtitles({ subtitles, onMerge = () => null }) { return async (art) => { const vtts = await Promise.all(subtitles.map((option) => loadSubtitleAsVtt(option, art))); - const vtt = mergeVtts(vtts, subtitles); - const url = URL.createObjectURL(new Blob([vtt], { type: 'text/vtt' })); - - art.option.subtitle.escape = false; - - art.subtitle.init({ - ...art.option.subtitle, - url, - type: 'vtt', - onVttLoad: unescape, - }); + const parser = new WebVTTParser(); + const trees = vtts.map((vtt) => parser.parse(vtt, 'metadata')); + const seri = new WebVTTSerializer(); + const tree = onMerge(trees, subtitles) || mergeTrees(trees, subtitles); + if (tree?.cues?.length) { + const vtt = seri.serialize(tree.cues); + const url = URL.createObjectURL(new Blob([vtt], { type: 'text/vtt' })); + art.option.subtitle.escape = false; + art.subtitle.init({ + ...art.option.subtitle, + url, + type: 'vtt', + onVttLoad: unescape, + }); + } else { + throw new Error('No subtitle found'); + } }; } + artplayerPluginMultipleSubtitles.env = process.env.NODE_ENV; artplayerPluginMultipleSubtitles.version = process.env.APP_VER; artplayerPluginMultipleSubtitles.build = process.env.BUILD_DATE; +artplayerPluginMultipleSubtitles.WebVTTParser = WebVTTParser; +artplayerPluginMultipleSubtitles.WebVTTSerializer = WebVTTSerializer; if (typeof window !== 'undefined') { window['artplayerPluginMultipleSubtitles'] = artplayerPluginMultipleSubtitles; diff --git a/packages/artplayer-plugin-multiple-subtitles/types/artplayer-plugin-multiple-subtitles.d.ts b/packages/artplayer-plugin-multiple-subtitles/types/artplayer-plugin-multiple-subtitles.d.ts index 9ad0bbff1..a4ba37c7f 100644 --- a/packages/artplayer-plugin-multiple-subtitles/types/artplayer-plugin-multiple-subtitles.d.ts +++ b/packages/artplayer-plugin-multiple-subtitles/types/artplayer-plugin-multiple-subtitles.d.ts @@ -9,6 +9,7 @@ declare const artplayerPluginMultipleSubtitles: (option: { name?: string; type?: 'vtt' | 'srt' | 'ass'; encoding?: string; + onParser?(...args: object[]): object; }[]; }) => (art: Artplayer) => { name: 'artplayerPluginMultipleSubtitles';