@@ -59,17 +59,13 @@ export const toPlaybackIdParts = (playbackIdWithOptionalParams: string): [string
5959 return [ idPart , queryPart ] ;
6060} ;
6161
62- export const getType = ( props : Partial < Pick < MuxMediaProps , 'type' | 'src' > > ) => {
63- const type = props . type ;
62+ export const getType = ( props : Partial < Pick < MuxMediaProps , 'type' | 'src' | 'customDomain' > > ) => {
63+ const { type } = props ;
6464 if ( type ) {
6565 const upperType = type . toUpperCase ( ) ;
6666 return isKeyOf ( upperType , MimeTypeShorthandMap ) ? MimeTypeShorthandMap [ upperType ] : type ;
6767 }
68-
69- const { src } = props ;
70- if ( ! src ) return '' ;
71-
72- return inferMimeTypeFromURL ( src ) ;
68+ return inferMimeTypeFromURL ( props ) ;
7369} ;
7470
7571export const toStreamTypeFromPlaylistType = ( playlistType : HlsPlaylistTypes ) => {
@@ -82,23 +78,50 @@ export const toTargetLiveWindowFromPlaylistType = (playlistType: HlsPlaylistType
8278 return 0 ;
8379} ;
8480
85- export const inferMimeTypeFromURL = ( url : string ) => {
81+ export const inferMimeTypeFromURL = ( props : Partial < Pick < MuxMediaProps , 'src' | 'customDomain' > > ) => {
82+ const { src } = props ;
83+ if ( ! src ) return '' ;
84+
8685 let pathname = '' ;
8786 try {
88- pathname = new URL ( url ) . pathname ;
87+ pathname = new URL ( src ) . pathname ;
8988 } catch ( _e ) {
9089 console . error ( 'invalid url' ) ;
9190 }
9291
9392 const extDelimIdx = pathname . lastIndexOf ( '.' ) ;
94- if ( extDelimIdx < 0 ) return '' ;
93+ if ( extDelimIdx < 0 ) {
94+ if ( isExtensionLessMuxM3U8URL ( props ) ) {
95+ return ExtensionMimeTypeMap . M3U8 ; // Treat extension-less Mux URLs as HLS
96+ }
97+ return '' ;
98+ }
9599
96100 const ext = pathname . slice ( extDelimIdx + 1 ) ;
97101 const upperExt = ext . toUpperCase ( ) ;
98102
99103 return isKeyOf ( upperExt , ExtensionMimeTypeMap ) ? ExtensionMimeTypeMap [ upperExt ] : '' ;
100104} ;
101105
106+ const MUX_VIDEO_DOMAIN = 'mux.com' ;
107+ export const isExtensionLessMuxM3U8URL = ( {
108+ src,
109+ customDomain = MUX_VIDEO_DOMAIN ,
110+ } : Partial < Pick < MuxMediaProps , 'src' | 'customDomain' > > ) => {
111+ let urlObj ;
112+ try {
113+ urlObj = new URL ( `${ src } ` ) ;
114+ } catch {
115+ return false ;
116+ }
117+ const validProtocol = urlObj . protocol === 'https:' ;
118+ const validHostname = urlObj . hostname === `stream.${ customDomain } ` . toLowerCase ( ) ;
119+ const pathParts = urlObj . pathname . split ( '/' ) ;
120+ const validPathPartsLength = pathParts . length === 2 ;
121+ const validExtensionlessPath = ! pathParts ?. [ 1 ] . includes ( '.' ) ;
122+ return validProtocol && validHostname && validPathPartsLength && validExtensionlessPath ;
123+ } ;
124+
102125export type MuxJWT = {
103126 sub : string ;
104127 aud : 'v' | 't' | 'g' | 's' | 'd' ;
0 commit comments