116 lines
3.1 KiB
TypeScript
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;
|
|
} |