diff --git a/public/theme/default.css b/public/theme/default.css index 60c145d..63eda6f 100644 --- a/public/theme/default.css +++ b/public/theme/default.css @@ -67,7 +67,38 @@ table > thead > tr > th { } table > tbody > tr:hover > td { - background: var(--background) + background: var(--background); +} + +form { + margin-top: 16px; +} + +form input { + background: var(--item); + border-color: var(--item); + border-radius: 3px; + border-style: solid; + border-width: 1px; + color: var(--default); + opacity: 0.9; +} + +form input:hover { + opacity: 1; +} + +form input[type="text"] { + padding: 8px; +} + +form input[type="text"]:focus { + border-color: var(--separator); +} + +form input[type="submit"] { + cursor: pointer; + padding: 8px 16px; } body > * { diff --git a/src/main.rs b/src/main.rs index e761b61..082aea6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,8 +19,9 @@ use scraper::{Scrape, Scraper}; use std::str::FromStr; use torrent::Torrent; -#[get("/?")] +#[get("/?&")] fn index( + search: Option<&str>, page: Option, scraper: &State, public: &State, @@ -39,6 +40,7 @@ fn index( } let (total, torrents) = public .torrents( + search, Some((Sort::Modified, Order::Desc)), page.map(|p| if p > 0 { p - 1 } else { p } * public.default_limit), Some(public.default_limit), @@ -52,6 +54,10 @@ fn index( context! { title: { let mut t = String::new(); + if let Some(q) = search && !q.is_empty() { + t.push_str(q); + t.push_str(S) + } if let Some(p) = page && p > 1 { t.push_str(&format!("Page {p}")); t.push_str(S) @@ -64,9 +70,9 @@ fn index( t }, meta: meta.inner(), - back: page.map(|p| uri!(index(if p > 2 { Some(p - 1) } else { None }))), + back: page.map(|p| uri!(index(search, if p > 2 { Some(p - 1) } else { None }))), next: if page.unwrap_or(1) * public.default_limit >= total { None } - else { Some(uri!(index(Some(page.map_or(2, |p| p + 1))))) }, + else { Some(uri!(index(search, Some(page.map_or(2, |p| p + 1))))) }, rows: torrents .into_iter() .filter_map(|t| match Torrent::from_public(&t.bytes, t.time) { @@ -90,7 +96,8 @@ fn index( page.unwrap_or(1), (total as f64 / public.default_limit as f64).ceil(), total.plurify(&["torrent", "torrents", "torrents"]) - ) + ), + search }, )) } @@ -164,6 +171,7 @@ fn rss(meta: &State, public: &State) -> Result, Sta ); for t in public .torrents( + None, Some((Sort::Modified, Order::Desc)), None, Some(public.default_limit), diff --git a/src/public.rs b/src/public.rs index 448d5c7..34327bf 100644 --- a/src/public.rs +++ b/src/public.rs @@ -26,8 +26,8 @@ pub struct Torrent { } pub struct Public { - pub default_limit: usize, default_capacity: usize, + pub default_limit: usize, root: PathBuf, } @@ -43,8 +43,8 @@ impl Public { return Err("Public root is not directory".into()); } Ok(Self { - default_limit, default_capacity, + default_limit, root: root.canonicalize().map_err(|e| e.to_string())?, }) } @@ -62,11 +62,12 @@ impl Public { pub fn torrents( &self, + keyword: Option<&str>, sort_order: Option<(Sort, Order)>, start: Option, limit: Option, ) -> Result<(usize, Vec), Error> { - let f = self.files(sort_order)?; + let f = self.files(keyword, sort_order)?; let t = f.len(); let l = limit.unwrap_or(t); let mut b = Vec::with_capacity(l); @@ -96,13 +97,40 @@ impl Public { // Helpers - fn files(&self, sort_order: Option<(Sort, Order)>) -> Result, Error> { + fn files( + &self, + keyword: Option<&str>, + sort_order: Option<(Sort, Order)>, + ) -> Result, Error> { let mut b = Vec::with_capacity(self.default_capacity); for entry in fs::read_dir(&self.root)? { let e = entry?; - if e.file_type()?.is_file() && e.path().extension().is_some_and(|e| e == EXTENSION) { - b.push((e.metadata()?.modified()?, e)) + let p = e.path(); + if !p.is_file() || p.extension().is_none_or(|e| e != EXTENSION) { + continue; } + if keyword.is_some_and(|k| { + !k.is_empty() + && !librqbit_core::torrent_metainfo::torrent_from_bytes( + &fs::read(e.path()).unwrap(), + ) + .is_ok_and( + |m: librqbit_core::torrent_metainfo::TorrentMetaV1Owned| { + m.info_hash.as_string().contains(k) + || m.info.name.is_some_and(|n| n.to_string().contains(k)) + || m.info.files.is_some_and(|f| { + f.iter().any(|f| { + let mut p = PathBuf::new(); + f.full_path(&mut p) + .is_ok_and(|_| p.to_string_lossy().contains(k)) + }) + }) + }, + ) // @TODO implement fast in-memory search index + }) { + continue; + } + b.push((e.metadata()?.modified()?, e)) } if let Some((sort, order)) = sort_order { match sort { diff --git a/templates/layout/default.html.tera b/templates/layout/default.html.tera index 8fc4231..52c0310 100644 --- a/templates/layout/default.html.tera +++ b/templates/layout/default.html.tera @@ -14,6 +14,10 @@ {% if meta.trackers %}
{% for tracker in meta.trackers %}{{ tracker }}{% endfor %}
{% endif %} +
+ + +
{% block content %}{% endblock content %}