dasha 3.0.5 → 3.1.0

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.
package/README.md CHANGED
@@ -18,7 +18,8 @@ npm i dasha
18
18
  import fs from 'node:fs/promises';
19
19
  import { parse } from 'dasha';
20
20
 
21
- const url = 'https://dash.akamaized.net/dash264/TestCases/1a/sony/SNE_DASH_SD_CASE1A_REVISED.mpd';
21
+ const url =
22
+ 'https://dash.akamaized.net/dash264/TestCases/1a/sony/SNE_DASH_SD_CASE1A_REVISED.mpd';
22
23
  const body = await fetch(url).then((res) => res.text());
23
24
  const manifest = await parse(body, url);
24
25
 
package/dist/dasha.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";var R=(e,r)=>()=>(r||e((r={exports:{}}).exports,r),r.exports);var ee=R((Tr,Z)=>{"use strict";function we(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 _=b.trim();_.length>0&&f.push(_)}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 U=`\r
6
+ >/= `;function V(){for(var g=t;U.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 _=t+1;t=e.indexOf("</script>",t),A=[e.slice(_,t)],t+=9}else if(g=="style"){let _=t+1;t=e.indexOf("</style>",t),A=[e.slice(_,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=W(y,r.filter)),r.setPos&&(y.pos=t),y}function W(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=W(i.children,r,t+1,(s?s+".":"")+o+"."+i.tagName);n=n.concat(a)}}),n}Z.exports={parse:we,filter:W}});var D=R((yr,ne)=>{"use strict";var te=(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]},Te=(e,r)=>({b:e*r,kb:e/1e3*r,mb:e/8e6*r,gb:e/8e9*r,toString(){return te(e*r)}}),ye=e=>({bps:e,kbps:e/1e3,mbps:e/8e6,gbps:e/8e9,toString(){return te(e,["bps","Kbps","Mbps","Gbps"])}}),re=[{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}],Ne=e=>re.find(r=>r.height===e)?.width,se=e=>re.find(r=>r.width===e)?.height,Be=e=>`${se(e.width)||e.height}p`,Ue=e=>{let r=Math.max(...e.map(t=>t.bitrate.bps));return e.find(t=>t.bitrate.bps===r)},_e=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)},Re=e=>{try{return Intl.getCanonicalLocales(e),!0}catch{return}};ne.exports={parseSize:Te,parseBitrate:ye,getWidth:Ne,getHeight:se,getQualityLabel:Be,getBestTrack:Ue,parseDuration:_e,isLanguageTagValid:Re}});var Y=R((Nr,ie)=>{"use strict";var{parseBitrate:Ee,getQualityLabel:Le,parseSize:Ie}=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},De={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},Fe=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`)},Me=(e,r,t)=>(r==5&&(r=q.BT_601),e==Q.Unspecified&&r==q.Unspecified&&t==De.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),Oe=({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=Ee(Number(o)),C=Number(c),S=Number(l),v=a?Ie(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:Le({width:C,height:S}),toString(){return["VIDEO",`[${s}, ${n}]`,d,`${c}x${l} @ ${p.kbps} kb/s, ${h} FPS`].join(" | ")}}},Pe=e=>{for(let r of e.toLowerCase().split(",")){let t=r.trim().split(".")[0];try{return Fe(t)}catch{continue}}throw new Error(`No MIME types matched any supported Video Codecs in ${e}`)},ke=(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 Me(l,h,d)};ie.exports={parseVideoCodec:Pe,parseDynamicRange:ke,createVideoTrack:Oe,VIDEO_CODECS:F}});var k=R((Br,de)=>{"use strict";var{getBestTrack:oe}=D(),Ve=e=>e.toLowerCase().split(",").map(r=>r.trim().split(".")[0]),ae=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},$e=e=>z(e),ce=e=>r=>{if(!r)return[oe(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:[oe(e)]},Ge=e=>z(e),ue=e=>(r=[],t)=>{if(!r.length)for(let o of e)r.includes(o.language)||r.push(o.language);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},le=e=>r=>{if(!r)return e;let t=typeof r=="string"?parseFloat(r):r;return e.filter(s=>s.channels===t)},qe=e=>r=>r.length?e.filter(t=>r.some(s=>t.language?.startsWith(s)||t.label?.startsWith(s))):e,He=(e,r)=>ae(e)(r),We=(e,r)=>ce(e)(r),Qe=(e,r)=>z(e)(r),Ye=(e,r,t)=>ue(e)(r,t),ze=(e,r)=>le(e)(r);de.exports={parseMimes:Ve,createResolutionFilter:ae,createVideoCodecFilter:$e,createVideoQualityFilter:ce,createAudioCodecFilter:Ge,createAudioLanguageFilter:ue,createAudioChannelsFilter:le,createSubtitleLanguageFilter:qe,filterByResolution:He,filterByQuality:We,filterByCodecs:Qe,filterByLanguages:Ye,filterByChannels:ze}});var j=R((Ur,pe)=>{"use strict";var{parseMimes:je}=k(),{parseBitrate:Ke,parseSize:Xe}=D(),E={AAC:"AAC",AC3:"DD",EC3:"DD+",OPUS:"OPUS",OGG:"VORB",DTS:"DTS",ALAC:"ALAC",FLAC:"FLAC"},xe=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`)}},Je=e=>{let r=je(e);for(let t of r)try{return xe(t)}catch{continue}throw new Error(`No MIME types matched any supported Audio Codecs in ${e}`)},Ze=(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)},et=(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},tt=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)},rt=({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=Ke(Number(i)),u=tt(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(" | ")}}};pe.exports={AUDIO_CODECS:E,parseAudioCodec:Je,createAudioTrack:rt,getDolbyDigitalPlusComplexityIndex:Ze,checkIsDescriptive:et}});var ge=R((_r,he)=>{"use strict";var{parseMimes:st}=k(),{parseBitrate:nt,parseSize:it}=D(),M={SubRip:"SRT",SubStationAlpha:"SSA",SubStationAlphav4:"ASS",TimedTextMarkupLang:"TTML",WebVTT:"VTT",fTTML:"STPP",fVTT:"WVTT"},ot=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`)}},at=e=>{let r=st(e);for(let t of r)try{return ot(t)}catch{continue}throw new Error(`No MIME types matched any supported Subtitle Codecs in ${e}`)},ct=(e=[])=>{for(let r of e)if(r.attributes.schemeIdUri==="urn:mpeg:dash:role:2011"&&r.attributes.value==="caption")return!0;return!1},ut=(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},lt=(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},dt=({id:e,label:r,bitrate:t,duration:s,type:n,codec:i,isClosedCaption:o,isSdh:a,isForced:c,language:l,segments:h})=>{let d=nt(Number(t)),u=s?it(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(" | ")}}};he.exports={parseSubtitleCodec:at,checkIsClosedCaption:ct,checkIsSdh:ut,checkIsForced:lt,createSubtitleTrack:dt}});var me=R((Rr,fe)=>{"use strict";var pt=ee(),{parseDuration:ht,isLanguageTagValid:gt}=D(),{parseVideoCodec:ft,parseDynamicRange:mt,createVideoTrack:Ct}=Y(),{parseAudioCodec:bt,createAudioTrack:St,getDolbyDigitalPlusComplexityIndex:vt,checkIsDescriptive:At}=j(),{parseSubtitleCodec:wt,checkIsClosedCaption:Tt,checkIsSdh:yt,checkIsForced:Nt,createSubtitleTrack:Bt}=ge(),{createResolutionFilter:Ut,createVideoQualityFilter:_t,createAudioLanguageFilter:Rt,createSubtitleLanguageFilter:Et,createVideoCodecFilter:Lt,createAudioCodecFilter:It,createAudioChannelsFilter:Dt}=k(),H=e=>e&&(Array.isArray(e)?e.get=r=>H(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]:H(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(H),e.getBaseUrls=()=>e.getAll("BaseURL").map(r=>r.children[0]),e.getBaseUrl=()=>e.getBaseUrls()[0]),e),Ft=(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}},Mt=(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()},Ot=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}},Pt=(e,r,t)=>r==="text"&&!t.includes("mp4")?t.split("/")[1]:e.get("codecs"),kt=(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();!gt(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},Vt=(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)}}},$t=(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},Gt=(e,r,t,s,n)=>{let i=Number(e.get("startNumber")||1),o=e.get("SegmentTimeline");Vt(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(...$t(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},qt=(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},Ht=async(e,r)=>{let t=e.get("Initialization");return{url:r,range:""}},Wt=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()}},Qt={"urn:mpeg:dash:mp4protection:2011":"common","urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95":"playready","urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed":"widevine"},Yt=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[Qt[s]]=a}return r},zt=async(e,r,t)=>{let s=H(pt.parse(e)).get("MPD"),n=s.get("Period"),i=n.get("duration")||s.get("mediaPresentationDuration"),o=ht(i),a=[],c=[],l=[];for(let h of n.getAll("AdaptationSet"))for(let d of h.getAll("Representation")){let{get:u,getAll:p}=Ft(d,h),{contentType:C,mimeType:S}=Ot(d),v=Pt(d,C,S),O=kt(d,h,t),U=Mt(r,s,n,d),V=u("SegmentTemplate"),G=u("SegmentList"),L=u("SegmentBase"),T=[];if(V){let w=Gt(V,U,r,o,d);T.push(...w)}else if(G){let w=qt(G,U);T.push(...w)}else if(L){let w=await Ht(L,U);T.push(w)}else if(U)T.push({url:U});else throw new Error("Could not find a way to get segments from this MPD manifest.");Wt(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"),_=p("ContentProtection"),b=[new URL(U).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=Ct({id:b,label:$,type:C,codec:ft(v),dynamicRange:mt(v,B,I),contentProtection:Yt(_),bitrate:A,duration:o,width:g,height:f,fps:y,language:O,segments:T});a.push(w);break}case"audio":{let w=St({id:b,label:$,type:C,codec:bt(v),channels:u("AudioChannelConfiguration")?.get("value"),jointObjectCoding:vt(B),isDescriptive:At(m),bitrate:A,duration:o,language:O,segments:T});c.push(w);break}case"text":{let w=Bt({id:b,label:$,type:C,codec:wt(v||"vtt"),isClosedCaption:Tt(N),isSdh:yt(m),isForced:Nt(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:Ut(a),withVideoCodecs:Lt(a),withVideoQuality:_t(a),withAudioCodecs:It(c),withAudioLanguages:Rt(c),withAudioChannels:Dt(c),withSubtitleLanguages:Et(l)}}};fe.exports={parseManifest:zt}});var Ae=R((Er,ve)=>{"use strict";var{dirname:jt,basename:Ce}=require("path"),Kt=require("m3u8-parser"),{parseBitrate:Xt,getQualityLabel:xt}=D(),{createResolutionFilter:Jt,createVideoQualityFilter:Zt,createAudioLanguageFilter:er,createSubtitleLanguageFilter:tr,createVideoCodecFilter:rr,createAudioCodecFilter:sr,createAudioChannelsFilter:nr}=k(),{createAudioTrack:ir}=j(),{createVideoTrack:or}=Y(),be=e=>{let r=new Kt.Parser;return r.push(e),r.end(),r.manifest},ar=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 be(t)},J=(e,r)=>{let t=e;return t.startsWith("https://")||(t=new URL(t,r).toString()+new URL(r).search),t},cr=(e,r)=>new URL(e).pathname===new URL(r).pathname,Se=(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=J(o.uri,r);t.find(l=>cr(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},ur=(e,r)=>e.mediaGroups?Se(e.mediaGroups.AUDIO,r):[],lr=(e,r)=>e.mediaGroups?Se(e.mediaGroups.SUBTITLES,r):[],dr=(e,r)=>e.playlists?e.playlists.map(t=>{let s=t.attributes?.BANDWIDTH,n=t.resolvedUri||J(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=xt(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}):[],pr=(e=[],r)=>{let t=i=>{let o=i.resolvedUri||i.uri;if(!o.startsWith("https://")&&r.url){let a=jt(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||J(n.uri,r.url);s.unshift({url:i,init:!0,duration:0,number:0,presentationTime:0})}return s},x=(e,r)=>{if(r.segments=pr(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 ar(r.url);x(t,r)})),hr=async(e,r)=>{let t=be(e),s=dr(t,r),n=ur(t,r),i=lr(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=ir({id:"audio"+Ce(a),label:"audio",type:"audio",codec:"",channels:2,jointObjectCoding:"",isDescriptive:!1,bitrate:NaN,duration:NaN,language:""});x(t,l),n.push(l)}else{let l=or({id:"video"+Ce(a),label:"video",type:"video",codec:"",dynamicRange:"",contentProtection:"",bitrate:NaN,duration:NaN,width:NaN,height:NaN,fps:NaN,language:""});x(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:Jt(s),withVideoCodecs:rr(s),withVideoQuality:Zt(s),withAudioCodecs:sr(n),withAudioLanguages:er(n),withAudioChannels:nr(n),withSubtitleLanguages:tr(i)}}};ve.exports={parseManifest:hr}});var gr=me(),fr=Ae(),{filterByResolution:mr,filterByQuality:Cr,filterByCodecs:br,filterByLanguages:Sr,filterByChannels:vr}=k(),Ar=(e,r,t)=>{if(e.includes("<MPD"))return gr.parseManifest(e,r,t);if(e.includes("#EXTM3U"))return fr.parseManifest(e,r);throw new Error("Invalid manifest")};module.exports={parse:Ar,filterByResolution:mr,filterByQuality:Cr,filterByCodecs:br,filterByLanguages:Sr,filterByChannels:vr};
package/dist/dasha.mjs ADDED
@@ -0,0 +1,6 @@
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=W(y,r.filter)),r.setPos&&(y.pos=t),y}function W(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=W(i.children,r,t+1,(s?s+".":"")+o+"."+i.tagName);n=n.concat(a)}}),n}ee.exports={parse:ye,filter:W}});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)]},He=e=>z(e),le=e=>(r=[],t)=>{if(!r.length)for(let o of e)r.includes(o.language)||r.push(o.language);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)},We=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:He,createAudioLanguageFilter:le,createAudioChannelsFilter:de,createSubtitleLanguageFilter:We,filterByResolution:Qe,filterByQuality:Ye,filterByCodecs:ze,filterByLanguages:je,filterByChannels:Ke}});var j=U((Er,he)=>{"use strict";var{parseMimes:Xe}=k(),{parseBitrate:xe,parseSize:Je}=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=xe(Number(i)),u=st(n),p=o?Je(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(),H=e=>e&&(Array.isArray(e)?e.get=r=>H(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]:H(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(H),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},Ht=(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},Wt=(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=H(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=Ht(V,_,r,o,d);T.push(...w)}else if(G){let w=Wt(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"),xt=Z("m3u8-parser"),{parseBitrate:Jt,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 xt.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)},J=(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=J(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||J(t.uri,r),i={id:t.uri.replace("/",""),bitrate:Jt(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||J(n.uri,r.url);s.unshift({url:i,init:!0,duration:0,number:0,presentationTime:0})}return s},x=(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);x(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:""});x(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:""});x(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();
package/package.json CHANGED
@@ -1,9 +1,23 @@
1
1
  {
2
2
  "name": "dasha",
3
- "version": "3.0.5",
4
- "author": "Vitaly Gashkov <vitalygashkov@vk.com>",
3
+ "version": "3.1.0",
5
4
  "description": "Streaming manifest parser",
6
- "license": "AGPL-3.0",
5
+ "files": [
6
+ "dist",
7
+ "types"
8
+ ],
9
+ "scripts": {
10
+ "test": "npm run lint && npm run types && node --test",
11
+ "types": "tsc -p tsconfig.json",
12
+ "lint": "eslint . && prettier --check .",
13
+ "fix": "eslint . --fix && prettier --write .",
14
+ "build": "tsup dasha.js --format esm,cjs --minify",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/vitalygashkov/dasha"
20
+ },
7
21
  "keywords": [
8
22
  "mpeg",
9
23
  "dash",
@@ -14,48 +28,50 @@
14
28
  "manifest",
15
29
  "playlist"
16
30
  ],
31
+ "author": "Vitaly Gashkov <vitalygashkov@vk.com>",
32
+ "license": "MIT",
17
33
  "readmeFilename": "README.md",
18
- "repository": {
19
- "type": "git",
20
- "url": "https://github.com/vitalygashkov/dasha"
21
- },
22
34
  "bugs": {
23
35
  "url": "https://github.com/vitalygashkov/dasha/issues",
24
36
  "email": "vitalygashkov@vk.com"
25
37
  },
26
- "main": "dasha.js",
27
- "types": "types/dasha.d.ts",
28
38
  "funding": [
29
39
  {
30
40
  "type": "individual",
31
- "url": "https://boosty.to/vitalygashkov/donate"
41
+ "url": "https://boosty.to/vitalygashkov"
42
+ },
43
+ {
44
+ "type": "patreon",
45
+ "url": "https://www.patreon.com/vitalygashkov"
32
46
  }
33
47
  ],
34
- "files": [
35
- "lib",
36
- "types"
37
- ],
38
- "scripts": {
39
- "test": "node --test",
40
- "types": "tsc -p tsconfig.json",
41
- "lint": "eslint \"**/*.js\" --fix",
42
- "lint:check": "eslint \"**/*.js\"",
43
- "format": "prettier --loglevel warn --write \"**/*.{ts,js,json,yaml}\"",
44
- "format:check": "prettier --loglevel warn --check \"**/*.{ts,js,json,yaml}\"",
45
- "build": "tsup ./dasha.js --format cjs",
46
- "build:bun": "bun build ./dasha.js --outdir ./dist --format cjs"
48
+ "exports": {
49
+ ".": {
50
+ "require": {
51
+ "types": "./types/dasha.d.ts",
52
+ "default": "./dist/dasha.js"
53
+ },
54
+ "import": {
55
+ "types": "./types/dasha.d.ts",
56
+ "default": "./dist/dasha.mjs"
57
+ }
58
+ }
59
+ },
60
+ "engines": {
61
+ "node": "20 || 21 || 22"
47
62
  },
48
63
  "dependencies": {
49
64
  "m3u8-parser": "^7.2.0"
50
65
  },
51
66
  "devDependencies": {
52
- "@types/node": "^22.5.5",
53
- "eslint": "^8.57.0",
67
+ "@eslint/js": "^9.13.0",
68
+ "@types/node": "^22.7.9",
69
+ "eslint": "^9.13.0",
54
70
  "eslint-config-prettier": "^9.1.0",
55
- "eslint-plugin-import-x": "^4.2.1",
56
71
  "eslint-plugin-prettier": "^5.2.1",
72
+ "globals": "^15.11.0",
57
73
  "prettier": "^3.3.3",
58
- "tsup": "^8.2.4",
59
- "typescript": "^5.6.2"
74
+ "tsup": "^8.3.0",
75
+ "typescript": "^5.6.3"
60
76
  }
61
77
  }
package/types/dasha.d.ts CHANGED
@@ -1,4 +1,8 @@
1
- export function parse(text: string, url?: string, fallbackLanguage?: string): Promise<Manifest>;
1
+ export function parse(
2
+ text: string,
3
+ url?: string,
4
+ fallbackLanguage?: string,
5
+ ): Promise<Manifest>;
2
6
 
3
7
  export interface Manifest {
4
8
  duration?: number;
@@ -7,25 +11,46 @@ export interface Manifest {
7
11
  videos: VideoTrack[];
8
12
  audios: AudioTrack[];
9
13
  subtitles: SubtitleTrack[];
10
- withResolution(resolution: { width?: string; height?: string }): VideoTrack[];
14
+ withResolution(resolution: {
15
+ width?: string;
16
+ height?: string;
17
+ }): VideoTrack[];
11
18
  withVideoCodecs(codecs: VideoCodec[]): VideoTrack[];
12
19
  withVideoQuality(quality: number | string): VideoTrack[];
13
20
  withAudioCodecs(codecs: AudioCodec[]): AudioTrack[];
14
- withAudioLanguages(languages: string[], maxTracksPerLanguage?: number): AudioTrack[];
21
+ withAudioLanguages(
22
+ languages: string[],
23
+ maxTracksPerLanguage?: number,
24
+ ): AudioTrack[];
15
25
  withSubtitleLanguages(languages: string[]): SubtitleTrack[];
16
26
  };
17
27
  }
18
28
 
19
- export function filterByResolution(resolution: { width?: string; height?: string }): VideoTrack[];
20
- export function filterByCodecs(tracks: VideoTrack[], codecs: VideoCodec[]): VideoTrack[];
21
- export function filterByCodecs(tracks: AudioTrack[], codecs: AudioCodec[]): AudioTrack[];
22
- export function filterByQuality(tracks: VideoTrack[], quality: number | string): VideoTrack[];
29
+ export function filterByResolution(resolution: {
30
+ width?: string;
31
+ height?: string;
32
+ }): VideoTrack[];
33
+ export function filterByCodecs(
34
+ tracks: VideoTrack[],
35
+ codecs: VideoCodec[],
36
+ ): VideoTrack[];
37
+ export function filterByCodecs(
38
+ tracks: AudioTrack[],
39
+ codecs: AudioCodec[],
40
+ ): AudioTrack[];
41
+ export function filterByQuality(
42
+ tracks: VideoTrack[],
43
+ quality: number | string,
44
+ ): VideoTrack[];
23
45
  export function filterByLanguages(
24
46
  tracks: AudioTrack[],
25
47
  languages: string[],
26
- maxTracksPerLanguage?: number
48
+ maxTracksPerLanguage?: number,
49
+ ): AudioTrack[];
50
+ export function filterByChannels(
51
+ tracks: AudioTrack[],
52
+ channels: number | string,
27
53
  ): AudioTrack[];
28
- export function filterByChannels(tracks: AudioTrack[], channels: number | string): AudioTrack[];
29
54
 
30
55
  export interface Track {
31
56
  id: string;
@@ -78,13 +103,30 @@ export interface VideoTrack extends Track {
78
103
  bitrate: Bitrate;
79
104
  width: number;
80
105
  height: number;
81
- quality: '144p' | '240p' | '360p' | '480p' | '720p' | '1080p' | '2160p' | '4320p' | string;
106
+ quality:
107
+ | '144p'
108
+ | '240p'
109
+ | '360p'
110
+ | '480p'
111
+ | '720p'
112
+ | '1080p'
113
+ | '2160p'
114
+ | '4320p'
115
+ | string;
82
116
  dynamicRange: DynamicRange;
83
117
  fps?: string;
84
118
  language?: string;
85
119
  }
86
120
 
87
- export type AudioCodec = 'AAC' | 'DD' | 'DD+' | 'OPUS' | 'VORB' | 'DTS' | 'ALAC' | 'FLAC';
121
+ export type AudioCodec =
122
+ | 'AAC'
123
+ | 'DD'
124
+ | 'DD+'
125
+ | 'OPUS'
126
+ | 'VORB'
127
+ | 'DTS'
128
+ | 'ALAC'
129
+ | 'FLAC';
88
130
 
89
131
  export interface AudioTrack extends Track {
90
132
  type: 'audio';
@@ -96,7 +138,15 @@ export interface AudioTrack extends Track {
96
138
  isDescriptive?: boolean;
97
139
  }
98
140
 
99
- export type SubtitleCodec = 'SRT' | 'SSA' | 'ASS' | 'TTML' | 'VTT' | 'STPP' | 'fTTML' | 'fVTT';
141
+ export type SubtitleCodec =
142
+ | 'SRT'
143
+ | 'SSA'
144
+ | 'ASS'
145
+ | 'TTML'
146
+ | 'VTT'
147
+ | 'STPP'
148
+ | 'fTTML'
149
+ | 'fVTT';
100
150
 
101
151
  export interface SubtitleTrack extends Track {
102
152
  type: 'text';
package/dasha.js DELETED
@@ -1,26 +0,0 @@
1
- 'use strict';
2
-
3
- const dash = require('./lib/dash');
4
- const hls = require('./lib/hls');
5
- const {
6
- filterByResolution,
7
- filterByQuality,
8
- filterByCodecs,
9
- filterByLanguages,
10
- filterByChannels,
11
- } = require('./lib/track');
12
-
13
- const parse = (text, url, fallbackLanguage) => {
14
- if (text.includes('<MPD')) return dash.parseManifest(text, url, fallbackLanguage);
15
- else if (text.includes('#EXTM3U')) return hls.parseManifest(text, url);
16
- else throw new Error('Invalid manifest');
17
- };
18
-
19
- module.exports = {
20
- parse,
21
- filterByResolution,
22
- filterByQuality,
23
- filterByCodecs,
24
- filterByLanguages,
25
- filterByChannels,
26
- };
package/lib/audio.js DELETED
@@ -1,128 +0,0 @@
1
- 'use strict';
2
-
3
- const { parseMimes } = require('./track');
4
- const { parseBitrate, parseSize } = require('./util');
5
-
6
- const AUDIO_CODECS = {
7
- AAC: 'AAC', // https://wikipedia.org/wiki/Advanced_Audio_Coding
8
- AC3: 'DD', // https://wikipedia.org/wiki/Dolby_Digital
9
- EC3: 'DD+', // https://wikipedia.org/wiki/Dolby_Digital_Plus
10
- OPUS: 'OPUS', // https://wikipedia.org/wiki/Opus_(audio_format)
11
- OGG: 'VORB', // https://wikipedia.org/wiki/Vorbis
12
- DTS: 'DTS', // https://en.wikipedia.org/wiki/DTS_(company)#DTS_Digital_Surround
13
- ALAC: 'ALAC', // https://en.wikipedia.org/wiki/Apple_Lossless_Audio_Codec
14
- FLAC: 'FLAC', // https://en.wikipedia.org/wiki/FLAC
15
- };
16
-
17
- const parseAudioCodecFromMime = (mime) => {
18
- const target = mime.toLowerCase().trim().split('.')[0];
19
- switch (target) {
20
- case 'mp4a':
21
- return AUDIO_CODECS.AAC;
22
- case 'ac-3':
23
- return AUDIO_CODECS.AC3;
24
- case 'ec-3':
25
- return AUDIO_CODECS.EC3;
26
- case 'opus':
27
- return AUDIO_CODECS.OPUS;
28
- case 'dtsc':
29
- return AUDIO_CODECS.DTS;
30
- case 'alac':
31
- return AUDIO_CODECS.ALAC;
32
- case 'flac':
33
- return AUDIO_CODECS.FLAC;
34
- default:
35
- throw new Error(`The MIME ${mime} is not supported as audio codec`);
36
- }
37
- };
38
-
39
- const parseAudioCodec = (codecs) => {
40
- const mimes = parseMimes(codecs);
41
- for (const mime of mimes) {
42
- try {
43
- return parseAudioCodecFromMime(mime);
44
- } catch (e) {
45
- continue;
46
- }
47
- }
48
- throw new Error(`No MIME types matched any supported Audio Codecs in ${codecs}`);
49
- };
50
-
51
- // https://professionalsupport.dolby.com/s/article/What-is-Dolby-Digital-Plus-JOC-Joint-Object-Coding?language=en_US
52
- const getDolbyDigitalPlusComplexityIndex = (supplementalProps = []) => {
53
- const targetScheme = 'tag:dolby.com,2018:dash:EC3_ExtensionComplexityIndex:2018';
54
- for (const prop of supplementalProps)
55
- if (prop.attributes.schemeIdUri === targetScheme) return parseInt(prop.attributes.value);
56
- };
57
-
58
- const checkIsDescriptive = (accessibilities = []) => {
59
- for (const accessibility of accessibilities) {
60
- const { schemeIdUri, value } = accessibility.attributes;
61
- const firstMatch = schemeIdUri == 'urn:mpeg:dash:role:2011' && value === 'descriptive';
62
- const secondMatch = schemeIdUri == 'urn:tva:metadata:cs:AudioPurposeCS:2007' && value === '1';
63
- const isDescriptive = firstMatch || secondMatch;
64
- if (isDescriptive) return true;
65
- }
66
- return false;
67
- };
68
-
69
- const parseChannels = (channels) => {
70
- const isDigit = (char) => char >= '0' && char <= '9';
71
- if (typeof channels === 'string') {
72
- if (channels.toUpperCase() == 'A000') return 2.0;
73
- else if (channels.toUpperCase() == 'F801') return 5.1;
74
- else if (isDigit(channels.replace('ch', '').replace('.', '')[0]))
75
- // e.g., '2ch', '2', '2.0', '5.1ch', '5.1'
76
- return parseFloat(channels.replace('ch', ''));
77
- throw new Error(`Unsupported audio channels value, '${channels}'`);
78
- }
79
- return parseFloat(channels);
80
- };
81
-
82
- const createAudioTrack = ({
83
- id,
84
- label,
85
- type,
86
- codec,
87
- channels,
88
- bitrate,
89
- duration,
90
- jointObjectCoding = 0,
91
- isDescriptive = false,
92
- language,
93
- segments,
94
- }) => {
95
- const parsedBitrate = parseBitrate(Number(bitrate));
96
- const parsedChannels = parseChannels(channels);
97
- const size = duration ? parseSize(Number(bitrate), Number(duration)) : undefined;
98
- return {
99
- id,
100
- label,
101
- type,
102
- codec,
103
- bitrate: parsedBitrate,
104
- size,
105
- language,
106
- segments,
107
- channels: parsedChannels,
108
- jointObjectCoding,
109
- isDescriptive,
110
- toString() {
111
- return [
112
- 'AUDIO',
113
- `[${codec}]`,
114
- `${parsedChannels || '?'}` + (jointObjectCoding ? ` (JOC ${jointObjectCoding})` : ''),
115
- `${parsedBitrate.kbps} kb/s`,
116
- language,
117
- ].join(' | ');
118
- },
119
- };
120
- };
121
-
122
- module.exports = {
123
- AUDIO_CODECS,
124
- parseAudioCodec,
125
- createAudioTrack,
126
- getDolbyDigitalPlusComplexityIndex,
127
- checkIsDescriptive,
128
- };