Split software arch desc for easier manintenance. Many fixes related to next video playing and remote playback
This commit is contained in:
@@ -402,6 +402,123 @@ describe("RepositoryClient", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Playlist Methods", () => {
|
||||
beforeEach(async () => {
|
||||
(invoke as any).mockResolvedValueOnce("test-handle-123");
|
||||
await client.create("https://server.com", "user1", "token123", "server1");
|
||||
});
|
||||
|
||||
it("should create a playlist", async () => {
|
||||
const mockResult = { id: "playlist-001" };
|
||||
(invoke as any).mockResolvedValueOnce(mockResult);
|
||||
|
||||
const result = await client.createPlaylist("My Playlist", ["track1", "track2"]);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(invoke).toHaveBeenCalledWith("playlist_create", {
|
||||
handle: "test-handle-123",
|
||||
name: "My Playlist",
|
||||
itemIds: ["track1", "track2"],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a playlist without initial items", async () => {
|
||||
const mockResult = { id: "playlist-002" };
|
||||
(invoke as any).mockResolvedValueOnce(mockResult);
|
||||
|
||||
await client.createPlaylist("Empty Playlist");
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith("playlist_create", {
|
||||
handle: "test-handle-123",
|
||||
name: "Empty Playlist",
|
||||
itemIds: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("should delete a playlist", async () => {
|
||||
(invoke as any).mockResolvedValueOnce(undefined);
|
||||
|
||||
await client.deletePlaylist("playlist-001");
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith("playlist_delete", {
|
||||
handle: "test-handle-123",
|
||||
playlistId: "playlist-001",
|
||||
});
|
||||
});
|
||||
|
||||
it("should rename a playlist", async () => {
|
||||
(invoke as any).mockResolvedValueOnce(undefined);
|
||||
|
||||
await client.renamePlaylist("playlist-001", "New Name");
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith("playlist_rename", {
|
||||
handle: "test-handle-123",
|
||||
playlistId: "playlist-001",
|
||||
name: "New Name",
|
||||
});
|
||||
});
|
||||
|
||||
it("should get playlist items", async () => {
|
||||
const mockItems = [
|
||||
{ playlistItemId: "entry1", id: "track1", name: "Track 1", type: "Audio" },
|
||||
{ playlistItemId: "entry2", id: "track2", name: "Track 2", type: "Audio" },
|
||||
];
|
||||
(invoke as any).mockResolvedValueOnce(mockItems);
|
||||
|
||||
const items = await client.getPlaylistItems("playlist-001");
|
||||
|
||||
expect(items).toEqual(mockItems);
|
||||
expect(invoke).toHaveBeenCalledWith("playlist_get_items", {
|
||||
handle: "test-handle-123",
|
||||
playlistId: "playlist-001",
|
||||
});
|
||||
});
|
||||
|
||||
it("should add items to a playlist", async () => {
|
||||
(invoke as any).mockResolvedValueOnce(undefined);
|
||||
|
||||
await client.addToPlaylist("playlist-001", ["track3", "track4"]);
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith("playlist_add_items", {
|
||||
handle: "test-handle-123",
|
||||
playlistId: "playlist-001",
|
||||
itemIds: ["track3", "track4"],
|
||||
});
|
||||
});
|
||||
|
||||
it("should remove items from a playlist using entry IDs", async () => {
|
||||
(invoke as any).mockResolvedValueOnce(undefined);
|
||||
|
||||
await client.removeFromPlaylist("playlist-001", ["entry1", "entry2"]);
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith("playlist_remove_items", {
|
||||
handle: "test-handle-123",
|
||||
playlistId: "playlist-001",
|
||||
entryIds: ["entry1", "entry2"],
|
||||
});
|
||||
});
|
||||
|
||||
it("should move a playlist item", async () => {
|
||||
(invoke as any).mockResolvedValueOnce(undefined);
|
||||
|
||||
await client.movePlaylistItem("playlist-001", "track1", 3);
|
||||
|
||||
expect(invoke).toHaveBeenCalledWith("playlist_move_item", {
|
||||
handle: "test-handle-123",
|
||||
playlistId: "playlist-001",
|
||||
itemId: "track1",
|
||||
newIndex: 3,
|
||||
});
|
||||
});
|
||||
|
||||
it("should throw error if not initialized before playlist operations", async () => {
|
||||
const newClient = new RepositoryClient();
|
||||
await expect(newClient.getPlaylistItems("pl-1")).rejects.toThrow("Repository not initialized");
|
||||
await expect(newClient.createPlaylist("test")).rejects.toThrow("Repository not initialized");
|
||||
await expect(newClient.deletePlaylist("pl-1")).rejects.toThrow("Repository not initialized");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Error Handling", () => {
|
||||
it("should throw error if invoke fails", async () => {
|
||||
(invoke as any).mockRejectedValueOnce(new Error("Network error"));
|
||||
|
||||
@@ -15,6 +15,8 @@ import type {
|
||||
ImageType,
|
||||
ImageOptions,
|
||||
Genre,
|
||||
PlaylistEntry,
|
||||
PlaylistCreatedResult,
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
@@ -305,6 +307,63 @@ export class RepositoryClient {
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Playlist Methods (via Rust) =====
|
||||
|
||||
async createPlaylist(name: string, itemIds?: string[]): Promise<PlaylistCreatedResult> {
|
||||
return invoke<PlaylistCreatedResult>("playlist_create", {
|
||||
handle: this.ensureHandle(),
|
||||
name,
|
||||
itemIds: itemIds ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
async deletePlaylist(playlistId: string): Promise<void> {
|
||||
return invoke("playlist_delete", {
|
||||
handle: this.ensureHandle(),
|
||||
playlistId,
|
||||
});
|
||||
}
|
||||
|
||||
async renamePlaylist(playlistId: string, name: string): Promise<void> {
|
||||
return invoke("playlist_rename", {
|
||||
handle: this.ensureHandle(),
|
||||
playlistId,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
async getPlaylistItems(playlistId: string): Promise<PlaylistEntry[]> {
|
||||
return invoke<PlaylistEntry[]>("playlist_get_items", {
|
||||
handle: this.ensureHandle(),
|
||||
playlistId,
|
||||
});
|
||||
}
|
||||
|
||||
async addToPlaylist(playlistId: string, itemIds: string[]): Promise<void> {
|
||||
return invoke("playlist_add_items", {
|
||||
handle: this.ensureHandle(),
|
||||
playlistId,
|
||||
itemIds,
|
||||
});
|
||||
}
|
||||
|
||||
async removeFromPlaylist(playlistId: string, entryIds: string[]): Promise<void> {
|
||||
return invoke("playlist_remove_items", {
|
||||
handle: this.ensureHandle(),
|
||||
playlistId,
|
||||
entryIds,
|
||||
});
|
||||
}
|
||||
|
||||
async movePlaylistItem(playlistId: string, itemId: string, newIndex: number): Promise<void> {
|
||||
return invoke("playlist_move_item", {
|
||||
handle: this.ensureHandle(),
|
||||
playlistId,
|
||||
itemId,
|
||||
newIndex,
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Getters =====
|
||||
|
||||
get serverUrl(): string {
|
||||
|
||||
@@ -240,6 +240,15 @@ export interface Genre {
|
||||
name: string;
|
||||
}
|
||||
|
||||
// Playlist types
|
||||
export interface PlaylistEntry extends MediaItem {
|
||||
playlistItemId: string;
|
||||
}
|
||||
|
||||
export interface PlaylistCreatedResult {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface GetItemsOptions {
|
||||
startIndex?: number;
|
||||
limit?: number;
|
||||
|
||||
Reference in New Issue
Block a user