From 9e4a8410e1b01367de23b8c98b5184b1462f6a74 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Sun, 26 Oct 2025 07:22:33 +0100 Subject: [PATCH] retire le support des codec non flac de radio paradise --- pmoparadise/src/client.rs | 37 ++------------- pmoparadise/src/lib.rs | 28 ++--------- pmoparadise/src/mediaserver/mod.rs | 4 +- pmoparadise/src/mediaserver/server.rs | 13 ----- pmoparadise/src/models.rs | 66 -------------------------- pmoparadise/src/pmoserver_ext.rs | 68 ++------------------------- 6 files changed, 13 insertions(+), 203 deletions(-) diff --git a/pmoparadise/src/client.rs b/pmoparadise/src/client.rs index 2a875489..bd976f40 100644 --- a/pmoparadise/src/client.rs +++ b/pmoparadise/src/client.rs @@ -1,7 +1,7 @@ //! HTTP client for Radio Paradise API use crate::error::{Error, Result}; -use crate::models::{Bitrate, Block, EventId, NowPlaying}; +use crate::models::{Block, EventId, NowPlaying}; use reqwest::Client; use std::time::Duration; use url::Url; @@ -50,7 +50,6 @@ pub struct RadioParadiseClient { pub(crate) client: Client, api_base: String, block_base: String, - bitrate: Bitrate, channel: u8, pub(crate) request_timeout: Duration, pub(crate) block_timeout: Duration, @@ -60,7 +59,7 @@ pub struct RadioParadiseClient { impl RadioParadiseClient { /// Create a new client with default settings /// - /// Uses FLAC quality (bitrate 4) and channel 0 (main mix) + /// Uses FLAC quality and channel 0 (main mix) pub async fn new() -> Result { Self::builder().build().await } @@ -78,7 +77,6 @@ impl RadioParadiseClient { client, api_base: DEFAULT_API_BASE.to_string(), block_base: DEFAULT_BLOCK_BASE.to_string(), - bitrate: Bitrate::default(), channel: 0, request_timeout: Duration::from_secs(DEFAULT_REQUEST_TIMEOUT_SECS), block_timeout: Duration::from_secs(DEFAULT_BLOCK_TIMEOUT_SECS), @@ -86,11 +84,6 @@ impl RadioParadiseClient { } } - /// Get the current bitrate setting - pub fn bitrate(&self) -> Bitrate { - self.bitrate - } - /// Get the current channel (0 = main mix) pub fn channel(&self) -> u8 { self.channel @@ -109,13 +102,6 @@ impl RadioParadiseClient { cloned } - /// Clone the client with a different bitrate while preserving other settings. - pub fn clone_with_bitrate(&self, bitrate: Bitrate) -> Self { - let mut cloned = self.clone(); - cloned.bitrate = bitrate; - cloned.next_block_url = None; - cloned - } /// Get a block by event ID /// @@ -147,7 +133,7 @@ impl RadioParadiseClient { let mut url = Url::parse(&format!("{}/get_block", self.api_base))?; url.query_pairs_mut() - .append_pair("bitrate", &self.bitrate.as_u8().to_string()) + .append_pair("bitrate", "4") // FLAC lossless .append_pair("info", "true") .append_pair("channel", &self.channel.to_string()); @@ -251,7 +237,6 @@ pub struct ClientBuilder { client: Option, api_base: String, block_base: String, - bitrate: Bitrate, channel: u8, request_timeout: Duration, block_timeout: Duration, @@ -265,7 +250,6 @@ impl Default for ClientBuilder { client: None, api_base: DEFAULT_API_BASE.to_string(), block_base: DEFAULT_BLOCK_BASE.to_string(), - bitrate: Bitrate::default(), channel: 0, request_timeout: Duration::from_secs(DEFAULT_REQUEST_TIMEOUT_SECS), block_timeout: Duration::from_secs(DEFAULT_BLOCK_TIMEOUT_SECS), @@ -299,19 +283,6 @@ impl ClientBuilder { self } - /// Set the bitrate/quality level - /// - /// # Example - /// - /// ``` - /// # use pmoparadise::{RadioParadiseClient, Bitrate}; - /// let builder = RadioParadiseClient::builder() - /// .bitrate(Bitrate::Aac320); - /// ``` - pub fn bitrate(mut self, bitrate: Bitrate) -> Self { - self.bitrate = bitrate; - self - } /// Set the channel (0 = main mix, 1 = mellow, 2 = rock, 3 = world/etc) pub fn channel(mut self, channel: u8) -> Self { @@ -371,7 +342,6 @@ impl ClientBuilder { client, api_base: self.api_base, block_base, - bitrate: self.bitrate, channel: self.channel, request_timeout: self.request_timeout, block_timeout: self.block_timeout, @@ -388,7 +358,6 @@ mod tests { fn test_builder_defaults() { let builder = ClientBuilder::default(); assert_eq!(builder.api_base, DEFAULT_API_BASE); - assert_eq!(builder.bitrate, Bitrate::Flac); assert_eq!(builder.channel, 0); } diff --git a/pmoparadise/src/lib.rs b/pmoparadise/src/lib.rs index 4d9cef04..bbff376f 100644 --- a/pmoparadise/src/lib.rs +++ b/pmoparadise/src/lib.rs @@ -7,8 +7,8 @@ //! ## Features //! //! - **Metadata Access**: Get current and historical block metadata with song information -//! - **Block Streaming**: Stream continuous FLAC/AAC blocks with automatic prefetching -//! - **Multiple Quality Levels**: Support for MP3, AAC (64/128/320 kbps), and FLAC +//! - **Block Streaming**: Stream continuous FLAC blocks with automatic prefetching +//! - **FLAC Quality**: Lossless CD quality or better //! - **Per-Track Extraction** (optional): Extract individual tracks from FLAC blocks //! - **Async/Await**: Built on tokio for efficient async I/O //! - **Type-Safe**: Strongly typed API with comprehensive error handling @@ -49,7 +49,7 @@ //! ## Streaming Blocks //! //! Radio Paradise broadcasts music in continuous "blocks" - each block is a single -//! FLAC or AAC file containing multiple songs with metadata indicating timing offsets. +//! FLAC file containing multiple songs with metadata indicating timing offsets. //! //! ```no_run //! use pmoparadise::RadioParadiseClient; @@ -72,24 +72,6 @@ //! } //! ``` //! -//! ## Quality Levels -//! -//! Radio Paradise offers multiple quality levels via the [`Bitrate`] enum: -//! -//! ```no_run -//! use pmoparadise::{RadioParadiseClient, Bitrate}; -//! -//! #[tokio::main] -//! async fn main() -> Result<(), Box> { -//! let client = RadioParadiseClient::builder() -//! .bitrate(Bitrate::Aac320) -//! .build() -//! .await?; -//! -//! Ok(()) -//! } -//! ``` -//! //! ## Per-Track Extraction (Feature: `per-track`) //! //! **Important**: This is an advanced feature with significant tradeoffs. @@ -135,7 +117,7 @@ //! //! Radio Paradise streams use a block-based format: //! -//! - Each block is a single audio file (FLAC or AAC) +//! - Each block is a single FLAC audio file //! - Blocks contain multiple songs (typically 10-15 minutes total) //! - Metadata includes timing offsets (`song[i].elapsed` in ms) for each song //! - Block URLs follow the pattern: `https://apps.radioparadise.com/blocks/chan/0/4/-.flac` @@ -256,7 +238,7 @@ pub mod pmoserver_ext; // Re-exports for convenience pub use client::{ClientBuilder, RadioParadiseClient}; pub use error::{Error, Result}; -pub use models::{Bitrate, Block, DurationMs, EventId, NowPlaying, Song}; +pub use models::{Block, DurationMs, EventId, NowPlaying, Song}; pub use source::RadioParadiseSource; pub use stream::BlockStream; diff --git a/pmoparadise/src/mediaserver/mod.rs b/pmoparadise/src/mediaserver/mod.rs index d5335f38..ed043c80 100644 --- a/pmoparadise/src/mediaserver/mod.rs +++ b/pmoparadise/src/mediaserver/mod.rs @@ -31,12 +31,10 @@ //! # #[cfg(feature = "mediaserver")] //! # { //! use pmoparadise::mediaserver::RadioParadiseMediaServer; -//! use pmoparadise::Bitrate; //! //! #[tokio::main] //! async fn main() -> Result<(), Box> { -//! let server = RadioParadiseMediaServer::new() -//! .with_bitrate(Bitrate::Flac) +//! let server = RadioParadiseMediaServer::builder() //! .with_friendly_name("Radio Paradise FLAC") //! .build() //! .await?; diff --git a/pmoparadise/src/mediaserver/server.rs b/pmoparadise/src/mediaserver/server.rs index 2ed9aafc..9274ba2e 100644 --- a/pmoparadise/src/mediaserver/server.rs +++ b/pmoparadise/src/mediaserver/server.rs @@ -1,7 +1,6 @@ //! Radio Paradise UPnP Media Server implementation use crate::error::{Error, Result}; -use crate::models::Bitrate; use crate::RadioParadiseClient; use pmoserver::Server; use pmoupnp::devices::Device; @@ -55,7 +54,6 @@ pub struct MediaServerBuilder { friendly_name: String, manufacturer: String, model_name: String, - bitrate: Bitrate, channel: u8, port: u16, } @@ -66,7 +64,6 @@ impl Default for MediaServerBuilder { friendly_name: "Radio Paradise Media Server".to_string(), manufacturer: "PMOMusic".to_string(), model_name: "Radio Paradise Adapter".to_string(), - bitrate: Bitrate::Flac, channel: 0, port: 8080, } @@ -97,12 +94,6 @@ impl MediaServerBuilder { self } - /// Set the bitrate/quality level - pub fn with_bitrate(mut self, bitrate: Bitrate) -> Self { - self.bitrate = bitrate; - self - } - /// Set the Radio Paradise channel (0=main, 1=mellow, 2=rock, 3=world) pub fn with_channel(mut self, channel: u8) -> Self { self.channel = channel; @@ -119,7 +110,6 @@ impl MediaServerBuilder { pub async fn build(self) -> Result { // Create Radio Paradise client let client = RadioParadiseClient::builder() - .bitrate(self.bitrate) .channel(self.channel) .build() .await?; @@ -180,7 +170,6 @@ mod tests { fn test_builder_defaults() { let builder = MediaServerBuilder::default(); assert_eq!(builder.friendly_name, "Radio Paradise Media Server"); - assert_eq!(builder.bitrate, Bitrate::Flac); assert_eq!(builder.channel, 0); assert_eq!(builder.port, 8080); } @@ -189,12 +178,10 @@ mod tests { fn test_builder_customization() { let builder = MediaServerBuilder::new() .with_friendly_name("Custom Server") - .with_bitrate(Bitrate::Aac320) .with_channel(1) .with_port(9090); assert_eq!(builder.friendly_name, "Custom Server"); - assert_eq!(builder.bitrate, Bitrate::Aac320); assert_eq!(builder.channel, 1); assert_eq!(builder.port, 9090); } diff --git a/pmoparadise/src/models.rs b/pmoparadise/src/models.rs index 70d50748..cfad4bc8 100644 --- a/pmoparadise/src/models.rs +++ b/pmoparadise/src/models.rs @@ -122,65 +122,6 @@ where } } -/// Bitrate quality levels for Radio Paradise streams -/// -/// Radio Paradise offers 5 quality levels: -/// - 0: 128 kbps MP3 -/// - 1: AAC 64 kbps -/// - 2: AAC 128 kbps -/// - 3: AAC 320 kbps -/// - 4: FLAC lossless (CD quality or better) -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[repr(u8)] -pub enum Bitrate { - /// 128 kbps MP3 - Mp3_128 = 0, - /// AAC 64 kbps - Aac64 = 1, - /// AAC 128 kbps - Aac128 = 2, - /// AAC 320 kbps - Aac320 = 3, - /// FLAC lossless - Flac = 4, -} - -impl Bitrate { - /// Convert from u8 value - pub fn from_u8(value: u8) -> Result { - match value { - 0 => Ok(Self::Mp3_128), - 1 => Ok(Self::Aac64), - 2 => Ok(Self::Aac128), - 3 => Ok(Self::Aac320), - 4 => Ok(Self::Flac), - _ => Err(crate::error::Error::InvalidBitrate(value)), - } - } - - /// Convert to u8 value - pub fn as_u8(self) -> u8 { - self as u8 - } - - /// Get human-readable description - pub fn description(&self) -> &'static str { - match self { - Self::Mp3_128 => "MP3 128 kbps", - Self::Aac64 => "AAC 64 kbps", - Self::Aac128 => "AAC 128 kbps", - Self::Aac320 => "AAC 320 kbps", - Self::Flac => "FLAC Lossless", - } - } -} - -impl Default for Bitrate { - fn default() -> Self { - Self::Flac - } -} - /// Duration in milliseconds pub type DurationMs = u64; @@ -376,13 +317,6 @@ impl NowPlaying { mod tests { use super::*; - #[test] - fn test_bitrate_conversion() { - assert_eq!(Bitrate::from_u8(0).unwrap(), Bitrate::Mp3_128); - assert_eq!(Bitrate::from_u8(4).unwrap(), Bitrate::Flac); - assert!(Bitrate::from_u8(5).is_err()); - } - #[test] fn test_song_timing() { let song = Song { diff --git a/pmoparadise/src/pmoserver_ext.rs b/pmoparadise/src/pmoserver_ext.rs index d18a9b49..06fd583c 100644 --- a/pmoparadise/src/pmoserver_ext.rs +++ b/pmoparadise/src/pmoserver_ext.rs @@ -4,7 +4,7 @@ //! à un serveur pmoserver. use crate::paradise::{max_channel_id, ParadiseChannel, PlaylistEntry, ALL_CHANNELS}; -use crate::{models::Bitrate, Block, NowPlaying, RadioParadiseClient, RadioParadiseSource}; +use crate::{Block, NowPlaying, RadioParadiseClient, RadioParadiseSource}; use axum::{ body::Body, extract::{Path, Query, State}, @@ -34,7 +34,6 @@ pub struct RadioParadiseState { #[serde(default)] struct ParadiseQuery { channel: Option, - bitrate: Option, } #[derive(Debug, Default, Deserialize)] @@ -106,14 +105,6 @@ impl RadioParadiseState { client = client.clone_with_channel(channel); } - if let Some(bitrate_id) = params.bitrate { - let bitrate = Bitrate::from_u8(bitrate_id).map_err(|e| { - tracing::warn!("Invalid Radio Paradise bitrate requested: {}", e); - StatusCode::BAD_REQUEST - })?; - client = client.clone_with_bitrate(bitrate); - } - Ok(client) } @@ -288,8 +279,7 @@ impl From for NowPlayingResponse { get, path = "/now-playing", params( - ("channel" = Option, Query, description = "Channel ID (0-3)"), - ("bitrate" = Option, Query, description = "Bitrate ID (0-4)") + ("channel" = Option, Query, description = "Channel ID (0-3)") ), responses( (status = 200, description = "Morceau en cours", body = NowPlayingResponse), @@ -315,8 +305,7 @@ async fn get_now_playing( get, path = "/block/current", params( - ("channel" = Option, Query, description = "Channel ID (0-3)"), - ("bitrate" = Option, Query, description = "Bitrate ID (0-4)") + ("channel" = Option, Query, description = "Channel ID (0-3)") ), responses( (status = 200, description = "Block actuel", body = BlockResponse), @@ -343,8 +332,7 @@ async fn get_current_block( path = "/block/{event_id}", params( ("event_id" = u64, Path, description = "Event ID du block"), - ("channel" = Option, Query, description = "Channel ID (0-3)"), - ("bitrate" = Option, Query, description = "Bitrate ID (0-4)") + ("channel" = Option, Query, description = "Channel ID (0-3)") ), responses( (status = 200, description = "Block demandé", body = BlockResponse), @@ -384,15 +372,6 @@ async fn get_channels() -> Json> { Json(channels) } -/// Information sur un bitrate -#[derive(Debug, Clone, Serialize, ToSchema)] -pub struct BitrateInfo { - /// ID du bitrate (0-4) - pub id: u8, - /// Nom/description - pub name: String, -} - /// Statut opérationnel d'un canal Radio Paradise #[derive(Debug, Clone, Serialize, ToSchema)] pub struct ChannelStatusResponse { @@ -532,42 +511,6 @@ pub struct ChannelHistoryResponse { pub entries: Vec, } -/// GET /bitrates - Liste les bitrates disponibles -#[utoipa::path( - get, - path = "/bitrates", - responses( - (status = 200, description = "Liste des bitrates disponibles", body = Vec) - ), - tag = "Radio Paradise" -)] -async fn get_bitrates() -> Json> { - let bitrates = vec![ - BitrateInfo { - id: 0, - name: "MP3 128 kbps".to_string(), - }, - BitrateInfo { - id: 1, - name: "AAC 64 kbps".to_string(), - }, - BitrateInfo { - id: 2, - name: "AAC 128 kbps".to_string(), - }, - BitrateInfo { - id: 3, - name: "AAC 320 kbps".to_string(), - }, - BitrateInfo { - id: 4, - name: "FLAC Lossless".to_string(), - }, - ]; - - Json(bitrates) -} - /// GET /channels/{channel_id}/status - Statut détaillé d'un canal #[utoipa::path( get, @@ -840,7 +783,6 @@ async fn stream_channel( get_channel_status, get_channel_playlist, get_channel_history, - get_bitrates, stream_channel ), components(schemas( @@ -848,7 +790,6 @@ async fn stream_channel( BlockResponse, SongInfo, ChannelInfo, - BitrateInfo, ChannelStatusResponse, ChannelPlaylistEntry, ChannelPlaylistResponse, @@ -872,7 +813,6 @@ pub fn create_api_router(state: RadioParadiseState) -> Router { .route("/channels/{channel_id}/status", get(get_channel_status)) .route("/channels/{channel_id}/playlist", get(get_channel_playlist)) .route("/channels/{channel_id}/history", get(get_channel_history)) - .route("/bitrates", get(get_bitrates)) .route("/stream", get(stream_channel)) .with_state(state) }