mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-17 18:03:01 +01:00
wip
This commit is contained in:
116
utils/movpkg-to-vlc/tools.ts
Normal file
116
utils/movpkg-to-vlc/tools.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import { parseBootXML } from "./parse/boot";
|
||||
import { parseStreamInfoXml, StreamInfo } from "./parse/streamInfoBoot";
|
||||
|
||||
export async function rewriteM3U8Files(baseDir: string): Promise<void> {
|
||||
const bootData = await loadBootData(baseDir);
|
||||
if (!bootData) return;
|
||||
|
||||
const localPlaylistPaths = await processAllStreams(baseDir, bootData);
|
||||
await updateMasterPlaylist(
|
||||
`${baseDir}/Data/${bootData.DataItems.DataItem.DataPath}`,
|
||||
localPlaylistPaths
|
||||
);
|
||||
}
|
||||
|
||||
async function loadBootData(baseDir: string): Promise<any | null> {
|
||||
const bootPath = `${baseDir}/boot.xml`;
|
||||
try {
|
||||
const bootInfo = await FileSystem.getInfoAsync(bootPath);
|
||||
if (!bootInfo.exists) throw new Error("boot.xml not found");
|
||||
|
||||
const bootXML = await FileSystem.readAsStringAsync(bootPath);
|
||||
return parseBootXML(bootXML);
|
||||
} catch (error) {
|
||||
console.error(`Failed to load boot.xml from ${baseDir}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function processAllStreams(
|
||||
baseDir: string,
|
||||
bootData: any
|
||||
): Promise<string[]> {
|
||||
const localPaths: string[] = [];
|
||||
|
||||
for (const stream of bootData.Streams.Stream) {
|
||||
const streamDir = `${baseDir}/${stream.ID}`;
|
||||
try {
|
||||
const streamInfo = await processStream(streamDir);
|
||||
if (streamInfo && streamInfo.MediaPlaylist.PathToLocalCopy) {
|
||||
localPaths.push(
|
||||
`${streamDir}/${streamInfo.MediaPlaylist.PathToLocalCopy}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Skipping stream ${stream.ID} due to error:`, error);
|
||||
}
|
||||
}
|
||||
return localPaths;
|
||||
}
|
||||
|
||||
async function updateMasterPlaylist(
|
||||
masterPath: string,
|
||||
localPlaylistPaths: string[]
|
||||
): Promise<void> {
|
||||
try {
|
||||
const masterContent = await FileSystem.readAsStringAsync(masterPath);
|
||||
const updatedContent = updatePlaylistWithLocalSegments(
|
||||
masterContent,
|
||||
localPlaylistPaths
|
||||
);
|
||||
await FileSystem.writeAsStringAsync(masterPath, updatedContent);
|
||||
} catch (error) {
|
||||
console.error(`Error updating master playlist at ${masterPath}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export function updatePlaylistWithLocalSegments(
|
||||
content: string,
|
||||
localPaths: string[]
|
||||
): string {
|
||||
const lines = content.split("\n");
|
||||
let index = 0;
|
||||
|
||||
for (let i = 0; i < lines.length && index < localPaths.length; i++) {
|
||||
if (lines[i].trim() && !lines[i].startsWith("#")) {
|
||||
lines[i] = localPaths[index++];
|
||||
}
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
export async function processStream(
|
||||
streamDir: string
|
||||
): Promise<StreamInfo | null> {
|
||||
const streamInfoPath = `${streamDir}/StreamInfoBoot.xml`;
|
||||
|
||||
try {
|
||||
const streamXML = await FileSystem.readAsStringAsync(streamInfoPath);
|
||||
const streamInfo = await parseStreamInfoXml(streamXML);
|
||||
|
||||
const localM3u8RelPath = streamInfo.MediaPlaylist?.PathToLocalCopy;
|
||||
if (!localM3u8RelPath) {
|
||||
console.warn(`No local m3u8 specified in ${streamDir}; skipping.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const m3u8Path = `${streamDir}/${localM3u8RelPath}`;
|
||||
const m3u8Content = await FileSystem.readAsStringAsync(m3u8Path);
|
||||
|
||||
const localSegmentPaths = streamInfo.MediaSegments.SEG.map(
|
||||
(seg) => `${streamDir}/${seg.PATH}`
|
||||
);
|
||||
const updatedContent = updatePlaylistWithLocalSegments(
|
||||
m3u8Content,
|
||||
localSegmentPaths
|
||||
);
|
||||
await FileSystem.writeAsStringAsync(m3u8Path, updatedContent);
|
||||
|
||||
return streamInfo;
|
||||
} catch (error) {
|
||||
console.error(`Error processing stream at ${streamDir}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user