Added network catalog slices

This commit is contained in:
Ultradesu
2026-07-25 22:40:27 +03:00
parent b725ca8d05
commit 788bc2e01f
14 changed files with 878 additions and 152 deletions
+94
View File
@@ -32,6 +32,7 @@ use rusqlite::{Connection, OpenFlags, params};
use serde::{Deserialize, Serialize};
use crate::library::Library;
use crate::library::NetworkArtistPreview;
use crate::library::models::{ArtistRef, TrackItem};
pub use audio::{AUDIO_ALPN, DownloadProgress, StreamingStart, TrackMetadata};
@@ -395,6 +396,12 @@ pub struct FedPlayable {
pub imported: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NetworkLibrarySource {
pub endpoint_id: String,
pub kind: &'static str,
}
// ---------------------------------------------------------------------------
// The federation manager (lives in Runtime, not AppState)
// ---------------------------------------------------------------------------
@@ -862,6 +869,93 @@ impl Federation {
status
}
pub async fn network_library_sources(
&self,
mode: crate::config::settings::LibrarySourceMode,
) -> Result<Vec<NetworkLibrarySource>> {
if !mode.includes_network() {
return Ok(Vec::new());
}
let service = self.service().await?;
let own = service.endpoint_id().to_string();
let mut seen = std::collections::HashSet::new();
seen.insert(own);
let mut sources = Vec::new();
for endpoint_id in self.devices.active_remote_endpoint_ids()? {
if seen.insert(endpoint_id.clone()) {
sources.push(NetworkLibrarySource {
endpoint_id,
kind: "personal",
});
}
}
if mode.includes_global_peers() {
for endpoint in service
.connected_peers()
.into_iter()
.map(|peer| peer.to_string())
.chain(
service
.known_peers()
.into_iter()
.map(|peer| peer.peer_id.to_string()),
)
{
if seen.insert(endpoint.clone()) {
sources.push(NetworkLibrarySource {
endpoint_id: endpoint,
kind: "federation",
});
}
if sources.len() >= 32 {
break;
}
}
}
Ok(sources)
}
pub async fn cache_artist_slice_from_source(
&self,
source: NetworkLibrarySource,
cursor: Option<String>,
limit: usize,
) -> Result<(usize, Option<String>)> {
let service = self.service().await?;
let owner = EndpointId::from_str(&source.endpoint_id)
.map_err(|_| anyhow::anyhow!("malformed endpoint id '{}'", source.endpoint_id))?;
let replace_source = cursor.is_none();
let (artists, next_cursor) = catalog::fetch_artist_slice(
&service,
owner,
cursor.as_deref(),
limit,
&self.transport_stats,
)
.await?;
let artists: Vec<NetworkArtistPreview> = artists
.into_iter()
.map(|artist| NetworkArtistPreview {
artist_key: if artist.artist_key.trim().is_empty() {
music_dht::normalize_name(&artist.name)
} else {
artist.artist_key
},
name: artist.name,
image_path: None,
release_count: artist.release_count,
track_count: artist.track_count,
})
.collect();
let count = self.library.replace_network_artist_cache(
&source.endpoint_id,
source.kind,
&artists,
replace_source,
)?;
Ok((count, next_cursor))
}
/// Searches the federated network: matching tracks plus the artists a
/// card can be assembled for (from artist records and from the artist
/// names of matching tracks/releases).