Better socket handling, loadfile api update for mpv 0.38.0
This commit is contained in:
@@ -38,8 +38,9 @@ enum UserEvent {
|
||||
}
|
||||
|
||||
export class MediaPlayer {
|
||||
private playerProcess: ChildProcess;
|
||||
private socket: Socket;
|
||||
private playerProcess: ChildProcess | null = null;
|
||||
private socket: Promise<Socket>;
|
||||
|
||||
private eventSubscribers: WebSocket[] = [];
|
||||
private favoritesStore: FavoritesStore;
|
||||
|
||||
@@ -49,9 +50,19 @@ export class MediaPlayer {
|
||||
private metadata: Map<string, LinkMetadata> = new Map();
|
||||
|
||||
constructor() {
|
||||
this.socket = this.tryRespawnPlayerProcess();
|
||||
|
||||
this.favoritesStore = new FavoritesStore();
|
||||
this.favoritesStore.onFavoritesChanged = (favorites) => {
|
||||
this.handleEvent(UserEvent.FavoritesUpdate, { favorites });
|
||||
};
|
||||
}
|
||||
|
||||
private tryRespawnPlayerProcess(): Promise<Socket> {
|
||||
const socketFilename = Math.random().toString(36).substring(2, 10);
|
||||
const socketPath = `/tmp/mpv-${socketFilename}`;
|
||||
const enableVideo = process.env.ENABLE_VIDEO || false;
|
||||
const logfilePath = `/tmp/mpv-logfile.txt`;
|
||||
|
||||
console.log("Starting player process (video: " + (enableVideo ? "enabled" : "disabled") + ")");
|
||||
this.playerProcess = spawn("mpv", [
|
||||
@@ -59,22 +70,26 @@ export class MediaPlayer {
|
||||
"--fullscreen",
|
||||
"--no-terminal",
|
||||
"--idle=yes",
|
||||
"--input-ipc-server=" + socketPath
|
||||
"--input-ipc-server=" + socketPath,
|
||||
"--log-file=" + logfilePath,
|
||||
"--msg-level=all=v"
|
||||
]);
|
||||
|
||||
this.socket = new Socket();
|
||||
|
||||
let socketReady!: (s: Socket) => void;
|
||||
let socketPromise = new Promise<Socket>(resolve => {
|
||||
socketReady = resolve;
|
||||
});
|
||||
|
||||
this.playerProcess.on("spawn", () => {
|
||||
console.log(`Player process spawned, opening socket @ ${socketPath}`);
|
||||
setTimeout(() => {
|
||||
this.connectToSocket(socketPath);
|
||||
let socket = this.connectToSocket(socketPath);
|
||||
socketReady(socket);
|
||||
}, 500);
|
||||
});
|
||||
|
||||
this.favoritesStore = new FavoritesStore();
|
||||
this.favoritesStore.onFavoritesChanged = (favorites) => {
|
||||
this.handleEvent(UserEvent.FavoritesUpdate, { favorites });
|
||||
};
|
||||
return socketPromise;
|
||||
}
|
||||
|
||||
public async getPlaylist(): Promise<PlaylistItem[]> {
|
||||
@@ -247,7 +262,7 @@ export class MediaPlayer {
|
||||
}
|
||||
|
||||
private async loadFile(url: string, mode: string, fetchMetadata: boolean = true, options: string[] = []) {
|
||||
this.modify(UserEvent.PlaylistUpdate, () => this.writeCommand("loadfile", [url, mode, options.join(',')]));
|
||||
this.modify(UserEvent.PlaylistUpdate, () => this.writeCommand("loadfile", [url, mode, "-1", options.join(',')]));
|
||||
|
||||
if (fetchMetadata) {
|
||||
this.fetchMetadataAndNotify(url).catch(error => {
|
||||
@@ -266,6 +281,9 @@ export class MediaPlayer {
|
||||
}
|
||||
|
||||
private async writeCommand(command: string, args: any[]): Promise<any> {
|
||||
// Wait for socket to become available.
|
||||
let socket = await this.socket;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = this.requestId++;
|
||||
|
||||
@@ -274,8 +292,13 @@ export class MediaPlayer {
|
||||
request_id: id
|
||||
});
|
||||
|
||||
this.pendingCommands.set(id, { resolve, reject });
|
||||
this.socket.write(commandObject + '\n');
|
||||
try {
|
||||
this.pendingCommands.set(id, { resolve, reject });
|
||||
socket.write(commandObject + '\n');
|
||||
} catch (e: any) {
|
||||
console.error(`Error writing to socket: ${e}. Trying to respawn.`)
|
||||
this.tryRespawnPlayerProcess();
|
||||
}
|
||||
|
||||
// Add timeout to prevent hanging promises
|
||||
setTimeout(() => {
|
||||
@@ -313,9 +336,12 @@ export class MediaPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
private connectToSocket(path: string) {
|
||||
this.socket.connect(path);
|
||||
this.socket.on("data", data => this.receiveData(data.toString()));
|
||||
private connectToSocket(path: string): Socket {
|
||||
let socket = new Socket();
|
||||
socket.connect(path);
|
||||
socket.on("data", data => this.receiveData(data.toString()));
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
private handleEvent(event: string, data: any) {
|
||||
|
||||
Reference in New Issue
Block a user