Skip to main content
Glama
playlist-crud.ts6.16 kB
/** * Navidrome MCP Server - Playlist CRUD Operations * Copyright (C) 2025 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ import type { NavidromeClient } from '../../client/navidrome-client.js'; import { transformPlaylistsToDTO, transformToPlaylistDTO, type RawPlaylist, } from '../../transformers/index.js'; import type { PlaylistDTO, CreatePlaylistRequest, UpdatePlaylistRequest, } from '../../types/index.js'; import { PlaylistPaginationSchema, CreatePlaylistSchema, UpdatePlaylistSchema, PlaylistIdSchema, } from '../../schemas/index.js'; /** * List all playlists accessible to the user */ export async function listPlaylists(client: NavidromeClient, args: unknown): Promise<{ playlists: PlaylistDTO[]; total: number; offset: number; limit: number; }> { const params = PlaylistPaginationSchema.parse(args); try { const queryParams = new URLSearchParams({ _start: params.offset.toString(), _end: (params.offset + params.limit).toString(), _sort: params.sort, _order: params.order, }); const rawPlaylists = await client.request<unknown>(`/playlist?${queryParams.toString()}`); const playlists = transformPlaylistsToDTO(rawPlaylists); return { playlists, total: playlists.length, offset: params.offset, limit: params.limit, }; } catch (error) { throw new Error( `Failed to fetch playlists: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Get a specific playlist by ID */ export async function getPlaylist(client: NavidromeClient, args: unknown): Promise<PlaylistDTO> { const params = PlaylistIdSchema.parse(args); try { const rawPlaylist = await client.request<unknown>(`/playlist/${params.id}`); return transformToPlaylistDTO(rawPlaylist as RawPlaylist); } catch (error) { throw new Error( `Failed to fetch playlist: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Create a new playlist */ export async function createPlaylist(client: NavidromeClient, args: unknown): Promise<PlaylistDTO> { const params = CreatePlaylistSchema.parse(args); try { const requestBody: CreatePlaylistRequest = { name: params.name, public: params.public, }; if (params.comment !== undefined) { requestBody.comment = params.comment; } const rawPlaylist = await client.request<unknown>('/playlist', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestBody), }); const playlist = transformToPlaylistDTO(rawPlaylist as RawPlaylist); // Fix the name if it's not properly returned from API if (playlist.name === null || playlist.name === undefined || playlist.name === '' || playlist.name === 'Unknown Playlist') { playlist.name = params.name; } // Fix the comment if it's not properly returned from API if (params.comment !== null && params.comment !== undefined && params.comment !== '' && (playlist.comment === null || playlist.comment === undefined || playlist.comment === '')) { playlist.comment = params.comment; } return playlist; } catch (error) { throw new Error( `Failed to create playlist: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Update a playlist's metadata */ export async function updatePlaylist(client: NavidromeClient, args: unknown): Promise<PlaylistDTO> { const params = UpdatePlaylistSchema.parse(args); try { const requestBody: UpdatePlaylistRequest = {}; if (params.name !== undefined) { requestBody.name = params.name; } if (params.comment !== undefined) { requestBody.comment = params.comment; } if (params.public !== undefined) { requestBody.public = params.public; } const rawPlaylist = await client.request<unknown>(`/playlist/${params.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestBody), }); const playlist = transformToPlaylistDTO(rawPlaylist as RawPlaylist); // Fix the name if it was updated but not properly returned from API if (params.name !== null && params.name !== undefined && params.name !== '' && (playlist.name === null || playlist.name === undefined || playlist.name === '' || playlist.name === 'Unknown Playlist')) { playlist.name = params.name; } // Fix the comment if it was updated but not properly returned from API if (params.comment !== undefined && (playlist.comment === null || playlist.comment === undefined || playlist.comment === '')) { playlist.comment = params.comment; } return playlist; } catch (error) { throw new Error( `Failed to update playlist: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Delete a playlist (owner or admin only) */ export async function deletePlaylist(client: NavidromeClient, args: unknown): Promise<{ success: boolean; id: string; message: string }> { const params = PlaylistIdSchema.parse(args); try { await client.request<unknown>(`/playlist/${params.id}`, { method: 'DELETE', }); return { success: true, id: params.id, message: `Successfully deleted playlist with ID: ${params.id}`, }; } catch (error) { throw new Error( `Failed to delete playlist: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Blakeem/Navidrome-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server