You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.2 KiB
JavaScript
85 lines
2.2 KiB
JavaScript
"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 };
|