Implémentation de l'API REST De PMOControl.
This commit is contained in:
305
pmocontrol/src/openapi.rs
Normal file
305
pmocontrol/src/openapi.rs
Normal file
@@ -0,0 +1,305 @@
|
||||
//! Documentation OpenAPI et DTOs pour l'API ControlPoint
|
||||
//!
|
||||
//! Ce module fournit les types de réponse / payloads pour l'API REST du ControlPoint,
|
||||
//! ainsi que la documentation OpenAPI via `utoipa`.
|
||||
|
||||
#[cfg(feature = "pmoserver")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "pmoserver")]
|
||||
use utoipa::{OpenApi, ToSchema};
|
||||
|
||||
// ============================================================================
|
||||
// RENDERERS
|
||||
// ============================================================================
|
||||
|
||||
/// Résumé d'un renderer découvert
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct RendererSummary {
|
||||
/// ID unique du renderer
|
||||
pub id: String,
|
||||
/// Nom convivial
|
||||
pub friendly_name: String,
|
||||
/// Modèle du renderer
|
||||
pub model_name: String,
|
||||
/// Protocole (Upnp, Hybrid, etc.)
|
||||
pub protocol: String,
|
||||
/// Renderer en ligne
|
||||
pub online: bool,
|
||||
}
|
||||
|
||||
/// État détaillé d'un renderer
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct RendererState {
|
||||
/// ID unique du renderer
|
||||
pub id: String,
|
||||
/// Nom convivial
|
||||
pub friendly_name: String,
|
||||
/// État de transport ("PLAYING", "PAUSED", "STOPPED", etc.)
|
||||
pub transport_state: String,
|
||||
/// Position courante en millisecondes
|
||||
pub position_ms: Option<u64>,
|
||||
/// Durée totale en millisecondes
|
||||
pub duration_ms: Option<u64>,
|
||||
/// Volume (0-100)
|
||||
pub volume: Option<u8>,
|
||||
/// Mute actif
|
||||
pub mute: Option<bool>,
|
||||
/// Nombre d'items dans la queue
|
||||
pub queue_len: usize,
|
||||
/// Playlist attachée (si applicable)
|
||||
pub attached_playlist: Option<AttachedPlaylistInfo>,
|
||||
}
|
||||
|
||||
/// Information sur la playlist attachée
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct AttachedPlaylistInfo {
|
||||
/// ID du serveur de médias
|
||||
pub server_id: String,
|
||||
/// ID du container playlist
|
||||
pub container_id: String,
|
||||
/// True si au moins une mise à jour a été vue
|
||||
pub has_seen_update: bool,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// QUEUE
|
||||
// ============================================================================
|
||||
|
||||
/// Item de la queue de lecture
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct QueueItem {
|
||||
/// Index dans la queue (0-based)
|
||||
pub index: usize,
|
||||
/// URI de la ressource
|
||||
pub uri: String,
|
||||
/// Titre du morceau
|
||||
pub title: Option<String>,
|
||||
/// Artiste
|
||||
pub artist: Option<String>,
|
||||
/// Album
|
||||
pub album: Option<String>,
|
||||
/// ID du serveur source
|
||||
pub server_id: Option<String>,
|
||||
/// ID de l'objet DIDL-Lite
|
||||
pub object_id: Option<String>,
|
||||
}
|
||||
|
||||
/// Snapshot de la queue d'un renderer
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct QueueSnapshot {
|
||||
/// ID du renderer
|
||||
pub renderer_id: String,
|
||||
/// Items de la queue
|
||||
pub items: Vec<QueueItem>,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// MEDIA SERVERS
|
||||
// ============================================================================
|
||||
|
||||
/// Résumé d'un serveur de médias découvert
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct MediaServerSummary {
|
||||
/// ID unique du serveur
|
||||
pub id: String,
|
||||
/// Nom convivial
|
||||
pub friendly_name: String,
|
||||
/// Modèle du serveur
|
||||
pub model_name: String,
|
||||
/// Serveur en ligne
|
||||
pub online: bool,
|
||||
}
|
||||
|
||||
/// Entrée de navigation (container ou item)
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct ContainerEntry {
|
||||
/// ID de l'objet
|
||||
pub id: String,
|
||||
/// Titre
|
||||
pub title: String,
|
||||
/// Classe UPnP (object.container.*, object.item.*, etc.)
|
||||
pub class: String,
|
||||
/// True si c'est un container (navigable)
|
||||
pub is_container: bool,
|
||||
/// Nombre d'enfants (si container)
|
||||
pub child_count: Option<u32>,
|
||||
/// Artiste (si item audio)
|
||||
pub artist: Option<String>,
|
||||
/// Album (si item audio)
|
||||
pub album: Option<String>,
|
||||
/// URI de la pochette d'album
|
||||
pub album_art_uri: Option<String>,
|
||||
}
|
||||
|
||||
/// Résultat de navigation dans un container
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct BrowseResponse {
|
||||
/// ID du container browsé
|
||||
pub container_id: String,
|
||||
/// Entrées du container
|
||||
pub entries: Vec<ContainerEntry>,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PAYLOADS DE COMMANDES
|
||||
// ============================================================================
|
||||
|
||||
/// Requête pour définir le volume
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Deserialize, ToSchema)]
|
||||
pub struct VolumeSetRequest {
|
||||
/// Nouveau volume (0-100)
|
||||
pub volume: u8,
|
||||
}
|
||||
|
||||
/// Requête pour attacher une playlist
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Deserialize, ToSchema)]
|
||||
pub struct AttachPlaylistRequest {
|
||||
/// ID du serveur de médias
|
||||
pub server_id: String,
|
||||
/// ID du container playlist
|
||||
pub container_id: String,
|
||||
}
|
||||
|
||||
/// Réponse générique de succès
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct SuccessResponse {
|
||||
/// Message de succès
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
/// Réponse d'erreur
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(Debug, Clone, Serialize, ToSchema)]
|
||||
pub struct ErrorResponse {
|
||||
/// Message d'erreur
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// DOCUMENTATION OPENAPI
|
||||
// ============================================================================
|
||||
|
||||
/// Documentation OpenAPI pour l'API ControlPoint
|
||||
#[cfg(feature = "pmoserver")]
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(
|
||||
title = "PMOMusic Control Point API",
|
||||
version = "1.0.0",
|
||||
description = r#"
|
||||
# API REST pour le Control Point PMOMusic
|
||||
|
||||
Cette API permet de contrôler les renderers UPnP et de naviguer dans les serveurs de médias.
|
||||
|
||||
## Fonctionnalités
|
||||
|
||||
### Renderers
|
||||
- **Découverte** : Liste des renderers disponibles
|
||||
- **État** : Récupération de l'état détaillé d'un renderer
|
||||
- **Contrôle transport** : Play, pause, stop, next
|
||||
- **Contrôle volume** : Lecture et modification du volume / mute
|
||||
- **Queue** : Gestion de la queue de lecture
|
||||
|
||||
### Playlists
|
||||
- **Binding** : Attachement de la queue à un container playlist d'un serveur
|
||||
- **Synchronisation automatique** : Mise à jour de la queue lors des changements côté serveur
|
||||
|
||||
### Serveurs de médias
|
||||
- **Découverte** : Liste des serveurs disponibles
|
||||
- **Navigation** : Exploration de la hiérarchie des containers
|
||||
|
||||
## Architecture
|
||||
|
||||
Le Control Point PMOMusic est un point de contrôle UPnP qui :
|
||||
1. Découvre automatiquement les renderers et serveurs via SSDP
|
||||
2. Maintient un registre des devices actifs
|
||||
3. Permet le contrôle unifié des renderers (UPnP AV, LinkPlay, Arylic TCP)
|
||||
4. Gère une queue de lecture locale avec synchronisation optionnelle
|
||||
|
||||
## Exemples d'utilisation
|
||||
|
||||
### Lister les renderers
|
||||
```
|
||||
GET /control/renderers
|
||||
```
|
||||
|
||||
### Contrôler un renderer
|
||||
```
|
||||
POST /control/renderers/{renderer_id}/play
|
||||
POST /control/renderers/{renderer_id}/pause
|
||||
POST /control/renderers/{renderer_id}/volume/set
|
||||
Body: {"volume": 50}
|
||||
```
|
||||
|
||||
### Attacher une playlist
|
||||
```
|
||||
POST /control/renderers/{renderer_id}/binding/attach
|
||||
Body: {
|
||||
"server_id": "uuid:...",
|
||||
"container_id": "0$/Music/MyPlaylist"
|
||||
}
|
||||
```
|
||||
|
||||
### Naviguer dans un serveur
|
||||
```
|
||||
GET /control/servers/{server_id}/containers/{container_id}
|
||||
```
|
||||
"#,
|
||||
contact(
|
||||
name = "PMOMusic",
|
||||
),
|
||||
license(
|
||||
name = "MIT",
|
||||
),
|
||||
),
|
||||
paths(
|
||||
crate::pmoserver_ext::list_renderers,
|
||||
crate::pmoserver_ext::get_renderer_state,
|
||||
crate::pmoserver_ext::get_renderer_queue,
|
||||
crate::pmoserver_ext::get_renderer_binding,
|
||||
crate::pmoserver_ext::play_renderer,
|
||||
crate::pmoserver_ext::pause_renderer,
|
||||
crate::pmoserver_ext::stop_renderer,
|
||||
crate::pmoserver_ext::next_renderer,
|
||||
crate::pmoserver_ext::set_renderer_volume,
|
||||
crate::pmoserver_ext::volume_up_renderer,
|
||||
crate::pmoserver_ext::volume_down_renderer,
|
||||
crate::pmoserver_ext::toggle_mute_renderer,
|
||||
crate::pmoserver_ext::attach_playlist_binding,
|
||||
crate::pmoserver_ext::detach_playlist_binding,
|
||||
crate::pmoserver_ext::list_servers,
|
||||
crate::pmoserver_ext::browse_container,
|
||||
crate::sse::all_events_sse,
|
||||
crate::sse::renderer_events_sse,
|
||||
crate::sse::media_server_events_sse,
|
||||
),
|
||||
components(schemas(
|
||||
RendererSummary,
|
||||
RendererState,
|
||||
AttachedPlaylistInfo,
|
||||
QueueItem,
|
||||
QueueSnapshot,
|
||||
MediaServerSummary,
|
||||
ContainerEntry,
|
||||
BrowseResponse,
|
||||
VolumeSetRequest,
|
||||
AttachPlaylistRequest,
|
||||
SuccessResponse,
|
||||
ErrorResponse,
|
||||
)),
|
||||
tags(
|
||||
(name = "control", description = "Contrôle des renderers et navigation des serveurs")
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
Reference in New Issue
Block a user