Une API Rest pour pmoplaylist
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
<router-link to="/debug/upnp" @click="showDebugMenu = false">🎵 UPnP Explorer</router-link>
|
||||
<router-link to="/debug/covers-cache" @click="showDebugMenu = false">🎨 Cover Cache</router-link>
|
||||
<router-link to="/debug/audio-cache" @click="showDebugMenu = false">🎵 Audio Cache</router-link>
|
||||
<router-link to="/debug/playlists" @click="showDebugMenu = false">🗂️ Playlists</router-link>
|
||||
<router-link to="/debug/api-dashboard" @click="showDebugMenu = false">🚀 API Dashboard</router-link>
|
||||
|
||||
<div class="submenu-divider">Sources</div>
|
||||
|
||||
1151
pmoapp/webapp/src/components/PlayListManager.vue
Normal file
1151
pmoapp/webapp/src/components/PlayListManager.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@ import GenericMusicPlayer from "../components/GenericMusicPlayer.vue";
|
||||
import LogView from "../components/LogView.vue";
|
||||
import CoverCacheManager from "../components/CoverCacheManager.vue";
|
||||
import AudioCacheManager from "../components/AudioCacheManager.vue";
|
||||
import PlayListManager from "../components/PlayListManager.vue";
|
||||
import UpnpExplorer from "../components/UpnpExplorer.vue";
|
||||
import APIDashboard from "../components/APIDashboard.vue";
|
||||
import RadioParadiseExplorer from "../components/RadioParadiseExplorer.vue";
|
||||
@@ -53,6 +54,11 @@ const routes = [
|
||||
name: "AudioCache",
|
||||
component: AudioCacheManager,
|
||||
},
|
||||
{
|
||||
path: "/debug/playlists",
|
||||
name: "PlaylistsManager",
|
||||
component: PlayListManager,
|
||||
},
|
||||
{
|
||||
path: "/debug/upnp",
|
||||
name: "UpnpExplorer",
|
||||
|
||||
153
pmoapp/webapp/src/services/playlists.ts
Normal file
153
pmoapp/webapp/src/services/playlists.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
export interface PlaylistSummary {
|
||||
id: string;
|
||||
title: string;
|
||||
role: string;
|
||||
persistent: boolean;
|
||||
track_count: number;
|
||||
max_size?: number | null;
|
||||
default_ttl_secs?: number | null;
|
||||
last_change: string;
|
||||
}
|
||||
|
||||
export interface PlaylistTrack {
|
||||
cache_pk: string;
|
||||
added_at: string;
|
||||
ttl_secs?: number | null;
|
||||
}
|
||||
|
||||
export interface PlaylistDetail {
|
||||
summary: PlaylistSummary;
|
||||
tracks: PlaylistTrack[];
|
||||
}
|
||||
|
||||
export interface ApiErrorPayload {
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface CreatePlaylistPayload {
|
||||
id: string;
|
||||
title?: string;
|
||||
role?: string;
|
||||
persistent?: boolean;
|
||||
max_size?: number;
|
||||
default_ttl_secs?: number;
|
||||
}
|
||||
|
||||
export interface UpdatePlaylistPayload {
|
||||
title?: string;
|
||||
role?: string;
|
||||
max_size?: number | null;
|
||||
default_ttl_secs?: number | null;
|
||||
}
|
||||
|
||||
export interface AddTracksPayload {
|
||||
cache_pks: string[];
|
||||
ttl_secs?: number;
|
||||
lazy?: boolean;
|
||||
}
|
||||
|
||||
async function parseJsonOrThrow<T>(response: Response): Promise<T> {
|
||||
if (!response.ok) {
|
||||
let message = `HTTP ${response.status}`;
|
||||
try {
|
||||
const error: ApiErrorPayload = await response.json();
|
||||
if (error?.message) {
|
||||
message = error.message;
|
||||
}
|
||||
} catch {
|
||||
// Ignore JSON parsing errors and keep default message
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
|
||||
async function ensureSuccess(response: Response): Promise<void> {
|
||||
if (!response.ok) {
|
||||
let message = `HTTP ${response.status}`;
|
||||
try {
|
||||
const error: ApiErrorPayload = await response.json();
|
||||
if (error?.message) {
|
||||
message = error.message;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
export async function listPlaylists(): Promise<PlaylistSummary[]> {
|
||||
const response = await fetch("/api/playlists");
|
||||
return parseJsonOrThrow(response);
|
||||
}
|
||||
|
||||
export async function getPlaylistDetail(id: string): Promise<PlaylistDetail> {
|
||||
const response = await fetch(`/api/playlists/${encodeURIComponent(id)}`);
|
||||
return parseJsonOrThrow(response);
|
||||
}
|
||||
|
||||
export async function createPlaylist(body: CreatePlaylistPayload): Promise<PlaylistDetail> {
|
||||
const response = await fetch("/api/playlists", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
return parseJsonOrThrow(response);
|
||||
}
|
||||
|
||||
export async function updatePlaylist(
|
||||
id: string,
|
||||
body: UpdatePlaylistPayload
|
||||
): Promise<PlaylistDetail> {
|
||||
const response = await fetch(`/api/playlists/${encodeURIComponent(id)}`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
return parseJsonOrThrow(response);
|
||||
}
|
||||
|
||||
export async function deletePlaylist(id: string): Promise<void> {
|
||||
const response = await fetch(`/api/playlists/${encodeURIComponent(id)}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
await ensureSuccess(response);
|
||||
}
|
||||
|
||||
export async function addTracksToPlaylist(
|
||||
id: string,
|
||||
payload: AddTracksPayload
|
||||
): Promise<PlaylistDetail> {
|
||||
const response = await fetch(`/api/playlists/${encodeURIComponent(id)}/tracks`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
return parseJsonOrThrow(response);
|
||||
}
|
||||
|
||||
export async function flushPlaylist(id: string): Promise<PlaylistDetail> {
|
||||
const response = await fetch(`/api/playlists/${encodeURIComponent(id)}/tracks`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
return parseJsonOrThrow(response);
|
||||
}
|
||||
|
||||
export async function removeTrackFromPlaylist(id: string, cachePk: string): Promise<PlaylistDetail> {
|
||||
const response = await fetch(
|
||||
`/api/playlists/${encodeURIComponent(id)}/tracks/${encodeURIComponent(cachePk)}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
return parseJsonOrThrow(response);
|
||||
}
|
||||
Reference in New Issue
Block a user