Finish Favorites UI and jumping

This commit is contained in:
2025-02-23 13:46:31 -08:00
parent d6a375fff3
commit fe05a27b51
7 changed files with 336 additions and 68 deletions

View File

@@ -2,31 +2,18 @@ import { ChildProcess, spawn } from "child_process";
import { Socket } from "net";
import { WebSocket } from "ws";
import { getLinkPreview } from "link-preview-js";
import { PlaylistItem, LinkMetadata } from './types';
import { FavoritesStore } from "./FavoritesStore";
interface PendingCommand {
resolve: (value: any) => void;
reject: (reason: any) => void;
}
interface LinkMetadata {
title?: string;
description?: string;
siteName?: string;
}
interface PlaylistItem {
id: number;
filename: string;
title?: string;
playing?: boolean;
current?: boolean;
metadata?: LinkMetadata;
}
export class MediaPlayer {
private playerProcess: ChildProcess;
private socket: Socket;
private eventSubscribers: WebSocket[] = [];
private favoritesStore: FavoritesStore;
private pendingCommands: Map<number, PendingCommand> = new Map();
private requestId: number = 1;
@@ -53,6 +40,11 @@ export class MediaPlayer {
this.connectToSocket(socketPath);
}, 500);
});
this.favoritesStore = new FavoritesStore();
this.favoritesStore.onFavoritesChanged = (favorites) => {
this.handleEvent("favorites_update", { favorites });
};
}
public async getPlaylist(): Promise<PlaylistItem[]> {
@@ -123,14 +115,11 @@ export class MediaPlayer {
}
public async append(url: string) {
const result = await this.modify(() => this.writeCommand("loadfile", [url, "append-play"]));
// Asynchronously fetch the metadata for this after we update the playlist
this.fetchMetadataAndNotify(url).catch(error => {
console.warn(`Failed to fetch metadata for ${url}:`, error);
});
return result;
await this.loadFile(url, "append-play");
}
public async replace(url: string) {
await this.loadFile(url, "replace");
}
public async play() {
@@ -169,6 +158,30 @@ export class MediaPlayer {
this.eventSubscribers = this.eventSubscribers.filter(subscriber => subscriber !== ws);
}
public async getFavorites(): Promise<PlaylistItem[]> {
return this.favoritesStore.getFavorites();
}
public async addFavorite(item: PlaylistItem) {
return this.favoritesStore.addFavorite(item);
}
public async removeFavorite(id: number) {
return this.favoritesStore.removeFavorite(id);
}
public async clearFavorites() {
return this.favoritesStore.clearFavorites();
}
private async loadFile(url: string, mode: string) {
this.modify(() => this.writeCommand("loadfile", [url, mode]));
this.fetchMetadataAndNotify(url).catch(error => {
console.warn(`Failed to fetch metadata for ${url}:`, error);
});
}
private async modify<T>(func: () => Promise<T>): Promise<T> {
return func()
.then((result) => {
@@ -205,12 +218,16 @@ export class MediaPlayer {
private async fetchMetadataAndNotify(url: string) {
try {
console.log("Fetching metadata for " + url);
const metadata = await getLinkPreview(url);
this.metadata.set(url, {
title: (metadata as any)?.title,
description: (metadata as any)?.description,
siteName: (metadata as any)?.siteName,
});
console.log("Metadata fetched for " + url);
console.log(this.metadata.get(url));
// Notify clients that metadata has been updated
this.handleEvent("metadata_update", {
@@ -228,7 +245,7 @@ export class MediaPlayer {
}
private handleEvent(event: string, data: any) {
console.log("MPV Event [" + event + "]: " + JSON.stringify(data, null, 2));
console.log("Event [" + event + "]: " + JSON.stringify(data, null, 2));
// Notify all subscribers
this.eventSubscribers.forEach(subscriber => {