wip: master playlist support for internal hls streams

for some reason vimeo still doesn't work
This commit is contained in:
mikhail 2024-05-30 17:14:28 +05:00
parent d40b1d1e48
commit f6460d5002
2 changed files with 59 additions and 31 deletions

View File

@ -0,0 +1,57 @@
import { createInternalStream } from './manage.js';
import HLS from 'hls-parser';
import path from "node:path";
function transformObject(streamInfo, hlsObject) {
if (hlsObject === undefined) {
return (hlsObject) => transformObject(streamInfo, hlsObject);
}
const fullUrl = hlsObject.uri.startsWith("/")
? new URL(url, base).toString()
: new URL(path.join(streamInfo.url, "/../", hlsObject.uri)).toString();
hlsObject.uri = createInternalStream(fullUrl, streamInfo);
return hlsObject;
}
function transformMasterPlaylist(streamInfo, hlsPlaylist) {
const makeInternalStream = transformObject(streamInfo);
const makeInternalVariants = (variant) => {
variant = transformObject(streamInfo, variant);
variant.video = variant.video.map(makeInternalStream);
variant.audio = variant.audio.map(makeInternalStream);
return variant;
};
hlsPlaylist.variants = hlsPlaylist.variants.map(makeInternalVariants);
return hlsPlaylist;
}
function transformMediaPlaylist(streamInfo, hlsPlaylist) {
const makeInternalSegments = transformObject(streamInfo);
hlsPlaylist.segments = hlsPlaylist.segments.map(makeInternalSegments);
hlsPlaylist.prefetchSegments = hlsPlaylist.prefetchSegments.map(makeInternalSegments);
return hlsPlaylist;
}
const HLS_MIME_TYPES = ["application/vnd.apple.mpegurl", "audio/mpegurl", "application/x-mpegURL"];
export function isHLSRequest (req) {
return HLS_MIME_TYPES.includes(req.headers['content-type']);
}
export async function handleHlsPlaylist(streamInfo, req, res) {
let hlsPlaylist = await req.body.text();
hlsPlaylist = HLS.parse(hlsPlaylist);
hlsPlaylist = hlsPlaylist.isMasterPlaylist
? transformMasterPlaylist(streamInfo, hlsPlaylist)
: transformMediaPlaylist(streamInfo, hlsPlaylist);
hlsPlaylist = HLS.stringify(hlsPlaylist);
res.write(hlsPlaylist);
res.end();
}

View File

@ -1,9 +1,8 @@
import { request } from 'undici'; import { request } from 'undici';
import { Readable } from 'node:stream'; import { Readable } from 'node:stream';
import { assert } from 'console'; import { assert } from 'console';
import { createInternalStream } from './manage.js';
import { getHeaders } from './shared.js'; import { getHeaders } from './shared.js';
import HLS from 'hls-parser'; import { handleHlsPlaylist, isHLSRequest } from './internal-hls.js';
const CHUNK_SIZE = BigInt(8e6); // 8 MB const CHUNK_SIZE = BigInt(8e6); // 8 MB
const min = (a, b) => a < b ? a : b; const min = (a, b) => a < b ? a : b;
@ -75,34 +74,6 @@ async function handleYoutubeStream(streamInfo, res) {
} }
} }
function transformHlsMediaPlaylist(streamInfo, hlsPlaylist) {
const makeInternalSegments = (segment) => {
const fullUri = new URL(segment.uri, streamInfo.url).toString();
segment.uri = createInternalStream(fullUri, streamInfo);
return segment;
}
hlsPlaylist.segments = hlsPlaylist.segments.map(makeInternalSegments);
hlsPlaylist.prefetchSegments = hlsPlaylist.prefetchSegments.map(makeInternalSegments);
return hlsPlaylist;
}
async function handleHlsPlaylist(streamInfo, req, res) {
let hlsPlaylist = await req.body.text();
hlsPlaylist = HLS.parse(hlsPlaylist);
// NOTE no processing module is passing the master playlist
assert(!hlsPlaylist.isMasterPlaylist);
hlsPlaylist = transformHlsMediaPlaylist(streamInfo, hlsPlaylist);
hlsPlaylist = HLS.stringify(hlsPlaylist);
res.write(hlsPlaylist);
res.end();
}
const HLS_MIME_TYPES = ["application/vnd.apple.mpegurl", "audio/mpegurl", "application/x-mpegURL"]; const HLS_MIME_TYPES = ["application/vnd.apple.mpegurl", "audio/mpegurl", "application/x-mpegURL"];
export async function internalStream(streamInfo, res) { export async function internalStream(streamInfo, res) {
@ -129,7 +100,7 @@ export async function internalStream(streamInfo, res) {
if (req.statusCode < 200 || req.statusCode > 299) if (req.statusCode < 200 || req.statusCode > 299)
return res.end(); return res.end();
if (HLS_MIME_TYPES.includes(req.headers['content-type'])) { if (isHLSRequest(req)) {
await handleHlsPlaylist(streamInfo, req, res); await handleHlsPlaylist(streamInfo, req, res);
} else { } else {
req.body.pipe(res); req.body.pipe(res);