All files m3u-parser.ts

100% Statements 41/41
100% Branches 7/7
100% Functions 10/10
100% Lines 40/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 1021x               1x               5x 5x 5x 27x 27x   5x                   5x 5x 5x   5x 5x 5x   5x                     12x 12x 12x 12x   5x 5x     4x 4x     1x 1x           2x 2x 2x 18x 12x   6x 6x 6x     2x       18x       3x       24x 3x 1x   2x      
import {
  M3uPlaylist,
  M3uMedia,
  M3uAttributes,
  M3uDirectives,
  M3U_COMMENT
} from "./m3u-playlist";
 
export class M3uParser {
 
  /**
   *
   * @param attributesString tvg-id="" group-title=""
   * @private
   */
  private static getAttributes(attributesString: string): M3uAttributes {
    const attributeValuePair = attributesString.split('" ');
    const attributes: M3uAttributes = new M3uAttributes();
    attributeValuePair.forEach((item) => {
      const [key, value] = item.split('="');
      attributes[key] = value.replace('"', '');
    });
    return attributes;
  }
 
  /**
   *
   * @param trackInformation -1 tvg-id="" group-title="",Tv Name
   * @param media
   * @private
   */
  private static processMedia(trackInformation: string, media: M3uMedia): void {
    const lastCommaIndex = trackInformation.lastIndexOf(',');
    const durationAttributes = trackInformation.substring(0, lastCommaIndex);
    media.name = trackInformation.substring(lastCommaIndex + 1);
 
    const firstSpaceIndex = durationAttributes.indexOf(' ');
    media.duration = Number(durationAttributes.substring(0, firstSpaceIndex));
    const attributes = durationAttributes.substring(firstSpaceIndex + 1);
 
    media.attributes = this.getAttributes(attributes);
  }
 
  /**
   *
   * @param item #EXTINF:-1 tvg-id="" group-title="",Tv Name
   * @param playlist
   * @param media
   * @private
   */
  private static processDirective(item: string, playlist: M3uPlaylist, media: M3uMedia): void {
    const firstSemicolonIndex = item.indexOf(':');
    const directive = item.substring(0, firstSemicolonIndex);
    const trackInformation = item.substring(firstSemicolonIndex + 1);
    switch(directive) {
      case M3uDirectives.EXTINF: {
        this.processMedia(trackInformation, media);
        break;
      }
      case M3uDirectives.EXTGRP: {
        media.group = trackInformation;
        break;
      }
      case M3uDirectives.PLAYLIST: {
        playlist.title = trackInformation;
        break;
      }
    }
  }
 
  private static getPlaylist(lines: string[]): M3uPlaylist {
    const playlist = new M3uPlaylist();
    let media = new M3uMedia('');
    lines.forEach(item => {
      if (this.isDirective(item)) {
        this.processDirective(item, playlist, media);
      } else {
        media.location = item;
        playlist.medias.push(media);
        media = new M3uMedia('');
      }
    });
    return playlist;
  }
 
  private static isDirective(item: string): boolean {
    return item[0] === M3U_COMMENT;
  }
 
  private static isValidM3u(firstLine: string[]): boolean {
    return firstLine[0].replace('\n', '') === M3uDirectives.EXTM3U;
  }
 
  static parse(m3uString: string): M3uPlaylist {
    const lines = m3uString.split('\n').filter(item => item);
    if (!this.isValidM3u(lines)) {
      throw new Error(`Missing ${M3uDirectives.EXTM3U} directive!`);
    }
    return this.getPlaylist(lines);
  }
}