Fix FLAC pk collision by skipping header for pk calculation

Problem: All FLAC files with the same format (44.1kHz, stereo, 16-bit)
had identical headers and thus the same pk (071c5713d5cf485ca688832207bef0f9).
This caused the cache to think all tracks were the same file, regardless
of channel selection or actual content.

Solution: Skip the FLAC header (first 512 bytes) and calculate the pk
from bytes 512-1024 (actual audio content) instead. This ensures each
track gets a unique pk based on its actual audio data, not just its
format header.

Changes:
- Modified add_from_reader_with_pk() to read 1024 bytes instead of 512
- Use bytes 512-1024 for pk calculation when explicit_pk is None
- This works even with poor metadata (empty artist/title)
- Maintains backward compatibility with explicit_pk parameter

Fixes the issue where changing radio channel played the same song.
This commit is contained in:
Claude
2025-11-07 06:23:35 +00:00
parent c92ad696de
commit 3bd2a33497
2 changed files with 38 additions and 4 deletions

View File

@@ -135,6 +135,8 @@ impl NodeLogic for FlacCacheSinkLogic {
// Ingérer le FLAC progressivement dans le cache
// add_from_reader lance l'ingestion en arrière-plan et retourne dès que
// le prebuffer (512 KB) est atteint, permettant un streaming progressif
// Le cache skip automatiquement le header FLAC (512 octets) pour calculer le pk
// à partir du contenu audio, évitant les collisions entre morceaux au même format
let collection_ref = self.collection.as_deref();
let cache_future = self.cache.add_from_reader(
None,

View File

@@ -368,13 +368,45 @@ impl<C: CacheConfig> Cache<C> {
where
R: AsyncRead + Send + Unpin + 'static,
{
// 1. Lire les 512 premiers octets pour calculer le pk
let header = crate::download::peek_reader_header(&mut reader, 512)
self.add_from_reader_with_pk(source_uri, reader, length, collection, None).await
}
/// Ajoute un fichier à partir d'un flux avec un pk explicite optionnel.
///
/// Si `explicit_pk` est fourni, utilise ce pk au lieu de le calculer à partir du contenu.
/// Ceci est utile quand plusieurs fichiers ont le même header mais doivent être cachés séparément
/// (par exemple, des fichiers FLAC avec le même format mais du contenu différent).
pub async fn add_from_reader_with_pk<R>(
&self,
source_uri: Option<&str>,
mut reader: R,
length: Option<u64>,
collection: Option<&str>,
explicit_pk: Option<String>,
) -> Result<String>
where
R: AsyncRead + Send + Unpin + 'static,
{
// 1. Lire les premiers octets pour calculer le pk
// Pour éviter les collisions entre fichiers FLAC au même format, on skip le header (512 octets)
// et on utilise les octets 512-1024 (début du contenu audio) pour calculer le pk
let buffer_size = if explicit_pk.is_none() { 1024 } else { 512 };
let header = crate::download::peek_reader_header(&mut reader, buffer_size)
.await
.map_err(|e| anyhow!("Failed to peek reader header: {}", e))?;
// 2. Calculer le pk basé sur le contenu
let pk = crate::cache_trait::pk_from_content_header(&header);
// 2. Calculer le pk: si pas de pk explicite, utiliser octets 512-1024 au lieu de 0-512
let pk = if let Some(explicit) = explicit_pk {
explicit
} else {
// Skip les 512 premiers octets (header FLAC) et utiliser les 512 suivants
let pk_bytes = if header.len() > 512 {
&header[512..]
} else {
&header[..]
};
crate::cache_trait::pk_from_content_header(pk_bytes)
};
if let Some(uri) = source_uri {
tracing::debug!("Computed pk {} for source_uri {}", pk, uri);
} else {