@transcrobes/subs-convert
Version:
Convert subtitles from one format to another
52 lines (48 loc) • 23.9 kB
JavaScript
;var jt=Object.defineProperty;var Nt=(t,e,n)=>e in t?jt(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var W=(t,e,n)=>Nt(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("ramda"),l=require("joi"),Dt=require("xml2js");function Ht(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const n in t)if(n!=="default"){const r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:()=>t[n]})}}return e.default=t,Object.freeze(e)}const N=Ht(y),Pt="(?:\\r\\n|\\n|\\r)",dt=`^\\s*WEBVTT[^]*?${Pt}{2,}`,Xt="\\d{2}:\\d{2}:\\d{2}[;:]\\d{2}",ft=`${Xt}(?:(\\s)[a-fA-F0-9]{4})+[ ]?`,mt="^([^]+?)?<tt.*?>",pt="^([^]+?)?\\[Script Info\\]",gt="-->",_t=new RegExp(`(${dt}|${ft}|${mt}|${pt}|${gt})`),kt=[{extension:".vtt",regex:new RegExp(dt)},{extension:".scc",regex:new RegExp(ft)},{extension:".ttml",regex:new RegExp(mt)},{extension:".ass",regex:new RegExp(pt)},{extension:".srt",regex:new RegExp(gt)}],O=l.object().keys({global:l.object().keys({language:l.string(),color:l.string(),textAlign:l.string()}),body:l.array().items(l.object().keys({id:l.string(),timecode:l.string(),startMicro:l.number().unit("microseconds"),endMicro:l.number().unit("microseconds"),captions:{frames:l.number().integer(),popOn:l.boolean(),paintOn:l.boolean(),rollUpRows:l.number().integer(),commands:l.string()},styles:l.object().keys({align:l.string(),line:l.string(),position:l.string(),size:l.string()}),text:l.string()})),source:l.any()}),Lt=l.object().keys({subtitleText:l.string().regex(_t).required().error(()=>"Input file type is not supported."),outputExtension:l.string().required(),options:l.object().keys({shiftTimecode:l.number(),sourceFps:l.number().positive(),outputFps:l.number().positive(),removeTextFormatting:l.boolean(),timecodeOverlapLimiter:l.alternatives().try(l.number().positive().allow(0),l.boolean()),combineOverlapping:l.boolean(),startAtZeroHour:l.boolean()})});function Bt(t){return t/1e3}function et(t){return Bt(t/1e3)}function ht(t){return t*1e3}function C(t){return ht(t*1e3)}function Et(t){return C(t*60)}function Tt(t){return Et(t*60)}function Vt(t,e){if(!t||!e)return 0;const n=t/e;return C(n)}function b(t,e){if(!t)return 0;const n=t.replace(",",".").split(":");let r="0",s="0",o="0",i="";n.length===4?[r,s,o,i]=n:n.length===3?[r,s,o]=n:n.length===2?[s,o]=n:n.length===1&&([o]=n);const c=o.split("."),a=c[0]||"0",u=c[1]||"0",m=a.split(";")[1]||i;if(m)throw Error(`Timecode (${t}) contains frames, but no fps was specified.`);return Tt(parseInt(r,10))+Et(parseInt(s,10))+C(parseInt(a,10))+ht(parseInt(u,10))+Vt(parseInt(m||"0",10),parseFloat("0"))}function nt(t){const e=Math.floor(t/1e3),n=e%1e3,r=Math.floor(e/1e3),s=r%60,o=Math.floor(r/60),i=o%60;return Math.floor(o/60).toString().padStart(2,"0")+":"+i.toString().padStart(2,"0")+":"+s.toString().padStart(2,"0")+","+n.toString().padStart(3,"0")}function Wt(t){return[{regex:/^<br>/m,value:""},{regex:/<br>/g,value:`
`},{regex:/<.*?>/g,value:""},{regex:/{.*?}/g,value:" "},{regex:/(>|<|{|})/g,value:""},{regex:/ {2,}/g,value:" "},{regex:/^\s+|\s+$/gm,value:""}].reduce((n,{regex:r,value:s})=>n.replace(r,s),t)}function F(t,e=!1){if(!t)return"";let n=t.replace(/[\n]+/g,`
`).trim();return e&&(n=Wt(n)),n}function vt(t){let e;return kt.some(n=>(n.regex.test(t)&&(e=n.extension),!!e)),e}const T={COMMANDS:{1020:"",1023:"",1140:""},CHARACTERS:{20:" ",a1:"!","7f":"",80:""},SPECIAL_CHARS:{"91b0":"®",9131:"°","91bf":"û"},EXTENDED_CHARS:{9220:"Á","92a1":"É","13bf":"┘"}},Ut="Scenarist_SCC V1.0",Gt=new RegExp(Ut),zt="([0-9:;]*)([ ]*)((.)*)",Zt=new RegExp(zt);let I,S="",k=!1,w=!1,p="",L=[],R="",P="";const qt=["9425","9426","94a7"];let $=0,x=[],X="",M=0,f=[];function z(t,e,n){const r={startTimeMicro:typeof e=="string"?parseFloat(e):e,endTimeMicro:void 0,frames:n,popOn:k,paintOn:w,rollUpRows:$,commands:L.join(" "),text:t};L=[],f.push(r)}function _(t){x.length>=$?x.shift():x.push(p),f[f.length-1]!==void 0&&f[f.length-1].endTimeMicro===void 0&&(f[f.length-1].endTimeMicro=parseFloat(R)),p=x.join(" "),z(p,R,M),p="",x=[],x.length===$&&(f[f.length-1]!==void 0&&f[f.length-1].endTimeMicro===void 0&&(f[f.length-1].endTimeMicro=parseFloat(R)),p=x.join(" "),z(p,R,M),p="",x=[])}function Z(t){return t===X?(X="",!0):(X=t,!1)}function Jt(t){return Gt.test(t.trim())}function Kt(t){let e=0;for(f=[],I="",S="",k=!1,w=!1,p="",L=[],R="",P="",$=0,x=[],X="",M=0,e=0;e<t.length;e+=1)Jt(t[e])||Yt(t[e].toLowerCase());return p.length>0&&_(),f.length===0?[{startTimeMicro:0,endTimeMicro:0,frames:0,popOn:!1,paintOn:!1,rollUpRows:0,commands:"default command",text:"Default caption text"}]:(f=f.map(n=>(n.endTimeMicro===void 0&&(n.endTimeMicro=n.startTimeMicro),n.text||(n.text="Empty caption"),n)),f)}function Yt(t){if(t.length===0)return;let e;const n=t.match(Zt);if(!n)return;const r=n[3].split(" ");for(I=n[1],M=0,e=0;e<r.length;e+=1)L.push(r[e]),Qt(r[e])}function Qt(t){M+=1,T.COMMANDS.hasOwnProperty(t)?te(t):T.SPECIAL_CHARS.hasOwnProperty(t)?ee(t):T.EXTENDED_CHARS.hasOwnProperty(t)&&ne(t),re(t)}function te(t){const e=t;Z(e)||(e==="9420"?(k=!0,w=!1):qt.indexOf(e)>-1?(w=!0,k=!1,e==="9429"?$=1:e==="9425"?$=2:e==="9426"?$=3:e==="94a7"&&($=4),p.length>0&&(_(),p=""),R=U(I,M)):e==="94ae"?S="":e==="942f"&&S.length>0?(P=U(I,M),f[f.length-1]!==void 0&&f[f.length-1].endTimeMicro===void 0&&(f[f.length-1].endTimeMicro=parseFloat(P)),z(S,P,M),S=""):e==="94ad"?p.length>0&&_():e==="942c"?(x=[],p.length>0&&_(),f[f.length-1]!==void 0&&f[f.length-1].endTimeMicro===void 0&&(f[f.length-1].endTimeMicro=parseFloat(U(I,M)))):w?p+=T.COMMANDS[e]||"":S+=T.COMMANDS[e]||"")}function ee(t){Z(t)||(w?p+=T.SPECIAL_CHARS[t]:S+=T.SPECIAL_CHARS[t])}function ne(t){Z(t)||(w?(p.length>0&&(p=p.substring(0,p.length-1)),p+=T.EXTENDED_CHARS[t]):(S.length>0&&(S=S.substring(0,S.length-1)),S+=T.EXTENDED_CHARS[t]))}function re(t){if(t.length>0){const e=t.match(/.{1,2}/gi);if(!e||T.CHARACTERS[e[0]]===void 0||T.CHARACTERS[e[1]]===void 0)return;w?(p+=T.CHARACTERS[e[0]],p+=T.CHARACTERS[e[1]]):(S+=T.CHARACTERS[e[0]],S+=T.CHARACTERS[e[1]])}}function U(t,e){let n;const r=/;/.test(t),s=t.replace(/;/g,":").split(":"),o=parseInt(s[s.length-1],10);return o+e<=9?n=`0${o+e}`:n=o+e,s[s.length-1]=n.toString(),se(s.join(":"),r)}function se(t,e){const n=e?1:1.001,r=t.split(":"),i=(parseInt(r[0],10)*3600+parseInt(r[1],10)*60+parseInt(r[2],10)+parseInt(r[3],10)/30)*n*1e3*1e3;return(i>0?i:0).toString()}function oe(t,e={}){const{removeTextFormatting:n=!1}=e;return{global:{},body:t.map((r,s)=>({id:(s+1).toString(),startMicro:r.startTimeMicro,endMicro:r.endTimeMicro??r.startTimeMicro,captions:{frames:r.frames,popOn:r.popOn,paintOn:r.paintOn,rollUpRows:r.rollUpRows,commands:r.commands},text:F(r.text,n)})).filter(r=>r.text).map((r,s)=>(r.id=(s+1).toString(),r)),source:t}}function ie(t,e={}){const n={success:!0,invalidEntries:[],invalidTimecodes:[],invalidIndices:[]},r=t.split(/\r\n|\n|\r/),s=Kt(r),{error:o,value:i}=O.validate(oe(s,e),{abortEarly:!1});if(o)throw new Error(o.details.map(c=>c.message).join(", "));return n.invalidEntries&&n.invalidEntries.length&&(n.success=!1),{data:i,status:n}}const j=".*\\d.*-->.*\\d.*",ae=`^\\n*?.+(?=\\n${j})`,ce=`(?=(?:\\n(?:\\n.+\\n||\\n)${j}|$))`,St="\\d{2}",xt="[0-5]\\d",Mt="[0-5]\\d",yt="\\d{3}",G="[^\\n\\d]+?",B=`${St}${G}${xt}${G}${Mt}${G}${yt}`,$t=`${B}[^\\n\\d]+?${B}(?=(\\n|$))`,le="[^]+",ue=`(${B})`,de=`(${B})`,fe=`(${le})`,wt=new RegExp(ae,"g"),rt=new RegExp(j,"g"),me=new RegExp(`(\\n*)(?:.+\\n)?${j}[^]+?${ce}`,"g"),pe=new RegExp(`^[^]+?(?=${j})`,"g"),ge=new RegExp($t),he=new RegExp(`${ue}[^\\n\\d]+?${de}[^\\n\\d]*?\\n${fe}`),Ee=new RegExp(`${$t}\\s*$`),Te=new RegExp(`${St}:${xt}:${Mt},${yt}`);function st(t){return Te.test(t)?t:t.replace(/[^\d]+/g,":").replace(/:(?=\d{3})/,",")}function ve(t,e,n,r,s){var m,g,h;t.status.success=!1;const o=e.match(wt),i=o?o[0]:"",c=e.match(rt),a=c?c[0]:void 0,u=c?e.split(rt)[1]:void 0,d={id:i,timecode:a,text:u};return n.invalidEntries&&((m=t.status.invalidEntries)==null||m.push(d)),n.invalidIndices&&s&&((g=t.status.invalidIndices)==null||g.push({id:i})),n.invalidTimecodes&&r&&((h=t.status.invalidTimecodes)==null||h.push({id:i,timecode:a})),t}function Se(t,e){const n=e.match(he);if(!n)return t;const r=st(n[1]),s=st(n[2]),o=n[3];return t.validEntries.push({id:t.currentIndex.toString(),timecode:`${r} --> ${s}`,startMicro:b(r),endMicro:b(s),text:o}),t.currentIndex+=1,t}function xe(t,e={invalidEntries:!0,invalidTimecodes:!0,invalidIndices:!0}){var a;const n={currentIndex:1,validEntries:[],status:{success:!0,invalidEntries:[],invalidTimecodes:[],invalidIndices:[]}};t=t.replace(/(\r\n|\r)/g,`
`);const r=t.match(me);if(!r)return n.validEntries=[],n.status.success=!1,{data:{global:{},body:[],source:[]},status:n.status};const s=t.match(pe),o=s?s[0]:"";!/^(\n*(.+\n)?|0)$/.test(o)&&(n.status.success=!1,(a=n.status.invalidEntries)==null||a.push({id:"0",timecode:"00:00:00:000",text:o}));const c=r.reduce((u,d)=>{d=d.replace(/\n{2,}/g,`
`).trim();const m=d.match(wt),g=m?!/^\d+$/.test(m[0]):!1,h=!d.match(ge);return h||g?ve(u,d,e,h,g):Ee.test(d)?u:Se(u,d)},n);return{data:{global:{},body:c.validEntries,source:[]},status:c.status}}function Me(t,e={}){const{removeTextFormatting:n=!1}=e;return{global:{},body:t.map(r=>({id:r.id,timecode:r.timecode??"",startMicro:r.startMicro,endMicro:r.endMicro,text:F(r.text,n).normalize("NFKC")})).filter(r=>r.text).map((r,s)=>(r.id=(s+1).toString(),r)),source:t}}function ye(t,e={}){const{data:n,status:r}=xe(t),{error:s,value:o}=O.validate(Me(n.body,e),{abortEarly:!1});if(s)throw new Error(s.details.map(i=>i.message).join(", "));return{data:o,status:r}}function $e(t,e={}){const{removeTextFormatting:n=!1}=e,r=N.path(["tt","$"],t),s=N.path(["tt","body","0","div","0","p"],t);return{global:{language:r["xml:lang"]},body:s.map((o,i)=>({id:i.toString(),startMicro:b(N.path(["$","begin"],o)),endMicro:b(N.path(["$","end"],o)),text:F(o._,n)})).filter(o=>o.text).map((o,i)=>(o.id=(i+1).toString(),o)),source:t}}function we(t,e={}){const n={success:!0,invalidEntries:[],invalidTimecodes:[],invalidIndices:[]},r=new Dt.Parser({async:!1});let s;if(r.parseString(t,(c,a)=>{c&&n.invalidEntries.push({id:"0",text:c.message}),s=a}),!s)throw Error("Failed to parse TTML/DFXP subtitle");const{error:o,value:i}=O.validate($e(s,e),{abortEarly:!1});if(o)throw new Error(o.details.map(c=>c.message).join(", "));return n.invalidEntries&&n.invalidEntries.length&&(n.success=!1),{data:i,status:n}}class v extends Error{constructor(n,r){super(n);W(this,"error");this.name="ParserError",this.error=r}}const q=/([0-9]+)?:?([0-9]{2}):([0-9]{2}\.[0-9]{2,3})/;function J(t,e={}){const{meta:n=!1,strict:r=!0}=e;if(typeof t!="string")throw new v("Input must be a string");t=t.trim(),t=t.replace(/\r\n/g,`
`),t=t.replace(/\r/g,`
`);const s=t.split(`
`).map(g=>g.trim()).filter(Boolean),o=s.shift()||"";if(!o.startsWith("WEBVTT"))throw new v('Must start with "WEBVTT"');const i=o.split(`
`),c=i[0].replace("WEBVTT","");if(c.length>0&&c[0]!==" "&&c[0]!==" ")throw new v("Header comment must start with space or tab");if(s.length===0&&i.length===1)return{valid:!0,strict:r,cues:[],errors:[]};if(!n&&i.length>1&&i[1]!=="")throw new v("Missing blank line after signature");const{cues:a,errors:u}=Ce(s,r);if(r&&u.length>0)throw u[0];const d=n?be(i):null,m={valid:u.length===0,strict:r,cues:a,errors:u};return n&&(m.meta=d),m}function be(t){const e={};return t.slice(1).forEach(n=>{const r=n.indexOf(":"),s=n.slice(0,r).trim(),o=n.slice(r+1).trim();e[s]=o}),Object.keys(e).length>0?e:null}function Ce(t,e){const n=[];return{cues:t.map((s,o)=>{try{return Re(s,o,e)}catch(i){return i instanceof v?n.push(i):i instanceof Error?n.push(new v(i.message,i)):n.push(new v("Unknown error parsing cue")),null}}).filter(s=>s!==null&&s!==!1),errors:n}}function Re(t,e,n){let r="",s=0,o=.01,i="",c="";const a=t.split(`
`).filter(Boolean);if(a.length>0&&a[0].trim().startsWith("NOTE"))return null;if(a.length===1&&!a[0].includes("-->"))throw new v(`Cue identifier cannot be standalone (cue #${e})`);if(a.length>1&&!(a[0].includes("-->")||a[1].includes("-->"))){const m=`Cue identifier needs to be followed by timestamp (cue #${e})`;throw new v(m)}a.length>1&&a[1].includes("-->")&&(r=a.shift()||"");const d=(a[0]||"").split(" --> ");if(d.length!==2||!ot(d[0])||!ot(d[1]))throw new v(`Invalid cue timestamp (cue #${e})`);if(s=it(d[0]),o=it(d[1]),n){if(s>o)throw new v(`Start timestamp greater than end (cue #${e})`);if(o<=s)throw new v(`End must be greater than start (cue #${e})`)}if(!n&&o<s)throw new v(`End must be greater or equal to start when not strict (cue #${e})`);return c=d[1].replace(q,"").trim(),a.shift(),i=a.join(`
`),i?{identifier:r,start:s,end:o,text:i,styles:c}:!1}function ot(t){return q.test(t)}function it(t){const e=t.match(q);if(!e)return 0;let n=parseFloat(e[1]||"0")*60*60;return n+=parseFloat(e[2])*60,n+=parseFloat(e[3]),n}class E extends Error{constructor(n,r){super(n);W(this,"error");this.name="CompilerError",this.error=r}}function bt(t){if(!t)throw new E("Input must be non-null");if(typeof t!="object")throw new E("Input must be an object");if(Array.isArray(t))throw new E("Input cannot be array");if(!t.valid)throw new E("Input must be valid");let e=`WEBVTT
`;if(t.meta){if(typeof t.meta!="object"||Array.isArray(t.meta))throw new E("Metadata must be an object");Object.entries(t.meta).forEach(r=>{if(typeof r[1]!="string")throw new E(`Metadata value for "${r[0]}" must be string`);e+=`${r[0]}: ${r[1]}
`})}let n=null;return t.cues.forEach((r,s)=>{if(n!==null&&n>r.start)throw new E(`Cue number ${s} is not in chronological order`);n=r.start,e+=`
`,e+=Ae(r),e+=`
`}),e}function Ae(t){if(typeof t!="object")throw new E("Cue malformed: not of type object");if(typeof t.identifier!="string"&&typeof t.identifier!="number"&&t.identifier!==null)throw new E(`Cue malformed: identifier value is not a string.
${JSON.stringify(t)}`);if(isNaN(t.start))throw new E(`Cue malformed: null start value.
${JSON.stringify(t)}`);if(isNaN(t.end))throw new E(`Cue malformed: null end value.
${JSON.stringify(t)}`);if(t.start>=t.end)throw new E(`Cue malformed: start timestamp greater than end
${JSON.stringify(t)}`);if(typeof t.text!="string")throw new E(`Cue malformed: null text value.
${JSON.stringify(t)}`);if(typeof t.styles!="string")throw new E(`Cue malformed: null styles value.
${JSON.stringify(t)}`);let e="";t.identifier&&t.identifier.length>0&&(e+=`${t.identifier}
`);const n=at(t.start),r=at(t.end);return e+=`${n} --> ${r}`,e+=t.styles?` ${t.styles}`:"",e+=`
${t.text}`,e}function at(t){const e=D(Ie(t),2),n=D(Oe(t),2),r=D(Fe(t),2),s=D(je(t),3);return`${e}:${n}:${r}.${s}`}function D(t,e){let n=`${Math.floor(t)}`;if(e===3&&t.toString().includes(".")){if(t>=.9995&&t<1)return"999";n=`${Math.round(t)}`}for(;n.length<e;)n=`0${n}`;return n.length>e&&(n=n.substring(0,e)),n}function Ie(t){return Math.floor(t/60/60)}function Oe(t){return Math.floor(t/60)%60}function Fe(t){return Math.floor(t%60)}function je(t){const e=t%1;return e>.999&&e<1?999:Math.round(e*1e3)}function K(t,e=10){const n=J(t),r=[];let s=[],o=null,i=0,c=0;return n.cues.forEach((a,u)=>{const d=u===0,m=u===n.cues.length-1,g=a.start,h=a.end,A=m?1/0:n.cues[u+1].start,Ft=d?h:h-g,V=d?0:g-n.cues[u-1].end;i=i+Ft+V,`${u}`,r.length+1,o&&(s.push(o),i+=o.end-c,o=null),s.push(a);let Q=A-h<e&&V<e&&i>e;if(Ne(c,e,A,V)){const tt=De(m,h,e,i,c);r.push({duration:tt,cues:s}),c+=tt,i=0,s=[]}else Q=!1;Q&&(o=a)}),r}function Ne(t,e,n,r){const s=Ct(r,e);return(r<=e||s+t<n)&&n-t>=e}function De(t,e,n,r,s){let o=n;return r>n&&(o=Ct(r-n,n)),t?o=parseFloat((e-s).toFixed(2)):o=Math.round(o),o}function Ct(t,e){return t+=e-t%e,t}function He(t,e,n="900000"){const r=K(t,e),s=[];return r.forEach((o,i)=>{const c=`WEBVTT
X-TIMESTAMP-MAP=MPEGTS:${n},LOCAL:00:00:00.000
${ke(o.cues)}
`,a=Rt(i);s.push({filename:a,content:c})}),s}function Pe(t,e){const n=K(t,e),r=Xe(n);return`#EXTM3U
#EXT-X-TARGETDURATION:${Math.round(_e(n))}
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
${r}
#EXT-X-ENDLIST
`}function H(t,e){return`${"0".repeat(Math.max(0,e-t.toString().length))}${t}`}function Rt(t){return`${t}.vtt`}function Xe(t){const e=[];return t.forEach((n,r)=>{e.push(`#EXTINF:${n.duration.toFixed(5)},
${Rt(r)}`)}),e.join(`
`)}function _e(t){let e=0;return t.forEach(n=>{n.duration>e&&(e=n.duration)}),e}function ke(t){const e=[];return t.forEach(n=>{e.push(Le(n))}),e.join(`
`)}function Le(t){const e=[];t.identifier&&e.push(t.identifier);const n=ct(t.start),r=ct(t.end);return t.styles?e.push(`${n} --> ${r} ${t.styles}`):e.push(`${n} --> ${r}`),e.push(t.text),e.join(`
`)}function ct(t){const e=parseFloat((t%1).toFixed(3));t=Math.round(t-e);const n=Math.floor(t/3600),r=Math.floor((t-n*3600)/60),s=t-n*3600-r*60;return`${`${H(n,2)}:`}${H(r,2)}:${H(s,2)}.${H(e*1e3,3)}`}function Be(t,e={}){const{removeTextFormatting:n=!1}=e;return{global:{},body:t.cues.map((r,s)=>{const o=r.styles?r.styles.split(" ").reduce((i,c)=>{const[a,u]=c.split(":");return i[a]=u,i},{}):{};return{id:s.toString(),startMicro:C(r.start),endMicro:C(r.end),styles:o,text:F(r.text,n)}}).filter(r=>r.text).map((r,s)=>(r.id=(s+1).toString(),r)),source:t}}function Ve(t,e={}){const n={success:!0,invalidEntries:[],invalidTimecodes:[],invalidIndices:[]},r=J(t,{meta:!0}),{error:s,value:o}=O.validate(Be(r,e),{abortEarly:!1});if(s)throw new Error(s.details.map(i=>i.message).join(", "));return n.invalidEntries&&n.invalidEntries.length&&(n.success=!1),{data:o,status:n}}const We=/\[Events\][\r\n]+Format:(.*?)[\r\n]+/,Ue=/^Dialogue:/,Ge=t=>{const e=t.match(We),n=e?e[1]:null;if(!n)throw new Error("Failed to parse keys in .ass file");return n.split(",").map(y.trim)},ze=t=>Ue.test(t),Ze=t=>{t=t.replace(/(\r\n|\r)/g,`
`);const e=t.split(/\n/),n=Ge(t),r=(o,i)=>{if(!ze(i))return o;const c=i.replace(/^Dialogue:\s*/,"");let a=[],u="",d=!1,m=0;for(let h=0;h<c.length;h++){const A=c[h];A===","&&!d&&m<n.length-1?(a.push(u.trim()),u="",m++):(u+=A,m>=n.length-1&&(d=!0))}for(u&&a.push(u.trim()),a[a.length-1]&&(a[a.length-1]=a[a.length-1].replace(/\\N/g,`
`));a.length<n.length;)a.push("");const g=y.zipObj(n,a);return o.concat(g)};return y.reduce(r,[],e)},lt=t=>`${t}0`;function ut(t,e={}){const{removeTextFormatting:n=!1}=e;return!t||t.length===0?{global:{},body:[],source:[]}:{global:{},body:t.map((r,s)=>{const o=r.Start||"0:00:00.00",i=r.End||"0:00:01.00";return{id:(s+1).toString(),timecode:`${o} --> ${i}`,startMicro:b(lt(o)),endMicro:b(lt(i)),text:F(r.Text,n)}}).filter(r=>r.text).map((r,s)=>(r.id=(s+1).toString(),r)),source:t}}function qe(t,e={}){const n={success:!0,invalidEntries:[],invalidTimecodes:[],invalidIndices:[]};try{const r=Ze(t),{error:s,value:o}=O.validate(ut(r,e),{abortEarly:!1});if(s)throw new Error(s.details.map(i=>i.message).join(", "));return n.invalidEntries&&n.invalidEntries.length&&(n.success=!1),{data:o,status:n}}catch(r){if(r instanceof Error&&r.message.includes("Failed to parse keys"))throw r;return{data:ut([],e),status:n}}}function Y(t,e,n={}){switch(e){case".srt":return ye(t,n);case".scc":return ie(t,n);case".vtt":return Ve(t,n);case".ass":return qe(t,n);case".dfxp":case".ttml":return we(t,n);default:throw Error(`File type ${e} is not supported. Supported input file types include:
dfxp, scc, srt, ttml, vtt, and ass`)}}function Je(t){return t.length?t.reduce((n,r)=>{const s=y.last(n)||{};if(r.startMicro<s.endMicro){const o={...r,id:s.id,startMicro:s.startMicro,endMicro:r.endMicro,text:`${s.text}
${r.text}`};return y.update(-1,o,n)}return n.concat(r)},[]).map((n,r)=>y.assoc("id",(r+1).toString(),n)):t}function Ke(t,e=!1){return!t.length||e===!1?t:t.map((r,s)=>{if(s<1)return r;const o=t[s-1],{startMicro:i}=r,{endMicro:c}=o;return c>i&&c-i<=C(e)&&(r.startMicro=c),r})}function Ye(t,e,n){const r=e/n;return t.map(s=>(s.startMicro*=r,s.endMicro*=r,s))}function Qe(t,e){const n=C(e);return t.map(r=>{if(r.startMicro+=n,r.endMicro+=n,r.startMicro<0||r.endMicro<0)throw Error(`shift by ${e} failed`);return r})}function tn(t){if(!t.length)return t;const e=Tt(1),n=Math.floor(t[0].startMicro/e);if(n<1)return t;const r=n*e;return t.forEach(s=>{if(s.startMicro-=r,s.endMicro-=r,s.startMicro<0||s.endMicro<0)throw Error("shift to zero hour failed")}),t}function en(t,e){const{timecodeOverlapLimiter:n,combineOverlapping:r,shiftTimecode:s,sourceFps:o,outputFps:i,startAtZeroHour:c}=e;let a=t;return n!==!1&&(a=Ke(a,n)),r&&(a=Je(a)),s&&(a=Qe(a,s)),o&&i&&(a=Ye(a,o,i)),c&&(a=tn(a)),a}function nn(t){const e={success:!0};return t.startsAtZeroHour&&(e.startsAtZeroHour=!0),(t.reversedTimecodes||t.overlappingTimecodes)&&(e.timecodeIssues={},t.reversedTimecodes&&(e.timecodeIssues.reversedTimecodes=[]),t.overlappingTimecodes&&(e.timecodeIssues.overlappingTimecodes=[])),t.formattedText&&(e.formattedText=[]),e}function At(t,e={startsAtZeroHour:!0,reversedTimecodes:!0,overlappingTimecodes:!0,formattedText:!0}){const n=nn(e);let r=0;return t.forEach((s,o)=>{var g,h;const{id:i,timecode:c,startMicro:a,endMicro:u,text:d}=s;e.startsAtZeroHour&&o===0&&a>=36e8&&(n.startsAtZeroHour=!1,n.success=!1),e.overlappingTimecodes&&a<r&&((g=n.timecodeIssues)!=null&&g.overlappingTimecodes)&&(n.timecodeIssues.overlappingTimecodes.push({id:i,timecode:c}),n.success=!1),e.reversedTimecodes&&a>u&&((h=n.timecodeIssues)!=null&&h.reversedTimecodes)&&(n.timecodeIssues.reversedTimecodes.push({id:i,timecode:c}),n.success=!1),e.formattedText&&d.match(/{|}|<|>/)&&n.formattedText&&(n.formattedText.push({id:i,text:d}),n.success=!1),r=u}),n}function rn(t){t=t.replace(/\r/g,"");const e=/(\d+)\n(\d{2}:\d{2}:\d{2},\d{3}) --> (\d{2}:\d{2}:\d{2},\d{3})/g,n=t.split(e);n.shift();const r=[];for(let s=0;s<n.length;s+=4)r.push({id:n[s].trim(),startMicro:b(n[s+1].trim()),endMicro:b(n[s+2].trim()),text:n[s+3].trim()});return r}function It(t){if(!Array.isArray(t))return"";let e="";for(const n of t){const r=nt(n.startMicro),s=nt(n.endMicro);e+=n.id+`\r
`,e+=r+" --> "+s+`\r
`,e+=n.text.replace(`
`,`\r
`)+`\r
\r
`}return e}function sn(t){return t.body.map(e=>({...e}))}function on(t){const e=sn(t);return It(e)}function an(t){return{valid:!0,strict:!1,errors:[],cues:t.body.map(e=>{const n=e.styles?Object.keys(e.styles).map(r=>{var s;return`${r}:${(s=e.styles)==null?void 0:s[r]}`}).join(" "):"";return{identifier:e.id||"",start:et(e.startMicro),end:et(e.endMicro),text:e.text,styles:n}})}}function cn(t){const e=an(t);return bt(e)}function Ot(t,e){switch(e){case".srt":return on(t);case".vtt":return cn(t);default:throw Error(`File type ${e} is not supported. Supported output file types include: '.srt', '.vtt'`)}}function ln(t,e,n={timecodeOverlapLimiter:!1}){const{error:r}=Lt.validate({subtitleText:t,outputExtension:e,options:n},{abortEarly:!1});if(r)throw new Error(r.details.map(g=>g.message).join(", "));const s=vt(t);if(!s)throw Error("Could not determine subtitle format");const{data:o,status:i}=Y(t,s,n);if(y.isEmpty(o.body))throw new Error("Parsed file is empty");const c=en(o.body,n),a={startsAtZeroHour:n.startAtZeroHour,reversedTimecodes:!0,overlappingTimecodes:!0,formattedText:n.removeTextFormatting},u=At(c,a);o.body=c;const d=Ot(o,e),m={...i,...u,success:i.success&&u.success};return{subtitle:d,status:m}}function un(t,e,n={}){const r=vt(t)||e;if(!r)throw Error("Could not determine subtitle format");const{data:s,status:o}=Y(t,r,n);if(y.isEmpty(s.body))throw Error("Parsed file is empty");const i=At(s.body,n),c=o.success&&i.success;return{...o,...i,success:c}}const dn=[".srt",".vtt",".dfxp",".ttml",".scc",".ass"],fn=[".srt",".vtt"];exports.CompilerError=E;exports.EXPORT_EXTENSIONS=fn;exports.PARSE_EXTENSIONS=dn;exports.ParserError=v;exports.compileWebVTT=bt;exports.convert=ln;exports.fromSrt=rn;exports.generateOutputData=Ot;exports.hlsSegment=He;exports.hlsSegmentPlaylist=Pe;exports.parse=Y;exports.parseWebVTT=J;exports.segmentWebVTT=K;exports.toSrt=It;exports.validate=un;
//# sourceMappingURL=subs-convert.cjs.map