mirror of
https://github.com/YGGverse/btracker.git
synced 2026-03-31 09:05:30 +00:00
init info page features
This commit is contained in:
parent
c5a0684466
commit
2fc9535710
7 changed files with 121 additions and 47 deletions
30
src/format.rs
Normal file
30
src/format.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
use crate::{Meta, Scrape, Scraper, Torrent};
|
||||
use rocket::{State, serde::Serialize};
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Format {
|
||||
pub created: Option<String>,
|
||||
pub files: String,
|
||||
pub indexed: String,
|
||||
pub magnet: String,
|
||||
pub scrape: Option<Scrape>,
|
||||
pub size: String,
|
||||
pub torrent: Torrent,
|
||||
}
|
||||
|
||||
impl Format {
|
||||
pub fn from_torrent(torrent: Torrent, scraper: &State<Scraper>, meta: &State<Meta>) -> Self {
|
||||
Self {
|
||||
created: torrent
|
||||
.creation_date
|
||||
.map(|t| t.format(&meta.format_time).to_string()),
|
||||
indexed: torrent.time.format(&meta.format_time).to_string(),
|
||||
magnet: torrent.magnet(meta.trackers.as_ref()),
|
||||
scrape: scraper.scrape(&torrent.info_hash),
|
||||
size: torrent.size(),
|
||||
files: torrent.files(),
|
||||
torrent,
|
||||
}
|
||||
}
|
||||
}
|
||||
75
src/main.rs
75
src/main.rs
|
|
@ -3,36 +3,27 @@ extern crate rocket;
|
|||
|
||||
mod config;
|
||||
mod feed;
|
||||
mod format;
|
||||
mod meta;
|
||||
mod scraper;
|
||||
mod storage;
|
||||
mod torrent;
|
||||
|
||||
use config::Config;
|
||||
use feed::Feed;
|
||||
use format::Format;
|
||||
use meta::Meta;
|
||||
use plurify::Plurify;
|
||||
use rocket::{
|
||||
State,
|
||||
http::Status,
|
||||
response::{content::RawXml, status::Custom},
|
||||
serde::Serialize,
|
||||
};
|
||||
use rocket_dyn_templates::{Template, context};
|
||||
use scraper::{Scrape, Scraper};
|
||||
use std::str::FromStr;
|
||||
use storage::{Order, Sort, Storage};
|
||||
use torrent::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(
|
||||
|
|
@ -41,18 +32,6 @@ fn index(
|
|||
storage: &State<Storage>,
|
||||
meta: &State<Meta>,
|
||||
) -> Result<Template, Custom<String>> {
|
||||
#[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)),
|
||||
|
|
@ -74,23 +53,13 @@ fn index(
|
|||
rows: torrents
|
||||
.into_iter()
|
||||
.filter_map(|t| match Torrent::from_storage(&t.bytes, t.time) {
|
||||
Ok(torrent) => Some(Row {
|
||||
created: torrent
|
||||
.creation_date
|
||||
.map(|t| t.format(&meta.format_time).to_string()),
|
||||
indexed: torrent.time.format(&meta.format_time).to_string(),
|
||||
magnet: torrent.magnet(meta.trackers.as_ref()),
|
||||
scrape: scraper.scrape(&torrent.info_hash),
|
||||
size: torrent.size(),
|
||||
files: torrent.files(),
|
||||
torrent,
|
||||
}),
|
||||
Ok(torrent) => Some(Format::from_torrent(torrent, scraper, meta)),
|
||||
Err(e) => {
|
||||
error!("Torrent storage read error: `{e}`");
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<Row>>(),
|
||||
.collect::<Vec<Format>>(),
|
||||
pagination_totals: format!(
|
||||
"Page {} / {} ({total} {} total)",
|
||||
page.unwrap_or(1),
|
||||
|
|
@ -101,6 +70,34 @@ fn index(
|
|||
))
|
||||
}
|
||||
|
||||
#[get("/<info_hash>")]
|
||||
fn info(
|
||||
info_hash: &str,
|
||||
storage: &State<Storage>,
|
||||
scraper: &State<Scraper>,
|
||||
meta: &State<Meta>,
|
||||
) -> Result<Template, Custom<String>> {
|
||||
match storage.torrent(librqbit_core::Id20::from_str(info_hash).map_err(|e| {
|
||||
warn!("Torrent info-hash parse error: `{e}`");
|
||||
Custom(Status::BadRequest, Status::BadRequest.to_string())
|
||||
})?) {
|
||||
Some(t) => Ok(Template::render(
|
||||
"info",
|
||||
context! {
|
||||
meta: meta.inner(),
|
||||
torrent: Format::from_torrent(
|
||||
Torrent::from_storage(&t.bytes, t.time).map_err(|e| {
|
||||
error!("Torrent parse error: `{e}`");
|
||||
Custom(Status::InternalServerError, E.to_string())
|
||||
})?, scraper, meta
|
||||
),
|
||||
info_hash
|
||||
},
|
||||
)),
|
||||
None => Err(Custom(Status::NotFound, E.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/rss")]
|
||||
fn rss(feed: &State<Feed>, storage: &State<Storage>) -> Result<RawXml<String>, Custom<String>> {
|
||||
let mut b = feed.transaction(1024); // @TODO
|
||||
|
|
@ -189,7 +186,7 @@ fn rocket() -> _ {
|
|||
version: env!("CARGO_PKG_VERSION").into(),
|
||||
})
|
||||
.mount("/", rocket::fs::FileServer::from(config.statics))
|
||||
.mount("/", routes![index, rss])
|
||||
.mount("/", routes![index, info, rss])
|
||||
}
|
||||
|
||||
/// Public placeholder text for the `Status::InternalServerError`
|
||||
|
|
|
|||
14
src/meta.rs
Normal file
14
src/meta.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use rocket::serde::Serialize;
|
||||
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,
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ use std::{
|
|||
path::PathBuf,
|
||||
};
|
||||
|
||||
const EXTENSION: &str = "torrent";
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub enum Sort {
|
||||
#[default]
|
||||
|
|
@ -49,6 +51,15 @@ impl Storage {
|
|||
|
||||
// Getters
|
||||
|
||||
pub fn torrent(&self, info_hash: librqbit_core::Id20) -> Option<Torrent> {
|
||||
let mut p = PathBuf::from(&self.root);
|
||||
p.push(format!("{}.{EXTENSION}", info_hash.as_string()));
|
||||
Some(Torrent {
|
||||
bytes: fs::read(&p).ok()?,
|
||||
time: p.metadata().ok()?.modified().ok()?.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn torrents(
|
||||
&self,
|
||||
sort_order: Option<(Sort, Order)>,
|
||||
|
|
@ -66,7 +77,7 @@ impl Storage {
|
|||
.filter(|f| {
|
||||
f.path()
|
||||
.extension()
|
||||
.is_some_and(|e| !e.is_empty() && e.to_string_lossy() == "torrent")
|
||||
.is_some_and(|e| !e.is_empty() && e.to_string_lossy() == EXTENSION)
|
||||
})
|
||||
{
|
||||
b.push(Torrent {
|
||||
|
|
|
|||
|
|
@ -43,12 +43,7 @@ h1, h2, h3, h4, h5 {
|
|||
font-weight: normal;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: var(--default);
|
||||
h1, h2 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
{% for row in rows %}
|
||||
<div>
|
||||
<a name="{{ row.torrent.info_hash }}"></a>
|
||||
<h2>{{ row.torrent.name }}</h2>
|
||||
<h2><a href="/{{ row.torrent.info_hash }}">{{ row.torrent.name }}</a></h2>
|
||||
{% if row.torrent.comment %}<p>{{ row.torrent.comment }}</p>{% endif %}
|
||||
<div>
|
||||
<ul>
|
||||
|
|
|
|||
27
templates/info.html.tera
Normal file
27
templates/info.html.tera
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{% extends "layout/default" %}
|
||||
{% block content %}
|
||||
{% if torrent %}
|
||||
<div>
|
||||
<h1>{% if torrent.name %}{{ torrent.name }}{% else %}{{ info_hash }}{% endif %}</h1>
|
||||
{% if torrent.comment %}<p>{{ torrent.comment }}</p>{% endif %}
|
||||
<div>
|
||||
<ul>
|
||||
<li><span title="Indexed">{{ torrent.indexed }}</span></li>
|
||||
{% if torrent.created %}<li><span title="Created">({{ torrent.created }})</span></li>{% endif %}
|
||||
{% if torrent.size %}<li><span title="Size">{{ torrent.size }}</span></li>{% endif %}
|
||||
<li><span title="Files">{{ torrent.files }}</span></li>
|
||||
{% if torrent.scrape %}
|
||||
<li><span title="Seeders" class="seeders">{{ torrent.scrape.seeders }}</span></li>
|
||||
<li><span title="Peers" class="peers">{{ torrent.scrape.peers }}</span></li>
|
||||
<li><span title="Leechers" class="leechers">{{ torrent.scrape.leechers }}</span></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<div>
|
||||
<a rel="nofollow" href="{{ torrent.magnet }}" title="Get magnet" class="action magnet"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div>Nothing.</div>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue