From 09dba402cd21b6b66d62e8a17eb89478c7d30553 Mon Sep 17 00:00:00 2001 From: yggverse Date: Mon, 8 Sep 2025 16:29:52 +0300 Subject: [PATCH] implement files list --- src/format.rs | 46 ++++++++++++++++++++++++---------------------- src/main.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/format.rs b/src/format.rs index 64a706b..eafbd8a 100644 --- a/src/format.rs +++ b/src/format.rs @@ -7,31 +7,33 @@ pub fn files(meta: &TorrentMetaV1Owned) -> String { format!("{total} {}", total.plurify(&["file", "files", "files"])) } -pub fn size(meta: &TorrentMetaV1Owned) -> String { - fn s(value: u64) -> String { - const KB: f32 = 1024.0; - const MB: f32 = KB * KB; - const GB: f32 = MB * KB; +pub fn size(value: u64) -> String { + const KB: f32 = 1024.0; + const MB: f32 = KB * KB; + const GB: f32 = MB * KB; - let f = value as f32; + let f = value as f32; - if f < KB { - format!("{value} B") - } else if f < MB { - format!("{:.2} KB", f / KB) - } else if f < GB { - format!("{:.2} MB", f / MB) - } else { - format!("{:.2} GB", f / GB) - } + if f < KB { + format!("{value} B") + } else if f < MB { + format!("{:.2} KB", f / KB) + } else if f < GB { + format!("{:.2} MB", f / MB) + } else { + format!("{:.2} GB", f / GB) } - s(meta - .info - .files - .as_ref() - .map(|files| files.iter().map(|file| file.length).sum::()) - .unwrap_or_default() - + meta.info.length.unwrap_or_default()) +} + +pub fn total(meta: &TorrentMetaV1Owned) -> String { + size( + meta.info + .files + .as_ref() + .map(|files| files.iter().map(|file| file.length).sum::()) + .unwrap_or_default() + + meta.info.length.unwrap_or_default(), + ) } pub fn magnet(meta: &TorrentMetaV1Owned, trackers: Option<&Vec>) -> String { diff --git a/src/main.rs b/src/main.rs index a734526..8f8fee2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ use std::{ fs::File, io::{Read, Write}, net::{SocketAddr, TcpListener, TcpStream}, + path::PathBuf, str::FromStr, sync::Arc, thread, @@ -301,7 +302,7 @@ fn index(config: &Config, public: &Public, page: Option) -> Result) -> Result Result { + struct File { + path: Option, + length: u64, + } + impl File { + pub fn path(&self) -> String { + self.path + .as_ref() + .map(|p| p.to_string_lossy().into()) + .unwrap_or("?".into()) + } + } + let i: TorrentMetaV1Owned = torrent_from_bytes(&torrent.bytes)?; let mut b = Vec::new(); @@ -351,7 +365,7 @@ fn info(config: &Config, torrent: Torrent) -> Result { b.push(format!( "{} • {} • {}\n", torrent.time.format(&config.date), - format::size(&i), + format::total(&i), format::files(&i), )); @@ -360,5 +374,29 @@ fn info(config: &Config, torrent: Torrent) -> Result { format::magnet(&i, config.tracker.as_ref()) )); + if let Some(files) = i.info.files.map(|files| { + let mut b = Vec::with_capacity(files.len()); + for f in files { + let mut p = std::path::PathBuf::new(); + b.push(File { + length: f.length, + path: match f.full_path(&mut p) { + Ok(()) => Some(p), + Err(e) => { + warn!("Filename decode error: {e}"); + None + } + }, + }) + } + b.sort_by(|a, b| a.path.cmp(&b.path)); // @TODO optional + b + }) { + b.push("## Files".into()); + for file in files { + b.push(format!("* {} ({})", file.path(), format::size(file.length))); + } + } + Ok(b.join("\n")) }