implement row meta info

This commit is contained in:
yggverse 2025-08-05 16:12:14 +03:00
parent 7da285ca69
commit d014358028
5 changed files with 66 additions and 5 deletions

View file

@ -40,6 +40,12 @@ pub struct Config {
#[arg(long)] #[arg(long)]
pub tracker: Option<Vec<Url>>, pub tracker: Option<Vec<Url>>,
/// Format timestamps (on the web view)
///
/// * tip: escape with `%%d/%%m/%%Y %%H:%%M` in the CLI/bash argument
#[arg(long, short, default_value_t = String::from("%d/%m/%Y %H:%M"))]
pub format_time: String,
/// Bind server on given host /// Bind server on given host
#[arg(long, short, default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))] #[arg(long, short, default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
pub address: IpAddr, pub address: IpAddr,

View file

@ -24,6 +24,7 @@ use url::Url;
pub struct Meta { pub struct Meta {
pub canonical: Option<Url>, pub canonical: Option<Url>,
pub description: Option<String>, pub description: Option<String>,
pub format_time: String,
pub stats: Option<Url>, pub stats: Option<Url>,
pub title: String, pub title: String,
pub trackers: Option<HashSet<Url>>, pub trackers: Option<HashSet<Url>>,
@ -34,8 +35,11 @@ fn index(storage: &State<Storage>, meta: &State<Meta>) -> Result<Template, Custo
#[derive(Serialize)] #[derive(Serialize)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
struct Row { struct Row {
torrent: Torrent, created: Option<String>,
indexed: String,
magnet: String, magnet: String,
size: String,
torrent: Torrent,
} }
Ok(Template::render( Ok(Template::render(
"index", "index",
@ -49,7 +53,10 @@ fn index(storage: &State<Storage>, meta: &State<Meta>) -> Result<Template, Custo
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))? .map_err(|e| Custom(Status::InternalServerError, e.to_string()))?
.into_iter() .into_iter()
.map(|torrent| Row { .map(|torrent| Row {
created: torrent.creation_date.map(|t|t.format(&meta.format_time).to_string()),
indexed: torrent.time.format(&meta.format_time).to_string(),
magnet: format::magnet(&torrent.info_hash, meta.trackers.as_ref()), magnet: format::magnet(&torrent.info_hash, meta.trackers.as_ref()),
size: format::bytes(torrent.size),
torrent, torrent,
}) })
.collect::<Vec<Row>>() .collect::<Vec<Row>>()
@ -95,6 +102,7 @@ fn rocket() -> _ {
.manage(Meta { .manage(Meta {
canonical: config.link, canonical: config.link,
description: config.description, description: config.description,
format_time: config.format_time,
stats: config.stats, stats: config.stats,
title: config.title, title: config.title,
trackers: config.tracker.map(|u| u.into_iter().collect()), trackers: config.tracker.map(|u| u.into_iter().collect()),

View file

@ -40,6 +40,7 @@ pub struct Torrent {
pub name: Option<String>, pub name: Option<String>,
pub publisher_url: Option<String>, pub publisher_url: Option<String>,
pub publisher: Option<String>, pub publisher: Option<String>,
pub size: u64,
/// File (modified) /// File (modified)
pub time: DateTime<Utc>, pub time: DateTime<Utc>,
} }
@ -90,6 +91,7 @@ impl Storage {
&fs::read(file.path()).map_err(|e| e.to_string())?, &fs::read(file.path()).map_err(|e| e.to_string())?,
) )
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
b.push(Torrent { b.push(Torrent {
info_hash: i.info_hash.as_string(), info_hash: i.info_hash.as_string(),
announce: i.announce.map(|a| a.to_string()), announce: i.announce.map(|a| a.to_string()),
@ -98,6 +100,12 @@ impl Storage {
creation_date: i creation_date: i
.creation_date .creation_date
.map(|t| DateTime::from_timestamp_nanos(t as i64)), .map(|t| DateTime::from_timestamp_nanos(t as i64)),
size: i.info.length.unwrap_or_default()
+ i.info
.files
.as_ref()
.map(|files| files.iter().map(|f| f.length).sum::<u64>())
.unwrap_or_default(),
files: i.info.files.map(|files| { files: i.info.files.map(|files| {
let limit = 1000; // @TODO let limit = 1000; // @TODO
let mut b = Vec::with_capacity(files.len()); let mut b = Vec::with_capacity(files.len());

View file

@ -4,7 +4,13 @@
<div> <div>
<a name="{{ row.torrent.info_hash }}"></a> <a name="{{ row.torrent.info_hash }}"></a>
<h2>{{ row.torrent.name }}</h2> <h2>{{ row.torrent.name }}</h2>
{% if row.torrent.comment %}<p>{{ row.torrent.comment }}</p>{% endif %}
<div> <div>
<ul>
<li><span title="Indexed">{{ row.indexed }}</span>{%
if row.created %} <span title="Created">({{ row.created }})</span>{% endif %}</li>{%
if row.size %}<li><span title="Size">{{ row.size }}</span></li>{% endif %}
</ul>
<a rel="nofollow" href="{{ row.magnet }}" title="Magnet"> <a rel="nofollow" href="{{ row.magnet }}" title="Magnet">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
<path d="M15 12h-4v3h4v-3ZM5 12H1v3h4v-3ZM0 8a8 8 0 1 1 16 0v8h-6V8a2 2 0 1 0-4 0v8H0V8Z"/> <path d="M15 12h-4v3h4v-3ZM5 12H1v3h4v-3ZM0 8a8 8 0 1 1 16 0v8h-6V8a2 2 0 1 0-4 0v8H0V8Z"/>

View file

@ -94,12 +94,45 @@
padding: 24px; padding: 24px;
} }
/* controls */ /* description */
main > div > div { main > div > p {
float: right; margin: 8px 0;
} }
main > div > div > a> svg { /* meta, controls */
main > div > div {
border-top: 1px #4f536a solid;
margin-top: 16px;
overflow: hidden;
padding-top: 16px;
}
main > div > div > ul {
list-style: none;
}
main > div > div > ul > li {
cursor: default;
float: left;
}
main > div > div > ul > li > span {
color: white;
font-size: smaller;
opacity: 0.7;
}
main > div > div > ul > li > span:hover {
opacity: 1;
}
main > div > div > ul > li:not(:last-child)::after {
content: "•";
margin: 0 6px;
}
main > div > div > a > svg {
float: right;
vertical-align: middle; vertical-align: middle;
} }
</style> </style>