mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-12 10:39:57 +00:00
Fix media server issues
This commit is contained in:
@@ -15,7 +15,7 @@ export let mediaServer: http.Server | undefined;
|
|||||||
|
|
||||||
export async function startMediaServer(filePath: string, port: number) {
|
export async function startMediaServer(filePath: string, port: number) {
|
||||||
if (mediaServer?.listening) {
|
if (mediaServer?.listening) {
|
||||||
stopMediaServer();
|
await stopMediaServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileDir: string;
|
let fileDir: string;
|
||||||
@@ -30,17 +30,17 @@ export async function startMediaServer(filePath: string, port: number) {
|
|||||||
fileName = path.basename(filePath);
|
fileName = path.basename(filePath);
|
||||||
fileSize = stat.size;
|
fileSize = stat.size;
|
||||||
} else {
|
} else {
|
||||||
console.error("Error: Media path is not a file.");
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "mediaCast:mediaServerError"
|
subject: "mediaCast:mediaServerError",
|
||||||
|
data: "Media path is not a file."
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error: Failed to find media path.");
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "mediaCast:mediaServerError"
|
subject: "mediaCast:mediaServerError",
|
||||||
|
data: "Failed to find media path."
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -48,9 +48,9 @@ export async function startMediaServer(filePath: string, port: number) {
|
|||||||
|
|
||||||
const contentType = mime.lookup(filePath);
|
const contentType = mime.lookup(filePath);
|
||||||
if (!contentType) {
|
if (!contentType) {
|
||||||
console.error("Error: Failed to find media type.");
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "mediaCast:mediaServerError"
|
subject: "mediaCast:mediaServerError",
|
||||||
|
data: "Failed to find media type."
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -78,7 +78,7 @@ export async function startMediaServer(filePath: string, port: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// TODO: Handle?
|
console.error(`Error: Failed to find/convert subtitles (${filePath}).`);
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaServer = http.createServer(async (req, res) => {
|
mediaServer = http.createServer(async (req, res) => {
|
||||||
@@ -86,12 +86,13 @@ export async function startMediaServer(filePath: string, port: number) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let decodedUrl = decodeURIComponent(req.url);
|
||||||
// Drop leading slash
|
// Drop leading slash
|
||||||
if (req.url.startsWith("/")) {
|
if (decodedUrl.startsWith("/")) {
|
||||||
req.url = req.url.slice(1);
|
decodedUrl = decodedUrl.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (req.url) {
|
switch (decodedUrl) {
|
||||||
case fileName: {
|
case fileName: {
|
||||||
const { range } = req.headers;
|
const { range } = req.headers;
|
||||||
|
|
||||||
@@ -135,22 +136,33 @@ export async function startMediaServer(filePath: string, port: number) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mediaServer.on("listening", () => {
|
mediaServer.on("close", () => {
|
||||||
let localAddress = "";
|
sendMessage({
|
||||||
const ifaces = Object.values(os.networkInterfaces());
|
subject: "mediaCast:mediaServerStopped"
|
||||||
for (const iface of ifaces) {
|
});
|
||||||
|
});
|
||||||
|
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(
|
const matchingIface = iface?.find(
|
||||||
details => details.family === "IPv4" && !details.internal
|
details => details.family === "IPv4" && !details.internal
|
||||||
);
|
);
|
||||||
if (matchingIface) {
|
if (matchingIface) {
|
||||||
localAddress = matchingIface.address;
|
localAddresses.push(matchingIface.address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!localAddress) {
|
if (!localAddresses.length) {
|
||||||
console.error("Failed to get local address.");
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "mediaCast:mediaServerError"
|
subject: "mediaCast:mediaServerError",
|
||||||
|
data: "Failed to get local address."
|
||||||
});
|
});
|
||||||
stopMediaServer();
|
stopMediaServer();
|
||||||
return;
|
return;
|
||||||
@@ -161,28 +173,24 @@ export async function startMediaServer(filePath: string, port: number) {
|
|||||||
data: {
|
data: {
|
||||||
mediaPath: fileName,
|
mediaPath: fileName,
|
||||||
subtitlePaths: Array.from(subtitles.keys()),
|
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() {
|
export function stopMediaServer() {
|
||||||
if (mediaServer?.listening) {
|
return new Promise<void>((resolve, reject) => {
|
||||||
mediaServer.close();
|
if (mediaServer?.listening) {
|
||||||
mediaServer = undefined;
|
mediaServer.close(err => {
|
||||||
}
|
if (err) {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
mediaServer = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ type MessageDefinitions = {
|
|||||||
* Sent to media sender from bridge when the media server has
|
* Sent to media sender from bridge when the media server has
|
||||||
* encountered an error.
|
* encountered an error.
|
||||||
*/
|
*/
|
||||||
"mediaCast:mediaServerError": {};
|
"mediaCast:mediaServerError": string;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface MessageBase<K extends keyof MessageDefinitions> {
|
interface MessageBase<K extends keyof MessageDefinitions> {
|
||||||
|
|||||||
@@ -150,8 +150,6 @@ export default class Session {
|
|||||||
media.mediaSessionId === mediaStatus.mediaSessionId
|
media.mediaSessionId === mediaStatus.mediaSessionId
|
||||||
);
|
);
|
||||||
|
|
||||||
console.info(media);
|
|
||||||
|
|
||||||
// Handle Media creation
|
// Handle Media creation
|
||||||
if (!media) {
|
if (!media) {
|
||||||
media = new Media(
|
media = new Media(
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ function startMediaServer(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "mediaCast:mediaServerError": {
|
case "mediaCast:mediaServerError": {
|
||||||
reject();
|
reject(message.data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,9 +100,8 @@ function getSession(opts: InitOptions): Promise<cast.Session> {
|
|||||||
function getMedia(opts: InitOptions): Promise<cast.media.Media> {
|
function getMedia(opts: InitOptions): Promise<cast.media.Media> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
let mediaUrl = new URL(opts.mediaUrl);
|
let mediaUrl = new URL(opts.mediaUrl);
|
||||||
let subtitleUrls: URL[] = [];
|
|
||||||
|
|
||||||
const mediaTitle = mediaUrl.pathname.slice(1);
|
const mediaTitle = mediaUrl.pathname.slice(1);
|
||||||
|
const subtitleUrls: URL[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the media is a local file, start an HTTP media server
|
* If the media is a local file, start an HTTP media server
|
||||||
@@ -118,11 +117,13 @@ function getMedia(opts: InitOptions): Promise<cast.media.Media> {
|
|||||||
|
|
||||||
const baseUrl = new URL(`http://${localAddress}:${port}/`);
|
const baseUrl = new URL(`http://${localAddress}:${port}/`);
|
||||||
mediaUrl = new URL(mediaPath, baseUrl);
|
mediaUrl = new URL(mediaPath, baseUrl);
|
||||||
subtitleUrls = subtitlePaths.map(
|
subtitleUrls.push(
|
||||||
path => new URL(path, baseUrl)
|
...subtitlePaths.map(path => new URL(path, baseUrl))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.info(mediaUrl);
|
||||||
} catch (err) {
|
} 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) {
|
export async function init(opts: InitOptions) {
|
||||||
backgroundPort = await ensureInit();
|
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 isLocalMedia = opts.mediaUrl.startsWith("file://");
|
||||||
const isLocalMediaEnabled = await options.get("localMediaEnabled");
|
const isLocalMediaEnabled = await options.get("localMediaEnabled");
|
||||||
|
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ type AppMessageDefinitions = {
|
|||||||
* Sent to media sender from bridge when the media server has
|
* Sent to media sender from bridge when the media server has
|
||||||
* encountered an error.
|
* encountered an error.
|
||||||
*/
|
*/
|
||||||
"mediaCast:mediaServerError": {};
|
"mediaCast:mediaServerError": string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type MessageDefinitions = ExtMessageDefinitions & AppMessageDefinitions;
|
type MessageDefinitions = ExtMessageDefinitions & AppMessageDefinitions;
|
||||||
|
|||||||
Reference in New Issue
Block a user