Replace hardcoded relative URLs and manual base_url concatenation with a unified absolute URL API via pmocache::covers_absolute_url_for() and CacheTrait::absolute_url_for().
- Add pmocache as a required dependency to pmoparadise
- Introduce absolute_url_for() and covers_absolute_url_for() helpers using PMO_SERVER_URL env var (default: http://localhost:8080)
- Update all callers to use absolute URLs for covers and audio in streaming, playlists, Qobuz, Radio France, UPnP, and server startup
- Remove redundant route_for() usage in URL construction
- Add pmocache to Cargo.lock
Introduce async helper methods `cache_album_covers` and `cache_playlist_covers` to cache album/playlist covers in parallel using JoinSet. Refactor browse functions for favorites, discover, and genre pages to reuse these helpers and avoid duplicate logic. Simplify cover URL resolution by unifying caching path and removing redundant base URL concatenation.
deps: update esbuild to 0.27.4, rollup to 4.60.0, vite to 7.3.1
- bump esbuild and all platform-specific binaries from 0.25.10 to 0.27.4
- bump rollup and all platform-specific binaries from 4.52.3 to 4.60.0
- bump vite from 7.1.7 to 7.3.1 (esbuild peer dep updated to ^0.27.0)
- bump dompurify from 3.2.7 to 3.3.3
web: improve cover image retry logic
- increase maxRetries default from 3 to 5
- reduce initial retryDelay from 1000ms to 500ms
- implement exponential backoff: delay = retryDelay * 2^(retryCount - 1)
- add detailed logging for retries and final failure
rust: minor cleanup
- remove unused imports (watch, Url, AudioSegment, SyncMarker)
- add tracing debug logs for cache file requests
- handle missing files gracefully with warning + client retry hint
- add #[allow(async_fn_in_trait)] where needed
- Replace old /api/live endpoint with new livemeta/pull API (api.radiofrance.fr)
- Add hardcoded station ID/stream mappings with runtime-updatable mapping
- Implement station rediscovery on unknown slug or stream failure
- Add persistent caching for station mappings (30-day TTL) via pmoconfig
- Update live_metadata to use numeric IDs and handle ID mismatches
- Add station validation (API + stream accessibility check)
- Refactor metadata caching with fetched_at and fallback TTL
- Update discover_local_radios to scrape SvelteKit page data
- Add new models: PullResponse, PullStep, EmbedImage for livemeta format
- Improve live_metadata.rs example to safely truncate intros
- Enable parallel DIDL generation for playlist groups
Invalidate the cached OGG header immediately when restarting the FLAC encoder to prevent clients from receiving stale data.
Also improve the player source cleanup by draining the chunk receiver and adding a timeout when waiting for the emit task to finish, preventing potential hangs when the downstream pipeline is saturated.
Ajout de l'événement Position pour envoyer la position courante ~1/s pendant la lecture.
Modification de la gestion de la durée dans le registry pour ne pas écraser une durée déjà connue par la source (priorité à la source pour les flux radio).
Mise à jour du handler position_update pour utiliser update_duration au lieu de update_position, et suppression de la gestion de position_sec qui est maintenant gérée par PlayerEvent::Position.
Le serveur gère maintenant la position via les événements Position émis par PlayerSource, et la durée est uniquement utilisée comme fallback pour les sources sans durée connue.
Ajout de PlayerSource avec contrôle complet AVTransport (Play/Pause/Stop/Seek/LoadUri) dans le pipeline audio
- Introduit PlayerSource comme nœud source audio avec gestion complète du cycle de vie UPnP
- Implémente les commandes LoadUri, LoadNextUri, Play, Pause, Stop, Seek
- Gestion des transitions gapless avec TrackBoundary pour un bitstream propre
- Révision du pipeline audio pour utiliser PlayerSource au lieu de la logique de contrôle existante
- Mise à jour des handlers UPnP pour utiliser PlayerHandle au lieu du canal de contrôle
- Suppression des anciennes commandes PipelineControl et logique de gestion de source
- Ajout de gestion d'événements PlayerEvent pour mise à jour de l'état UPnP
- Migration vers StreamingOggFlacSink pour la diffusion audio
Implémente la reprise depuis la position pausée lors du redémarrage de la source, en conservant la position dans l'état. Met à jour les logs pour mieux refléter le comportement de pause et d'arrêt. Les modifications incluent :
- Ajout du seek lors du redémarrage de la source
- Mise à jour de la gestion de la pause pour conserver la position
- Amélioration des messages de log pour plus de clarté
Migrate from single-client direct OGG-FLAC sink to multi-client broadcast streaming sink.
- Replace DirectOggFlacHandle with OggFlacStreamHandle for multi-client support
- Update sink implementation to use StreamingOggFlacSink with proper backpressure
- Change connection model from 'connect()' to 'subscribe()'
- Adjust stream handling to support independent client streams
- Update stream endpoint to always respond with 200 chunked instead of range requests
- Add tracing for stream lifecycle events
- Reduce OGG channel capacity to strict backpressure (1)
- Add Drop implementation for stream cleanup
- Improve logging and error handling for concurrent access
This change enables multiple simultaneous clients to connect to the same audio stream without interfering with each other, while maintaining proper TCP backpressure and stream lifecycle management.
Migrate pmoutils crate to registry version 0.1.2 and update all dependencies to use the registry version instead of local path references. Remove pmoutils from Cargo.lock and Cargo.toml files where it was previously used as a local path dependency. Move ToXmlElement trait to pmodidl crate and update all usages to import from pmodidl instead of pmoutils. Fix parameter order in find_process_using_port function call.
Cette mise à jour ajoute la prise en charge de l'adresse IP du serveur hébergeant les renderers UPnP. Cela permet d'afficher l'adresse IP des renderers dans l'interface utilisateur lorsqu'ils ont des noms identiques. Les modifications incluent :
- Mise à jour des types pour inclure le champ server_host
- Extraction de l'adresse IP depuis la location UPnP
- Affichage de l'adresse IP dans l'interface utilisateur pour les renderers avec des noms en double
- Modification des appels à register_device pour désactiver le SSDP lors de l'enregistrement des renderers
Cela améliore la clarté de l'interface utilisateur en permettant de distinguer les renderers avec des noms identiques mais hébergés sur des serveurs différents.
Switch instance ID storage from localStorage to sessionStorage in useWebRenderer composable to ensure better session management and prevent data persistence across browser sessions.
Also update the DirectOggFlacSink implementation to improve backpressure handling, streamline the OGG chaining logic, and add proper Safari range header support for the stream endpoint.
Ajoute un reporting de la position audio toutes les secondes depuis le navigateur vers le serveur pour une meilleure synchronisation.
- Implémente un intervalle pour envoyer la position courante et la durée de l'audio
- Ajoute les endpoints POST /api/webrenderer/{id}/position
- Met à jour la logique de gestion de la position dans le registre
- Supprime le tracking de position dans le pipeline audio (déplacé côté client)
Cette modification introduit le support du OGG chaining dans le flux audio, permettant une transition transparente entre les pistes sans interruption. Cela inclut la gestion des encodeurs successifs dans le même canal Bytes, l'annulation des encodeurs précédents lors des transitions, et le maintien d'une connexion persistante avec backpressure TCP. Les modifications affectent les composants de sink et de pipeline audio, ainsi que les endpoints d'écoute.
When a continuous stream (like radio) stops naturally, do not auto-advance to the next track. Instead, clear the playback source and played flag to ensure proper state management.
This commit adds support for AAC audio decoding via the fdk-aac library, including:
- New AAC decoder module (ADTS streaming)
- Integration into the autodetection system
- Support for AAC in transcoding
- Updated version to 0.3.23
- Added necessary dependencies in Cargo.toml and Cargo.lock
- Added tests for AAC decoding
Refactor the audio pipeline to support multi-client streaming with new OggFlacStreamHandle and StreamingOggFlacSink.
- Replace DirectOggFlacSink with StreamingOggFlacSink in pipeline
- Update documentation and comments to reflect multi-client support
- Add detailed warning logs for buffer underruns and client disconnections
- Remove TimerBufferNode from pipeline as it's no longer needed
- Update connect() calls to subscribe() for new streaming behavior
This change enables multiple clients to subscribe to the same audio stream, with each subscription getting a live feed from the current point in time.
Cette mise à jour refactorise les nœuds audio pour utiliser la méthode `boxed()` lors de l'enregistrement des enfants, améliorant ainsi la cohérence et la lisibilité du code. Les méthodes `make()` sont ajoutées pour faciliter la création d'instances boxées des nœuds, et les exemples sont mis à jour en conséquence.
This commit refactors the WebRenderer to use a server-side streaming architecture with OGG-FLAC sink instead of the previous WebSocket-based approach. The changes include:
- Replaced WebSocket communication with HTTP streaming using DirectOggFlacSink
- Implemented a new pipeline architecture with dedicated handlers for UPnP commands
- Added new modules for registration, registry, and streaming
- Updated the renderer to work with a pipeline control system
- Removed old WebSocket session management
- Added support for HTTP streaming with gapless playback
- Updated dependencies and features for the new architecture
The WebRenderer now acts as a MediaRenderer UPnP device that serves audio streams via HTTP endpoints, with commands relayed to the audio pipeline through a new control system.
Cette mise à jour implémente le streaming audio côté serveur pour WebRenderer, en remplaçant l'ancienne architecture basée sur WebSocket par une nouvelle approche utilisant des endpoints HTTP. Les modifications incluent l'ajout de dépendances audio, la création de nouveaux modules pour le pipeline audio, la gestion des registres et des flux, ainsi que la modification des handlers UPnP pour utiliser le nouveau pipeline. Le frontend a également été mis à jour pour utiliser un seul élément <audio> pointant vers le nouveau endpoint de streaming.
Cette mise à jour permet une reconnexion stable du renderer Web après un reload de page, en conservant l'état audio (URI, volume, lecture en cours).
- Ajout d'un identifiant d'instance stable (UUID) dans le navigateur pour retrouver le même renderer UPnP
- Implémentation d'un mécanisme de synchronisation d'état (StateSync) lors des reconnexions
- Mise à jour du système de sender partagé (SharedSender) pour permettre le remplacement des connexions WebSocket
- Correction des handlers UPnP pour utiliser le nouveau type SharedSender
- Amélioration de la gestion des erreurs d'autoplay dans le moteur audio
- Mise à jour du numéro de version vers 0.3.21
Corrige une condition de course où play() pouvait être appelé avant set_uri. Ajoute un flag playPending pour reporter la lecture jusqu'à ce que la source soit définie, et gère correctement les cas où l'élément média n'a pas encore les données nécessaires.
This commit refactors the album art URL normalization logic in Rust to use match expressions for cleaner and more concise code. It also simplifies the image display logic in Vue by removing the redundant cacheBustedUrl check, ensuring the image is displayed based solely on load and error states.
This commit removes various console.log statements that were used for debugging purposes. These logs clutter the output and provide no value in production. The changes affect multiple files including components and composables related to media control and rendering.
Cette modification implémente un système de playback gapless pour les renderers web, permettant une transition fluide entre les pistes. Le changement inclut l'ajout d'un moteur audio qui utilise deux éléments <audio> en ping-pong connectés à un AudioContext pour le contrôle du volume/mute et le contrôle du flux gapless. Les commandes UPnP ont été mises à jour pour gérer le préchargement des pistes suivantes via SetNextAVTransportURI. Le backend a été modifié pour gérer les transitions gapless et précharger les pistes suivantes. Des ajustements ont également été apportés au serveur pour permettre les requêtes CORS nécessaires à ce fonctionnement.
This commit adds the CurrentSpeed field to the GetTransportInfo action, including updates to the action definition, handler, and web renderer. The speed is set to '1' as a default value.
Ce commit normalise le format de l'UDN en ajoutant le préfixe 'uuid:' pour qu'il corresponde au format SSDP. Cela permet d'éviter les doublons et garantit une compatibilité avec les protocoles réseau. Les modifications affectent la création de l'instance et l'initialisation de la session WebRenderer.
Ajout de la fonctionnalité WebRenderer permettant au navigateur de se connecter comme renderer UPnP.
- Implémentation du composant Vue useWebRenderer pour gérer la connexion WebSocket et le contrôle audio
- Ajout d'un proxy WebSocket dans Vite pour rediriger les requêtes /api/webrenderer/ws vers le serveur
- Modification du serveur pour permettre l'enregistrement dynamique de routes et extraction du JoinHandle
- Améliorations du parsing des métadonnées AVTransport pour gérer les types String et DIDLLite
- Ajout de la détection et du nommage des navigateurs dans le WebRenderer
- Mise à jour des dépendances avec tower 0.5.2
- Correction de la gestion des threads lors de l'arrêt du serveur HTTP
Corrige les problèmes de multicast SSDP sur macOS Sequoia+ en ajustant les interfaces multicast et en utilisant Terminal.app pour l'exécution des binaires en debug et release.
- Dans le Makefile : modifie les cibles 'run' et 'run-release' pour lancer l'application via Terminal.app, nécessaire pour le multicast sur macOS Sequoia+
- Dans pmoupnp/src/ssdp/client.rs : améliore la gestion des interfaces multicast en rejoignant le groupe sur toutes les interfaces non loopback et en configurant explicitement l'interface de sortie
- Dans pmoupnp/src/ssdp/server.rs : corrige la configuration multicast du serveur en maintenant l'interface de sortie correcte et en désactivant le multicast loopback
Ajout de la fonctionnalité WebRenderer permettant à chaque navigateur connecté de devenir un MediaRenderer UPnP privé.
- Création du crate pmowebrenderer avec l'architecture complète
- Implémentation des handlers SOAP → WebSocket pour les services AVTransport, RenderingControl et ConnectionManager
- Intégration avec le ControlPoint pour l'enregistrement dynamique des renderers
- Gestion des sessions avec timeout et cleanup automatique
- Support des commandes de transport (play, pause, stop, seek) et du contrôle du volume
- Mise à jour des dépendances dans Cargo.toml et Cargo.lock
- Documentation de l'architecture dans Blackboard/Architecture/webrenderer.md
Ajout de la documentation et de l'architecture pour le MediaRenderer UPnP privé par navigateur avec token, ainsi que les améliorations du client et serveur SSDP pour gérer les réseaux bloquant le multicast.
Update version from 0.3.19 to 0.3.20
- Enhanced metadata handling in ArylicTcpRenderer and LinkPlayRenderer to use queue metadata for consistent duration protection
- Added shared queue functionality for HybridUpnpArylic to synchronize metadata between UPnP and Arylic backends
- Improved error logging and debug information for playback position fetching
- Updated version in Cargo.toml and version.txt
Cette mise à jour protège les durées des streams continus contre la diminution, en s'assurant qu'une fois une chanson diffusée, sa durée ne peut jamais être réduite. Elle améliore également la récupération des métadonnées dans le rendu UPnP en utilisant les données de la queue plutôt que celles de GetPositionInfo, ce qui évite les métadonnées obsolètes. Des ajustements ont été apportés à la gestion des files d'attente interne et OpenHome pour intégrer ces nouvelles règles de protection des durées.
Ajout d'une nouvelle propriété `is_continuous_stream` pour identifier les flux continus (radio, stream) plutôt que les fichiers avec durée fixe.
- Ajout de la propriété `is_continuous_stream` dans `TrackMetadata`
- Implémentation de la détection dans plusieurs fichiers : control_point.rs, media_server.rs, music_renderer/watcher.rs et openhome_client.rs
- Utilisation de la fonction `is_continuous_stream_url` pour déterminer si l'URI correspond à un flux continu
This commit addresses several issues related to playback state reporting and metadata handling:
1. In the backend (pmocontrol), the music renderer now correctly uses raw playback states instead of computed logical states for event emission, and fixes stream time calculation to only occur when the device is actually playing.
2. The frontend (CurrentTrack.vue) now logs additional debug information for duration and transport state to help trace playback issues.
3. The SSE event handling in useRenderers.ts has been enhanced with more detailed logging and uses deep copying to prevent shared state issues between renderers.
4. The OpenHome queue implementation now uses a Mutex for metadata caching and implements logic to prevent duration from decreasing for the same track, which helps stabilize metadata for streaming content.
These changes improve the reliability and accuracy of playback state and metadata display across all components.
This commit introduces caching mechanisms for track IDs in OpenHome queues to reduce redundant SOAP calls. It adds a new `CurrentTrackIdCache` struct and integrates it into `OpenHomeQueue` to cache current track information with a 250ms TTL. The `queue_snapshot` method now uses cached track IDs instead of calling `read_all_tracks()` directly, and batched metadata reads are implemented. Cache invalidation is properly handled on write operations like `seek_id`, `stop`, `delete_all`, and `clear_queue`. The `read_all_tracks` function was removed from `openhome_client.rs` as it's now superseded by the caching logic. Additionally, the `Clone` derive was removed from `InternalQueue` and `MusicQueue` structs, and `trace` was added to the tracing imports in `openhome.rs`.
This commit introduces caching mechanisms for OpenHome playlist operations to reduce redundant SOAP calls and improve performance. Key changes include:
- Added track IDs caching in OpenHomeQueue to avoid repeated id_array() calls
- Implemented cache invalidation for all playlist modification operations
- Added caching for source XML and source index in OhProductClient
- Updated playlist length, ID retrieval, and track ID fetching to use cached data
- Ensured cache is invalidated on write operations to maintain consistency
The caching strategy uses time-based expiration (1 second for track IDs, 10 minutes for sources) and employs mutex locking for thread safety.
Corrected polling regression causing 2-3 second jumps in OpenHome renderer progress bar
- Fixed watcher loop timing to use fixed intervals instead of fixed pauses
- Eliminated redundant SOAP calls to playback_position() by implementing intelligent caching
- Restructured poll_and_emit_changes() to minimize lock contention
- Reduced unnecessary network calls and improved performance
This resolves the UI progress bar stuttering issue while maintaining correct playback state detection.
This commit addresses two main issues:
1. In the webapp, we ensure proper reactivity by explicitly reassigning the snapshot object when updating track information, which triggers Vue's reactivity system.
2. In the music renderer, we improve position tracking by:
- Adding detailed tracing when position changes
- Refactoring rel_time calculation to only apply to streams, preserving backend values for regular files
- Enhancing logging in the OpenHome renderer to include elapsed time and formatted relative time
These changes improve the reliability of playback position tracking and ensure proper UI updates when track information changes.
Cette modification corrige le calcul de la position et de la durée pour les flux continus (webradio) en ajustant la méthode `poll_and_emit_changes()` dans `pmocontrol`. Elle détecte maintenant les flux via `is_playing_a_stream()`, extrait la durée depuis les métadonnées DIDL, et calcule la position relative basée sur `track_start_time`. Les valeurs par défaut (zéro pour la position, none pour la durée) sont utilisées si aucune durée n'est disponible. Les fichiers modifiés incluent `musicrenderer.rs`, `CurrentTrack.vue` et `useRenderers.ts` pour assurer une gestion cohérente des données de position et de durée.
Ajout du fichier Rules_optimal.md contenant les règles strictes pour l'interaction avec l'LLM dans le projet PMOMusic. Ce fichier définit les interdictions, le workflow à suivre ainsi que les templates à utiliser pour les rapports et les tâches terminées.
Implémentation complète de l'étape 2 : ajout d'un indicateur visuel "Web Radio" dans l'interface web pour signaler la lecture d'un flux continu. Cet indicateur s'affiche à côté de l'indicateur "Attachée à une playlist" dans le composant QueueViewer.
Changements principaux :
- Ajout du champ `is_stream` dans `FullRendererSnapshot` pour transmettre l'état du flux au frontend
- Intégration de l'indicateur visuel dans `QueueViewer.vue` avec l'icône Radio
- Gestion de l'événement `stream_state_changed` dans le composant `useRenderers.ts`
- Mise à jour des types TypeScript pour inclure le nouveau champ `is_stream`
- Refactorisation de `sse.rs` pour éliminer la duplication de code
Cette fonctionnalité permet aux utilisateurs de savoir rapidement si la lecture en cours est un flux continu (webradio) ou un fichier audio traditionnel.