m3u8-parser.js 4.07 KB
(function(window) {
  var M3U8 = window.videojs.hls.M3U8;

  window.videojs.hls.M3U8Parser = function() {

    var self = this;
    self.directory;

    var tagTypes = window.videojs.hls.m3u8TagType;
    var lines = [];
    var data;

    self.getTagType = function( lineData ) {
      for ( var s in tagTypes )
      {
	if (lineData.indexOf(tagTypes[s]) == 0)
	{
	  return tagTypes[s];
	}
      }
    }

    self.getTagValue = function ( lineData ) {
      for ( var s in tagTypes )
      {
	if (lineData.indexOf(tagTypes[s]) == 0)
	{
	  return lineData.substr(tagTypes[s].length);
	}
      }
    }

    self.parse = function( rawDataString ) {
      data = new M3U8();

      if(self.directory)
      {
	data.directory = self.directory;
      }

      if( rawDataString != undefined && rawDataString.toString().length > 0 )
      {
	lines = rawDataString.split('\n');

	lines.forEach(
	  function(value,index) {
	    switch( self.getTagType(value) )
	    {
	    case tagTypes.EXTM3U:
	      data.hasValidM3UTag = (index == 0);
	      if(!data.hasValidM3UTag)
	      {
		data.invalidReasons.push("Invalid EXTM3U Tag");
	      }
	      break;

	    case tagTypes.DISCONTINUITY:
	      break;

	    case tagTypes.PLAYLIST_TYPE:
	      if(self.getTagValue(value) == "VOD" || self.getTagValue(value) == "EVENT")
	      {
		data.playlistType = self.getTagValue(value);
		data.isPlaylist = true;
	      } else {
		data.invalidReasons.push("Invalid Playlist Type Value");
	      }
	      break;

	    case tagTypes.EXTINF:
	      var segment = {url: "unknown", byterange: -1, targetDuration: data.targetDuration };

	      if( self.getTagType(lines[index+1]) == tagTypes.BYTERANGE )
	      {
		segment.byterange = self.getTagValue(lines[index+1]).split('@');
		segment.url = lines[index+2];
	      } else
	      {
		segment.url = lines[index+1];
	      }

	      if(segment.url.indexOf("http")===-1 && self.directory)
	      {
		if(data.directory[data.directory.length-1] === segment.url[0] && segment.url[0] === "/")
		{
		  segment.url = segment.url.substr(1);
		}
		segment.url = self.directory + segment.url;
	      }

	      data.mediaItems.push(segment);

	      break;

	    case tagTypes.STREAM_INF:
	      var rendition = {};
	      var attributes = value.substr(tagTypes.STREAM_INF.length).split(',');

	      attributes.forEach(function(attr_value,attr_index) {
		if(isNaN(attr_value.split('=')[1])){
		  rendition[attr_value.split('=')[0].toLowerCase()] = attr_value.split('=')[1];

		  if(rendition[attr_value.split('=')[0].toLowerCase()].split('x').length = 2)
		  {
		    rendition.resolution = {
		      width: Number(rendition[attr_value.split('=')[0].toLowerCase()].split('x')[0]),
		      height: Number(rendition[attr_value.split('=')[0].toLowerCase()].split('x')[1])
		    }
		  }

		} else {
		  rendition[attr_value.split('=')[0].toLowerCase()] = Number(attr_value.split('=')[1]);
		}
	      });


	      if( self.getTagType(lines[index+1]) == tagTypes.BYTERANGE )
	      {
		rendition.byterange = self.getTagValue(lines[index+1]).split('@');
		rendition.url = lines[index+2];
	      } else
	      {
		rendition.url = lines[index+1];
	      }

	      data.isPlaylist = true;
	      data.playlistItems.push(rendition);
	      break;

	    case tagTypes.TARGETDURATION:
	      data.targetDuration = Number(self.getTagValue(value).split(',')[0]);
	      break;

	    case tagTypes.ZEN_TOTAL_DURATION:
	      data.totalDuration = Number(self.getTagValue(value));
	      break;

	    case tagTypes.VERSION:
	      data.version = Number(self.getTagValue(value));
	      break;

	    case tagTypes.MEDIA_SEQUENCE:
	      data.mediaSequence = parseInt(self.getTagValue(value));
	      break;

	    case tagTypes.ALLOW_CACHE:
	      if(self.getTagValue(value) == "YES" || self.getTagValue(value) == "NO")
	      {
		data.allowCache = self.getTagValue(value);
	      } else {
		data.invalidReasons.push("Invalid ALLOW_CACHE Value");
	      }
	      break;

	    case tagTypes.ENDLIST:
	      data.hasEndTag = true;
	      break;
	    }
	  }
	)
      } else {
	data.invalidReasons.push("Empty Manifest");
      }

      return data;

    };
  };

})(this);