vendor: 9,642 bytes, lines 1-293
1import { b as VTTCue, p as parseVTTTimestamp } from './index.js'; 2 3const FORMAT_START_RE = /^Format:[\s\t]*/, STYLE_START_RE = /^Style:[\s\t]*/, DIALOGUE_START_RE = /^Dialogue:[\s\t]*/, FORMAT_SPLIT_RE = /[\s\t]*,[\s\t]*/, STYLE_FUNCTION_RE = /\{[^}]+\}/g, NEW_LINE_RE = /\\N/g, STYLES_SECTION_START_RE = /^\[(.*)[\s\t]?Styles\]$/, EVENTS_SECTION_START_RE = /^\[(.*)[\s\t]?Events\]$/; 4class SSAParser { 5 f; 6 O = 0; 7 a = null; 8 j = []; 9 k = []; 10 N = null; 11 d; 12 P = {}; 13 async init(init) { 14 this.f = init; 15 if (init.errors) 16 this.d = (await import('./errors.js')).ParseErrorBuilder; 17 } 18 parse(line, lineCount) { 19 if (this.O) { 20 switch (this.O) { 21 case 1: 22 if (line === "") { 23 this.O = 0; 24 } else if (STYLE_START_RE.test(line)) { 25 if (this.N) { 26 const styles = line.replace(STYLE_START_RE, "").split(FORMAT_SPLIT_RE); 27 this.S(styles); 28 } else { 29 this.e(this.d?.T("Style", lineCount)); 30 } 31 } else if (FORMAT_START_RE.test(line)) { 32 this.N = line.replace(FORMAT_START_RE, "").split(FORMAT_SPLIT_RE); 33 } else if (EVENTS_SECTION_START_RE.test(line)) { 34 this.N = null; 35 this.O = 2; 36 } 37 break; 38 case 2: 39 if (line === "") { 40 this.Q(); 41 } else if (DIALOGUE_START_RE.test(line)) { 42 this.Q(); 43 if (this.N) { 44 const dialogue = line.replace(DIALOGUE_START_RE, "").split(FORMAT_SPLIT_RE), cue = this.U(dialogue, lineCount); 45 if (cue) 46 this.a = cue; 47 } else { 48 this.e(this.d?.T("Dialogue", lineCount)); 49 } 50 } else if (this.a) { 51 this.a.text += "\n" + line.replace(STYLE_FUNCTION_RE, "").replace(NEW_LINE_RE, "\n"); 52 } else if (FORMAT_START_RE.test(line)) { 53 this.N = line.replace(FORMAT_START_RE, "").split(FORMAT_SPLIT_RE); 54 } else if (STYLES_SECTION_START_RE.test(line)) { 55 this.N = null; 56 this.O = 1; 57 } else if (EVENTS_SECTION_START_RE.test(line)) { 58 this.N = null; 59 } 60 } 61 } else if (line === "") ; else if (STYLES_SECTION_START_RE.test(line)) { 62 this.N = null; 63 this.O = 1; 64 } else if (EVENTS_SECTION_START_RE.test(line)) { 65 this.N = null; 66 this.O = 2; 67 } 68 } 69 done() { 70 return { 71 metadata: {}, 72 cues: this.j, 73 regions: [], 74 errors: this.k 75 }; 76 } 77 Q() { 78 if (!this.a) 79 return; 80 this.j.push(this.a); 81 this.f.onCue?.(this.a); 82 this.a = null; 83 } 84 S(values) { 85 let name = "Default", styles = {}, outlineX, align = "center", vertical = "bottom", marginV, outlineY = 1.2, outlineColor, bgColor, borderStyle = 3, transform = []; 86 for (let i = 0; i < this.N.length; i++) { 87 const field = this.N[i], value = values[i]; 88 switch (field) { 89 case "Name": 90 name = value; 91 break; 92 case "Fontname": 93 styles["font-family"] = value; 94 break; 95 case "Fontsize": 96 styles["font-size"] = `calc(${value} / var(--overlay-height))`; 97 break; 98 case "PrimaryColour": 99 const color = parseColor(value); 100 if (color) 101 styles["--cue-color"] = color; 102 break; 103 case "BorderStyle": 104 borderStyle = parseInt(value, 10); 105 break; 106 case "BackColour": 107 bgColor = parseColor(value); 108 break; 109 case "OutlineColour": 110 const _outlineColor = parseColor(value); 111 if (_outlineColor) 112 outlineColor = _outlineColor; 113 break; 114 case "Bold": 115 if (parseInt(value)) 116 styles["font-weight"] = "bold"; 117 break; 118 case "Italic": 119 if (parseInt(value)) 120 styles["font-style"] = "italic"; 121 break; 122 case "Underline": 123 if (parseInt(value)) 124 styles["text-decoration"] = "underline"; 125 break; 126 case "StrikeOut": 127 if (parseInt(value)) 128 styles["text-decoration"] = "line-through"; 129 break; 130 case "Spacing": 131 styles["letter-spacing"] = value + "px"; 132 break; 133 case "AlphaLevel": 134 styles["opacity"] = parseFloat(value); 135 break; 136 case "ScaleX": 137 transform.push(`scaleX(${parseFloat(value) / 100})`); 138 break; 139 case "ScaleY": 140 transform.push(`scaleY(${parseFloat(value) / 100})`); 141 break; 142 case "Angle": 143 transform.push(`rotate(${value}deg)`); 144 break; 145 case "Shadow": 146 outlineY = parseInt(value, 10) * 1.2; 147 break; 148 case "MarginL": 149 styles["--cue-width"] = "auto"; 150 styles["--cue-left"] = parseFloat(value) + "px"; 151 break; 152 case "MarginR": 153 styles["--cue-width"] = "auto"; 154 styles["--cue-right"] = parseFloat(value) + "px"; 155 break; 156 case "MarginV": 157 marginV = parseFloat(value); 158 break; 159 case "Outline": 160 outlineX = parseInt(value, 10); 161 break; 162 case "Alignment": 163 const alignment = parseInt(value, 10); 164 if (alignment >= 4) 165 vertical = alignment >= 7 ? "top" : "center"; 166 switch (alignment % 3) { 167 case 1: 168 align = "start"; 169 break; 170 case 2: 171 align = "center"; 172 break; 173 case 3: 174 align = "end"; 175 break; 176 } 177 } 178 } 179 styles.R = vertical; 180 styles["--cue-white-space"] = "normal"; 181 styles["--cue-line-height"] = "normal"; 182 styles["--cue-text-align"] = align; 183 if (vertical === "center") { 184 styles[`--cue-top`] = "50%"; 185 transform.push("translateY(-50%)"); 186 } else { 187 styles[`--cue-${vertical}`] = (marginV || 0) + "px"; 188 } 189 if (borderStyle === 1) { 190 styles["--cue-padding-y"] = "0"; 191 } 192 if (borderStyle === 1 || bgColor) { 193 styles["--cue-bg-color"] = borderStyle === 1 ? "none" : bgColor; 194 } 195 if (borderStyle === 3 && outlineColor) { 196 styles["--cue-outline"] = `${outlineX}px solid ${outlineColor}`; 197 } 198 if (borderStyle === 1 && typeof outlineX === "number") { 199 const color = bgColor ?? "#000"; 200 styles["--cue-text-shadow"] = [ 201 outlineColor && buildTextShadow(outlineX * 1.2, outlineY * 1.2, outlineColor), 202 outlineColor ? buildTextShadow(outlineX * (outlineX / 2), outlineY * (outlineX / 2), color) : buildTextShadow(outlineX, outlineY, color) 203 ].filter(Boolean).join(", "); 204 } 205 if (transform.length) 206 styles["--cue-transform"] = transform.join(" "); 207 this.P[name] = styles; 208 } 209 U(values, lineCount) { 210 const fields = this.V(values); 211 const timestamp = this.o(fields.Start, fields.End, lineCount); 212 if (!timestamp) 213 return; 214 const cue = new VTTCue(timestamp[0], timestamp[1], ""), styles = { ...this.P[fields.Style] || {} }, voice = fields.Name ? `<v ${fields.Name}>` : ""; 215 const vertical = styles.R, marginLeft = fields.MarginL && parseFloat(fields.MarginL), marginRight = fields.MarginR && parseFloat(fields.MarginR), marginV = fields.MarginV && parseFloat(fields.MarginV); 216 if (marginLeft) { 217 styles["--cue-width"] = "auto"; 218 styles["--cue-left"] = marginLeft + "px"; 219 } 220 if (marginRight) { 221 styles["--cue-width"] = "auto"; 222 styles["--cue-right"] = marginRight + "px"; 223 } 224 if (marginV && vertical !== "center") { 225 styles[`--cue-${vertical}`] = marginV + "px"; 226 } 227 cue.text = voice + values.slice(this.N.length - 1).join(", ").replace(STYLE_FUNCTION_RE, "").replace(NEW_LINE_RE, "\n"); 228 delete styles.R; 229 if (Object.keys(styles).length) 230 cue.style = styles; 231 return cue; 232 } 233 V(values) { 234 const fields = {}; 235 for (let i = 0; i < this.N.length; i++) { 236 fields[this.N[i]] = values[i]; 237 } 238 return fields; 239 } 240 o(startTimeText, endTimeText, lineCount) { 241 const startTime = parseVTTTimestamp(startTimeText), endTime = parseVTTTimestamp(endTimeText); 242 if (startTime !== null && endTime !== null && endTime > startTime) { 243 return [startTime, endTime]; 244 } else { 245 if (startTime === null) { 246 this.e(this.d?.q(startTimeText, lineCount)); 247 } 248 if (endTime === null) { 249 this.e(this.d?.r(endTimeText, lineCount)); 250 } 251 if (startTime != null && endTime !== null && endTime > startTime) { 252 this.e(this.d?.s(startTime, endTime, lineCount)); 253 } 254 } 255 } 256 e(error) { 257 if (!error) 258 return; 259 this.k.push(error); 260 if (this.f.strict) { 261 this.f.cancel(); 262 throw error; 263 } else { 264 this.f.onError?.(error); 265 } 266 } 267} 268function parseColor(color) { 269 const abgr = parseInt(color.replace("&H", ""), 16); 270 if (abgr >= 0) { 271 const a = abgr >> 24 & 255 ^ 255; 272 const alpha = a / 255; 273 const b = abgr >> 16 & 255; 274 const g = abgr >> 8 & 255; 275 const r = abgr & 255; 276 return "rgba(" + [r, g, b, alpha].join(",") + ")"; 277 } 278 return null; 279} 280function buildTextShadow(x, y, color) { 281 const noOfShadows = Math.ceil(2 * Math.PI * x); 282 let textShadow = ""; 283 for (let i = 0; i < noOfShadows; i++) { 284 const theta = 2 * Math.PI * i / noOfShadows; 285 textShadow += x * Math.cos(theta) + "px " + y * Math.sin(theta) + "px 0 " + color + (i == noOfShadows - 1 ? "" : ","); 286 } 287 return textShadow; 288} 289function createSSAParser() { 290 return new SSAParser(); 291} 292 293export { SSAParser, createSSAParser as default };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.