From 792ac5cb95c6feb342c7e00b3cc1091d068f36ad Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Sat, 22 Nov 2025 10:51:14 +0100 Subject: [PATCH] =?UTF-8?q?metadonn=C3=A9e=20technique=20dans=20le=20cache?= =?UTF-8?q?=20audio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + pmoaudio-ext/Cargo.toml | 3 +- pmoaudio-ext/src/sinks/flac_cache_sink.rs | 40 +++++++++++++++++++++++ pmoaudiocache/src/cache.rs | 36 ++++++++++++++++++++ pmoaudiocache/src/streaming.rs | 15 ++++++++- pmocache/src/download.rs | 4 +++ 6 files changed, 97 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb607e13..cda2f193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3065,6 +3065,7 @@ dependencies = [ "pmoplaylist", "rand 0.8.5", "serde", + "serde_json", "tokio", "tokio-util", "tracing", diff --git a/pmoaudio-ext/Cargo.toml b/pmoaudio-ext/Cargo.toml index 112c8a8a..e78cc9a9 100644 --- a/pmoaudio-ext/Cargo.toml +++ b/pmoaudio-ext/Cargo.toml @@ -29,10 +29,11 @@ rand = "0.8" # HTTP streaming dependencies bytes = { version = "1.0", optional = true } serde = { version = "1.0", features = ["derive"], optional = true } +serde_json = { version = "1.0", optional = true } [features] default = [] -cache-sink = ["dep:pmoaudiocache", "dep:pmoflac", "dep:pmometadata"] +cache-sink = ["dep:pmoaudiocache", "dep:pmoflac", "dep:pmometadata", "dep:serde_json"] playlist = ["cache-sink", "dep:pmoplaylist", "dep:pmocache"] http-stream = ["dep:pmoflac", "dep:pmometadata", "dep:bytes", "dep:serde"] all = ["cache-sink", "playlist", "http-stream"] diff --git a/pmoaudio-ext/src/sinks/flac_cache_sink.rs b/pmoaudio-ext/src/sinks/flac_cache_sink.rs index 43f0cf2f..26598090 100755 --- a/pmoaudio-ext/src/sinks/flac_cache_sink.rs +++ b/pmoaudio-ext/src/sinks/flac_cache_sink.rs @@ -8,6 +8,7 @@ use pmoaudio::{ }; use pmoaudiocache::AudioTrackMetadataExt; use pmoflac::{encode_flac_stream, EncoderOptions, PcmFormat}; +use serde_json::{Number, Value}; use std::{ collections::VecDeque, pin::Pin, @@ -289,6 +290,10 @@ impl NodeLogic for FlacCacheSinkLogic { } }; + if let Some(transform) = self.cache.transform_metadata(&pk).await { + persist_transform_streaminfo(&self.cache, &pk, &transform); + } + // Phase 2: Prebuffer terminé! Copier les métadonnées et pusher à la playlist // Copier les métadonnées du TrackBoundary dans le cache // IMPORTANT: Faire ceci AVANT d'ajouter à la playlist pour que les métadonnées soient disponibles @@ -910,6 +915,41 @@ async fn pump_track_segments_from_channel( } } +fn persist_transform_streaminfo( + cache: &pmoaudiocache::Cache, + pk: &str, + tmeta: &pmocache::download::TransformMetadata, +) { + if let Some(sr) = tmeta.sample_rate { + let _ = cache + .db + .set_a_metadata(pk, "sample_rate", Value::Number(Number::from(sr))); + } + if let Some(bps) = tmeta.bits_per_sample { + let _ = cache + .db + .set_a_metadata(pk, "bits_per_sample", Value::Number(Number::from(bps))); + } + if let Some(ch) = tmeta.channels { + let _ = cache + .db + .set_a_metadata(pk, "channels", Value::Number(Number::from(ch))); + } + if let Some(ts) = tmeta.total_samples { + let _ = cache + .db + .set_a_metadata(pk, "total_samples", Value::Number(Number::from(ts))); + if let Some(sr) = tmeta.sample_rate { + if sr > 0 { + let secs = (ts as f64 / sr as f64).round() as u64; + let _ = cache + .db + .set_a_metadata(pk, "duration_secs", Value::Number(Number::from(secs))); + } + } + } +} + /// Détermine la profondeur de bit d'un chunk audio fn get_chunk_bit_depth(chunk: &AudioChunk) -> u8 { match chunk { diff --git a/pmoaudiocache/src/cache.rs b/pmoaudiocache/src/cache.rs index 7a02ebdd..c408d2dd 100644 --- a/pmoaudiocache/src/cache.rs +++ b/pmoaudiocache/src/cache.rs @@ -8,6 +8,7 @@ use anyhow::Result; use pmocache::CacheConfig; use serde_json::{Number, Value}; use std::sync::Arc; +use pmocache::download::TransformMetadata; /// Configuration pour le cache audio pub struct AudioConfig; @@ -56,6 +57,37 @@ pub fn new_cache(dir: &str, limit: usize) -> Result { Cache::with_transformer(dir, limit, Some(transformer_factory)) } +fn persist_transform_streaminfo(cache: &Cache, pk: &str, tmeta: &TransformMetadata) { + if let Some(sr) = tmeta.sample_rate { + let _ = cache + .db + .set_a_metadata(pk, "sample_rate", Value::Number(Number::from(sr))); + } + if let Some(bps) = tmeta.bits_per_sample { + let _ = cache + .db + .set_a_metadata(pk, "bits_per_sample", Value::Number(Number::from(bps))); + } + if let Some(ch) = tmeta.channels { + let _ = cache + .db + .set_a_metadata(pk, "channels", Value::Number(Number::from(ch))); + } + if let Some(ts) = tmeta.total_samples { + let _ = cache + .db + .set_a_metadata(pk, "total_samples", Value::Number(Number::from(ts))); + if let Some(sr) = tmeta.sample_rate { + if sr > 0 { + let secs = (ts as f64 / sr as f64).round() as u64; + let _ = cache + .db + .set_a_metadata(pk, "duration_secs", Value::Number(Number::from(secs))); + } + } + } +} + /// Crée un cache audio et lance la consolidation en arrière-plan /// /// Cette fonction crée le cache et lance immédiatement une consolidation @@ -138,6 +170,10 @@ pub async fn add_with_metadata_extraction( // Attendre que le fichier soit téléchargé et converti cache.wait_until_finished(&pk).await?; + if let Some(transform) = cache.transform_metadata(&pk).await { + persist_transform_streaminfo(cache, &pk, &transform); + } + // Lire le fichier FLAC pour extraire les métadonnées let file_path = cache.get_file_path(&pk); let flac_bytes = tokio::fs::read(&file_path).await?; diff --git a/pmoaudiocache/src/streaming.rs b/pmoaudiocache/src/streaming.rs index 86e9f40a..c086de30 100644 --- a/pmoaudiocache/src/streaming.rs +++ b/pmoaudiocache/src/streaming.rs @@ -9,6 +9,7 @@ use bytes::Bytes; use pmocache::download::TransformMetadata; use pmocache::StreamTransformer; use pmoflac::{transcode_to_flac_stream, AudioCodec, TranscodeOptions}; +use serde_json::json; use tokio::io::{AsyncReadExt, AsyncWriteExt}; /// Creates the transformer consumed by the audio cache. @@ -36,7 +37,19 @@ pub fn create_streaming_flac_transformer() -> StreamTransformer { .set_metadata(TransformMetadata { mode: Some(mode.to_string()), input_codec: Some(codec_to_string(codec)), - details: None, + details: Some( + json!({ + "sample_rate": info.sample_rate, + "bits_per_sample": info.bits_per_sample, + "channels": info.channels, + "total_samples": info.total_samples, + }) + .to_string(), + ), + sample_rate: Some(info.sample_rate), + bits_per_sample: Some(info.bits_per_sample), + channels: Some(info.channels), + total_samples: info.total_samples, }) .await; diff --git a/pmocache/src/download.rs b/pmocache/src/download.rs index aaeb12d6..9e58efa7 100644 --- a/pmocache/src/download.rs +++ b/pmocache/src/download.rs @@ -290,6 +290,10 @@ pub struct TransformMetadata { pub mode: Option, pub input_codec: Option, pub details: Option, + pub sample_rate: Option, + pub bits_per_sample: Option, + pub channels: Option, + pub total_samples: Option, } pub struct TransformContext {