This repository has been archived on 2024-04-06. You can view files and clone it, but cannot push or open issues or pull requests.
WebIPTV/lib/parseM3u.ts

116 lines
3.1 KiB
TypeScript

export interface M3UObject {
url: string[];
name?: string;
logo?: string;
groups?: string[];
}
export async function parseM3u(fileStream: ReadableStream<Uint8Array>) {
const mapList: string[][] = [];
let skipFist = false;
let storageChunck: string = "";
let lineSplits: string[];
console.log();
const reader = fileStream.getReader();
while (true) {
const data = await reader.read();
if (data.done) break;
storageChunck = String.prototype.concat(storageChunck, ((new TextDecoder()).decode(data.value)));
lineSplits = storageChunck.split("\n");
if (!skipFist) {
skipFist = true;
if (lineSplits[0].toLowerCase() !== "#extm3u") {
await reader.cancel();
throw new Error("Not extm3u file!");
}
lineSplits = lineSplits.slice(1);
}
let extIndex = 0;
for (; extIndex < lineSplits.length; extIndex++) {
if (lineSplits[extIndex].trim().toUpperCase().startsWith("#EXTINF:")) {
const startIn = extIndex;
extIndex++;
for (; extIndex < lineSplits.length; extIndex++) {
if (lineSplits[extIndex].trim().toUpperCase().startsWith("#EXTINF:")) {
const ext = lineSplits.slice(startIn, extIndex);
lineSplits = lineSplits.slice(extIndex);
if (!(ext.at(-1).trim().startsWith("#"))) mapList.push(ext);
break;
}
}
}
}
// Concat data
storageChunck = lineSplits.join("\n");
}
const files = new Set<M3UObject>();
for (const lines of mapList) {
let [ ext, ...filesUrls ] = lines;
ext = ext.trim().slice(8).trim(); ext = ext.slice(ext.indexOf(" ")).trim();
// key=string
const binfi: Record<string, string> = {};
while (ext.length > 0) {
const key = ext.slice(0, ext.indexOf("="));
ext = ext.slice(key.length+1);
if (ext[0] === "'" || ext[0] === '"') {
for (let ind = 1; ind < ext.length; ind++) {
if (ext[0] === ext[ind] && ext[ind+1] !== ",") {
binfi[key] = ext.slice(1, ind);
ext = ext.slice(ind+1).trim();
break;
}
}
}
if (ext.length > 0 && ext.indexOf("=") === -1) {
binfi[key] = ext;
break;
}
}
const making: M3UObject = { url: filesUrls.map(s => s.trim()).filter(s => !(s.startsWith("#"))) };
for (const keyName in binfi) {
const data = binfi[keyName];;
switch (keyName.toLowerCase()) {
case "name":
case "tvg-name": {
making.name = data;
break;
}
case "logo":
case "tvg-logo": {
making.logo = data;
break;
}
case "group-title": {
data.split(",").map(s => {
if (s[0] === "'" || s[0] === '"') return s.slice(1, -1);
return s;
});
break;
}
case "tvg-id": {
break;
}
default: {
console.log(keyName, data);
console.log(making);
console.log(binfi);
break;
}
}
}
files.add(making);
}
return files;
}