mirror of
https://github.com/YGGverse/btracker.git
synced 2026-03-31 17:15:31 +00:00
152 lines
4.7 KiB
Rust
152 lines
4.7 KiB
Rust
#[macro_use]
|
|
extern crate rocket;
|
|
|
|
mod config;
|
|
mod feed;
|
|
mod format;
|
|
mod scraper;
|
|
mod storage;
|
|
|
|
use config::Config;
|
|
use feed::Feed;
|
|
use rocket::{
|
|
State,
|
|
http::Status,
|
|
response::{content::RawXml, status::Custom},
|
|
serde::Serialize,
|
|
};
|
|
use rocket_dyn_templates::{Template, context};
|
|
use scraper::{Scrape, Scraper};
|
|
use storage::{Order, Sort, Storage, Torrent};
|
|
use url::Url;
|
|
|
|
#[derive(Clone, Debug, Serialize)]
|
|
#[serde(crate = "rocket::serde")]
|
|
pub struct Meta {
|
|
pub canonical: Option<Url>,
|
|
pub description: Option<String>,
|
|
pub format_time: String,
|
|
pub title: String,
|
|
/// * use vector to keep the order from the arguments list
|
|
pub trackers: Option<Vec<Url>>,
|
|
pub version: String,
|
|
}
|
|
|
|
#[get("/?<page>")]
|
|
fn index(
|
|
page: Option<usize>,
|
|
scraper: &State<Scraper>,
|
|
storage: &State<Storage>,
|
|
meta: &State<Meta>,
|
|
) -> Result<Template, Custom<String>> {
|
|
use plurify::Plurify;
|
|
#[derive(Serialize)]
|
|
#[serde(crate = "rocket::serde")]
|
|
struct Row {
|
|
created: Option<String>,
|
|
files: String,
|
|
indexed: String,
|
|
magnet: String,
|
|
scrape: Option<Scrape>,
|
|
size: String,
|
|
torrent: Torrent,
|
|
}
|
|
let (total, torrents) = storage
|
|
.torrents(
|
|
Some((Sort::Modified, Order::Desc)),
|
|
page.map(|p| if p > 0 { p - 1 } else { p } * storage.default_limit),
|
|
Some(storage.default_limit),
|
|
)
|
|
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))?;
|
|
Ok(Template::render(
|
|
"index",
|
|
context! {
|
|
meta: meta.inner(),
|
|
back: page.map(|p| uri!(index(if p > 2 { Some(p - 1) } else { None }))),
|
|
next: if page.unwrap_or(1) * storage.default_limit >= total { None }
|
|
else { Some(uri!(index(Some(page.map_or(2, |p| p + 1))))) },
|
|
rows: torrents
|
|
.into_iter()
|
|
.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()),
|
|
scrape: scraper.scrape(&torrent.info_hash),
|
|
size: format::bytes(torrent.size),
|
|
files: torrent.files.as_ref().map_or("1 file".into(), |f| {
|
|
let l = f.len();
|
|
format!("{l} {}", l.plurify(&["file", "files", "files"]))
|
|
}),
|
|
torrent,
|
|
})
|
|
.collect::<Vec<Row>>(),
|
|
pagination_totals: format!(
|
|
"Page {} / {} ({total} {} total)",
|
|
page.unwrap_or(1),
|
|
(total as f64 / storage.default_limit as f64).ceil(),
|
|
total.plurify(&["torrent", "torrents", "torrents"])
|
|
)
|
|
},
|
|
))
|
|
}
|
|
|
|
#[get("/rss")]
|
|
fn rss(feed: &State<Feed>, storage: &State<Storage>) -> Result<RawXml<String>, Custom<String>> {
|
|
let mut b = feed.transaction(1024); // @TODO
|
|
for torrent in storage
|
|
.torrents(
|
|
Some((Sort::Modified, Order::Desc)),
|
|
None,
|
|
Some(storage.default_limit),
|
|
)
|
|
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))?
|
|
.1
|
|
{
|
|
feed.push(&mut b, torrent)
|
|
}
|
|
Ok(RawXml(feed.commit(b)))
|
|
}
|
|
|
|
#[launch]
|
|
fn rocket() -> _ {
|
|
use clap::Parser;
|
|
let config = Config::parse();
|
|
let feed = Feed::init(
|
|
config.title.clone(),
|
|
config.description.clone(),
|
|
config.canonical_url.clone(),
|
|
config.tracker.clone(),
|
|
);
|
|
let scraper = Scraper::init(
|
|
config
|
|
.scrape_udp_server
|
|
.map(|s| (config.scrape_udp_client, s)),
|
|
);
|
|
let storage = Storage::init(config.preload, config.list_limit, config.capacity).unwrap(); // @TODO handle
|
|
rocket::build()
|
|
.attach(Template::fairing())
|
|
.configure(rocket::Config {
|
|
port: config.port,
|
|
address: config.host,
|
|
..if config.debug {
|
|
rocket::Config::debug_default()
|
|
} else {
|
|
rocket::Config::default()
|
|
}
|
|
})
|
|
.manage(feed)
|
|
.manage(scraper)
|
|
.manage(storage)
|
|
.manage(Meta {
|
|
canonical: config.canonical_url,
|
|
description: config.description,
|
|
format_time: config.format_time,
|
|
title: config.title,
|
|
trackers: config.tracker,
|
|
version: env!("CARGO_PKG_VERSION").into(),
|
|
})
|
|
.mount("/", rocket::fs::FileServer::from(config.statics))
|
|
.mount("/", routes![index, rss])
|
|
}
|