2 lines
32 KiB
JavaScript
2 lines
32 KiB
JavaScript
let t={};function e(e){if(t.strictMode)throw e;t.silent||console.error(e.message)}function s(t,...s){for(const[i,n]of s.entries())n||e(new Error(`${t} : Failed at [${i}]`))}function i(...t){for(const[s,[i,n]]of t.entries())i&&(n||e(new Error(`Conditional Assert : Failed at [${s}]`)))}function n(...t){for(const[s,i]of t.entries())void 0===i&&e(new Error(`Param Check : Failed at [${s}]`))}function a(...t){for(const[s,[i,n]]of t.entries())i&&void 0===n&&e(new Error(`Conditional Param Check : Failed at [${s}]`))}function r(t){e(new Error(`Invalid Playlist : ${t}`))}function o(t,e=10){if("number"==typeof t)return t;const s=10===e?Number.parseFloat(t):Number.parseInt(t,e);return Number.isNaN(s)?0:s}function E(t){(t.startsWith("0x")||t.startsWith("0X"))&&(t=t.slice(2));const e=new Uint8Array(t.length/2);for(let s=0;s<t.length;s+=2)e[s/2]=o(t.slice(s,s+2),16);return e}function T(t,s=0,i=t.length){i<=s&&e(new Error(`end must be larger than start : start=${s}, end=${i}`));const n=[];for(let e=s;e<i;e++)n.push(`0${(255&t[e]).toString(16).toUpperCase()}`.slice(-2));return`0x${n.join("")}`}function u(t,e,s=0){let i=-1;for(let n=0,a=0;n<t.length;n++)if(t[n]===e){if(a++===s)return[t.slice(0,n),t.slice(n+1)];i=n}return-1!==i?[t.slice(0,i),t.slice(i+1)]:[t]}function c(t){const e=[];let s=!1;for(const i of t)"-"!==i&&"_"!==i?s?(e.push(i.toUpperCase()),s=!1):e.push(i.toLowerCase()):s=!0;return e.join("")}function l(t){return`${t.getUTCFullYear()}-${("0"+(t.getUTCMonth()+1)).slice(-2)}-${("0"+t.getUTCDate()).slice(-2)}T${("0"+t.getUTCHours()).slice(-2)}:${("0"+t.getUTCMinutes()).slice(-2)}:${("0"+t.getUTCSeconds()).slice(-2)}.${("00"+t.getUTCMilliseconds()).slice(-3)}Z`}function h(e={}){t=Object.assign(t,e)}function X(){return Object.assign({},t)}class p{constructor({type:t,uri:e,groupId:s,language:a,assocLanguage:r,name:o,isDefault:E,autoselect:T,forced:u,instreamId:c,characteristics:l,channels:h}){n(t,s,o),i(["SUBTITLES"===t,e],["CLOSED-CAPTIONS"===t,c],["CLOSED-CAPTIONS"===t,!e],[u,"SUBTITLES"===t]),this.type=t,this.uri=e,this.groupId=s,this.language=a,this.assocLanguage=r,this.name=o,this.isDefault=E,this.autoselect=T,this.forced=u,this.instreamId=c,this.characteristics=l,this.channels=h}}class I{constructor({uri:t,isIFrameOnly:e=!1,bandwidth:s,averageBandwidth:i,score:a,codecs:r,resolution:o,frameRate:E,hdcpLevel:T,allowedCpc:u,videoRange:c,stableVariantId:l,programId:h,audio:X=[],video:p=[],subtitles:I=[],closedCaptions:N=[],currentRenditions:d={audio:0,video:0,subtitles:0,closedCaptions:0}}){n(t,s),this.uri=t,this.isIFrameOnly=e,this.bandwidth=s,this.averageBandwidth=i,this.score=a,this.codecs=r,this.resolution=o,this.frameRate=E,this.hdcpLevel=T,this.allowedCpc=u,this.videoRange=c,this.stableVariantId=l,this.programId=h,this.audio=X,this.video=p,this.subtitles=I,this.closedCaptions=N,this.currentRenditions=d}}class N{constructor({id:t,value:e,uri:i,language:a}){n(t,e||i),s("SessionData cannot have both value and uri, shoud be either.",!(e&&i)),this.id=t,this.value=e,this.uri=i,this.language=a}}class d{constructor({method:t,uri:e,iv:s,format:r,formatVersion:o}){n(t),a(["NONE"!==t,e]),i(["NONE"===t,!(e||s||r||o)]),this.method=t,this.uri=e,this.iv=s,this.format=r,this.formatVersion=o}}class A{constructor({hint:t=!1,uri:e,mimeType:s,byterange:i}){n(e),this.hint=t,this.uri=e,this.mimeType=s,this.byterange=i}}class S{constructor({id:t,classId:e,start:s,end:r,duration:o,plannedDuration:E,endOnNext:T,attributes:u={}}){n(t),a([!0===T,e]),i([r,s],[r,s<=r],[o,o>=0],[E,E>=0]),this.id=t,this.classId=e,this.start=s,this.end=r,this.duration=o,this.plannedDuration=E,this.endOnNext=T,this.attributes=u}}class f{constructor({type:t,duration:e,tagName:s,value:i}){n(t),a(["OUT"===t,e]),a(["RAW"===t,s]),this.type=t,this.duration=e,this.tagName=s,this.value=i}}class R{constructor(t){n(t),this.type=t}}class m extends R{constructor({isMasterPlaylist:t,uri:e,version:s,independentSegments:i=!1,start:a,source:r}){super("playlist"),n(t),this.isMasterPlaylist=t,this.uri=e,this.version=s,this.independentSegments=i,this.start=a,this.source=r}}class g extends m{constructor(t={}){super(Object.assign(Object.assign({},t),{isMasterPlaylist:!0}));const{variants:e=[],currentVariant:s,sessionDataList:i=[],sessionKeyList:n=[]}=t;this.variants=e,this.currentVariant=s,this.sessionDataList=i,this.sessionKeyList=n}}class O extends m{constructor(t={}){super(Object.assign(Object.assign({},t),{isMasterPlaylist:!1}));const{targetDuration:e,mediaSequenceBase:s=0,discontinuitySequenceBase:i=0,endlist:n=!1,playlistType:a,isIFrame:r,segments:o=[],prefetchSegments:E=[],lowLatencyCompatibility:T,partTargetDuration:u,renditionReports:c=[],skip:l=0,hash:h}=t;this.targetDuration=e,this.mediaSequenceBase=s,this.discontinuitySequenceBase=i,this.endlist=n,this.playlistType=a,this.isIFrame=r,this.segments=o,this.prefetchSegments=E,this.lowLatencyCompatibility=T,this.partTargetDuration=u,this.renditionReports=c,this.skip=l,this.hash=h}}class D extends R{constructor({uri:t,mimeType:e,data:s,duration:i,title:n,byterange:a,discontinuity:r,mediaSequenceNumber:o=0,discontinuitySequence:E=0,key:T,map:u,programDateTime:c,dateRange:l,markers:h=[],parts:X=[]}){super("segment"),this.uri=t,this.mimeType=e,this.data=s,this.duration=i,this.title=n,this.byterange=a,this.discontinuity=r,this.mediaSequenceNumber=o,this.discontinuitySequence=E,this.key=T,this.map=u,this.programDateTime=c,this.dateRange=l,this.markers=h,this.parts=X}}class P extends R{constructor({hint:t=!1,uri:e,duration:s,independent:i,byterange:a,gap:r}){super("part"),n(e),this.hint=t,this.uri=e,this.duration=s,this.independent=i,this.duration=s,this.byterange=a,this.gap=r}}class y extends R{constructor({uri:t,discontinuity:e,mediaSequenceNumber:s=0,discontinuitySequence:i=0,key:a}){super("prefetch"),n(t),this.uri=t,this.discontinuity=e,this.mediaSequenceNumber=s,this.discontinuitySequence=i,this.key=a}}class C{constructor({uri:t,lastMSN:e,lastPart:s}){n(t),this.uri=t,this.lastMSN=e,this.lastPart=s}}var U=Object.freeze({__proto__:null,Rendition:p,Variant:I,SessionData:N,Key:d,MediaInitializationSection:A,DateRange:S,SpliceInfo:f,Playlist:m,MasterPlaylist:g,MediaPlaylist:O,Segment:D,PartialSegment:P,PrefetchSegment:y,RenditionReport:C});function M(t){return function(t,e=" "){return t?(t=t.trim()," "===e||(t.startsWith(e)&&(t=t.slice(1)),t.endsWith(e)&&(t=t.slice(0,-1))),t):t}(t,'"')}function b(t){const e=u(t,",");return{duration:o(e[0]),title:decodeURIComponent(escape(e[1]))}}function L(t){const e=u(t,"@");return{length:o(e[0]),offset:e[1]?o(e[1]):-1}}function v(t){const e=u(t,"x");return{width:o(e[0]),height:o(e[1])}}function $(t){const e="ALLOWED-CPC: Each entry must consit of KEYFORMAT and Content Protection Configuration",s=t.split(",");0===s.length&&r(e);const i=[];for(const t of s){const[s,n]=u(t,":");s&&n?i.push({format:s,cpcList:n.split("/")}):r(e)}return i}function Y(t){const e=E(t);return 16!==e.length&&r("IV must be a 128-bit unsigned integer"),e}function F(t,e){e.IV&&t.compatibleVersion<2&&(t.compatibleVersion=2),(e.KEYFORMAT||e.KEYFORMATVERSIONS)&&t.compatibleVersion<5&&(t.compatibleVersion=5)}function G(t){const e={};for(const i of function(t){const e=[];let s=!0,i=0;const n=[];for(let a=0;a<t.length;a++){const r=t[a];s&&","===r?(e.push(t.slice(i,a).trim()),i=a+1):'"'!==r&&"'"!==r||(s?(n.push(r),s=!1):r===n.at(-1)?(n.pop(),s=!0):n.push(r))}return e.push(t.slice(i).trim()),e}(t)){const[t,n]=u(i,"="),a=M(n);switch(t){case"URI":e[t]=a;break;case"START-DATE":case"END-DATE":e[t]=new Date(a);break;case"IV":e[t]=Y(a);break;case"BYTERANGE":e[t]=L(a);break;case"RESOLUTION":e[t]=v(a);break;case"ALLOWED-CPC":e[t]=$(a);break;case"END-ON-NEXT":case"DEFAULT":case"AUTOSELECT":case"FORCED":case"PRECISE":case"CAN-BLOCK-RELOAD":case"INDEPENDENT":case"GAP":e[t]="YES"===a;break;case"DURATION":case"PLANNED-DURATION":case"BANDWIDTH":case"AVERAGE-BANDWIDTH":case"FRAME-RATE":case"TIME-OFFSET":case"CAN-SKIP-UNTIL":case"HOLD-BACK":case"PART-HOLD-BACK":case"PART-TARGET":case"BYTERANGE-START":case"BYTERANGE-LENGTH":case"LAST-MSN":case"LAST-PART":case"SKIPPED-SEGMENTS":case"SCORE":case"PROGRAM-ID":e[t]=o(a);break;default:t.startsWith("SCTE35-")?e[t]=E(a):t.startsWith("X-")?e[t]=(s=n).startsWith('"')?M(s):s.startsWith("0x")||s.startsWith("0X")?E(s):o(s):("VIDEO-RANGE"===t&&"SDR"!==a&&"HLG"!==a&&"PQ"!==a&&r(`VIDEO-RANGE: unknown value "${a}"`),e[t]=a)}}var s;return e}function V(){r("The file contains both media and master playlist tags.")}function w(t,e,s){const i=function({attributes:t}){return new p({type:t.TYPE,uri:t.URI,groupId:t["GROUP-ID"],language:t.LANGUAGE,assocLanguage:t["ASSOC-LANGUAGE"],name:t.NAME,isDefault:t.DEFAULT,autoselect:t.AUTOSELECT,forced:t.FORCED,instreamId:t["INSTREAM-ID"],characteristics:t.CHARACTERISTICS,channels:t.CHANNELS})}(e),n=t[c(s)],a=function(t,e){let s=!1;for(const i of t){if(i.name===e.name)return"All EXT-X-MEDIA tags in the same Group MUST have different NAME attributes.";i.isDefault&&(s=!0)}return s&&e.isDefault?"EXT-X-MEDIA A Group MUST NOT have more than one member with a DEFAULT attribute of YES.":""}(n,i);a&&r(a),n.push(i),i.isDefault&&(t.currentRenditions[c(s)]=n.length-1)}function B(t,e,s,i,n){const a=new I({uri:s,bandwidth:e.BANDWIDTH,averageBandwidth:e["AVERAGE-BANDWIDTH"],score:e.SCORE,codecs:e.CODECS,resolution:e.RESOLUTION,frameRate:e["FRAME-RATE"],hdcpLevel:e["HDCP-LEVEL"],allowedCpc:e["ALLOWED-CPC"],videoRange:e["VIDEO-RANGE"],stableVariantId:e["STABLE-VARIANT-ID"],programId:e["PROGRAM-ID"]});for(const s of t)if("EXT-X-MEDIA"===s.name){const t=s.attributes,i=t.TYPE;if(i&&t["GROUP-ID"]||r("EXT-X-MEDIA TYPE attribute is REQUIRED."),e[i]===t["GROUP-ID"]&&(w(a,s,i),"CLOSED-CAPTIONS"===i))for(const{instreamId:t}of a.closedCaptions)if(t&&t.startsWith("SERVICE")&&n.compatibleVersion<7){n.compatibleVersion=7;break}}return function(t,e,s){for(const i of["AUDIO","VIDEO","SUBTITLES","CLOSED-CAPTIONS"])"CLOSED-CAPTIONS"===i&&"NONE"===t[i]?(s.isClosedCaptionsNone=!0,e.closedCaptions=[]):t[i]&&!e[c(i)].some((e=>e.groupId===t[i]))&&r(`${i} attribute MUST match the value of the GROUP-ID attribute of an EXT-X-MEDIA tag whose TYPE attribute is ${i}.`)}(e,a,n),a.isIFrameOnly=i,a}function H(t,e){if(t.method!==e.method)return!1;if(t.uri!==e.uri)return!1;if(t.iv){if(!e.iv)return!1;if(t.iv.length!==e.iv.length)return!1;for(let s=0;s<t.iv.length;s++)if(t.iv[s]!==e.iv[s])return!1}else if(e.iv)return!1;return t.format===e.format&&t.formatVersion===e.formatVersion}function K(t,e,s,i,n,a,o){const E=new D({uri:e,mediaSequenceNumber:n,discontinuitySequence:a});let T=!1,u=!1;for(let e=s;e<=i;e++){const{name:s,value:i,attributes:n}=t[e];if("EXTINF"===s)!Number.isInteger(i.duration)&&o.compatibleVersion<3&&(o.compatibleVersion=3),Math.round(i.duration)>o.targetDuration&&r("EXTINF duration, when rounded to the nearest integer, MUST be less than or equal to the target duration"),E.duration=i.duration,E.title=i.title;else if("EXT-X-BYTERANGE"===s)o.compatibleVersion<4&&(o.compatibleVersion=4),E.byterange=i;else if("EXT-X-DISCONTINUITY"===s)E.parts.length>0&&r("EXT-X-DISCONTINUITY must appear before the first EXT-X-PART tag of the Parent Segment."),E.discontinuity=!0;else if("EXT-X-KEY"===s)E.parts.length>0&&r("EXT-X-KEY must appear before the first EXT-X-PART tag of the Parent Segment."),F(o,n),E.key=new d({method:n.METHOD,uri:n.URI,iv:n.IV,format:n.KEYFORMAT,formatVersion:n.KEYFORMATVERSIONS});else if("EXT-X-MAP"===s)E.parts.length>0&&r("EXT-X-MAP must appear before the first EXT-X-PART tag of the Parent Segment."),o.compatibleVersion<5&&(o.compatibleVersion=5),o.hasMap=!0,E.map=new A({uri:n.URI,byterange:n.BYTERANGE});else if("EXT-X-PROGRAM-DATE-TIME"===s)E.programDateTime=i;else if("EXT-X-DATERANGE"===s){const t={};for(const e of Object.keys(n))(e.startsWith("SCTE35-")||e.startsWith("X-"))&&(t[e]=n[e]);E.dateRange=new S({id:n.ID,classId:n.CLASS,start:n["START-DATE"],end:n["END-DATE"],duration:n.DURATION,plannedDuration:n["PLANNED-DURATION"],endOnNext:n["END-ON-NEXT"],attributes:t})}else if("EXT-X-CUE-OUT"===s)E.markers.push(new f({type:"OUT",duration:n&&n.DURATION||i}));else if("EXT-X-CUE-IN"===s)E.markers.push(new f({type:"IN"}));else if("EXT-X-CUE-OUT-CONT"===s||"EXT-X-CUE"===s||"EXT-OATCLS-SCTE35"===s||"EXT-X-ASSET"===s||"EXT-X-SCTE35"===s)E.markers.push(new f({type:"RAW",tagName:s,value:i}));else if("EXT-X-PRELOAD-HINT"!==s||n.TYPE)if("EXT-X-PRELOAD-HINT"===s&&"PART"===n.TYPE&&u)r("Servers should not add more than one EXT-X-PRELOAD-HINT tag with the same TYPE attribute to a Playlist.");else if("EXT-X-PART"!==s&&"EXT-X-PRELOAD-HINT"!==s||n.URI){if("EXT-X-PRELOAD-HINT"===s&&"MAP"===n.TYPE)T&&r("Servers should not add more than one EXT-X-PRELOAD-HINT tag with the same TYPE attribute to a Playlist."),T=!0,o.hasMap=!0,E.map=new A({hint:!0,uri:n.URI,byterange:{length:n["BYTERANGE-LENGTH"],offset:n["BYTERANGE-START"]||0}});else if("EXT-X-PART"===s||"EXT-X-PRELOAD-HINT"===s&&"PART"===n.TYPE){"EXT-X-PART"!==s||n.DURATION||r("EXT-X-PART: DURATION attribute is mandatory"),"EXT-X-PRELOAD-HINT"===s&&(u=!0);const t=new P({hint:"EXT-X-PRELOAD-HINT"===s,uri:n.URI,byterange:"EXT-X-PART"===s?n.BYTERANGE:{length:n["BYTERANGE-LENGTH"],offset:n["BYTERANGE-START"]||0},duration:n.DURATION,independent:n.INDEPENDENT,gap:n.GAP});E.parts.push(t)}}else r("EXT-X-PART / EXT-X-PRELOAD-HINT: URI attribute is mandatory");else r("EXT-X-PRELOAD-HINT: TYPE attribute is mandatory")}return E}function k(t,e,s,i,n,a,o){const E=new y({uri:e,mediaSequenceNumber:n,discontinuitySequence:a});for(let e=s;e<=i;e++){const{name:s,attributes:i}=t[e];"EXTINF"===s?r("A prefetch segment must not be advertised with an EXTINF tag."):"EXT-X-DISCONTINUITY"===s?r("A prefetch segment must not be advertised with an EXT-X-DISCONTINUITY tag."):"EXT-X-PREFETCH-DISCONTINUITY"===s?E.discontinuity=!0:"EXT-X-KEY"===s?(F(o,i),E.key=new d({method:i.METHOD,uri:i.URI,iv:i.IV,format:i.KEYFORMAT,formatVersion:i.KEYFORMATVERSIONS})):"EXT-X-MAP"===s&&r("Prefetch segments must not be advertised with an EXT-X-MAP tag.")}return E}function W(t,e){var s;const i=new O;let n=-1,a=0,o=!1,E=!1,T=0,u=null,c=null,l=!1;for(const[s,h]of t.entries()){const{name:X,value:p,attributes:I,category:N}=h;if("Segment"!==N){if("EXT-X-VERSION"===X)void 0===i.version?i.version=p:r("A Playlist file MUST NOT contain more than one EXT-X-VERSION tag.");else if("EXT-X-TARGETDURATION"===X)i.targetDuration=e.targetDuration=p;else if("EXT-X-MEDIA-SEQUENCE"===X)i.segments.length>0&&r("The EXT-X-MEDIA-SEQUENCE tag MUST appear before the first Media Segment in the Playlist."),i.mediaSequenceBase=a=p;else if("EXT-X-DISCONTINUITY-SEQUENCE"===X)i.segments.length>0&&r("The EXT-X-DISCONTINUITY-SEQUENCE tag MUST appear before the first Media Segment in the Playlist."),o&&r("The EXT-X-DISCONTINUITY-SEQUENCE tag MUST appear before any EXT-X-DISCONTINUITY tag."),i.discontinuitySequenceBase=T=p;else if("EXT-X-ENDLIST"===X)i.endlist=!0;else if("EXT-X-PLAYLIST-TYPE"===X)i.playlistType=p;else if("EXT-X-I-FRAMES-ONLY"===X)e.compatibleVersion<4&&(e.compatibleVersion=4),i.isIFrame=!0;else if("EXT-X-INDEPENDENT-SEGMENTS"===X)i.independentSegments&&r("EXT-X-INDEPENDENT-SEGMENTS tag MUST NOT appear more than once in a Playlist"),i.independentSegments=!0;else if("EXT-X-START"===X)i.start&&r("EXT-X-START tag MUST NOT appear more than once in a Playlist"),"number"!=typeof I["TIME-OFFSET"]&&r("EXT-X-START: TIME-OFFSET attribute is REQUIRED"),i.start={offset:I["TIME-OFFSET"],precise:I.PRECISE||!1};else if("EXT-X-SERVER-CONTROL"===X)I["CAN-BLOCK-RELOAD"]||r("EXT-X-SERVER-CONTROL: CAN-BLOCK-RELOAD=YES is mandatory for Low-Latency HLS"),i.lowLatencyCompatibility={canBlockReload:I["CAN-BLOCK-RELOAD"],canSkipUntil:I["CAN-SKIP-UNTIL"],holdBack:I["HOLD-BACK"],partHoldBack:I["PART-HOLD-BACK"]};else if("EXT-X-PART-INF"===X)I["PART-TARGET"]||r("EXT-X-PART-INF: PART-TARGET attribute is mandatory"),i.partTargetDuration=I["PART-TARGET"];else if("EXT-X-RENDITION-REPORT"===X)I.URI||r("EXT-X-RENDITION-REPORT: URI attribute is mandatory"),0===I.URI.search(/^[a-z]+:/)&&r("EXT-X-RENDITION-REPORT: URI must be relative to the playlist uri"),i.renditionReports.push(new C({uri:I.URI,lastMSN:I["LAST-MSN"],lastPart:I["LAST-PART"]}));else if("EXT-X-SKIP"===X)I["SKIPPED-SEGMENTS"]||r("EXT-X-SKIP: SKIPPED-SEGMENTS attribute is mandatory"),e.compatibleVersion<9&&(e.compatibleVersion=9),i.skip=I["SKIPPED-SEGMENTS"],a+=i.skip;else if("EXT-X-PREFETCH"===X){const r=k(t,p,-1===n?s:n,s-1,a++,T,e);r&&(r.discontinuity&&(r.discontinuitySequence++,T=r.discontinuitySequence),r.key?u=r.key:r.key=u,i.prefetchSegments.push(r)),E=!0,n=-1}else if("string"==typeof h){-1===n&&r("A URI line is not preceded by any segment tags"),i.targetDuration||r("The EXT-X-TARGETDURATION tag is REQUIRED"),E&&r("These segments must appear after all complete segments.");const o=K(t,h,n,s-1,a++,T,e);o&&([T,u,c]=q(i,o,T,u,c),!l&&o.parts.length>0&&(l=!0)),n=-1}}else-1===n&&(n=s),"EXT-X-DISCONTINUITY"===X&&(o=!0)}if(-1!==n){const o=K(t,"",n,t.length-1,a++,T,e);if(o){const{parts:t}=o;t.length>0&&!i.endlist&&!(null===(s=t.at(-1))||void 0===s?void 0:s.hint)&&r("If the Playlist contains EXT-X-PART tags and does not contain an EXT-X-ENDLIST tag, the Playlist must contain an EXT-X-PRELOAD-HINT tag with a TYPE=PART attribute"),q(i,o,u,c),!l&&o.parts.length>0&&(l=!0)}}return function(t){const e=new Map,s=new Map;let i=!1,n=!1;for(let a=t.length-1;a>=0;a--){const{programDateTime:o,dateRange:E}=t[a];if(o&&(n=!0),E&&E.start){i=!0,E.endOnNext&&(E.end||E.duration)&&r("An EXT-X-DATERANGE tag with an END-ON-NEXT=YES attribute MUST NOT contain DURATION or END-DATE attributes.");const t=E.start.getTime(),n=E.duration||0;E.end&&E.duration&&t+1e3*n!==E.end.getTime()&&r("END-DATE MUST be equal to the value of the START-DATE attribute plus the value of the DURATION"),E.endOnNext&&(E.end=e.get(E.classId)),e.set(E.classId,E.start);const a=E.end?E.end.getTime():E.start.getTime()+1e3*(E.duration||0),o=s.get(E.classId);if(o){for(const e of o)(e.start<=t&&e.end>t||e.start>=t&&e.start<a)&&r("DATERANGE tags with the same CLASS should not overlap");o.push({start:t,end:a})}else E.classId&&s.set(E.classId,[{start:t,end:a}])}}i&&!n&&r("If a Playlist contains an EXT-X-DATERANGE tag, it MUST also contain at least one EXT-X-PROGRAM-DATE-TIME tag.")}(i.segments),i.lowLatencyCompatibility&&function({lowLatencyCompatibility:t,targetDuration:e,partTargetDuration:s,segments:i,renditionReports:n},a){const{canSkipUntil:o,holdBack:E,partHoldBack:T}=t;o<6*e&&r("The Skip Boundary must be at least six times the EXT-X-TARGETDURATION.");E<3*e&&r("HOLD-BACK must be at least three times the EXT-X-TARGETDURATION.");if(a){void 0===s&&r("EXT-X-PART-INF is required if a Playlist contains one or more EXT-X-PART tags"),void 0===T&&r("EXT-X-PART: PART-HOLD-BACK attribute is mandatory"),T<s&&r("PART-HOLD-BACK must be at least PART-TARGET");for(const[t,{parts:e}]of i.entries()){e.length>0&&t<i.length-3&&r("Remove EXT-X-PART tags from the Playlist after they are greater than three target durations from the end of the Playlist.");for(const[t,{duration:i}]of e.entries())void 0!==i&&(i>s&&r("PART-TARGET is the maximum duration of any Partial Segment"),t<e.length-1&&i<.85*s&&r("All Partial Segments except the last part of a segment must have a duration of at least 85% of PART-TARGET"))}}for(const t of n){const e=i.at(-1);null!==t.lastMSN&&void 0!==t.lastMSN||(t.lastMSN=e.mediaSequenceNumber),(null===t.lastPart||void 0===t.lastPart)&&e.parts.length>0&&(t.lastPart=e.parts.length-1)}}(i,l),i}function q(t,e,s,i,n){const{discontinuity:a,key:o,map:E,byterange:T,uri:u}=e;if(a&&(e.discontinuitySequence=s+1),o||(e.key=i),E||(e.map=n),T&&-1===T.offset){const{segments:e}=t;if(e.length>0){const t=e.at(-1);t.byterange&&t.uri===u?T.offset=t.byterange.offset+t.byterange.length:r("If offset of EXT-X-BYTERANGE is not present, a previous Media Segment MUST be a sub-range of the same media resource")}else r("If offset of EXT-X-BYTERANGE is not present, a previous Media Segment MUST appear in the Playlist file")}return t.segments.push(e),[e.discontinuitySequence,e.key,e.map]}function x(t,e){const[s,i]=function(t){const e=t.indexOf(":");return-1===e?[t.slice(1).trim(),null]:[t.slice(1,e).trim(),t.slice(e+1).trim()]}(t),n=function(t){switch(t){case"EXTM3U":case"EXT-X-VERSION":return"Basic";case"EXTINF":case"EXT-X-BYTERANGE":case"EXT-X-DISCONTINUITY":case"EXT-X-PREFETCH-DISCONTINUITY":case"EXT-X-KEY":case"EXT-X-MAP":case"EXT-X-PROGRAM-DATE-TIME":case"EXT-X-DATERANGE":case"EXT-X-CUE-OUT":case"EXT-X-CUE-IN":case"EXT-X-CUE-OUT-CONT":case"EXT-X-CUE":case"EXT-OATCLS-SCTE35":case"EXT-X-ASSET":case"EXT-X-SCTE35":case"EXT-X-PART":case"EXT-X-PRELOAD-HINT":return"Segment";case"EXT-X-TARGETDURATION":case"EXT-X-MEDIA-SEQUENCE":case"EXT-X-DISCONTINUITY-SEQUENCE":case"EXT-X-ENDLIST":case"EXT-X-PLAYLIST-TYPE":case"EXT-X-I-FRAMES-ONLY":case"EXT-X-SERVER-CONTROL":case"EXT-X-PART-INF":case"EXT-X-PREFETCH":case"EXT-X-RENDITION-REPORT":case"EXT-X-SKIP":return"MediaPlaylist";case"EXT-X-MEDIA":case"EXT-X-STREAM-INF":case"EXT-X-I-FRAME-STREAM-INF":case"EXT-X-SESSION-DATA":case"EXT-X-SESSION-KEY":return"MasterPlaylist";case"EXT-X-INDEPENDENT-SEGMENTS":case"EXT-X-START":return"MediaorMasterPlaylist";default:return"Unknown"}}(s);if(function(t,e){if("Segment"===t||"MediaPlaylist"===t)return void 0===e.isMasterPlaylist?void(e.isMasterPlaylist=!1):void(e.isMasterPlaylist&&V());if("MasterPlaylist"===t){if(void 0===e.isMasterPlaylist)return void(e.isMasterPlaylist=!0);!1===e.isMasterPlaylist&&V()}}(n,e),"Unknown"===n)return null;"MediaPlaylist"===n&&"EXT-X-RENDITION-REPORT"!==s&&"EXT-X-PREFETCH"!==s&&(e.hash[s]&&r("There MUST NOT be more than one Media Playlist tag of each type in any Media Playlist"),e.hash[s]=!0);const[a,E]=function(t,e){switch(t){case"EXTM3U":case"EXT-X-DISCONTINUITY":case"EXT-X-ENDLIST":case"EXT-X-I-FRAMES-ONLY":case"EXT-X-INDEPENDENT-SEGMENTS":case"EXT-X-CUE-IN":return[null,null];case"EXT-X-VERSION":case"EXT-X-TARGETDURATION":case"EXT-X-MEDIA-SEQUENCE":case"EXT-X-DISCONTINUITY-SEQUENCE":return[o(e),null];case"EXT-X-CUE-OUT":return Number.isNaN(Number(e))?[null,G(e)]:[o(e),null];case"EXT-X-KEY":case"EXT-X-MAP":case"EXT-X-DATERANGE":case"EXT-X-MEDIA":case"EXT-X-STREAM-INF":case"EXT-X-I-FRAME-STREAM-INF":case"EXT-X-SESSION-DATA":case"EXT-X-SESSION-KEY":case"EXT-X-START":case"EXT-X-SERVER-CONTROL":case"EXT-X-PART-INF":case"EXT-X-PART":case"EXT-X-PRELOAD-HINT":case"EXT-X-RENDITION-REPORT":case"EXT-X-SKIP":return[null,G(e)];case"EXTINF":return[b(e),null];case"EXT-X-BYTERANGE":return[L(e),null];case"EXT-X-PROGRAM-DATE-TIME":return[new Date(e),null];default:return[e,null]}}(s,i);return{name:s,category:n,value:a,attributes:E}}function j(t,e){let s;return e.isMasterPlaylist?s=function(t,e){const s=new g;let i=!1;for(const[n,{name:a,value:o,attributes:E}]of t.entries())if("EXT-X-VERSION"===a)s.version=o;else if("EXT-X-STREAM-INF"===a){const a=t[n+1];("string"!=typeof a||a.startsWith("#EXT"))&&r("EXT-X-STREAM-INF must be followed by a URI line");const o=B(t,E,a,!1,e);o&&("number"==typeof o.score&&(i=!0,o.score<0&&r("SCORE attribute on EXT-X-STREAM-INF must be positive decimal-floating-point number.")),s.variants.push(o))}else if("EXT-X-I-FRAME-STREAM-INF"===a){const i=B(t,E,E.URI,!0,e);i&&s.variants.push(i)}else if("EXT-X-SESSION-DATA"===a){const t=new N({id:E["DATA-ID"],value:E.VALUE,uri:E.URI,language:E.LANGUAGE});s.sessionDataList.some((e=>e.id===t.id&&e.language===t.language))&&r("A Playlist MUST NOT contain more than one EXT-X-SESSION-DATA tag with the same DATA-ID attribute and the same LANGUAGE attribute."),s.sessionDataList.push(t)}else if("EXT-X-SESSION-KEY"===a){"NONE"===E.METHOD&&r("EXT-X-SESSION-KEY: The value of the METHOD attribute MUST NOT be NONE");const t=new d({method:E.METHOD,uri:E.URI,iv:E.IV,format:E.KEYFORMAT,formatVersion:E.KEYFORMATVERSIONS});s.sessionKeyList.some((e=>H(e,t)))&&r("A Master Playlist MUST NOT contain more than one EXT-X-SESSION-KEY tag with the same METHOD, URI, IV, KEYFORMAT, and KEYFORMATVERSIONS attribute values."),F(e,E),s.sessionKeyList.push(t)}else"EXT-X-INDEPENDENT-SEGMENTS"===a?(s.independentSegments&&r("EXT-X-INDEPENDENT-SEGMENTS tag MUST NOT appear more than once in a Playlist"),s.independentSegments=!0):"EXT-X-START"===a&&(s.start&&r("EXT-X-START tag MUST NOT appear more than once in a Playlist"),"number"!=typeof E["TIME-OFFSET"]&&r("EXT-X-START: TIME-OFFSET attribute is REQUIRED"),s.start={offset:E["TIME-OFFSET"],precise:E.PRECISE||!1});if(i)for(const t of s.variants)"number"!=typeof t.score&&r("If any Variant Stream contains the SCORE attribute, then all Variant Streams in the Master Playlist SHOULD have a SCORE attribute");if(e.isClosedCaptionsNone)for(const t of s.variants)t.closedCaptions.length>0&&r("If there is a variant with CLOSED-CAPTIONS attribute of NONE, all EXT-X-STREAM-INF tags MUST have this attribute with a value of NONE");return s}(t,e):(s=W(t,e),!s.isIFrame&&e.hasMap&&e.compatibleVersion<6&&(e.compatibleVersion=6)),e.compatibleVersion>1&&(!s.version||s.version<e.compatibleVersion)&&r(`EXT-X-VERSION needs to be ${e.compatibleVersion} or higher.`),s}function Q(t){const e={version:void 0,isMasterPlaylist:void 0,hasMap:!1,targetDuration:0,compatibleVersion:1,isClosedCaptionsNone:!1,hash:{}},s=function(t,e){const s=[];for(const i of t.split("\n")){const t=i.trim();if(t)if(t.startsWith("#")){if(t.startsWith("#EXT")){const i=x(t,e);i&&s.push(i)}}else s.push(t)}return 0!==s.length&&"EXTM3U"===s[0].name||r("The EXTM3U tag MUST be the first line."),s}(t,e),i=j(s,e);return i.source=t,i}const _=["#EXTINF","#EXT-X-BYTERANGE","#EXT-X-DISCONTINUITY","#EXT-X-STREAM-INF","#EXT-X-CUE-OUT","#EXT-X-CUE-IN","#EXT-X-KEY","#EXT-X-MAP"],z=["#EXT-X-MEDIA"];class Z extends Array{constructor(t){super(),this.baseUri=t}push(...t){for(const e of t)if(e.startsWith("#"))if(_.some((t=>e.startsWith(t))))super.push(e);else{if(this.includes(e)){if(z.some((t=>e.startsWith(t))))continue;r(`Redundant item (${e})`)}super.push(e)}else super.push(e);return this.length}}function J(t,e){let s=1e3;e&&(s=Math.pow(10,e));const i=Math.round(t*s)/s;return e?i.toFixed(e):i}function tt(t){const e=[`DATA-ID="${t.id}"`];return t.language&&e.push(`LANGUAGE="${t.language}"`),t.value?e.push(`VALUE="${t.value}"`):t.uri&&e.push(`URI="${t.uri}"`),`#EXT-X-SESSION-DATA:${e.join(",")}`}function et(t,e){const s=e?"#EXT-X-SESSION-KEY":"#EXT-X-KEY",i=[`METHOD=${t.method}`];return t.uri&&i.push(`URI="${t.uri}"`),t.iv&&(16!==t.iv.length&&r("IV must be a 128-bit unsigned integer"),i.push(`IV=${T(t.iv)}`)),t.format&&i.push(`KEYFORMAT="${t.format}"`),t.formatVersion&&i.push(`KEYFORMATVERSIONS="${t.formatVersion}"`),`${s}:${i.join(",")}`}function st(t,e){const s=e.isIFrameOnly?"#EXT-X-I-FRAME-STREAM-INF":"#EXT-X-STREAM-INF",i=[`BANDWIDTH=${e.bandwidth}`];if(e.averageBandwidth&&i.push(`AVERAGE-BANDWIDTH=${e.averageBandwidth}`),e.isIFrameOnly&&i.push(`URI="${e.uri}"`),e.codecs&&i.push(`CODECS="${e.codecs}"`),e.resolution&&i.push(`RESOLUTION=${e.resolution.width}x${e.resolution.height}`),e.frameRate&&i.push(`FRAME-RATE=${J(e.frameRate,3)}`),e.hdcpLevel&&i.push(`HDCP-LEVEL=${e.hdcpLevel}`),e.audio.length>0){i.push(`AUDIO="${e.audio[0].groupId}"`);for(const s of e.audio)t.push(it(s))}if(e.video.length>0){i.push(`VIDEO="${e.video[0].groupId}"`);for(const s of e.video)t.push(it(s))}if(e.subtitles.length>0){i.push(`SUBTITLES="${e.subtitles[0].groupId}"`);for(const s of e.subtitles)t.push(it(s))}if(X().allowClosedCaptionsNone&&0===e.closedCaptions.length)i.push("CLOSED-CAPTIONS=NONE");else if(e.closedCaptions.length>0){i.push(`CLOSED-CAPTIONS="${e.closedCaptions[0].groupId}"`);for(const s of e.closedCaptions)t.push(it(s))}if(e.score&&i.push(`SCORE=${e.score}`),e.allowedCpc){const t=[];for(const{format:s,cpcList:i}of e.allowedCpc)t.push(`${s}:${i.join("/")}`);i.push(`ALLOWED-CPC="${t.join(",")}"`)}e.videoRange&&i.push(`VIDEO-RANGE=${e.videoRange}`),e.stableVariantId&&i.push(`STABLE-VARIANT-ID="${e.stableVariantId}"`),e.programId&&i.push(`PROGRAM-ID=${e.programId}`),t.push(`${s}:${i.join(",")}`),e.isIFrameOnly||t.push(`${e.uri}`)}function it(t){const e=[`TYPE=${t.type}`,`GROUP-ID="${t.groupId}"`,`NAME="${t.name}"`];return void 0!==t.isDefault&&e.push("DEFAULT="+(t.isDefault?"YES":"NO")),void 0!==t.autoselect&&e.push("AUTOSELECT="+(t.autoselect?"YES":"NO")),void 0!==t.forced&&e.push("FORCED="+(t.forced?"YES":"NO")),t.language&&e.push(`LANGUAGE="${t.language}"`),t.assocLanguage&&e.push(`ASSOC-LANGUAGE="${t.assocLanguage}"`),t.instreamId&&e.push(`INSTREAM-ID="${t.instreamId}"`),t.characteristics&&e.push(`CHARACTERISTICS="${t.characteristics}"`),t.channels&&e.push(`CHANNELS="${t.channels}"`),t.uri&&e.push(`URI="${t.uri}"`),`#EXT-X-MEDIA:${e.join(",")}`}function nt(t,e,s,i,n=1,a=null){let r=!1,o="";if(e.discontinuity&&t.push("#EXT-X-DISCONTINUITY"),e.key){const i=et(e.key);i!==s&&(t.push(i),s=i)}if(e.map){const s=function(t){const e=[`URI="${t.uri}"`];t.byterange&&e.push(`BYTERANGE="${at(t.byterange)}"`);return`#EXT-X-MAP:${e.join(",")}`}(e.map);s!==i&&(t.push(s),i=s)}if(e.programDateTime&&t.push(`#EXT-X-PROGRAM-DATE-TIME:${l(e.programDateTime)}`),e.dateRange&&t.push(function(t){const e=[`ID="${t.id}"`];t.start&&e.push(`START-DATE="${l(t.start)}"`);t.end&&e.push(`END-DATE="${l(t.end)}"`);t.duration&&e.push(`DURATION=${t.duration}`);t.plannedDuration&&e.push(`PLANNED-DURATION=${t.plannedDuration}`);t.classId&&e.push(`CLASS="${t.classId}"`);t.endOnNext&&e.push("END-ON-NEXT=YES");for(const s of Object.keys(t.attributes))s.startsWith("X-")?"number"==typeof t.attributes[s]?e.push(`${s}=${t.attributes[s]}`):e.push(`${s}="${t.attributes[s]}"`):s.startsWith("SCTE35-")&&e.push(`${s}=${T(t.attributes[s])}`);return`#EXT-X-DATERANGE:${e.join(",")}`}(e.dateRange)),e.markers.length>0&&(o=function(t,e){let s="";for(const i of e)if("OUT"===i.type)s="OUT",t.push(`#EXT-X-CUE-OUT:DURATION=${i.duration}`);else if("IN"===i.type)s="IN",t.push("#EXT-X-CUE-IN");else if("RAW"===i.type){const e=i.value?`:${i.value}`:"";t.push(`#${i.tagName}${e}`)}return s}(t,e.markers)),e.parts.length>0&&(r=function(t,e){let s=!1;for(const i of e)if(i.hint){const e=[];if(e.push("TYPE=PART",`URI="${i.uri}"`),i.byterange){const{offset:t,length:s}=i.byterange;e.push(`BYTERANGE-START=${t}`),s&&e.push(`BYTERANGE-LENGTH=${s}`)}t.push(`#EXT-X-PRELOAD-HINT:${e.join(",")}`),s=!0}else{const e=[];e.push(`DURATION=${i.duration}`,`URI="${i.uri}"`),i.byterange&&e.push(`BYTERANGE=${at(i.byterange)}`),i.independent&&e.push("INDEPENDENT=YES"),i.gap&&e.push("GAP=YES"),t.push(`#EXT-X-PART:${e.join(",")}`)}return s}(t,e.parts)),r)return[s,i];const E=n<3?Math.round(e.duration):J(e.duration,function(t){const e=t.toString(10),s=e.indexOf(".");return-1===s?0:e.length-s-1}(e.duration));return t.push(`#EXTINF:${E},${unescape(encodeURIComponent(e.title||""))}`),e.byterange&&t.push(`#EXT-X-BYTERANGE:${at(e.byterange)}`),null!=a?Array.prototype.push.call(t,a(e)):Array.prototype.push.call(t,`${e.uri}`),[s,i,o]}function at({offset:t,length:e}){return`${e}@${t}`}function rt(t,e=null){n(t),s("Not a playlist","playlist"===t.type);const i=new Z(t.uri);return i.push("#EXTM3U"),t.version&&i.push(`#EXT-X-VERSION:${t.version}`),t.independentSegments&&i.push("#EXT-X-INDEPENDENT-SEGMENTS"),t.start&&i.push(`#EXT-X-START:TIME-OFFSET=${J(t.start.offset)}${t.start.precise?",PRECISE=YES":""}`),t.isMasterPlaylist?function(t,e){for(const s of e.sessionDataList)t.push(tt(s));for(const s of e.sessionKeyList)t.push(et(s,!0));for(const s of e.variants)st(t,s)}(i,t):function(t,e,s=null){let i="",n="",a=!1;if(e.targetDuration&&t.push(`#EXT-X-TARGETDURATION:${e.targetDuration}`),e.lowLatencyCompatibility){const{canBlockReload:s,canSkipUntil:i,holdBack:n,partHoldBack:a}=e.lowLatencyCompatibility,r=[];r.push("CAN-BLOCK-RELOAD="+(s?"YES":"NO")),void 0!==i&&r.push(`CAN-SKIP-UNTIL=${i}`),void 0!==n&&r.push(`HOLD-BACK=${n}`),void 0!==a&&r.push(`PART-HOLD-BACK=${a}`),t.push(`#EXT-X-SERVER-CONTROL:${r.join(",")}`)}e.partTargetDuration&&t.push(`#EXT-X-PART-INF:PART-TARGET=${e.partTargetDuration}`),e.mediaSequenceBase&&t.push(`#EXT-X-MEDIA-SEQUENCE:${e.mediaSequenceBase}`),e.discontinuitySequenceBase&&t.push(`#EXT-X-DISCONTINUITY-SEQUENCE:${e.discontinuitySequenceBase}`),e.playlistType&&t.push(`#EXT-X-PLAYLIST-TYPE:${e.playlistType}`),e.isIFrame&&t.push("#EXT-X-I-FRAMES-ONLY"),e.skip>0&&t.push(`#EXT-X-SKIP:SKIPPED-SEGMENTS=${e.skip}`);for(const r of e.segments){let o="";[i,n,o]=nt(t,r,i,n,e.version,s),"OUT"===o?a=!0:"IN"===o&&a&&(a=!1)}"VOD"===e.playlistType&&a&&t.push("#EXT-X-CUE-IN"),e.prefetchSegments.length>2&&r("The server must deliver no more than two prefetch segments");for(const s of e.prefetchSegments)s.discontinuity&&t.push("#EXT-X-PREFETCH-DISCONTINUITY"),t.push(`#EXT-X-PREFETCH:${s.uri}`);e.endlist&&t.push("#EXT-X-ENDLIST");for(const s of e.renditionReports){const e=[];e.push(`URI="${s.uri}"`,`LAST-MSN=${s.lastMSN}`),void 0!==s.lastPart&&e.push(`LAST-PART=${s.lastPart}`),t.push(`#EXT-X-RENDITION-REPORT:${e.join(",")}`)}}(i,t,e),i.join("\n")}export{X as getOptions,Q as parse,h as setOptions,rt as stringify,U as types};
|