From 224216b692afcafd91a83221c999fbdff9eed1dd Mon Sep 17 00:00:00 2001 From: hensm Date: Mon, 18 Apr 2022 09:18:23 +0100 Subject: [PATCH] Fix media server issues --- app/src/bridge/components/mediaServer.ts | 82 +++++++++++++----------- app/src/bridge/messaging.ts | 2 +- ext/src/cast/api/Session.ts | 2 - ext/src/cast/senders/media/index.ts | 21 ++++-- ext/src/messaging.ts | 2 +- 5 files changed, 62 insertions(+), 47 deletions(-) diff --git a/app/src/bridge/components/mediaServer.ts b/app/src/bridge/components/mediaServer.ts index 5fb1921..900c7b2 100644 --- a/app/src/bridge/components/mediaServer.ts +++ b/app/src/bridge/components/mediaServer.ts @@ -15,7 +15,7 @@ export let mediaServer: http.Server | undefined; export async function startMediaServer(filePath: string, port: number) { if (mediaServer?.listening) { - stopMediaServer(); + await stopMediaServer(); } let fileDir: string; @@ -30,17 +30,17 @@ export async function startMediaServer(filePath: string, port: number) { fileName = path.basename(filePath); fileSize = stat.size; } else { - console.error("Error: Media path is not a file."); sendMessage({ - subject: "mediaCast:mediaServerError" + subject: "mediaCast:mediaServerError", + data: "Media path is not a file." }); return; } } catch (err) { - console.error("Error: Failed to find media path."); sendMessage({ - subject: "mediaCast:mediaServerError" + subject: "mediaCast:mediaServerError", + data: "Failed to find media path." }); return; @@ -48,9 +48,9 @@ export async function startMediaServer(filePath: string, port: number) { const contentType = mime.lookup(filePath); if (!contentType) { - console.error("Error: Failed to find media type."); sendMessage({ - subject: "mediaCast:mediaServerError" + subject: "mediaCast:mediaServerError", + data: "Failed to find media type." }); return; @@ -78,7 +78,7 @@ export async function startMediaServer(filePath: string, port: number) { } } } catch (err) { - // TODO: Handle? + console.error(`Error: Failed to find/convert subtitles (${filePath}).`); } mediaServer = http.createServer(async (req, res) => { @@ -86,12 +86,13 @@ export async function startMediaServer(filePath: string, port: number) { return; } + let decodedUrl = decodeURIComponent(req.url); // Drop leading slash - if (req.url.startsWith("/")) { - req.url = req.url.slice(1); + if (decodedUrl.startsWith("/")) { + decodedUrl = decodedUrl.slice(1); } - switch (req.url) { + switch (decodedUrl) { case fileName: { const { range } = req.headers; @@ -135,22 +136,33 @@ export async function startMediaServer(filePath: string, port: number) { } }); - mediaServer.on("listening", () => { - let localAddress = ""; - const ifaces = Object.values(os.networkInterfaces()); - for (const iface of ifaces) { + mediaServer.on("close", () => { + sendMessage({ + subject: "mediaCast:mediaServerStopped" + }); + }); + mediaServer.on("error", err => { + sendMessage({ + subject: "mediaCast:mediaServerError", + data: err.message + }); + }); + + mediaServer.listen(port, () => { + const localAddresses: string[] = []; + for (const iface of Object.values(os.networkInterfaces())) { const matchingIface = iface?.find( details => details.family === "IPv4" && !details.internal ); if (matchingIface) { - localAddress = matchingIface.address; + localAddresses.push(matchingIface.address); } } - if (!localAddress) { - console.error("Failed to get local address."); + if (!localAddresses.length) { sendMessage({ - subject: "mediaCast:mediaServerError" + subject: "mediaCast:mediaServerError", + data: "Failed to get local address." }); stopMediaServer(); return; @@ -161,28 +173,24 @@ export async function startMediaServer(filePath: string, port: number) { data: { mediaPath: fileName, subtitlePaths: Array.from(subtitles.keys()), - localAddress + localAddress: localAddresses[0] } }); }); - - mediaServer.on("close", () => - sendMessage({ - subject: "mediaCast:mediaServerStopped" - }) - ); - mediaServer.on("error", () => - sendMessage({ - subject: "mediaCast:mediaServerError" - }) - ); - - mediaServer.listen(port); } export function stopMediaServer() { - if (mediaServer?.listening) { - mediaServer.close(); - mediaServer = undefined; - } + return new Promise((resolve, reject) => { + if (mediaServer?.listening) { + mediaServer.close(err => { + if (err) { + reject(); + } + + resolve(); + }); + + mediaServer = undefined; + } + }); } diff --git a/app/src/bridge/messaging.ts b/app/src/bridge/messaging.ts index aaa2f28..2d504cc 100644 --- a/app/src/bridge/messaging.ts +++ b/app/src/bridge/messaging.ts @@ -169,7 +169,7 @@ type MessageDefinitions = { * Sent to media sender from bridge when the media server has * encountered an error. */ - "mediaCast:mediaServerError": {}; + "mediaCast:mediaServerError": string; }; interface MessageBase { diff --git a/ext/src/cast/api/Session.ts b/ext/src/cast/api/Session.ts index f0350bc..83d69f9 100644 --- a/ext/src/cast/api/Session.ts +++ b/ext/src/cast/api/Session.ts @@ -150,8 +150,6 @@ export default class Session { media.mediaSessionId === mediaStatus.mediaSessionId ); - console.info(media); - // Handle Media creation if (!media) { media = new Media( diff --git a/ext/src/cast/senders/media/index.ts b/ext/src/cast/senders/media/index.ts index eceeada..953b991 100644 --- a/ext/src/cast/senders/media/index.ts +++ b/ext/src/cast/senders/media/index.ts @@ -37,7 +37,7 @@ function startMediaServer( break; } case "mediaCast:mediaServerError": { - reject(); + reject(message.data); break; } } @@ -100,9 +100,8 @@ function getSession(opts: InitOptions): Promise { function getMedia(opts: InitOptions): Promise { return new Promise(async (resolve, reject) => { let mediaUrl = new URL(opts.mediaUrl); - let subtitleUrls: URL[] = []; - const mediaTitle = mediaUrl.pathname.slice(1); + const subtitleUrls: URL[] = []; /** * If the media is a local file, start an HTTP media server @@ -118,11 +117,13 @@ function getMedia(opts: InitOptions): Promise { const baseUrl = new URL(`http://${localAddress}:${port}/`); mediaUrl = new URL(mediaPath, baseUrl); - subtitleUrls = subtitlePaths.map( - path => new URL(path, baseUrl) + subtitleUrls.push( + ...subtitlePaths.map(path => new URL(path, baseUrl)) ); + + console.info(mediaUrl); } catch (err) { - throw logger.error("Failed to start media server"); + throw logger.error("Failed to start media server", err); } } @@ -341,6 +342,14 @@ interface InitOptions { export async function init(opts: InitOptions) { backgroundPort = await ensureInit(); + backgroundPort.addEventListener("message", ev => { + const message = ev.data as Message; + switch (message.subject) { + case "mediaCast:mediaServerError": + logger.error("Media server error", message.data); + } + }); + const isLocalMedia = opts.mediaUrl.startsWith("file://"); const isLocalMediaEnabled = await options.get("localMediaEnabled"); diff --git a/ext/src/messaging.ts b/ext/src/messaging.ts index 5febff8..d17b9e9 100644 --- a/ext/src/messaging.ts +++ b/ext/src/messaging.ts @@ -228,7 +228,7 @@ type AppMessageDefinitions = { * Sent to media sender from bridge when the media server has * encountered an error. */ - "mediaCast:mediaServerError": {}; + "mediaCast:mediaServerError": string; }; type MessageDefinitions = ExtMessageDefinitions & AppMessageDefinitions;