dasha 3.1.1 → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/dist/dasha.js +1556 -6
  2. package/dist/dasha.mjs +1566 -6
  3. package/package.json +11 -10
  4. package/dasha.js +0 -27
package/dist/dasha.mjs CHANGED
@@ -1,6 +1,1566 @@
1
- var Z=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(r,t)=>(typeof require<"u"?require:r)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var U=(e,r)=>()=>(r||e((r={exports:{}}).exports,r),r.exports);var te=U((Br,ee)=>{"use strict";function ye(e,r={}){var t=r.pos||0,s=!!r.keepComments,n=!!r.keepWhitespace,i="<",o=60,a=">",c=62,l=45,h=47,d=33,u=39,p=34,C=91,S=93;function v(g){for(var f=[];e[t];)if(e.charCodeAt(t)==o){if(e.charCodeAt(t+1)===h){var A=t+2;t=e.indexOf(a,t);var B=e.substring(A,t);if(B.indexOf(g)==-1){let b=e.substring(0,t).split(`
2
- `);throw new Error(`Unexpected close tag
3
- Line: `+(b.length-1)+`
4
- Column: `+(b[b.length-1].length+1)+`
5
- Char: `+e[t])}return t+1&&(t+=1),f}else if(e.charCodeAt(t+1)===d){if(e.charCodeAt(t+2)==l){let b=t;for(;t!==-1&&!(e.charCodeAt(t)===c&&e.charCodeAt(t-1)==l&&e.charCodeAt(t-2)==l&&t!=-1);)t=e.indexOf(a,t+1);t===-1&&(t=e.length),s&&f.push(e.substring(b,t+1))}else if(e.charCodeAt(t+2)===C&&e.charCodeAt(t+8)===C&&e.substr(t+3,5).toLowerCase()==="cdata"){var I=e.indexOf("]]>",t);I==-1?(f.push(e.substr(t+9)),t=e.length):(f.push(e.substring(t+9,I)),t=I+3);continue}else{let b=t+1;t+=2;for(var m=!1;(e.charCodeAt(t)!==c||m===!0)&&e[t];)e.charCodeAt(t)===C?m=!0:m===!0&&e.charCodeAt(t)===S&&(m=!1),t++;f.push(e.substring(b,t))}t++;continue}var N=L();f.push(N),N.tagName[0]==="?"&&(f.push(...N.children),N.children=[])}else{let b=O();if(n)b.length>0&&f.push(b);else{var R=b.trim();R.length>0&&f.push(R)}t++}return f}function O(){var g=t;return t=e.indexOf(i,t)-1,t===-2&&(t=e.length),e.slice(g,t+1)}var _=`\r
6
- >/= `;function V(){for(var g=t;_.indexOf(e[t])===-1&&e[t];)t++;return e.slice(g,t)}var G=r.noChildNodes||["img","br","input","meta","link","hr"];function L(){t++;let g=V(),f={},A=[];for(;e.charCodeAt(t)!==c&&e[t];){var B=e.charCodeAt(t);if(B>64&&B<91||B>96&&B<123){for(var I=V(),m=e.charCodeAt(t);m&&m!==u&&m!==p&&!(m>64&&m<91||m>96&&m<123)&&m!==c;)t++,m=e.charCodeAt(t);if(m===u||m===p){var N=T();if(t===-1)return{tagName:g,attributes:f,children:A}}else N=null,t--;f[I]=N}t++}if(e.charCodeAt(t-1)!==h)if(g=="script"){let R=t+1;t=e.indexOf("</script>",t),A=[e.slice(R,t)],t+=9}else if(g=="style"){let R=t+1;t=e.indexOf("</style>",t),A=[e.slice(R,t)],t+=8}else G.indexOf(g)===-1?(t++,A=v(g)):t++;else t++;return{tagName:g,attributes:f,children:A}}function T(){var g=e[t],f=t+1;return t=e.indexOf(g,f),e.slice(f,t)}function $(){var g=new RegExp("\\s"+r.attrName+`\\s*=['"]`+r.attrValue+`['"]`).exec(e);return g?g.index:-1}let y=null;if(r.attrValue!==void 0)for(r.attrName=r.attrName||"id",y=[];(t=$())!==-1;)t=e.lastIndexOf("<",t),t!==-1&&y.push(L()),e=e.substr(t),t=0;else r.parseNode?y=L():y=v("");return r.filter&&(y=H(y,r.filter)),r.setPos&&(y.pos=t),y}function H(e,r,t=0,s=""){var n=[];return e.forEach(function(i,o){if(typeof i=="object"&&r(i,o,t,s)&&n.push(i),i.children){var a=H(i.children,r,t+1,(s?s+".":"")+o+"."+i.tagName);n=n.concat(a)}}),n}ee.exports={parse:ye,filter:H}});var D=U((Ur,ie)=>{"use strict";var re=(e,r=["Bytes","KB","MB","GB","TB"])=>{if(e==0)return`0 ${r[0]}`;let t=parseInt(Math.floor(Math.log(e)/Math.log(1024)));return t==0?e+" "+r[t]:(e/Math.pow(1024,t)).toFixed(1)+" "+r[t]},Ne=(e,r)=>({b:e*r,kb:e/1e3*r,mb:e/8e6*r,gb:e/8e9*r,toString(){return re(e*r)}}),Be=e=>({bps:e,kbps:e/1e3,mbps:e/8e6,gbps:e/8e9,toString(){return re(e,["bps","Kbps","Mbps","Gbps"])}}),se=[{width:7680,height:4320},{width:3840,height:2160},{width:2560,height:1440},{width:1920,height:1080},{width:1280,height:720},{width:1024,height:576},{width:854,height:480},{width:640,height:360},{width:426,height:240},{width:256,height:144}],Ue=e=>se.find(r=>r.height===e)?.width,ne=e=>se.find(r=>r.width===e)?.height,_e=e=>`${ne(e.width)||e.height}p`,Re=e=>{let r=Math.max(...e.map(t=>t.bitrate.bps));return e.find(t=>t.bitrate.bps===r)},Ee=e=>{let a=/P(?:(\d*)Y)?(?:(\d*)M)?(?:(\d*)D)?(?:T(?:(\d*)H)?(?:(\d*)M)?(?:([\d.]*)S)?)?/.exec(e);if(!a)return 0;let[c,l,h,d,u,p]=a.slice(1);return parseFloat(c||0)*31536e3+parseFloat(l||0)*2592e3+parseFloat(h||0)*86400+parseFloat(d||0)*3600+parseFloat(u||0)*60+parseFloat(p||0)},Le=e=>{try{return Intl.getCanonicalLocales(e),!0}catch{return}};ie.exports={parseSize:Ne,parseBitrate:Be,getWidth:Ue,getHeight:ne,getQualityLabel:_e,getBestTrack:Re,parseDuration:Ee,isLanguageTagValid:Le}});var Y=U((_r,oe)=>{"use strict";var{parseBitrate:Ie,getQualityLabel:De,parseSize:Fe}=D(),F={avc:"H.264",hevc:"H.265",vc1:"VC-1",vp8:"VP8",vp9:"VP9",av1:"AV1"},P={sdr:"SDR",hlg:"HLG",hdr10:"HDR10",hdr10p:"HDR10+",dv:"DV"},Q={Unspecified:0,BT_709:1,BT_601_625:5,BT_601_525:6,BT_2020_and_2100:9,SMPTE_ST_2113_and_EG_4321:12},q={Unspecified:0,BT_709:1,BT_601:6,BT_2020:14,BT_2100:15,BT_2100_PQ:16,BT_2100_HLG:18},Me={RGB:0,YCbCr_BT_709:1,YCbCr_BT_601_625:5,YCbCr_BT_601_525:6,YCbCr_BT_2020_and_2100:9,ICtCp_BT_2100:14},Oe=e=>{let r=e.toLowerCase().trim().split(".")[0],t=["avc1","avc2","avc3","dva1","dvav"],s=["hev1","hev2","hev3","hvc1","hvc2","hvc3","dvh1","dvhe","lhv1","lhe1"],n=["vc-1"],i=["vp08","vp8"],o=["vp09","vp9"],a=["av01"];if(t.includes(r))return F.avc;if(s.includes(r)||n.includes(r))return F.hevc;if(i.includes(r))return F.vp8;if(o.includes(r))return F.vp9;if(a.includes(r))return F.av1;throw new Error(`The MIME ${e} is not supported as video codec`)},Pe=(e,r,t)=>(r==5&&(r=q.BT_601),e==Q.Unspecified&&r==q.Unspecified&&t==Me.RGB||[Q.BT_601_625,Q.BT_601_525].includes(e)?P.sdr:q.BT_2100_PQ===r?P.hdr10:q.BT_2100_HLG===r?P.hlg:P.sdr),ke=({id:e,label:r,type:t,codec:s,dynamicRange:n,contentProtection:i,bitrate:o,duration:a,width:c,height:l,fps:h,language:d,segments:u})=>{let p=Ie(Number(o)),C=Number(c),S=Number(l),v=a?Fe(Number(o),Number(a)):void 0;return{id:e,label:r,type:t,codec:s,bitrate:p,size:v,protection:i,segments:u,dynamicRange:n,language:d,width:C,height:S,fps:Number(h),quality:De({width:C,height:S}),toString(){return["VIDEO",`[${s}, ${n}]`,d,`${c}x${l} @ ${p.kbps} kb/s, ${h} FPS`].join(" | ")}}},Ve=e=>{for(let r of e.toLowerCase().split(",")){let t=r.trim().split(".")[0];try{return Oe(t)}catch{continue}}throw new Error(`No MIME types matched any supported Video Codecs in ${e}`)},$e=(e,r=[],t=[])=>{if(["dva1","dvav","dvhe","dvh1"].some(u=>e.startsWith(u)))return P.dv;let n="urn:mpeg:mpegB:cicp:ColourPrimaries",i="urn:mpeg:mpegB:cicp:TransferCharacteristics",o="urn:mpeg:mpegB:cicp:MatrixCoefficients",a=[...t,...r],c=u=>a.filter(p=>p.attributes.schemeIdUri===u).map(p=>parseInt(p.attributes.value)),l=c(n).reduce((u,p)=>u+p,0),h=c(i).reduce((u,p)=>u+p,0),d=c(o).reduce((u,p)=>u+p,0);return Pe(l,h,d)};oe.exports={parseVideoCodec:Ve,parseDynamicRange:$e,createVideoTrack:ke,VIDEO_CODECS:F}});var k=U((Rr,pe)=>{"use strict";var{getBestTrack:ae}=D(),Ge=e=>e.toLowerCase().split(",").map(r=>r.trim().split(".")[0]),ce=e=>({width:r,height:t})=>e.filter(s=>(!r||s.width===r)&&(!t||s.height===t)),z=e=>r=>{if(!r?.length)return e;let t=e.filter(s=>r.includes(s.codec));return t.sort((s,n)=>n.bitrate.bps-s.bitrate.bps),t},qe=e=>z(e),ue=e=>r=>{if(!r)return[ae(e)];let t=String(r).includes("p")?r:`${r}p`,s=e.filter(n=>n.quality===t);return s.sort((n,i)=>i.bitrate.bps-n.bitrate.bps),s.length?s:[ae(e)]},We=e=>z(e),le=e=>(r=[],t)=>{if(!r.length){let o=e.filter(a=>a.language);if(o.length)for(let a of o)r.includes(a.language)||r.push(a.language);else return e.sort((a,c)=>c.bitrate.bps-a.bitrate.bps),e.slice(0,t)}let s=[];for(let o of r){let a=e.filter(c=>c.language?.startsWith(o));s.push(...a)}let n=[],i=[...new Set(s.map(o=>o.language))];for(let o of i){let a=s.filter(c=>c.language===o).slice(0,t);n.push(...a)}return n},de=e=>r=>{if(!r)return e;let t=typeof r=="string"?parseFloat(r):r;return e.filter(s=>s.channels===t)},He=e=>r=>r.length?e.filter(t=>r.some(s=>t.language?.startsWith(s)||t.label?.startsWith(s))):e,Qe=(e,r)=>ce(e)(r),Ye=(e,r)=>ue(e)(r),ze=(e,r)=>z(e)(r),je=(e,r,t)=>le(e)(r,t),Ke=(e,r)=>de(e)(r);pe.exports={parseMimes:Ge,createResolutionFilter:ce,createVideoCodecFilter:qe,createVideoQualityFilter:ue,createAudioCodecFilter:We,createAudioLanguageFilter:le,createAudioChannelsFilter:de,createSubtitleLanguageFilter:He,filterByResolution:Qe,filterByQuality:Ye,filterByCodecs:ze,filterByLanguages:je,filterByChannels:Ke}});var j=U((Er,he)=>{"use strict";var{parseMimes:Xe}=k(),{parseBitrate:Je,parseSize:xe}=D(),E={AAC:"AAC",AC3:"DD",EC3:"DD+",OPUS:"OPUS",OGG:"VORB",DTS:"DTS",ALAC:"ALAC",FLAC:"FLAC"},Ze=e=>{switch(e.toLowerCase().trim().split(".")[0]){case"mp4a":return E.AAC;case"ac-3":return E.AC3;case"ec-3":return E.EC3;case"opus":return E.OPUS;case"dtsc":return E.DTS;case"alac":return E.ALAC;case"flac":return E.FLAC;default:throw new Error(`The MIME ${e} is not supported as audio codec`)}},et=e=>{let r=Xe(e);for(let t of r)try{return Ze(t)}catch{continue}throw new Error(`No MIME types matched any supported Audio Codecs in ${e}`)},tt=(e=[])=>{let r="tag:dolby.com,2018:dash:EC3_ExtensionComplexityIndex:2018";for(let t of e)if(t.attributes.schemeIdUri===r)return parseInt(t.attributes.value)},rt=(e=[])=>{for(let r of e){let{schemeIdUri:t,value:s}=r.attributes,n=t=="urn:mpeg:dash:role:2011"&&s==="descriptive",i=t=="urn:tva:metadata:cs:AudioPurposeCS:2007"&&s==="1";if(n||i)return!0}return!1},st=e=>{let r=t=>t>="0"&&t<="9";if(typeof e=="string"){if(e.toUpperCase()=="A000")return 2;if(e.toUpperCase()=="F801")return 5.1;if(r(e.replace("ch","").replace(".","")[0]))return parseFloat(e.replace("ch",""));throw new Error(`Unsupported audio channels value, '${e}'`)}return parseFloat(e)},nt=({id:e,label:r,type:t,codec:s,channels:n,bitrate:i,duration:o,jointObjectCoding:a=0,isDescriptive:c=!1,language:l,segments:h})=>{let d=Je(Number(i)),u=st(n),p=o?xe(Number(i),Number(o)):void 0;return{id:e,label:r,type:t,codec:s,bitrate:d,size:p,language:l,segments:h,channels:u,jointObjectCoding:a,isDescriptive:c,toString(){return["AUDIO",`[${s}]`,`${u||"?"}`+(a?` (JOC ${a})`:""),`${d.kbps} kb/s`,l].join(" | ")}}};he.exports={AUDIO_CODECS:E,parseAudioCodec:et,createAudioTrack:nt,getDolbyDigitalPlusComplexityIndex:tt,checkIsDescriptive:rt}});var fe=U((Lr,ge)=>{"use strict";var{parseMimes:it}=k(),{parseBitrate:ot,parseSize:at}=D(),M={SubRip:"SRT",SubStationAlpha:"SSA",SubStationAlphav4:"ASS",TimedTextMarkupLang:"TTML",WebVTT:"VTT",fTTML:"STPP",fVTT:"WVTT"},ct=e=>{switch(e.toLowerCase().trim().split(".")[0]){case"srt":case"x-subrip":return M.SubRip;case"ssa":return M.SubStationAlpha;case"ass":return M.SubStationAlphav4;case"ttml":return M.TimedTextMarkupLang;case"vtt":return M.WebVTT;case"stpp":return M.fTTML;case"wvtt":return M.fVTT;default:throw new Error(`The MIME ${e} is not supported as subtitle codec`)}},ut=e=>{let r=it(e);for(let t of r)try{return ct(t)}catch{continue}throw new Error(`No MIME types matched any supported Subtitle Codecs in ${e}`)},lt=(e=[])=>{for(let r of e)if(r.attributes.schemeIdUri==="urn:mpeg:dash:role:2011"&&r.attributes.value==="caption")return!0;return!1},dt=(e=[])=>{for(let r of e){let{schemeIdUri:t,value:s}=r.attributes;if(t==="urn:tva:metadata:cs:AudioPurposeCS:2007"&&s==="2")return!0}return!1},pt=(e=[])=>{for(let r of e)if(r.attributes.schemeIdUri==="urn:mpeg:dash:role:2011"&&(r.attributes.value==="forced-subtitle"||r.attributes.value==="forced_subtitle"))return!0;return!1},ht=({id:e,label:r,bitrate:t,duration:s,type:n,codec:i,isClosedCaption:o,isSdh:a,isForced:c,language:l,segments:h})=>{let d=ot(Number(t)),u=s?at(Number(t),Number(s)):void 0;return{id:e,label:r,bitrate:d,size:u,type:n,codec:i,isClosedCaption:o,isSdh:a,isForced:c,segments:h,language:l,toString(){return["SUBTITLE",`[${i}]`,l].join(" | ")}}};ge.exports={parseSubtitleCodec:ut,checkIsClosedCaption:lt,checkIsSdh:dt,checkIsForced:pt,createSubtitleTrack:ht}});var Ce=U((Ir,me)=>{"use strict";var gt=te(),{parseDuration:ft,isLanguageTagValid:mt}=D(),{parseVideoCodec:Ct,parseDynamicRange:bt,createVideoTrack:St}=Y(),{parseAudioCodec:vt,createAudioTrack:At,getDolbyDigitalPlusComplexityIndex:wt,checkIsDescriptive:Tt}=j(),{parseSubtitleCodec:yt,checkIsClosedCaption:Nt,checkIsSdh:Bt,checkIsForced:Ut,createSubtitleTrack:_t}=fe(),{createResolutionFilter:Rt,createVideoQualityFilter:Et,createAudioLanguageFilter:Lt,createSubtitleLanguageFilter:It,createVideoCodecFilter:Dt,createAudioCodecFilter:Ft,createAudioChannelsFilter:Mt}=k(),W=e=>e&&(Array.isArray(e)?e.get=r=>W(e.find(t=>t.tagName===r)):(e.getAttr=r=>e.attributes[r],e.getChild=r=>{let t=e.children.find(n=>n.tagName===r);return!r&&typeof e.children?.[0]=="string"?e.children[0]:W(t)},e.set=(r,t)=>e.attributes[r]=t,e.get=r=>e.getAttr(r)||e.getChild(r),e.getNumber=r=>Number(e.find(r)),e.getAll=r=>e.children.filter(t=>t.tagName===r).map(W),e.getBaseUrls=()=>e.getAll("BaseURL").map(r=>r.children[0]),e.getBaseUrl=()=>e.getBaseUrls()[0]),e),Ot=(e,r)=>{let t=e.get,s=e.getAll,n=o=>t(o)||r.get(o),i=o=>[...s(o),...r.getAll(o)].filter(Boolean);return e.get=n,e.getAll=i,{get:n,getAll:i}},Pt=(e,r,t,s)=>{let n=r.getBaseUrl();return n?n.startsWith("https://")||(n=new URL(n,e).toString()):n=e,(t.getBaseUrl()||n)&&(n=new URL(t.getBaseUrl()||"",n).toString()),new URL(s.getBaseUrl()||"",n).toString()},kt=e=>{let r=e.get("mimeType"),t=e.get("contentType")||r?.split("/")[0];if(!t&&!r)throw new Error("Unable to determine the format of a Representation, cannot continue...");return{contentType:t,mimeType:r}},Vt=(e,r,t)=>r==="text"&&!t.includes("mp4")?t.split("/")[1]:e.get("codecs"),$t=(e,r,t)=>{let s="",n=[],i=e.get("lang"),o=e.get("id");if(e&&(n.push(i),o)){let a=o.match(/\w+_(\w+)=\d+/);a&&a[1]&&n.push(a[1])}n.push(r.get("lang")),t&&n.push(t);for(let a of n){let c=(a||"").trim();!mt(c)||c.startsWith("und")||(s=c)}return s},K=(e,r)=>{let t=e;for(let[s,n]of Object.entries(r))t=t.replace("$"+s+"$",n);return t},Gt=(e,r,t)=>{for(let s of["initialization","media"]){let n=e.get(s);if(n){if(!n.startsWith("https://")){if(!r)throw new Error("Resolved Segment URL is not absolute, and no Base URL is available.");n=new URL(n,r).toString()}if(!new URL(n).search){let i=new URL(t).search;i&&(n+=`?${i}`)}e.set(s,n)}}},qt=(e,r,t,s)=>{let n=[],i=0;for(let c of e.getAll("S")){let l=Number(c.get("t")),h=Number(c.get("r")||0),d=Number(c.get("d"));l&&(i=l);for(let u=0;u<h+1;u++)n.push(i),i+=d}let o=[],a=[...Array(n.length).keys()].map(c=>c+s);for(let c=0;c<n.length;c++){let l=n[c],h=a[c],d=K(r.get("media"),{Bandwidth:t.get("bandwidth"),RepresentationID:t.get("id"),Number:h,Time:l});o.push({url:d})}return o},Wt=(e,r,t,s,n)=>{let i=Number(e.get("startNumber")||1),o=e.get("SegmentTimeline");Gt(e,r,t);let a=parseFloat(e.get("duration")),c=parseFloat(e.get("timescale")||1),h=s?Math.ceil(s/(a/c)):35,d=n.get("bandwidth"),u=n.get("id"),p=[];if(o)p.push(...qt(o,e,n,i));else for(let S=i;S<i+h;S++){let v=K(e.get("media"),{Bandwidth:d,RepresentationID:u,Number:S,Time:S});p.push({url:v})}let C=e.get("initialization");if(C){let S=K(C,{Bandwidth:d,RepresentationID:u});p.unshift({url:S,init:!0})}return p},Ht=(e,r)=>{let t=e.get("SegmentURL"),s=[];for(let n of t){let i=n.get("media");i?i.startsWith("https://")||(i=new URL(i,r).toString()):i=r,s.push({url:i,range:n.get("mediaRange")})}return s},Qt=async(e,r)=>{let t=e.get("Initialization");return{url:r,range:""}},Yt=e=>{for(let r of e)if(r.url.includes("&amp;")){let s=new URL(r.url),n=new URLSearchParams(s.searchParams.toString()).entries();for(let[i,o]of n)s.searchParams.delete(i),s.searchParams.append(i.replaceAll("amp;",""),o);r.url=s.toString()}},zt={"urn:mpeg:dash:mp4protection:2011":"common","urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95":"playready","urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed":"widevine"},jt=e=>{let r={};for(let t of e){let s=t.get("schemeIdUri")?.toLowerCase(),n=t.get("value"),i=t.get("cenc:pssh")?.get(),o=t.get("cenc:default_KID"),a={id:s,value:n,pssh:i,defaultKeyId:o};r[zt[s]]=a}return r},Kt=async(e,r,t)=>{let s=W(gt.parse(e)).get("MPD"),n=s.get("Period"),i=n.get("duration")||s.get("mediaPresentationDuration"),o=ft(i),a=[],c=[],l=[];for(let h of n.getAll("AdaptationSet"))for(let d of h.getAll("Representation")){let{get:u,getAll:p}=Ot(d,h),{contentType:C,mimeType:S}=kt(d),v=Vt(d,C,S),O=$t(d,h,t),_=Pt(r,s,n,d),V=u("SegmentTemplate"),G=u("SegmentList"),L=u("SegmentBase"),T=[];if(V){let w=Wt(V,_,r,o,d);T.push(...w)}else if(G){let w=Ht(G,_);T.push(...w)}else if(L){let w=await Qt(L,_);T.push(w)}else if(_)T.push({url:_});else throw new Error("Could not find a way to get segments from this MPD manifest.");Yt(T);let $=u("label"),y=u("frameRate")??L?.attributes.timescale,g=u("width")??0,f=u("height")??0,A=u("bandwidth"),B=p("SupplementalProperty"),I=p("EssentialProperty"),m=h.getAll("Accessibility"),N=h.getAll("Role"),R=p("ContentProtection"),b=[new URL(_).hostname,C,v,A,O,s.get("id"),n.get("id"),u("id"),u("audioTrackId")].filter(Boolean).join("-").replaceAll("/","-");switch(C){case"video":{let w=St({id:b,label:$,type:C,codec:Ct(v),dynamicRange:bt(v,B,I),contentProtection:jt(R),bitrate:A,duration:o,width:g,height:f,fps:y,language:O,segments:T});a.push(w);break}case"audio":{let w=At({id:b,label:$,type:C,codec:vt(v),channels:u("AudioChannelConfiguration")?.get("value"),jointObjectCoding:wt(B),isDescriptive:Tt(m),bitrate:A,duration:o,language:O,segments:T});c.push(w);break}case"text":{let w=_t({id:b,label:$,type:C,codec:yt(v||"vtt"),isClosedCaption:Nt(N),isSdh:Bt(m),isForced:Ut(N),bitrate:A,duration:o,language:O,segments:T});l.push(w);break}case"image":break;default:throw new Error(`Unknown content type: ${C}`)}}return a.sort((h,d)=>d.bitrate.bps-h.bitrate.bps),{duration:o,tracks:{all:a.concat(c).concat(l),videos:a,audios:c,subtitles:l,withResolution:Rt(a),withVideoCodecs:Dt(a),withVideoQuality:Et(a),withAudioCodecs:Ft(c),withAudioLanguages:Lt(c),withAudioChannels:Mt(c),withSubtitleLanguages:It(l)}}};me.exports={parseManifest:Kt}});var we=U((Dr,Ae)=>{"use strict";var{dirname:Xt,basename:be}=Z("node:path"),Jt=Z("m3u8-parser"),{parseBitrate:xt,getQualityLabel:Zt}=D(),{createResolutionFilter:er,createVideoQualityFilter:tr,createAudioLanguageFilter:rr,createSubtitleLanguageFilter:sr,createVideoCodecFilter:nr,createAudioCodecFilter:ir,createAudioChannelsFilter:or}=k(),{createAudioTrack:ar}=j(),{createVideoTrack:cr}=Y(),Se=e=>{let r=new Jt.Parser;return r.push(e),r.end(),r.manifest},ur=async e=>{let r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch playlist (${r.status}): ${e}`);let t=await r.text();return Se(t)},x=(e,r)=>{let t=e;return t.startsWith("https://")||(t=new URL(t,r).toString()+new URL(r).search),t},lr=(e,r)=>new URL(e).pathname===new URL(r).pathname,ve=(e,r)=>{let t=[];if(!e)return t;for(let[s,n]of Object.entries(e))for(let[i,o]of Object.entries(n)){let a=x(o.uri,r);t.find(l=>lr(l.url,a))||t.push({groupId:s,id:o.uri.replace("/",""),type:s,label:i,language:o.language,url:a,default:o.default})}return t},dr=(e,r)=>e.mediaGroups?ve(e.mediaGroups.AUDIO,r):[],pr=(e,r)=>e.mediaGroups?ve(e.mediaGroups.SUBTITLES,r):[],hr=(e,r)=>e.playlists?e.playlists.map(t=>{let s=t.attributes?.BANDWIDTH,n=t.resolvedUri||x(t.uri,r),i={id:t.uri.replace("/",""),bitrate:xt(s),url:n};return i.type="video",t.attributes.RESOLUTION&&(i.resolution=t.attributes.RESOLUTION,i.quality=Zt(i.resolution)),t.attributes["VIDEO-RANGE"]&&(i.dynamicRange=t.attributes["VIDEO-RANGE"]),t.attributes.CODECS&&(i.codecs=t.attributes.CODECS),t.attributes["FRAME-RATE"]&&(i.frameRate=t.attributes["FRAME-RATE"]),i}):[],gr=(e=[],r)=>{let t=i=>{let o=i.resolvedUri||i.uri;if(!o.startsWith("https://")&&r.url){let a=Xt(r.url)+"/";o=new URL(o,a).toString()}return{url:o,duration:i.duration,number:i.number,presentationTime:i.presentationTime}},s=e.map(t),n=e[0].map;if(e.length&&(n?.resolvedUri||n?.uri)){let i=n?.resolvedUri||x(n.uri,r.url);s.unshift({url:i,init:!0,duration:0,number:0,presentationTime:0})}return s},J=(e,r)=>{if(r.segments=gr(e.segments,r),e.contentProtection){r.protection={};let t=e.contentProtection["com.apple.fps.1_0"];t&&(r.protection.fairplay={keyFormat:t.attributes.KEYFORMAT,uri:t.attributes.URI,method:t.attributes.METHOD});let s=e.contentProtection["com.widevine.alpha"];s&&(r.protection.widevine={pssh:s.pssh,uri:s.attributes.schemeIdUri,keyId:s.attributes.keyId})}},X=e=>Promise.all(e.map(async r=>{let t=await ur(r.url);J(t,r)})),fr=async(e,r)=>{let t=Se(e),s=hr(t,r),n=dr(t,r),i=pr(t,r);if(!t.playlists&&t.segments){let{pathname:a}=new URL(r);if(a.includes(".m4a")||a.includes(".mp3")||a.includes(".opus")){let l=ar({id:"audio"+be(a),label:"audio",type:"audio",codec:"",channels:2,jointObjectCoding:"",isDescriptive:!1,bitrate:NaN,duration:NaN,language:""});J(t,l),n.push(l)}else{let l=cr({id:"video"+be(a),label:"video",type:"video",codec:"",dynamicRange:"",contentProtection:"",bitrate:NaN,duration:NaN,width:NaN,height:NaN,fps:NaN,language:""});J(t,l),s.push(l)}}else await Promise.all([X(s),X(n),X(i)]);return{tracks:{all:s.concat(n).concat(i),videos:s,audios:n,subtitles:i,withResolution:er(s),withVideoCodecs:nr(s),withVideoQuality:tr(s),withAudioCodecs:ir(n),withAudioLanguages:rr(n),withAudioChannels:or(n),withSubtitleLanguages:sr(i)}}};Ae.exports={parseManifest:fr}});var yr=U((Fr,Te)=>{var mr=Ce(),Cr=we(),{filterByResolution:br,filterByQuality:Sr,filterByCodecs:vr,filterByLanguages:Ar,filterByChannels:wr}=k(),Tr=(e,r,t)=>{if(e.includes("<MPD"))return mr.parseManifest(e,r,t);if(e.includes("#EXTM3U"))return Cr.parseManifest(e,r);throw new Error("Invalid manifest")};Te.exports={parse:Tr,filterByResolution:br,filterByQuality:Sr,filterByCodecs:vr,filterByLanguages:Ar,filterByChannels:wr}});export default yr();
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+ var __commonJS = (cb, mod) => function __require2() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+
12
+ // lib/xml.js
13
+ var require_xml = __commonJS({
14
+ "lib/xml.js"(exports, module) {
15
+ "use strict";
16
+ function parse(text, options = {}) {
17
+ var pos = options.pos || 0;
18
+ var keepComments = !!options.keepComments;
19
+ var keepWhitespace = !!options.keepWhitespace;
20
+ var openBracket = "<";
21
+ var openBracketCC = "<".charCodeAt(0);
22
+ var closeBracket = ">";
23
+ var closeBracketCC = ">".charCodeAt(0);
24
+ var minusCC = "-".charCodeAt(0);
25
+ var slashCC = "/".charCodeAt(0);
26
+ var exclamationCC = "!".charCodeAt(0);
27
+ var singleQuoteCC = "'".charCodeAt(0);
28
+ var doubleQuoteCC = '"'.charCodeAt(0);
29
+ var openCornerBracketCC = "[".charCodeAt(0);
30
+ var closeCornerBracketCC = "]".charCodeAt(0);
31
+ function parseChildren(tagName) {
32
+ var children = [];
33
+ while (text[pos]) {
34
+ if (text.charCodeAt(pos) == openBracketCC) {
35
+ if (text.charCodeAt(pos + 1) === slashCC) {
36
+ var closeStart = pos + 2;
37
+ pos = text.indexOf(closeBracket, pos);
38
+ var closeTag = text.substring(closeStart, pos);
39
+ if (closeTag.indexOf(tagName) == -1) {
40
+ const parsedText = text.substring(0, pos).split("\n");
41
+ throw new Error(
42
+ "Unexpected close tag\nLine: " + (parsedText.length - 1) + "\nColumn: " + (parsedText[parsedText.length - 1].length + 1) + "\nChar: " + text[pos]
43
+ );
44
+ }
45
+ if (pos + 1) pos += 1;
46
+ return children;
47
+ } else if (text.charCodeAt(pos + 1) === exclamationCC) {
48
+ if (text.charCodeAt(pos + 2) == minusCC) {
49
+ const startCommentPos = pos;
50
+ while (pos !== -1 && !(text.charCodeAt(pos) === closeBracketCC && text.charCodeAt(pos - 1) == minusCC && text.charCodeAt(pos - 2) == minusCC && pos != -1)) {
51
+ pos = text.indexOf(closeBracket, pos + 1);
52
+ }
53
+ if (pos === -1) {
54
+ pos = text.length;
55
+ }
56
+ if (keepComments) {
57
+ children.push(text.substring(startCommentPos, pos + 1));
58
+ }
59
+ } else if (text.charCodeAt(pos + 2) === openCornerBracketCC && text.charCodeAt(pos + 8) === openCornerBracketCC && text.substr(pos + 3, 5).toLowerCase() === "cdata") {
60
+ var cdataEndIndex = text.indexOf("]]>", pos);
61
+ if (cdataEndIndex == -1) {
62
+ children.push(text.substr(pos + 9));
63
+ pos = text.length;
64
+ } else {
65
+ children.push(text.substring(pos + 9, cdataEndIndex));
66
+ pos = cdataEndIndex + 3;
67
+ }
68
+ continue;
69
+ } else {
70
+ const startDoctype = pos + 1;
71
+ pos += 2;
72
+ var encapsuled = false;
73
+ while ((text.charCodeAt(pos) !== closeBracketCC || encapsuled === true) && text[pos]) {
74
+ if (text.charCodeAt(pos) === openCornerBracketCC) {
75
+ encapsuled = true;
76
+ } else if (encapsuled === true && text.charCodeAt(pos) === closeCornerBracketCC) {
77
+ encapsuled = false;
78
+ }
79
+ pos++;
80
+ }
81
+ children.push(text.substring(startDoctype, pos));
82
+ }
83
+ pos++;
84
+ continue;
85
+ }
86
+ var node = parseNode();
87
+ children.push(node);
88
+ if (node.tagName[0] === "?") {
89
+ children.push(...node.children);
90
+ node.children = [];
91
+ }
92
+ } else {
93
+ const parsedText = parseText();
94
+ if (keepWhitespace) {
95
+ if (parsedText.length > 0) {
96
+ children.push(parsedText);
97
+ }
98
+ } else {
99
+ var trimmed = parsedText.trim();
100
+ if (trimmed.length > 0) {
101
+ children.push(trimmed);
102
+ }
103
+ }
104
+ pos++;
105
+ }
106
+ }
107
+ return children;
108
+ }
109
+ function parseText() {
110
+ var start = pos;
111
+ pos = text.indexOf(openBracket, pos) - 1;
112
+ if (pos === -2) pos = text.length;
113
+ return text.slice(start, pos + 1);
114
+ }
115
+ var nameSpacer = "\r\n >/= ";
116
+ function parseName() {
117
+ var start = pos;
118
+ while (nameSpacer.indexOf(text[pos]) === -1 && text[pos]) {
119
+ pos++;
120
+ }
121
+ return text.slice(start, pos);
122
+ }
123
+ var NoChildNodes = options.noChildNodes || [
124
+ "img",
125
+ "br",
126
+ "input",
127
+ "meta",
128
+ "link",
129
+ "hr"
130
+ ];
131
+ function parseNode() {
132
+ pos++;
133
+ const tagName = parseName();
134
+ const attributes = {};
135
+ let children = [];
136
+ while (text.charCodeAt(pos) !== closeBracketCC && text[pos]) {
137
+ var c = text.charCodeAt(pos);
138
+ if (c > 64 && c < 91 || c > 96 && c < 123) {
139
+ var name = parseName();
140
+ var code = text.charCodeAt(pos);
141
+ while (code && code !== singleQuoteCC && code !== doubleQuoteCC && !(code > 64 && code < 91 || code > 96 && code < 123) && code !== closeBracketCC) {
142
+ pos++;
143
+ code = text.charCodeAt(pos);
144
+ }
145
+ if (code === singleQuoteCC || code === doubleQuoteCC) {
146
+ var value = parseString();
147
+ if (pos === -1) {
148
+ return {
149
+ tagName,
150
+ attributes,
151
+ children
152
+ };
153
+ }
154
+ } else {
155
+ value = null;
156
+ pos--;
157
+ }
158
+ attributes[name] = value;
159
+ }
160
+ pos++;
161
+ }
162
+ if (text.charCodeAt(pos - 1) !== slashCC) {
163
+ if (tagName == "script") {
164
+ const start = pos + 1;
165
+ pos = text.indexOf("</script>", pos);
166
+ children = [text.slice(start, pos)];
167
+ pos += 9;
168
+ } else if (tagName == "style") {
169
+ const start = pos + 1;
170
+ pos = text.indexOf("</style>", pos);
171
+ children = [text.slice(start, pos)];
172
+ pos += 8;
173
+ } else if (NoChildNodes.indexOf(tagName) === -1) {
174
+ pos++;
175
+ children = parseChildren(tagName);
176
+ } else {
177
+ pos++;
178
+ }
179
+ } else {
180
+ pos++;
181
+ }
182
+ return {
183
+ tagName,
184
+ attributes,
185
+ children
186
+ };
187
+ }
188
+ function parseString() {
189
+ var startChar = text[pos];
190
+ var startpos = pos + 1;
191
+ pos = text.indexOf(startChar, startpos);
192
+ return text.slice(startpos, pos);
193
+ }
194
+ function findElements() {
195
+ var r = new RegExp(
196
+ "\\s" + options.attrName + `\\s*=['"]` + options.attrValue + `['"]`
197
+ ).exec(text);
198
+ if (r) {
199
+ return r.index;
200
+ } else {
201
+ return -1;
202
+ }
203
+ }
204
+ let out = null;
205
+ if (options.attrValue !== void 0) {
206
+ options.attrName = options.attrName || "id";
207
+ out = [];
208
+ while ((pos = findElements()) !== -1) {
209
+ pos = text.lastIndexOf("<", pos);
210
+ if (pos !== -1) {
211
+ out.push(parseNode());
212
+ }
213
+ text = text.substr(pos);
214
+ pos = 0;
215
+ }
216
+ } else if (options.parseNode) {
217
+ out = parseNode();
218
+ } else {
219
+ out = parseChildren("");
220
+ }
221
+ if (options.filter) {
222
+ out = filter(out, options.filter);
223
+ }
224
+ if (options.setPos) {
225
+ out.pos = pos;
226
+ }
227
+ return out;
228
+ }
229
+ function filter(children, f, dept = 0, path = "") {
230
+ var out = [];
231
+ children.forEach(function(child, i) {
232
+ if (typeof child === "object" && f(child, i, dept, path)) out.push(child);
233
+ if (child.children) {
234
+ var kids = filter(
235
+ child.children,
236
+ f,
237
+ dept + 1,
238
+ (path ? path + "." : "") + i + "." + child.tagName
239
+ );
240
+ out = out.concat(kids);
241
+ }
242
+ });
243
+ return out;
244
+ }
245
+ module.exports = { parse, filter };
246
+ }
247
+ });
248
+
249
+ // lib/util.js
250
+ var require_util = __commonJS({
251
+ "lib/util.js"(exports, module) {
252
+ "use strict";
253
+ var formatBytes = (bytes, sizes = ["Bytes", "KB", "MB", "GB", "TB"]) => {
254
+ if (bytes == 0) return `0 ${sizes[0]}`;
255
+ const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
256
+ if (i == 0) return bytes + " " + sizes[i];
257
+ return (bytes / Math.pow(1024, i)).toFixed(1) + " " + sizes[i];
258
+ };
259
+ var parseSize = (bandwidth, duration) => ({
260
+ b: bandwidth * duration,
261
+ kb: bandwidth / 1e3 * duration,
262
+ mb: bandwidth / 8e6 * duration,
263
+ gb: bandwidth / 8e9 * duration,
264
+ toString() {
265
+ return formatBytes(bandwidth * duration);
266
+ }
267
+ });
268
+ var parseBitrate = (bandwidth) => ({
269
+ bps: bandwidth,
270
+ kbps: bandwidth / 1e3,
271
+ mbps: bandwidth / 8e6,
272
+ gbps: bandwidth / 8e9,
273
+ toString() {
274
+ return formatBytes(bandwidth, ["bps", "Kbps", "Mbps", "Gbps"]);
275
+ }
276
+ });
277
+ var qualities = [
278
+ { width: 7680, height: 4320 },
279
+ { width: 3840, height: 2160 },
280
+ { width: 2560, height: 1440 },
281
+ { width: 1920, height: 1080 },
282
+ { width: 1280, height: 720 },
283
+ { width: 1024, height: 576 },
284
+ { width: 854, height: 480 },
285
+ { width: 640, height: 360 },
286
+ { width: 426, height: 240 },
287
+ { width: 256, height: 144 }
288
+ ];
289
+ var getWidth = (height) => qualities.find((q) => q.height === height)?.width;
290
+ var getHeight = (width) => qualities.find((q) => q.width === width)?.height;
291
+ var getQualityLabel = (resolution) => `${getHeight(resolution.width) || resolution.height}p`;
292
+ var getBestTrack = (tracks) => {
293
+ const maxBitrate = Math.max(...tracks.map((track) => track.bitrate.bps));
294
+ return tracks.find((track) => track.bitrate.bps === maxBitrate);
295
+ };
296
+ var parseDuration = (str) => {
297
+ const SECONDS_IN_YEAR = 365 * 24 * 60 * 60;
298
+ const SECONDS_IN_MONTH = 30 * 24 * 60 * 60;
299
+ const SECONDS_IN_DAY = 24 * 60 * 60;
300
+ const SECONDS_IN_HOUR = 60 * 60;
301
+ const SECONDS_IN_MIN = 60;
302
+ const durationRegex = /P(?:(\d*)Y)?(?:(\d*)M)?(?:(\d*)D)?(?:T(?:(\d*)H)?(?:(\d*)M)?(?:([\d.]*)S)?)?/;
303
+ const match = durationRegex.exec(str);
304
+ if (!match) {
305
+ return 0;
306
+ }
307
+ const [year, month, day, hour, minute, second] = match.slice(1);
308
+ return parseFloat(year || 0) * SECONDS_IN_YEAR + parseFloat(month || 0) * SECONDS_IN_MONTH + parseFloat(day || 0) * SECONDS_IN_DAY + parseFloat(hour || 0) * SECONDS_IN_HOUR + parseFloat(minute || 0) * SECONDS_IN_MIN + parseFloat(second || 0);
309
+ };
310
+ var isLanguageTagValid = (value) => {
311
+ try {
312
+ Intl.getCanonicalLocales(value);
313
+ return true;
314
+ } catch (e) {
315
+ return;
316
+ }
317
+ };
318
+ module.exports = {
319
+ parseSize,
320
+ parseBitrate,
321
+ getWidth,
322
+ getHeight,
323
+ getQualityLabel,
324
+ getBestTrack,
325
+ parseDuration,
326
+ isLanguageTagValid
327
+ };
328
+ }
329
+ });
330
+
331
+ // lib/video.js
332
+ var require_video = __commonJS({
333
+ "lib/video.js"(exports, module) {
334
+ "use strict";
335
+ var { parseBitrate, getQualityLabel, parseSize } = require_util();
336
+ var VIDEO_CODECS = {
337
+ avc: "H.264",
338
+ hevc: "H.265",
339
+ vc1: "VC-1",
340
+ vp8: "VP8",
341
+ vp9: "VP9",
342
+ av1: "AV1"
343
+ };
344
+ var DYNAMIC_RANGE = {
345
+ sdr: "SDR",
346
+ // Standart Dynamic Range
347
+ hlg: "HLG",
348
+ // Hybrid log-gamma (HDR)
349
+ hdr10: "HDR10",
350
+ hdr10p: "HDR10+",
351
+ dv: "DV"
352
+ // Dolby Vision
353
+ };
354
+ var PRIMARIES = {
355
+ Unspecified: 0,
356
+ BT_709: 1,
357
+ BT_601_625: 5,
358
+ BT_601_525: 6,
359
+ BT_2020_and_2100: 9,
360
+ SMPTE_ST_2113_and_EG_4321: 12
361
+ // P3D65
362
+ };
363
+ var TRANSFER = {
364
+ Unspecified: 0,
365
+ BT_709: 1,
366
+ BT_601: 6,
367
+ BT_2020: 14,
368
+ BT_2100: 15,
369
+ BT_2100_PQ: 16,
370
+ BT_2100_HLG: 18
371
+ };
372
+ var MATRIX = {
373
+ RGB: 0,
374
+ YCbCr_BT_709: 1,
375
+ YCbCr_BT_601_625: 5,
376
+ YCbCr_BT_601_525: 6,
377
+ YCbCr_BT_2020_and_2100: 9,
378
+ // YCbCr BT.2100 shares the same CP
379
+ ICtCp_BT_2100: 14
380
+ };
381
+ var parseVideoCodecFromMime = (mime) => {
382
+ const target = mime.toLowerCase().trim().split(".")[0];
383
+ const avc = ["avc1", "avc2", "avc3", "dva1", "dvav"];
384
+ const hevc = [
385
+ "hev1",
386
+ "hev2",
387
+ "hev3",
388
+ "hvc1",
389
+ "hvc2",
390
+ "hvc3",
391
+ "dvh1",
392
+ "dvhe",
393
+ "lhv1",
394
+ "lhe1"
395
+ ];
396
+ const vc1 = ["vc-1"];
397
+ const vp8 = ["vp08", "vp8"];
398
+ const vp9 = ["vp09", "vp9"];
399
+ const av1 = ["av01"];
400
+ if (avc.includes(target)) return VIDEO_CODECS.avc;
401
+ if (hevc.includes(target)) return VIDEO_CODECS.hevc;
402
+ if (vc1.includes(target)) return VIDEO_CODECS.hevc;
403
+ if (vp8.includes(target)) return VIDEO_CODECS.vp8;
404
+ if (vp9.includes(target)) return VIDEO_CODECS.vp9;
405
+ if (av1.includes(target)) return VIDEO_CODECS.av1;
406
+ throw new Error(`The MIME ${mime} is not supported as video codec`);
407
+ };
408
+ var parseDynamicRangeFromCicp = (primaries, transfer, matrix) => {
409
+ if (transfer == 5) transfer = TRANSFER.BT_601;
410
+ if (primaries == PRIMARIES.Unspecified && transfer == TRANSFER.Unspecified && matrix == MATRIX.RGB)
411
+ return DYNAMIC_RANGE.sdr;
412
+ else if ([PRIMARIES.BT_601_625, PRIMARIES.BT_601_525].includes(primaries))
413
+ return DYNAMIC_RANGE.sdr;
414
+ else if (TRANSFER.BT_2100_PQ === transfer) return DYNAMIC_RANGE.hdr10;
415
+ else if (TRANSFER.BT_2100_HLG === transfer) return DYNAMIC_RANGE.hlg;
416
+ else return DYNAMIC_RANGE.sdr;
417
+ };
418
+ var createVideoTrack = ({
419
+ id,
420
+ label,
421
+ type,
422
+ codec,
423
+ dynamicRange,
424
+ contentProtection,
425
+ bitrate,
426
+ duration,
427
+ width,
428
+ height,
429
+ fps,
430
+ language,
431
+ segments
432
+ }) => {
433
+ const parsedBitrate = parseBitrate(Number(bitrate));
434
+ const parsedWidth = Number(width);
435
+ const parsedHeight = Number(height);
436
+ const size = duration ? parseSize(Number(bitrate), Number(duration)) : void 0;
437
+ return {
438
+ id,
439
+ label,
440
+ type,
441
+ codec,
442
+ bitrate: parsedBitrate,
443
+ size,
444
+ protection: contentProtection,
445
+ segments,
446
+ dynamicRange,
447
+ language,
448
+ width: parsedWidth,
449
+ height: parsedHeight,
450
+ fps: Number(fps),
451
+ quality: getQualityLabel({ width: parsedWidth, height: parsedHeight }),
452
+ toString() {
453
+ return [
454
+ "VIDEO",
455
+ `[${codec}, ${dynamicRange}]`,
456
+ language,
457
+ `${width}x${height} @ ${parsedBitrate.kbps} kb/s, ${fps} FPS`
458
+ ].join(" | ");
459
+ }
460
+ };
461
+ };
462
+ var parseVideoCodec = (codecs) => {
463
+ for (const codec of codecs.toLowerCase().split(",")) {
464
+ const mime = codec.trim().split(".")[0];
465
+ try {
466
+ return parseVideoCodecFromMime(mime);
467
+ } catch (e) {
468
+ continue;
469
+ }
470
+ }
471
+ throw new Error(
472
+ `No MIME types matched any supported Video Codecs in ${codecs}`
473
+ );
474
+ };
475
+ var tryParseVideoCodec = (codecs) => {
476
+ try {
477
+ return parseVideoCodec(codecs);
478
+ } catch (e) {
479
+ return null;
480
+ }
481
+ };
482
+ var parseDynamicRange = (codecs, supplementalProps = [], essentialProps = []) => {
483
+ const dv = ["dva1", "dvav", "dvhe", "dvh1"];
484
+ if (dv.some((value) => codecs.startsWith(value))) return DYNAMIC_RANGE.dv;
485
+ const primariesScheme = "urn:mpeg:mpegB:cicp:ColourPrimaries";
486
+ const transferScheme = "urn:mpeg:mpegB:cicp:TransferCharacteristics";
487
+ const matrixScheme = "urn:mpeg:mpegB:cicp:MatrixCoefficients";
488
+ const allProps = [...essentialProps, ...supplementalProps];
489
+ const getValues = (scheme) => allProps.filter((prop) => prop.attributes.schemeIdUri === scheme).map((prop) => parseInt(prop.attributes.value));
490
+ const primaries = getValues(primariesScheme).reduce(
491
+ (acc, current) => acc + current,
492
+ 0
493
+ );
494
+ const transfer = getValues(transferScheme).reduce(
495
+ (acc, current) => acc + current,
496
+ 0
497
+ );
498
+ const matrix = getValues(matrixScheme).reduce(
499
+ (acc, current) => acc + current,
500
+ 0
501
+ );
502
+ return parseDynamicRangeFromCicp(primaries, transfer, matrix);
503
+ };
504
+ module.exports = {
505
+ parseVideoCodec,
506
+ tryParseVideoCodec,
507
+ parseDynamicRange,
508
+ createVideoTrack,
509
+ VIDEO_CODECS
510
+ };
511
+ }
512
+ });
513
+
514
+ // lib/track.js
515
+ var require_track = __commonJS({
516
+ "lib/track.js"(exports, module) {
517
+ "use strict";
518
+ var { getBestTrack } = require_util();
519
+ var parseMimes = (codecs) => codecs.toLowerCase().split(",").map((codec) => codec.trim().split(".")[0]);
520
+ var createResolutionFilter = (videos) => {
521
+ return ({ width, height }) => {
522
+ return videos.filter(
523
+ (track) => (!width || track.width === width) && (!height || track.height === height)
524
+ );
525
+ };
526
+ };
527
+ var createCodecFilter = (tracks) => {
528
+ return (codecs) => {
529
+ if (!codecs?.length) return tracks;
530
+ const results = tracks.filter((track) => codecs.includes(track.codec));
531
+ results.sort((a, b) => b.bitrate.bps - a.bitrate.bps);
532
+ return results;
533
+ };
534
+ };
535
+ var createVideoCodecFilter = (videos) => createCodecFilter(videos);
536
+ var createVideoQualityFilter = (videos) => {
537
+ return (quality) => {
538
+ if (!quality) return [getBestTrack(videos)];
539
+ const trackQuality = String(quality).includes("p") ? quality : `${quality}p`;
540
+ const results = videos.filter((track) => track.quality === trackQuality);
541
+ results.sort((a, b) => b.bitrate.bps - a.bitrate.bps);
542
+ return results.length ? results : [getBestTrack(videos)];
543
+ };
544
+ };
545
+ var createAudioCodecFilter = (audios) => createCodecFilter(audios);
546
+ var createAudioLanguageFilter = (audios) => {
547
+ return (languages = [], maxTracksPerLanguage) => {
548
+ if (!languages.length) {
549
+ const audiosWithLanguage = audios.filter((track) => track.language);
550
+ if (audiosWithLanguage.length) {
551
+ for (const audio of audiosWithLanguage) {
552
+ const alreadyAdded = languages.includes(audio.language);
553
+ if (!alreadyAdded) languages.push(audio.language);
554
+ }
555
+ } else {
556
+ audios.sort((a, b) => b.bitrate.bps - a.bitrate.bps);
557
+ return audios.slice(0, maxTracksPerLanguage);
558
+ }
559
+ }
560
+ const filtered = [];
561
+ for (const language of languages) {
562
+ const tracks = audios.filter(
563
+ (track) => track.language?.startsWith(language)
564
+ );
565
+ filtered.push(...tracks);
566
+ }
567
+ const results = [];
568
+ const filteredLanguages = [
569
+ ...new Set(filtered.map((track) => track.language))
570
+ ];
571
+ for (const language of filteredLanguages) {
572
+ const tracks = filtered.filter((track) => track.language === language).slice(0, maxTracksPerLanguage);
573
+ results.push(...tracks);
574
+ }
575
+ return results;
576
+ };
577
+ };
578
+ var createAudioChannelsFilter = (audios) => {
579
+ return (channels) => {
580
+ if (!channels) return audios;
581
+ const value = typeof channels === "string" ? parseFloat(channels) : channels;
582
+ return audios.filter((track) => track.channels === value);
583
+ };
584
+ };
585
+ var createSubtitleLanguageFilter = (subtitles) => {
586
+ return (languages) => {
587
+ if (!languages.length) return subtitles;
588
+ return subtitles.filter(
589
+ (track) => languages.some(
590
+ (language) => track.language?.startsWith(language) || track.label?.startsWith(language)
591
+ )
592
+ );
593
+ };
594
+ };
595
+ var filterByResolution = (tracks, resolution) => createResolutionFilter(tracks)(resolution);
596
+ var filterByQuality = (tracks, quality) => createVideoQualityFilter(tracks)(quality);
597
+ var filterByCodecs = (tracks, codecs) => createCodecFilter(tracks)(codecs);
598
+ var filterByLanguages = (tracks, languages, maxTracksPerLanguage) => createAudioLanguageFilter(tracks)(languages, maxTracksPerLanguage);
599
+ var filterByChannels = (tracks, channels) => createAudioChannelsFilter(tracks)(channels);
600
+ module.exports = {
601
+ parseMimes,
602
+ createResolutionFilter,
603
+ createVideoCodecFilter,
604
+ createVideoQualityFilter,
605
+ createAudioCodecFilter,
606
+ createAudioLanguageFilter,
607
+ createAudioChannelsFilter,
608
+ createSubtitleLanguageFilter,
609
+ filterByResolution,
610
+ filterByQuality,
611
+ filterByCodecs,
612
+ filterByLanguages,
613
+ filterByChannels
614
+ };
615
+ }
616
+ });
617
+
618
+ // lib/audio.js
619
+ var require_audio = __commonJS({
620
+ "lib/audio.js"(exports, module) {
621
+ "use strict";
622
+ var { parseMimes } = require_track();
623
+ var { parseBitrate, parseSize } = require_util();
624
+ var AUDIO_CODECS = {
625
+ AAC: "AAC",
626
+ // https://wikipedia.org/wiki/Advanced_Audio_Coding
627
+ AC3: "DD",
628
+ // https://wikipedia.org/wiki/Dolby_Digital
629
+ EC3: "DD+",
630
+ // https://wikipedia.org/wiki/Dolby_Digital_Plus
631
+ OPUS: "OPUS",
632
+ // https://wikipedia.org/wiki/Opus_(audio_format)
633
+ OGG: "VORB",
634
+ // https://wikipedia.org/wiki/Vorbis
635
+ DTS: "DTS",
636
+ // https://en.wikipedia.org/wiki/DTS_(company)#DTS_Digital_Surround
637
+ ALAC: "ALAC",
638
+ // https://en.wikipedia.org/wiki/Apple_Lossless_Audio_Codec
639
+ FLAC: "FLAC"
640
+ // https://en.wikipedia.org/wiki/FLAC
641
+ };
642
+ var parseAudioCodecFromMime = (mime) => {
643
+ const target = mime.toLowerCase().trim().split(".")[0];
644
+ switch (target) {
645
+ case "mp4a":
646
+ return AUDIO_CODECS.AAC;
647
+ case "ac-3":
648
+ return AUDIO_CODECS.AC3;
649
+ case "ec-3":
650
+ return AUDIO_CODECS.EC3;
651
+ case "opus":
652
+ return AUDIO_CODECS.OPUS;
653
+ case "dtsc":
654
+ return AUDIO_CODECS.DTS;
655
+ case "alac":
656
+ return AUDIO_CODECS.ALAC;
657
+ case "flac":
658
+ return AUDIO_CODECS.FLAC;
659
+ default:
660
+ throw new Error(`The MIME ${mime} is not supported as audio codec`);
661
+ }
662
+ };
663
+ var parseAudioCodec = (codecs) => {
664
+ const mimes = parseMimes(codecs);
665
+ for (const mime of mimes) {
666
+ try {
667
+ return parseAudioCodecFromMime(mime);
668
+ } catch (e) {
669
+ continue;
670
+ }
671
+ }
672
+ throw new Error(
673
+ `No MIME types matched any supported Audio Codecs in ${codecs}`
674
+ );
675
+ };
676
+ var tryParseAudioCodec = (codecs) => {
677
+ try {
678
+ return parseAudioCodec(codecs);
679
+ } catch (e) {
680
+ return null;
681
+ }
682
+ };
683
+ var getDolbyDigitalPlusComplexityIndex = (supplementalProps = []) => {
684
+ const targetScheme = "tag:dolby.com,2018:dash:EC3_ExtensionComplexityIndex:2018";
685
+ for (const prop of supplementalProps)
686
+ if (prop.attributes.schemeIdUri === targetScheme)
687
+ return parseInt(prop.attributes.value);
688
+ };
689
+ var checkIsDescriptive = (accessibilities = []) => {
690
+ for (const accessibility of accessibilities) {
691
+ const { schemeIdUri, value } = accessibility.attributes;
692
+ const firstMatch = schemeIdUri == "urn:mpeg:dash:role:2011" && value === "descriptive";
693
+ const secondMatch = schemeIdUri == "urn:tva:metadata:cs:AudioPurposeCS:2007" && value === "1";
694
+ const isDescriptive = firstMatch || secondMatch;
695
+ if (isDescriptive) return true;
696
+ }
697
+ return false;
698
+ };
699
+ var parseChannels = (channels) => {
700
+ const isDigit = (char) => char >= "0" && char <= "9";
701
+ if (typeof channels === "string") {
702
+ if (channels.toUpperCase() == "A000") return 2;
703
+ else if (channels.toUpperCase() == "F801") return 5.1;
704
+ else if (isDigit(channels.replace("ch", "").replace(".", "")[0]))
705
+ return parseFloat(channels.replace("ch", ""));
706
+ throw new Error(`Unsupported audio channels value, '${channels}'`);
707
+ }
708
+ return parseFloat(channels);
709
+ };
710
+ var createAudioTrack = ({
711
+ id,
712
+ label,
713
+ type,
714
+ codec,
715
+ channels,
716
+ contentProtection,
717
+ bitrate,
718
+ duration,
719
+ jointObjectCoding = 0,
720
+ isDescriptive = false,
721
+ language,
722
+ segments
723
+ }) => {
724
+ const parsedBitrate = parseBitrate(Number(bitrate));
725
+ const parsedChannels = parseChannels(channels);
726
+ const size = duration ? parseSize(Number(bitrate), Number(duration)) : void 0;
727
+ return {
728
+ id,
729
+ label,
730
+ type,
731
+ codec,
732
+ bitrate: parsedBitrate,
733
+ size,
734
+ protection: contentProtection,
735
+ language,
736
+ segments,
737
+ channels: parsedChannels,
738
+ jointObjectCoding,
739
+ isDescriptive,
740
+ toString() {
741
+ return [
742
+ "AUDIO",
743
+ `[${codec}]`,
744
+ `${parsedChannels || "?"}` + (jointObjectCoding ? ` (JOC ${jointObjectCoding})` : ""),
745
+ `${parsedBitrate.kbps} kb/s`,
746
+ language
747
+ ].join(" | ");
748
+ }
749
+ };
750
+ };
751
+ module.exports = {
752
+ AUDIO_CODECS,
753
+ parseAudioCodec,
754
+ tryParseAudioCodec,
755
+ createAudioTrack,
756
+ getDolbyDigitalPlusComplexityIndex,
757
+ checkIsDescriptive
758
+ };
759
+ }
760
+ });
761
+
762
+ // lib/subtitle.js
763
+ var require_subtitle = __commonJS({
764
+ "lib/subtitle.js"(exports, module) {
765
+ "use strict";
766
+ var { parseMimes } = require_track();
767
+ var { parseBitrate, parseSize } = require_util();
768
+ var SUBTITLE_CODECS = {
769
+ SubRip: "SRT",
770
+ // https://wikipedia.org/wiki/SubRip
771
+ SubStationAlpha: "SSA",
772
+ // https://wikipedia.org/wiki/SubStation_Alpha
773
+ SubStationAlphav4: "ASS",
774
+ // https://wikipedia.org/wiki/SubStation_Alpha#Advanced_SubStation_Alpha=
775
+ TimedTextMarkupLang: "TTML",
776
+ // https://wikipedia.org/wiki/Timed_Text_Markup_Language
777
+ WebVTT: "VTT",
778
+ // https://wikipedia.org/wiki/WebVTT
779
+ // MPEG-DASH box-encapsulated subtitle formats
780
+ fTTML: "STPP",
781
+ // https://www.w3.org/TR/2018/REC-ttml-imsc1.0.1-20180424
782
+ fVTT: "WVTT"
783
+ // https://www.w3.org/TR/webvtt1
784
+ };
785
+ var parseSubtitleCodecFromMime = (mime) => {
786
+ const target = mime.toLowerCase().trim().split(".")[0];
787
+ switch (target) {
788
+ case "srt":
789
+ case "x-subrip":
790
+ return SUBTITLE_CODECS.SubRip;
791
+ case "ssa":
792
+ return SUBTITLE_CODECS.SubStationAlpha;
793
+ case "ass":
794
+ return SUBTITLE_CODECS.SubStationAlphav4;
795
+ case "ttml":
796
+ return SUBTITLE_CODECS.TimedTextMarkupLang;
797
+ case "vtt":
798
+ return SUBTITLE_CODECS.WebVTT;
799
+ case "stpp":
800
+ return SUBTITLE_CODECS.fTTML;
801
+ case "wvtt":
802
+ return SUBTITLE_CODECS.fVTT;
803
+ default:
804
+ throw new Error(`The MIME ${mime} is not supported as subtitle codec`);
805
+ }
806
+ };
807
+ var parseSubtitleCodec = (codecs) => {
808
+ const mimes = parseMimes(codecs);
809
+ for (const mime of mimes) {
810
+ try {
811
+ return parseSubtitleCodecFromMime(mime);
812
+ } catch (e) {
813
+ continue;
814
+ }
815
+ }
816
+ throw new Error(
817
+ `No MIME types matched any supported Subtitle Codecs in ${codecs}`
818
+ );
819
+ };
820
+ var tryParseSubtitleCodec = (codecs) => {
821
+ try {
822
+ return parseSubtitleCodec(codecs);
823
+ } catch (e) {
824
+ return null;
825
+ }
826
+ };
827
+ var checkIsClosedCaption = (roles = []) => {
828
+ for (const role of roles) {
829
+ const isClosedCaption = role.attributes.schemeIdUri === "urn:mpeg:dash:role:2011" && role.attributes.value === "caption";
830
+ if (isClosedCaption) return true;
831
+ }
832
+ return false;
833
+ };
834
+ var checkIsSdh = (accessibilities = []) => {
835
+ for (const accessibility of accessibilities) {
836
+ const { schemeIdUri, value } = accessibility.attributes;
837
+ const isSdh = schemeIdUri === "urn:tva:metadata:cs:AudioPurposeCS:2007" && value === "2";
838
+ if (isSdh) return true;
839
+ }
840
+ return false;
841
+ };
842
+ var checkIsForced = (roles = []) => {
843
+ for (const role of roles) {
844
+ const isForced = role.attributes.schemeIdUri === "urn:mpeg:dash:role:2011" && (role.attributes.value === "forced-subtitle" || role.attributes.value === "forced_subtitle");
845
+ if (isForced) return true;
846
+ }
847
+ return false;
848
+ };
849
+ var createSubtitleTrack = ({
850
+ id,
851
+ label,
852
+ bitrate,
853
+ duration,
854
+ type,
855
+ codec,
856
+ isClosedCaption,
857
+ isSdh,
858
+ isForced,
859
+ language,
860
+ segments
861
+ }) => {
862
+ const parsedBitrate = parseBitrate(Number(bitrate));
863
+ const size = duration ? parseSize(Number(bitrate), Number(duration)) : void 0;
864
+ return {
865
+ id,
866
+ label,
867
+ bitrate: parsedBitrate,
868
+ size,
869
+ type,
870
+ codec,
871
+ isClosedCaption,
872
+ isSdh,
873
+ isForced,
874
+ segments,
875
+ language,
876
+ toString() {
877
+ return ["SUBTITLE", `[${codec}]`, language].join(" | ");
878
+ }
879
+ };
880
+ };
881
+ module.exports = {
882
+ parseSubtitleCodec,
883
+ tryParseSubtitleCodec,
884
+ checkIsClosedCaption,
885
+ checkIsSdh,
886
+ checkIsForced,
887
+ createSubtitleTrack
888
+ };
889
+ }
890
+ });
891
+
892
+ // lib/dash.js
893
+ var require_dash = __commonJS({
894
+ "lib/dash.js"(exports, module) {
895
+ "use strict";
896
+ var xml = require_xml();
897
+ var { parseDuration, isLanguageTagValid } = require_util();
898
+ var {
899
+ parseVideoCodec,
900
+ tryParseVideoCodec,
901
+ parseDynamicRange,
902
+ createVideoTrack
903
+ } = require_video();
904
+ var {
905
+ parseAudioCodec,
906
+ tryParseAudioCodec,
907
+ createAudioTrack,
908
+ getDolbyDigitalPlusComplexityIndex,
909
+ checkIsDescriptive
910
+ } = require_audio();
911
+ var {
912
+ parseSubtitleCodec,
913
+ tryParseSubtitleCodec,
914
+ checkIsClosedCaption,
915
+ checkIsSdh,
916
+ checkIsForced,
917
+ createSubtitleTrack
918
+ } = require_subtitle();
919
+ var {
920
+ createResolutionFilter,
921
+ createVideoQualityFilter,
922
+ createAudioLanguageFilter,
923
+ createSubtitleLanguageFilter,
924
+ createVideoCodecFilter,
925
+ createAudioCodecFilter,
926
+ createAudioChannelsFilter
927
+ } = require_track();
928
+ var appendUtils = (element) => {
929
+ if (!element) return element;
930
+ if (Array.isArray(element)) {
931
+ element.get = (name) => appendUtils(element.find((item) => item.tagName === name));
932
+ } else {
933
+ element.getAttr = (name) => element.attributes[name];
934
+ element.getChild = (name) => {
935
+ const tag = element.children.find((item) => item.tagName === name);
936
+ const isString = !name && typeof element.children?.[0] === "string";
937
+ return isString ? element.children[0] : appendUtils(tag);
938
+ };
939
+ element.set = (name, value) => element.attributes[name] = value;
940
+ element.get = (name) => element.getAttr(name) || element.getChild(name);
941
+ element.getNumber = (name) => Number(element.find(name));
942
+ element.getAll = (name) => element.children.filter((item) => item.tagName === name).map(appendUtils);
943
+ element.getBaseUrls = () => element.getAll("BaseURL").map((item) => item.children[0]);
944
+ element.getBaseUrl = () => element.getBaseUrls()[0];
945
+ }
946
+ return element;
947
+ };
948
+ var combineGetters = (representation, adaptationSet) => {
949
+ const prevGet = representation.get;
950
+ const prevGetAll = representation.getAll;
951
+ const get = (name) => prevGet(name) || adaptationSet.get(name);
952
+ const getAll = (name) => [...prevGetAll(name), ...adaptationSet.getAll(name)].filter(Boolean);
953
+ representation.get = get;
954
+ representation.getAll = getAll;
955
+ return { get, getAll };
956
+ };
957
+ var parseBaseUrl = (manifestUrl, mpd, period, representation) => {
958
+ let base = mpd.getBaseUrl();
959
+ if (!base) base = manifestUrl;
960
+ else if (!base.startsWith("https://"))
961
+ base = new URL(base, manifestUrl).toString();
962
+ if (!!period.getBaseUrl() || !!base)
963
+ base = new URL(period.getBaseUrl() || "", base).toString();
964
+ const baseUrl = new URL(representation.getBaseUrl() || "", base).toString();
965
+ return baseUrl;
966
+ };
967
+ var getTrackTypeByCodecs = (codecs) => {
968
+ if (tryParseVideoCodec(codecs)) return "video";
969
+ else if (tryParseAudioCodec(codecs)) return "audio";
970
+ else if (tryParseSubtitleCodec(codecs)) return "text";
971
+ return null;
972
+ };
973
+ var parseContentTypes = (representation) => {
974
+ const codecs = representation.get("codecs");
975
+ const mimeType = representation.get("mimeType");
976
+ const contentTypeByCodecs = getTrackTypeByCodecs(codecs);
977
+ const contentType = representation.get("contentType") || mimeType?.split("/")[0];
978
+ if (!contentType && !mimeType)
979
+ throw new Error(
980
+ "Unable to determine the format of a Representation, cannot continue..."
981
+ );
982
+ return { contentType: contentTypeByCodecs || contentType, mimeType };
983
+ };
984
+ var parseCodecs = (representation, contentType, mimeType) => {
985
+ const shouldUseCodecsFromMime = contentType === "text" && !mimeType.includes("mp4");
986
+ const codecs = shouldUseCodecsFromMime ? mimeType.split("/")[1] : representation.get("codecs");
987
+ return codecs;
988
+ };
989
+ var parseLanguage = (representation, adaptationSet, fallbackLanguage) => {
990
+ let language = "";
991
+ const options = [];
992
+ const lang = representation.get("lang");
993
+ const id = representation.get("id");
994
+ if (representation) {
995
+ options.push(lang);
996
+ if (id) {
997
+ const m = id.match(/\w+_(\w+)=\d+/);
998
+ if (m && m[1]) options.push(m[1]);
999
+ }
1000
+ }
1001
+ options.push(adaptationSet.get("lang"));
1002
+ if (fallbackLanguage) options.push(fallbackLanguage);
1003
+ for (const option of options) {
1004
+ const value = (option || "").trim();
1005
+ if (!isLanguageTagValid(value) || value.startsWith("und")) continue;
1006
+ language = value;
1007
+ continue;
1008
+ }
1009
+ if (!language) {
1010
+ }
1011
+ return language;
1012
+ };
1013
+ var buildSegmentUrl = (template, fields) => {
1014
+ let result = template;
1015
+ for (const [key, value] of Object.entries(fields))
1016
+ result = result.replace("$" + key + "$", value);
1017
+ return result;
1018
+ };
1019
+ var resolveSegmentTemplateUrls = (segmentTemplate, baseUrl, manifestUrl) => {
1020
+ for (const type of ["initialization", "media"]) {
1021
+ let value = segmentTemplate.get(type);
1022
+ if (!value) continue;
1023
+ if (!value.startsWith("https://")) {
1024
+ if (!baseUrl)
1025
+ throw new Error(
1026
+ `Resolved Segment URL is not absolute, and no Base URL is available.`
1027
+ );
1028
+ value = new URL(value, baseUrl).toString();
1029
+ }
1030
+ if (!new URL(value).search) {
1031
+ const manifestUrlQuery = new URL(manifestUrl).search;
1032
+ if (manifestUrlQuery) value += `?${manifestUrlQuery}`;
1033
+ }
1034
+ segmentTemplate.set(type, value);
1035
+ }
1036
+ };
1037
+ var parseSegmentsFromTimeline = (segmentTimeline, segmentTemplate, representation, startNumber) => {
1038
+ const times = [];
1039
+ let currentTime = 0;
1040
+ for (const s of segmentTimeline.getAll("S")) {
1041
+ const t = Number(s.get("t"));
1042
+ const r = Number(s.get("r") || 0);
1043
+ const d = Number(s.get("d"));
1044
+ if (t) currentTime = t;
1045
+ for (let i = 0; i < r + 1; i++) {
1046
+ times.push(currentTime);
1047
+ currentTime += d;
1048
+ }
1049
+ }
1050
+ const segments = [];
1051
+ const numbers = [...Array(times.length).keys()].map((n) => n + startNumber);
1052
+ for (let i = 0; i < times.length; i++) {
1053
+ const t = times[i];
1054
+ const n = numbers[i];
1055
+ const url = buildSegmentUrl(segmentTemplate.get("media"), {
1056
+ Bandwidth: representation.get("bandwidth"),
1057
+ RepresentationID: representation.get("id"),
1058
+ Number: n,
1059
+ Time: t
1060
+ });
1061
+ segments.push({ url });
1062
+ }
1063
+ return segments;
1064
+ };
1065
+ var parseSegmentsFromTemplate = (segmentTemplate, baseUrl, manifestUrl, duration, representation) => {
1066
+ const startNumber = Number(segmentTemplate.get("startNumber") || 1);
1067
+ const segmentTimeline = segmentTemplate.get("SegmentTimeline");
1068
+ resolveSegmentTemplateUrls(segmentTemplate, baseUrl, manifestUrl);
1069
+ const segmentDuration = parseFloat(segmentTemplate.get("duration"));
1070
+ const segmentTimescale = parseFloat(segmentTemplate.get("timescale") || 1);
1071
+ const DEFAULT_SEGMENTS_COUNT = 35;
1072
+ const segmentsCount = duration ? Math.ceil(duration / (segmentDuration / segmentTimescale)) : DEFAULT_SEGMENTS_COUNT;
1073
+ const bandwidth = representation.get("bandwidth");
1074
+ const id = representation.get("id");
1075
+ const sanitizeTemplate = (template) => template?.replace(/\$.*?(RepresentationID|Number|Time).*?\$/g, "$$$1$$");
1076
+ const segments = [];
1077
+ if (segmentTimeline) {
1078
+ segments.push(
1079
+ ...parseSegmentsFromTimeline(
1080
+ segmentTimeline,
1081
+ segmentTemplate,
1082
+ representation,
1083
+ startNumber
1084
+ )
1085
+ );
1086
+ } else {
1087
+ const template = sanitizeTemplate(segmentTemplate.get("media"));
1088
+ for (let i = startNumber; i < startNumber + segmentsCount; i++) {
1089
+ const url = buildSegmentUrl(template, {
1090
+ Bandwidth: bandwidth,
1091
+ RepresentationID: id,
1092
+ Number: i,
1093
+ Time: i
1094
+ });
1095
+ segments.push({ url });
1096
+ }
1097
+ }
1098
+ const initialization = sanitizeTemplate(
1099
+ segmentTemplate.get("initialization")
1100
+ );
1101
+ if (initialization) {
1102
+ const url = buildSegmentUrl(initialization, {
1103
+ Bandwidth: bandwidth,
1104
+ RepresentationID: id
1105
+ });
1106
+ segments.unshift({ url, init: true });
1107
+ }
1108
+ return segments;
1109
+ };
1110
+ var parseSegmentsFromList = (segmentList, baseUrl) => {
1111
+ const segmentUrls = segmentList.get("SegmentURL");
1112
+ const segments = [];
1113
+ for (const segmentUrl of segmentUrls) {
1114
+ let mediaUrl = segmentUrl.get("media");
1115
+ if (!mediaUrl) mediaUrl = baseUrl;
1116
+ else if (!mediaUrl.startsWith("https://"))
1117
+ mediaUrl = new URL(mediaUrl, baseUrl).toString();
1118
+ segments.push({ url: mediaUrl, range: segmentUrl.get("mediaRange") });
1119
+ }
1120
+ return segments;
1121
+ };
1122
+ var parseSegmentFromBase = async (segmentBase, baseUrl) => {
1123
+ const initialization = segmentBase.get("Initialization");
1124
+ let mediaRange = "";
1125
+ if (initialization) {
1126
+ }
1127
+ return { url: baseUrl, range: mediaRange };
1128
+ };
1129
+ var transformSegmentUrls = (segments) => {
1130
+ for (const segment of segments) {
1131
+ const hasHtmlEscapeCode = segment.url.includes("&amp;");
1132
+ if (hasHtmlEscapeCode) {
1133
+ const url = new URL(segment.url);
1134
+ const entries = new URLSearchParams(
1135
+ url.searchParams.toString()
1136
+ ).entries();
1137
+ for (const [key, value] of entries) {
1138
+ url.searchParams.delete(key);
1139
+ url.searchParams.append(key.replaceAll("amp;", ""), value);
1140
+ }
1141
+ segment.url = url.toString();
1142
+ }
1143
+ }
1144
+ };
1145
+ var protectionSchemas = {
1146
+ "urn:mpeg:dash:mp4protection:2011": "common",
1147
+ "urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95": "playready",
1148
+ "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed": "widevine"
1149
+ };
1150
+ var parseContentProtection = (contentProtections) => {
1151
+ const protection = {};
1152
+ for (const contentProtection of contentProtections) {
1153
+ const id = contentProtection.get("schemeIdUri")?.toLowerCase();
1154
+ const value = contentProtection.get("value");
1155
+ const pssh = contentProtection.get("cenc:pssh")?.get();
1156
+ const defaultKeyId = contentProtection.get("cenc:default_KID");
1157
+ const data = { id, value, pssh, defaultKeyId };
1158
+ protection[protectionSchemas[id]] = data;
1159
+ }
1160
+ return protection;
1161
+ };
1162
+ var parseManifest = async (text, url, fallbackLanguage) => {
1163
+ const mpd = appendUtils(xml.parse(text)).get("MPD");
1164
+ const period = mpd.get("Period");
1165
+ const durationString = period.get("duration") || mpd.get("mediaPresentationDuration");
1166
+ const duration = parseDuration(durationString);
1167
+ const videos = [];
1168
+ const audios = [];
1169
+ const subtitles = [];
1170
+ for (const adaptationSet of period.getAll("AdaptationSet")) {
1171
+ for (const representation of adaptationSet.getAll("Representation")) {
1172
+ const { get, getAll } = combineGetters(representation, adaptationSet);
1173
+ const { contentType, mimeType } = parseContentTypes(representation);
1174
+ const codecs = parseCodecs(representation, contentType, mimeType);
1175
+ const language = parseLanguage(
1176
+ representation,
1177
+ adaptationSet,
1178
+ fallbackLanguage
1179
+ );
1180
+ const baseUrl = parseBaseUrl(url, mpd, period, representation);
1181
+ const segmentTemplate = get("SegmentTemplate");
1182
+ const segmentList = get("SegmentList");
1183
+ const segmentBase = get("SegmentBase");
1184
+ const segments = [];
1185
+ if (segmentTemplate) {
1186
+ const segmentsFromTemplate = parseSegmentsFromTemplate(
1187
+ segmentTemplate,
1188
+ baseUrl,
1189
+ url,
1190
+ duration,
1191
+ representation
1192
+ );
1193
+ segments.push(...segmentsFromTemplate);
1194
+ } else if (segmentList) {
1195
+ const segmentsFromList = parseSegmentsFromList(segmentList, baseUrl);
1196
+ segments.push(...segmentsFromList);
1197
+ } else if (segmentBase) {
1198
+ const segmentFromBase = await parseSegmentFromBase(
1199
+ segmentBase,
1200
+ baseUrl
1201
+ );
1202
+ segments.push(segmentFromBase);
1203
+ } else if (baseUrl) {
1204
+ segments.push({ url: baseUrl });
1205
+ } else {
1206
+ throw new Error(
1207
+ "Could not find a way to get segments from this MPD manifest."
1208
+ );
1209
+ }
1210
+ transformSegmentUrls(segments);
1211
+ const label = get("label");
1212
+ const fps = get("frameRate") ?? segmentBase?.attributes.timescale;
1213
+ const width = get("width") ?? 0;
1214
+ const height = get("height") ?? 0;
1215
+ const bitrate = get("bandwidth");
1216
+ const supplementalProps = getAll("SupplementalProperty");
1217
+ const essentialProps = getAll("EssentialProperty");
1218
+ const accessibilities = adaptationSet.getAll("Accessibility");
1219
+ const roles = adaptationSet.getAll("Role");
1220
+ const contentProtections = getAll("ContentProtection");
1221
+ const id = [
1222
+ new URL(baseUrl).hostname,
1223
+ contentType,
1224
+ codecs,
1225
+ bitrate,
1226
+ language,
1227
+ mpd.get("id"),
1228
+ period.get("id"),
1229
+ get("id"),
1230
+ get("audioTrackId")
1231
+ ].filter(Boolean).join("-").replaceAll("/", "-");
1232
+ switch (contentType) {
1233
+ case "video": {
1234
+ const track = createVideoTrack({
1235
+ id,
1236
+ label,
1237
+ type: contentType,
1238
+ codec: parseVideoCodec(codecs),
1239
+ dynamicRange: parseDynamicRange(
1240
+ codecs,
1241
+ supplementalProps,
1242
+ essentialProps
1243
+ ),
1244
+ contentProtection: parseContentProtection(contentProtections),
1245
+ bitrate,
1246
+ duration,
1247
+ width,
1248
+ height,
1249
+ fps,
1250
+ language,
1251
+ segments
1252
+ });
1253
+ videos.push(track);
1254
+ break;
1255
+ }
1256
+ case "audio": {
1257
+ const track = createAudioTrack({
1258
+ id,
1259
+ label,
1260
+ type: contentType,
1261
+ codec: parseAudioCodec(codecs),
1262
+ channels: get("AudioChannelConfiguration")?.get("value"),
1263
+ jointObjectCoding: getDolbyDigitalPlusComplexityIndex(supplementalProps),
1264
+ isDescriptive: checkIsDescriptive(accessibilities),
1265
+ contentProtection: parseContentProtection(contentProtections),
1266
+ bitrate,
1267
+ duration,
1268
+ language,
1269
+ segments
1270
+ });
1271
+ audios.push(track);
1272
+ break;
1273
+ }
1274
+ case "text": {
1275
+ const track = createSubtitleTrack({
1276
+ id,
1277
+ label,
1278
+ type: contentType,
1279
+ codec: parseSubtitleCodec(codecs || "vtt"),
1280
+ isClosedCaption: checkIsClosedCaption(roles),
1281
+ isSdh: checkIsSdh(accessibilities),
1282
+ isForced: checkIsForced(roles),
1283
+ bitrate,
1284
+ duration,
1285
+ language,
1286
+ segments
1287
+ });
1288
+ subtitles.push(track);
1289
+ break;
1290
+ }
1291
+ case "image":
1292
+ break;
1293
+ default:
1294
+ throw new Error(`Unknown content type: ${contentType}`);
1295
+ }
1296
+ }
1297
+ }
1298
+ videos.sort((a, b) => b.bitrate.bps - a.bitrate.bps);
1299
+ return {
1300
+ duration,
1301
+ tracks: {
1302
+ all: videos.concat(audios).concat(subtitles),
1303
+ videos,
1304
+ audios,
1305
+ subtitles,
1306
+ withResolution: createResolutionFilter(videos),
1307
+ withVideoCodecs: createVideoCodecFilter(videos),
1308
+ withVideoQuality: createVideoQualityFilter(videos),
1309
+ withAudioCodecs: createAudioCodecFilter(audios),
1310
+ withAudioLanguages: createAudioLanguageFilter(audios),
1311
+ withAudioChannels: createAudioChannelsFilter(audios),
1312
+ withSubtitleLanguages: createSubtitleLanguageFilter(subtitles)
1313
+ }
1314
+ };
1315
+ };
1316
+ module.exports = { parseManifest };
1317
+ }
1318
+ });
1319
+
1320
+ // lib/hls.js
1321
+ var require_hls = __commonJS({
1322
+ "lib/hls.js"(exports, module) {
1323
+ "use strict";
1324
+ var { dirname, basename } = __require("node:path");
1325
+ var m3u8Parser = __require("m3u8-parser");
1326
+ var { parseBitrate, getQualityLabel } = require_util();
1327
+ var {
1328
+ createResolutionFilter,
1329
+ createVideoQualityFilter,
1330
+ createAudioLanguageFilter,
1331
+ createSubtitleLanguageFilter,
1332
+ createVideoCodecFilter,
1333
+ createAudioCodecFilter,
1334
+ createAudioChannelsFilter
1335
+ } = require_track();
1336
+ var { createAudioTrack } = require_audio();
1337
+ var { createVideoTrack } = require_video();
1338
+ var parseM3u8 = (manifestString) => {
1339
+ const parser = new m3u8Parser.Parser();
1340
+ parser.push(manifestString);
1341
+ parser.end();
1342
+ return parser.manifest;
1343
+ };
1344
+ var fetchPlaylist = async (url) => {
1345
+ const response = await fetch(url);
1346
+ if (!response.ok)
1347
+ throw new Error(`Failed to fetch playlist (${response.status}): ${url}`);
1348
+ const text = await response.text();
1349
+ return parseM3u8(text);
1350
+ };
1351
+ var parseUrl = (playlistUri, manifestUri) => {
1352
+ let value = playlistUri;
1353
+ if (!value.startsWith("https://"))
1354
+ value = new URL(value, manifestUri).toString() + new URL(manifestUri).search;
1355
+ return value;
1356
+ };
1357
+ var urlsSame = (url1, url2) => {
1358
+ return new URL(url1).pathname === new URL(url2).pathname;
1359
+ };
1360
+ var parseMediaGroup = (groups, manifestUri) => {
1361
+ const results = [];
1362
+ if (!groups) return results;
1363
+ for (const [groupId, group] of Object.entries(groups)) {
1364
+ for (const [label, entity] of Object.entries(group)) {
1365
+ const url = parseUrl(entity.uri, manifestUri);
1366
+ const existing = results.find((result) => urlsSame(result.url, url));
1367
+ if (!existing)
1368
+ results.push({
1369
+ groupId,
1370
+ id: entity.uri.replace("/", ""),
1371
+ type: groupId,
1372
+ label,
1373
+ language: entity.language,
1374
+ url,
1375
+ default: entity.default
1376
+ });
1377
+ }
1378
+ }
1379
+ return results;
1380
+ };
1381
+ var getAudioPlaylists = (m3u8, manifestUri) => {
1382
+ if (!m3u8.mediaGroups) return [];
1383
+ return parseMediaGroup(m3u8.mediaGroups.AUDIO, manifestUri);
1384
+ };
1385
+ var getSubtitlePlaylists = (m3u8, manifestUri) => {
1386
+ if (!m3u8.mediaGroups) return [];
1387
+ return parseMediaGroup(m3u8.mediaGroups.SUBTITLES, manifestUri);
1388
+ };
1389
+ var getVideoPlaylists = (m3u8, manifestUri) => {
1390
+ if (!m3u8.playlists) return [];
1391
+ return m3u8.playlists.map((data) => {
1392
+ const bandwidth = data.attributes?.BANDWIDTH;
1393
+ const url = data.resolvedUri || parseUrl(data.uri, manifestUri);
1394
+ const track = {
1395
+ id: data.uri.replace("/", ""),
1396
+ bitrate: parseBitrate(bandwidth),
1397
+ url
1398
+ };
1399
+ track.type = "video";
1400
+ if (data.attributes.RESOLUTION) {
1401
+ track.resolution = data.attributes.RESOLUTION;
1402
+ track.quality = getQualityLabel(track.resolution);
1403
+ }
1404
+ if (data.attributes["VIDEO-RANGE"])
1405
+ track.dynamicRange = data.attributes["VIDEO-RANGE"];
1406
+ if (data.attributes.CODECS) track.codecs = data.attributes.CODECS;
1407
+ if (data.attributes["FRAME-RATE"])
1408
+ track.frameRate = data.attributes["FRAME-RATE"];
1409
+ return track;
1410
+ });
1411
+ };
1412
+ var segmentsDto = (data = [], track) => {
1413
+ const mapSegment = (item) => {
1414
+ let url = item.resolvedUri || item.uri;
1415
+ if (!url.startsWith("https://") && track.url) {
1416
+ const baseUrl = dirname(track.url) + "/";
1417
+ url = new URL(url, baseUrl).toString();
1418
+ }
1419
+ return {
1420
+ url,
1421
+ duration: item.duration,
1422
+ number: item.number,
1423
+ presentationTime: item.presentationTime
1424
+ };
1425
+ };
1426
+ const segments = data.map(mapSegment);
1427
+ const init = data[0].map;
1428
+ if (data.length && (init?.resolvedUri || init?.uri)) {
1429
+ const url = init?.resolvedUri || parseUrl(init.uri, track.url);
1430
+ segments.unshift({
1431
+ url,
1432
+ init: true,
1433
+ duration: 0,
1434
+ number: 0,
1435
+ presentationTime: 0
1436
+ });
1437
+ }
1438
+ return segments;
1439
+ };
1440
+ var parseSegments = (playlist, track) => {
1441
+ track.segments = segmentsDto(playlist.segments, track);
1442
+ if (playlist.contentProtection) {
1443
+ track.protection = {};
1444
+ const fairplayLegacy = playlist.contentProtection["com.apple.fps.1_0"];
1445
+ if (fairplayLegacy)
1446
+ track.protection.fairplay = {
1447
+ keyFormat: fairplayLegacy.attributes.KEYFORMAT,
1448
+ uri: fairplayLegacy.attributes.URI,
1449
+ method: fairplayLegacy.attributes.METHOD
1450
+ };
1451
+ const widevine = playlist.contentProtection["com.widevine.alpha"];
1452
+ if (widevine) {
1453
+ track.protection.widevine = {
1454
+ pssh: widevine.pssh,
1455
+ uri: widevine.attributes.schemeIdUri,
1456
+ keyId: widevine.attributes.keyId
1457
+ };
1458
+ }
1459
+ }
1460
+ };
1461
+ var fetchTrackSegments = (tracks) => {
1462
+ return Promise.all(
1463
+ tracks.map(async (track) => {
1464
+ const playlist = await fetchPlaylist(track.url);
1465
+ parseSegments(playlist, track);
1466
+ })
1467
+ );
1468
+ };
1469
+ var parseManifest = async (manifestString, manifestUri) => {
1470
+ const m3u8 = parseM3u8(manifestString);
1471
+ const videos = getVideoPlaylists(m3u8, manifestUri);
1472
+ const audios = getAudioPlaylists(m3u8, manifestUri);
1473
+ const subtitles = getSubtitlePlaylists(m3u8, manifestUri);
1474
+ if (!m3u8.playlists && m3u8.segments) {
1475
+ const { pathname } = new URL(manifestUri);
1476
+ const isAudio = pathname.includes(".m4a") || pathname.includes(".mp3") || pathname.includes(".opus");
1477
+ if (isAudio) {
1478
+ const track = createAudioTrack({
1479
+ id: "audio" + basename(pathname),
1480
+ label: "audio",
1481
+ type: "audio",
1482
+ codec: "",
1483
+ channels: 2,
1484
+ jointObjectCoding: "",
1485
+ isDescriptive: false,
1486
+ bitrate: NaN,
1487
+ duration: NaN,
1488
+ language: ""
1489
+ });
1490
+ parseSegments(m3u8, track);
1491
+ audios.push(track);
1492
+ } else {
1493
+ const track = createVideoTrack({
1494
+ id: "video" + basename(pathname),
1495
+ label: "video",
1496
+ type: "video",
1497
+ codec: "",
1498
+ dynamicRange: "",
1499
+ contentProtection: "",
1500
+ bitrate: NaN,
1501
+ duration: NaN,
1502
+ width: NaN,
1503
+ height: NaN,
1504
+ fps: NaN,
1505
+ language: ""
1506
+ });
1507
+ parseSegments(m3u8, track);
1508
+ videos.push(track);
1509
+ }
1510
+ } else {
1511
+ await Promise.all([
1512
+ fetchTrackSegments(videos),
1513
+ fetchTrackSegments(audios),
1514
+ fetchTrackSegments(subtitles)
1515
+ ]);
1516
+ }
1517
+ const manifest = {
1518
+ tracks: {
1519
+ all: videos.concat(audios).concat(subtitles),
1520
+ videos,
1521
+ audios,
1522
+ subtitles,
1523
+ withResolution: createResolutionFilter(videos),
1524
+ withVideoCodecs: createVideoCodecFilter(videos),
1525
+ withVideoQuality: createVideoQualityFilter(videos),
1526
+ withAudioCodecs: createAudioCodecFilter(audios),
1527
+ withAudioLanguages: createAudioLanguageFilter(audios),
1528
+ withAudioChannels: createAudioChannelsFilter(audios),
1529
+ withSubtitleLanguages: createSubtitleLanguageFilter(subtitles)
1530
+ }
1531
+ };
1532
+ return manifest;
1533
+ };
1534
+ module.exports = { parseManifest };
1535
+ }
1536
+ });
1537
+
1538
+ // dasha.js
1539
+ var require_dasha = __commonJS({
1540
+ "dasha.js"(exports, module) {
1541
+ var dash = require_dash();
1542
+ var hls = require_hls();
1543
+ var {
1544
+ filterByResolution,
1545
+ filterByQuality,
1546
+ filterByCodecs,
1547
+ filterByLanguages,
1548
+ filterByChannels
1549
+ } = require_track();
1550
+ var parse = (text, url, fallbackLanguage) => {
1551
+ if (text.includes("<MPD"))
1552
+ return dash.parseManifest(text, url, fallbackLanguage);
1553
+ else if (text.includes("#EXTM3U")) return hls.parseManifest(text, url);
1554
+ else throw new Error("Invalid manifest");
1555
+ };
1556
+ module.exports = {
1557
+ parse,
1558
+ filterByResolution,
1559
+ filterByQuality,
1560
+ filterByCodecs,
1561
+ filterByLanguages,
1562
+ filterByChannels
1563
+ };
1564
+ }
1565
+ });
1566
+ export default require_dasha();