UNPKG

@iptv/playlist

Version:

An extremely fast M3U playlist parser and generator for Node and the browser.

121 lines (120 loc) 4.27 kB
const x = { "tvg-id": "tvgId", "tvg-name": "tvgName", "tvg-language": "tvgLanguage", "tvg-logo": "tvgLogo", "tvg-url": "tvgUrl", "tvg-rec,": "tvgRec", "group-title": "groupTitle", timeshift: "timeshift", catchup: "catchup", "catchup-days": "catchupDays", "catchup-source": "catchupSource", "x-tvg-url": "xTvgUrl", "url-tvg": "urlTvg" }, $ = 32, O = 35, I = 61, U = 58, N = 44, T = 45, b = 49, w = 50, C = 51, L = 52, M = 53, E = 54, S = 55, y = 56, D = 57, P = 48, A = 10, R = 9, X = 13, v = 69, l = 88, f = 84, j = 73, k = 78, q = 70, H = 77, z = 72, Q = 80, V = 85, B = 104, G = 112, p = 116, J = [ P, b, w, C, L, M, E, S, y, D, T ]; function K(r) { const e = [], c = {}; let t = 0, o = {}, g = "", s = null, u = null; for (; t < r.length; ) { const a = r.charCodeAt(t); if (t === u) throw new Error("Infinite loop detected while parsing M3U file"); if (u = t, a === $ || a === R || a === X || a === A) { t++, a === A && (g = ""); continue; } let n = r.indexOf(` `, t); if (n === -1 && (n = r.length), J.includes(a)) { let h = r.indexOf(" ", t), d = r.indexOf(",", t), i = -1; d > -1 && (i = d), h > -1 && d > -1 && h < d && (i = h), d === -1 && h > -1 && (i = h), i === -1 && (i = n), o.duration = parseInt( r.slice(t, i), 10 ), t = i; continue; } if (a === O) if (s = null, r.charCodeAt(t + 1) === v && r.charCodeAt(t + 2) === l && r.charCodeAt(t + 3) === f && r.charCodeAt(t + 4) === H && r.charCodeAt(t + 5) === C && r.charCodeAt(t + 6) === V) t += 6, s = "header"; else if (r.charCodeAt(t + 1) === v && r.charCodeAt(t + 2) === l && r.charCodeAt(t + 3) === f && r.charCodeAt(t + 4) === j && r.charCodeAt(t + 5) === k && r.charCodeAt(t + 6) === q && r.charCodeAt(t + 7) === U) t += 7, s = "channel", o = {}; else { t = n; continue; } if (a === B || a === z) { if ( // http !((r.charCodeAt(t + 1) === p || r.charCodeAt(t + 1) === f) && (r.charCodeAt(t + 2) === p || r.charCodeAt(t + 2) === f) && (r.charCodeAt(t + 3) === G || r.charCodeAt(t + 3) === Q)) || !(o.name || o.tvgName || o.tvgId) ) { t = n; continue; } s = "http"; const h = r.slice(t, n).trim(); o.url || (o.url = h), o.urls || (o.urls = []), o.urls = [...o.urls, h], t = n, e.indexOf(o) === -1 && e.push(o); continue; } if (a === N) { s = "channel", o.name = r.slice(t + 1, n).trim(), t = n, s = null; continue; } if (a > 64 && a < 91 || a > 96 && a < 123 || a === 45) { const h = r.indexOf("=", t); if (h === -1 || h > n) { t = n, g = ""; continue; } g = r.slice( t, h ), t = h; continue; } if (a === I) { t = t + 2; const h = r.indexOf('"', t), d = r.slice( t, h ); t = h; const i = x[g]; i ? s === "header" ? c[i] = d : o[i] = d : (o.extras = o.extras || {}, o.extras[g] = d), g = ""; } t++; } return { channels: e, headers: c }; } function W(r) { let e = "#EXTM3U"; if (r.headers && Object.entries(r.headers)) for (const [c, t] of Object.entries(r.headers)) e += ` ${c}="${t}"`; for (const c of r.channels) if (c.url) { if (e += ` #EXTINF:`, e += c != null && c.duration ? c.duration : "-1", c.tvgId && (e += ` tvg-id="${c.tvgId}"`), c.tvgName && (e += ` tvg-name="${c.tvgName}"`), c.tvgLanguage && (e += ` tvg-language="${c.tvgLanguage}"`), c.tvgLogo && (e += ` tvg-logo="${c.tvgLogo}"`), c.tvgRec && (e += ` tvg-rec="${c.tvgRec}"`), c.tvgChno && (e += ` tvg-chno="${c.tvgChno}"`), c.groupTitle && (e += ` group-title="${c.groupTitle}"`), c.tvgUrl && (e += ` tvg-url="${c.tvgUrl}"`), c.timeshift && (e += ` timeshift="${c.timeshift}"`), c.catchup && (e += ` catchup="${c.catchup}"`), c.catchupDays && (e += ` catchup-days="${c.catchupDays}"`), c.catchupSource && (e += ` catchup-source="${c.catchupSource}"`), c.extras) for (const [t, o] of Object.entries(c.extras)) e += ` ${t}="${o}"`; e += ",", c.name && (e += c.name), e += ` ${c.url}`; } return e; } export { K as parseM3U, W as writeM3U };