"use strict"; const matchValue = require("match-value"); const { either, oneOrMore, EndOfInput, zeroOrMore, optional } = require("./operations"); const Newline = require("./simple/lines/newline").looseCRLF; const RestOfLine = require("./simple/lines/rest-of-line").looseCRLF; const Integer = require("./simple/numeric/integer"); const Decimal = require("./simple/numeric/decimal"); const spacedLine = require("./simple/template/spaced-line").looseCRLF; const format = require("./simple/template/format"); function* MaybeEmptyLines() { yield zeroOrMore(Newline); } function* Playlist() { return yield either([ MediaPlaylist ]); } function* FormatHeader() { yield spacedLine`#EXTM3U`; } function MetaField(namePrefix, valueParser) { // NOTE: prefix must include `:` if required, as this varies between fields return function* CommentField() { yield format`#${namePrefix}`; return yield valueParser; }; } function* MetaLine() { let line = yield either([ MetaField("EXTINF:", function* MetaExtraInfo() { // TODO: Support additional property fields in EXTINF, figure out what the correct parsing rules actually are for this let [ duration, trackTitle ] = yield spacedLine`${Decimal},${optional(RestOfLine)}`; return { type: "track", duration, trackTitle }; }), MetaField("PLAYLIST:", function* MetaPlaylistTitle() { return { type: "playlist", playlistTitle: yield RestOfLine }; }), MetaField("EXTGRP:", function* MetaGroup() { return { type: "groupStart", name: yield RestOfLine }; }) ]); return line; } function* MediaPlaylist() { let playlistMeta = {}; yield FormatHeader; let [ targetDuration ] = yield spacedLine`#EXT-X-TARGETDURATION:${Integer}`; let items = yield oneOrMore(function* () { let trackMeta = {}; let metaComments = yield zeroOrMore(MetaLine); let url = yield RestOfLine; yield MaybeEmptyLines; for (let { type, ... properties } of metaComments) { matchValue(type, { track: () => { Object.assign(trackMeta, properties); }, playlist: () => { Object.assign(playlistMeta, properties); }, groupStart: () => { // Ignore for now } }); } return { url, ... trackMeta }; }); return { targetDuration, items, ... playlistMeta }; } module.exports = { Playlist };