11import { assert } from "shared/assert" ;
22import { lexicalParse } from "./lexical-parse" ;
3- import type { Media , StreamInf , Tag } from "./lexical-parse" ;
3+ import type { Tag } from "./lexical-parse" ;
44import type {
55 DateRange ,
66 MasterPlaylist ,
@@ -13,14 +13,52 @@ import type {
1313} from "./types" ;
1414import type { DateTime } from "luxon" ;
1515
16+ function formatMasterPlaylist ( tags : Tag [ ] ) : MasterPlaylist {
17+ let independentSegments = false ;
18+ const variants : Variant [ ] = [ ] ;
19+ const renditions : Rendition [ ] = [ ] ;
20+
21+ tags . forEach ( ( [ name , value ] , index ) => {
22+ if ( name === "EXT-X-INDEPENDENT-SEGMENTS" ) {
23+ independentSegments = true ;
24+ }
25+ if ( name === "EXT-X-MEDIA" ) {
26+ renditions . push ( {
27+ type : value . type ,
28+ groupId : value . groupId ,
29+ name : value . name ,
30+ uri : value . uri ,
31+ channels : value . channels ,
32+ language : value . language ,
33+ } ) ;
34+ }
35+ if ( name === "EXT-X-STREAM-INF" ) {
36+ const uri = nextLiteral ( tags , index ) ;
37+ variants . push ( {
38+ uri,
39+ bandwidth : value . bandwidth ,
40+ resolution : value . resolution ,
41+ codecs : value . codecs ,
42+ audio : value . audio ,
43+ subtitles : value . subtitles ,
44+ } ) ;
45+ }
46+ } ) ;
47+
48+ return {
49+ independentSegments,
50+ variants,
51+ renditions,
52+ } ;
53+ }
54+
1655function formatMediaPlaylist ( tags : Tag [ ] ) : MediaPlaylist {
1756 let targetDuration : number | undefined ;
1857 let endlist = false ;
1958 let playlistType : PlaylistType | undefined ;
2059 let independentSegments = false ;
2160 let mediaSequenceBase : number | undefined ;
2261 let discontinuitySequenceBase : number | undefined ;
23- let map : MediaInitializationSection | undefined ;
2462 const dateRanges : DateRange [ ] = [ ] ;
2563
2664 tags . forEach ( ( [ name , value ] ) => {
@@ -33,9 +71,6 @@ function formatMediaPlaylist(tags: Tag[]): MediaPlaylist {
3371 if ( name === "EXT-X-PLAYLIST-TYPE" ) {
3472 playlistType = value ;
3573 }
36- if ( name === "EXT-X-MAP" ) {
37- map = value ;
38- }
3974 if ( name === "EXT-X-INDEPENDENT-SEGMENTS" ) {
4075 independentSegments = true ;
4176 }
@@ -53,7 +88,12 @@ function formatMediaPlaylist(tags: Tag[]): MediaPlaylist {
5388 const segments : Segment [ ] = [ ] ;
5489 let segmentStart = - 1 ;
5590
56- tags . forEach ( ( [ name ] , index ) => {
91+ let map : MediaInitializationSection | undefined ;
92+ tags . forEach ( ( [ name , value ] , index ) => {
93+ if ( name === "EXT-X-MAP" ) {
94+ map = value ;
95+ }
96+
5797 if ( isSegmentTag ( name ) ) {
5898 segmentStart = index - 1 ;
5999 }
@@ -86,6 +126,31 @@ function formatMediaPlaylist(tags: Tag[]): MediaPlaylist {
86126 } ;
87127}
88128
129+ function nextLiteral ( tags : Tag [ ] , index : number ) {
130+ if ( ! tags [ index + 1 ] ) {
131+ throw new Error ( "Expecting next tag to be found" ) ;
132+ }
133+ const tag = tags [ index + 1 ] ;
134+ if ( ! tag ) {
135+ throw new Error ( `Expected valid tag on ${ index + 1 } ` ) ;
136+ }
137+ const [ name , value ] = tag ;
138+ if ( name !== "LITERAL" ) {
139+ throw new Error ( "Expecting next tag to be a literal" ) ;
140+ }
141+ return value ;
142+ }
143+
144+ function isSegmentTag ( name : Tag [ 0 ] ) {
145+ switch ( name ) {
146+ case "EXTINF" :
147+ case "EXT-X-DISCONTINUITY" :
148+ case "EXT-X-PROGRAM-DATE-TIME" :
149+ return true ;
150+ }
151+ return false ;
152+ }
153+
89154function parseSegment (
90155 tags : Tag [ ] ,
91156 uri : string ,
@@ -118,120 +183,6 @@ function parseSegment(
118183 } ;
119184}
120185
121- function createRendition ( media : Media , renditions : Map < string , Rendition > ) {
122- let rendition = renditions . get ( media . uri ) ;
123- if ( rendition ) {
124- return rendition ;
125- }
126-
127- rendition = {
128- type : media . type ,
129- groupId : media . groupId ,
130- name : media . name ,
131- language : media . language ,
132- uri : media . uri ,
133- channels : media . channels ,
134- } ;
135-
136- renditions . set ( media . uri , rendition ) ;
137-
138- return rendition ;
139- }
140-
141- function addRendition (
142- variant : Variant ,
143- media : Media ,
144- renditions : Map < string , Rendition > ,
145- ) {
146- const rendition = createRendition ( media , renditions ) ;
147-
148- if ( media . type === "AUDIO" ) {
149- variant . audio . push ( rendition ) ;
150- }
151-
152- if ( media . type === "SUBTITLES" ) {
153- variant . subtitles . push ( rendition ) ;
154- }
155- }
156-
157- function parseVariant (
158- tags : Tag [ ] ,
159- streamInf : StreamInf ,
160- uri : string ,
161- renditions : Map < string , Rendition > ,
162- ) {
163- const variant : Variant = {
164- uri,
165- bandwidth : streamInf . bandwidth ,
166- resolution : streamInf . resolution ,
167- codecs : streamInf . codecs ,
168- audio : [ ] ,
169- subtitles : [ ] ,
170- } ;
171-
172- for ( const [ name , value ] of tags ) {
173- if ( name === "EXT-X-MEDIA" ) {
174- if (
175- streamInf . audio === value . groupId ||
176- streamInf . subtitles === value . groupId
177- ) {
178- addRendition ( variant , value , renditions ) ;
179- }
180- }
181- }
182-
183- return variant ;
184- }
185-
186- function formatMasterPlaylist ( tags : Tag [ ] ) : MasterPlaylist {
187- const variants : Variant [ ] = [ ] ;
188- let independentSegments = false ;
189-
190- const renditions = new Map < string , Rendition > ( ) ;
191-
192- tags . forEach ( ( [ name , value ] , index ) => {
193- if ( name === "EXT-X-STREAM-INF" ) {
194- const uri = nextLiteral ( tags , index ) ;
195- const variant = parseVariant ( tags , value , uri , renditions ) ;
196- variants . push ( variant ) ;
197- }
198- if ( name === "EXT-X-INDEPENDENT-SEGMENTS" ) {
199- independentSegments = true ;
200- }
201- } ) ;
202-
203- return {
204- independentSegments,
205- variants,
206- } ;
207- }
208-
209- function nextLiteral ( tags : Tag [ ] , index : number ) {
210- if ( ! tags [ index + 1 ] ) {
211- throw new Error ( "Expecting next tag to be found" ) ;
212- }
213- const tag = tags [ index + 1 ] ;
214- if ( ! tag ) {
215- throw new Error ( `Expected valid tag on ${ index + 1 } ` ) ;
216- }
217- const [ name , value ] = tag ;
218- if ( name !== "LITERAL" ) {
219- throw new Error ( "Expecting next tag to be a literal" ) ;
220- }
221- return value ;
222- }
223-
224- function isSegmentTag ( name : Tag [ 0 ] ) {
225- switch ( name ) {
226- case "EXTINF" :
227- case "EXT-X-DISCONTINUITY" :
228- case "EXT-X-MAP" :
229- case "EXT-X-PROGRAM-DATE-TIME" :
230- return true ;
231- }
232- return false ;
233- }
234-
235186export function parseMasterPlaylist ( text : string ) {
236187 const tags = lexicalParse ( text ) ;
237188 return formatMasterPlaylist ( tags ) ;
0 commit comments