mirror of
https://github.com/YGGverse/btracker.git
synced 2026-03-31 17:15:31 +00:00
implement files list
This commit is contained in:
parent
c84e0ffbdb
commit
fa748fbd18
7 changed files with 133 additions and 76 deletions
|
|
@ -1,30 +0,0 @@
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
73
src/main.rs
73
src/main.rs
|
|
@ -3,7 +3,6 @@ extern crate rocket;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod feed;
|
mod feed;
|
||||||
mod format;
|
|
||||||
mod meta;
|
mod meta;
|
||||||
mod scraper;
|
mod scraper;
|
||||||
mod storage;
|
mod storage;
|
||||||
|
|
@ -11,13 +10,13 @@ mod torrent;
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use feed::Feed;
|
use feed::Feed;
|
||||||
use format::Format;
|
|
||||||
use meta::Meta;
|
use meta::Meta;
|
||||||
use plurify::Plurify;
|
use plurify::Plurify;
|
||||||
use rocket::{
|
use rocket::{
|
||||||
State,
|
State,
|
||||||
http::Status,
|
http::Status,
|
||||||
response::{content::RawXml, status::Custom},
|
response::{content::RawXml, status::Custom},
|
||||||
|
serde::Serialize,
|
||||||
};
|
};
|
||||||
use rocket_dyn_templates::{Template, context};
|
use rocket_dyn_templates::{Template, context};
|
||||||
use scraper::{Scrape, Scraper};
|
use scraper::{Scrape, Scraper};
|
||||||
|
|
@ -32,6 +31,17 @@ fn index(
|
||||||
storage: &State<Storage>,
|
storage: &State<Storage>,
|
||||||
meta: &State<Meta>,
|
meta: &State<Meta>,
|
||||||
) -> Result<Template, Custom<String>> {
|
) -> Result<Template, Custom<String>> {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
struct R {
|
||||||
|
created: Option<String>,
|
||||||
|
files: String,
|
||||||
|
indexed: String,
|
||||||
|
magnet: String,
|
||||||
|
scrape: Option<Scrape>,
|
||||||
|
size: String,
|
||||||
|
torrent: Torrent,
|
||||||
|
}
|
||||||
let (total, torrents) = storage
|
let (total, torrents) = storage
|
||||||
.torrents(
|
.torrents(
|
||||||
Some((Sort::Modified, Order::Desc)),
|
Some((Sort::Modified, Order::Desc)),
|
||||||
|
|
@ -42,7 +52,6 @@ fn index(
|
||||||
error!("Torrents storage read error: `{e}`");
|
error!("Torrents storage read error: `{e}`");
|
||||||
Custom(Status::InternalServerError, E.to_string())
|
Custom(Status::InternalServerError, E.to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Template::render(
|
Ok(Template::render(
|
||||||
"index",
|
"index",
|
||||||
context! {
|
context! {
|
||||||
|
|
@ -53,13 +62,21 @@ fn index(
|
||||||
rows: torrents
|
rows: torrents
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|t| match Torrent::from_storage(&t.bytes, t.time) {
|
.filter_map(|t| match Torrent::from_storage(&t.bytes, t.time) {
|
||||||
Ok(torrent) => Some(Format::from_torrent(torrent, scraper, meta)),
|
Ok(torrent) => Some(R {
|
||||||
|
created: torrent.creation_date.map(|t| t.format(&meta.format_time).to_string()),
|
||||||
|
files: torrent.files(),
|
||||||
|
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(),
|
||||||
|
torrent
|
||||||
|
}),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Torrent storage read error: `{e}`");
|
error!("Torrent storage read error: `{e}`");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<Format>>(),
|
.collect::<Vec<R>>(),
|
||||||
pagination_totals: format!(
|
pagination_totals: format!(
|
||||||
"Page {} / {} ({total} {} total)",
|
"Page {} / {} ({total} {} total)",
|
||||||
page.unwrap_or(1),
|
page.unwrap_or(1),
|
||||||
|
|
@ -81,19 +98,39 @@ fn info(
|
||||||
warn!("Torrent info-hash parse error: `{e}`");
|
warn!("Torrent info-hash parse error: `{e}`");
|
||||||
Custom(Status::BadRequest, Status::BadRequest.to_string())
|
Custom(Status::BadRequest, Status::BadRequest.to_string())
|
||||||
})?) {
|
})?) {
|
||||||
Some(t) => Ok(Template::render(
|
Some(t) => {
|
||||||
"info",
|
#[derive(Serialize)]
|
||||||
context! {
|
#[serde(crate = "rocket::serde")]
|
||||||
meta: meta.inner(),
|
struct F {
|
||||||
torrent: Format::from_torrent(
|
name: String,
|
||||||
Torrent::from_storage(&t.bytes, t.time).map_err(|e| {
|
size: String,
|
||||||
error!("Torrent parse error: `{e}`");
|
}
|
||||||
Custom(Status::InternalServerError, E.to_string())
|
let torrent = Torrent::from_storage(&t.bytes, t.time).map_err(|e| {
|
||||||
})?, scraper, meta
|
error!("Torrent parse error: `{e}`");
|
||||||
),
|
Custom(Status::InternalServerError, E.to_string())
|
||||||
info_hash
|
})?;
|
||||||
},
|
Ok(Template::render(
|
||||||
)),
|
"info",
|
||||||
|
context! {
|
||||||
|
meta: meta.inner(),
|
||||||
|
created: torrent.creation_date.map(|t| t.format(&meta.format_time).to_string()),
|
||||||
|
files_total: torrent.files(),
|
||||||
|
files_list: torrent.files.as_ref().map(|f| {
|
||||||
|
f.iter()
|
||||||
|
.map(|f| F {
|
||||||
|
name: f.name(),
|
||||||
|
size: f.size(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<F>>()
|
||||||
|
}),
|
||||||
|
indexed: torrent.time.format(&meta.format_time).to_string(),
|
||||||
|
magnet: torrent.magnet(meta.trackers.as_ref()),
|
||||||
|
scrape: scraper.scrape(info_hash),
|
||||||
|
size: torrent.size(),
|
||||||
|
torrent
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
None => Err(Custom(Status::NotFound, E.to_string())),
|
None => Err(Custom(Status::NotFound, E.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,21 +88,7 @@ impl Torrent {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> String {
|
pub fn size(&self) -> String {
|
||||||
const KB: f32 = 1024.0;
|
size(self.size)
|
||||||
const MB: f32 = KB * KB;
|
|
||||||
const GB: f32 = MB * KB;
|
|
||||||
|
|
||||||
let f = self.size as f32;
|
|
||||||
|
|
||||||
if f < KB {
|
|
||||||
format!("{} B", self.size)
|
|
||||||
} else if f < MB {
|
|
||||||
format!("{:.2} KB", f / KB)
|
|
||||||
} else if f < GB {
|
|
||||||
format!("{:.2} MB", f / MB)
|
|
||||||
} else {
|
|
||||||
format!("{:.2} GB", f / GB)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn magnet(&self, trackers: Option<&Vec<url::Url>>) -> String {
|
pub fn magnet(&self, trackers: Option<&Vec<url::Url>>) -> String {
|
||||||
|
|
@ -120,3 +106,21 @@ impl Torrent {
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,12 @@ pub struct File {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub length: u64,
|
pub length: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl File {
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.name.as_deref().unwrap_or("?").into()
|
||||||
|
}
|
||||||
|
pub fn size(&self) -> String {
|
||||||
|
super::size(self.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@
|
||||||
--background: #282b3c;
|
--background: #282b3c;
|
||||||
--default: #ccc;
|
--default: #ccc;
|
||||||
--item: #34384f;
|
--item: #34384f;
|
||||||
|
--separator: #4f536a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
color: var(--default);
|
color: var(--default);
|
||||||
|
|
@ -47,6 +47,24 @@ h1, h2 {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td,
|
||||||
|
table th {
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table > thead > tr > th {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table > tbody > tr:hover > td {
|
||||||
|
background: var(--background)
|
||||||
|
}
|
||||||
|
|
||||||
body > * {
|
body > * {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
@ -108,7 +126,7 @@ main > div > p {
|
||||||
|
|
||||||
/* item row meta, controls */
|
/* item row meta, controls */
|
||||||
main > div > div {
|
main > div > div {
|
||||||
border-top: 1px #4f536a solid;
|
border-top: 1px solid var(--separator);
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
<li><span title="Indexed">{{ row.indexed }}</span></li>
|
<li><span title="Indexed">{{ row.indexed }}</span></li>
|
||||||
{% if row.created %}<li><span title="Created">({{ row.created }})</span></li>{% endif %}
|
{% if row.created %}<li><span title="Created">({{ row.created }})</span></li>{% endif %}
|
||||||
{% if row.size %}<li><span title="Size">{{ row.size }}</span></li>{% endif %}
|
{% if row.size %}<li><span title="Size">{{ row.size }}</span></li>{% endif %}
|
||||||
<li><span title="Files">{{ row.files }}</span></li>
|
<li><span title="Files">{{ row.files }}</span></li>
|
||||||
{% if row.scrape %}
|
{% if row.scrape %}
|
||||||
<li><span title="Seeders" class="seeders">{{ row.scrape.seeders }}</span></li>
|
<li><span title="Seeders" class="seeders">{{ row.scrape.seeders }}</span></li>
|
||||||
<li><span title="Peers" class="peers">{{ row.scrape.peers }}</span></li>
|
<li><span title="Peers" class="peers">{{ row.scrape.peers }}</span></li>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,42 @@
|
||||||
{% extends "layout/default" %}
|
{% extends "layout/default" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div>
|
<div>
|
||||||
<h1>{% if torrent.name %}{{ torrent.name }}{% else %}{{ info_hash }}{% endif %}</h1>
|
<h1>{% if torrent.name %}{{ torrent.name }}{% else %}{{ torrent.info_hash }}{% endif %}</h1>
|
||||||
{% if torrent.comment %}<p>{{ torrent.comment }}</p>{% endif %}
|
{% if torrent.comment %}<p>{{ torrent.comment }}</p>{% endif %}
|
||||||
<div>
|
<div>
|
||||||
<ul>
|
<ul>
|
||||||
<li><span title="Indexed">{{ torrent.indexed }}</span></li>
|
<li><span title="Indexed">{{ indexed }}</span></li>
|
||||||
{% if torrent.created %}<li><span title="Created">({{ torrent.created }})</span></li>{% endif %}
|
{% if created %}<li><span title="Created">({{ created }})</span></li>{% endif %}
|
||||||
{% if torrent.size %}<li><span title="Size">{{ torrent.size }}</span></li>{% endif %}
|
<li><span title="Size">{{ size }}</span></li>
|
||||||
<li><span title="Files">{{ torrent.files }}</span></li>
|
<li><span title="Files">{{ files_total }}</span></li>
|
||||||
{% if torrent.scrape %}
|
{% if scrape %}
|
||||||
<li><span title="Seeders" class="seeders">{{ torrent.scrape.seeders }}</span></li>
|
<li><span title="Seeders" class="seeders">{{ scrape.seeders }}</span></li>
|
||||||
<li><span title="Peers" class="peers">{{ torrent.scrape.peers }}</span></li>
|
<li><span title="Peers" class="peers">{{ scrape.peers }}</span></li>
|
||||||
<li><span title="Leechers" class="leechers">{{ torrent.scrape.leechers }}</span></li>
|
<li><span title="Leechers" class="leechers">{{ scrape.leechers }}</span></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
<div>
|
<div>
|
||||||
<a rel="nofollow" href="{{ torrent.magnet }}" title="Get magnet" class="action magnet"></a>
|
<a rel="nofollow" href="{{ magnet }}" title="Get magnet" class="action magnet"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div></div>
|
||||||
|
{% if files_list %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File</th>
|
||||||
|
<th>Size</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for file in files_list %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ file.name }}</td>
|
||||||
|
<td>{{ file.size }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue