feat(lib): carry audio attributes in browse and folder listings

A browse listed each file as a name and a size, so a searcher who saw a
bitrate in a search reply lost it the moment they opened the sharer's
files. Listings (codes 5 and 37) now carry each file's attributes the
way Nicotine+ sends them, as a SharedFileEntry with name, size and
attributes in place of the (name, size) pair; the CLI's browse record
gains bitrate and duration, and the daemon protocol moves to version 2
for the new listing shape.
This commit is contained in:
Michel de Graaf
2026-09-08 01:44:49 +02:00
parent 5a20d69056
commit f6423a2ed6
20 changed files with 307 additions and 95 deletions
+14 -2
View File
@@ -30,12 +30,24 @@ use std::time::{Duration, Instant};
use soulseek_rs::message::Message;
use soulseek_rs::message::peer::{
FileEntry, SharedDirectory, build_file_search_response,
FileEntry, SharedDirectory, SharedFileEntry, build_file_search_response,
build_shared_file_list,
};
use soulseek_rs::message::server::MessageFactory;
use soulseek_rs::{Client, ClientSettings, ClientVersion, PeerAddress};
/// A mock's `(name, size)` files in listing form; mocks advertise no attributes.
fn entries(files: &[(String, u64)]) -> Vec<SharedFileEntry> {
files
.iter()
.map(|(name, size)| SharedFileEntry {
name: name.clone(),
size: *size,
attributes: Vec::new(),
})
.collect()
}
/// Files matching this tag are what every mock seeder answers searches for.
const TAG: &str = "zqxstress";
@@ -536,7 +548,7 @@ impl SeederState {
fn send_listing(&self, p: &mut TcpStream, shared: bool) -> bool {
let dir = SharedDirectory {
name: format!("stress\\{}", self.name),
files: self.files.clone(),
files: entries(&self.files),
};
let list = build_shared_file_list(std::slice::from_ref(&dir));
self.reply(p, shared, &list.get_buffer())