mirror of
https://github.com/YGGverse/btracker-gemini.git
synced 2026-03-31 09:05:30 +00:00
init torrent info page
This commit is contained in:
parent
90d8e48b55
commit
43052a0d38
2 changed files with 150 additions and 66 deletions
|
|
@ -1,4 +1,14 @@
|
||||||
pub fn size(value: u64) -> String {
|
use librqbit_core::torrent_metainfo::TorrentMetaV1Owned;
|
||||||
|
use plurify::Plurify;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
pub fn files(meta: &TorrentMetaV1Owned) -> String {
|
||||||
|
let total = meta.info.files.as_ref().map(|f| f.len()).unwrap_or(1);
|
||||||
|
format!("{total} {}", total.plurify(&["file", "files", "files"]))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(meta: &TorrentMetaV1Owned) -> String {
|
||||||
|
fn s(value: u64) -> String {
|
||||||
const KB: f32 = 1024.0;
|
const KB: f32 = 1024.0;
|
||||||
const MB: f32 = KB * KB;
|
const MB: f32 = KB * KB;
|
||||||
const GB: f32 = MB * KB;
|
const GB: f32 = MB * KB;
|
||||||
|
|
@ -15,3 +25,26 @@ pub fn size(value: u64) -> String {
|
||||||
format!("{:.2} GB", f / GB)
|
format!("{:.2} GB", f / GB)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s(meta
|
||||||
|
.info
|
||||||
|
.files
|
||||||
|
.as_ref()
|
||||||
|
.map(|files| files.iter().map(|file| file.length).sum::<u64>())
|
||||||
|
.unwrap_or_default()
|
||||||
|
+ meta.info.length.unwrap_or_default())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn magnet(meta: &TorrentMetaV1Owned, trackers: Option<&Vec<Url>>) -> String {
|
||||||
|
let mut b = format!("magnet:?xt=urn:btih:{}", meta.info_hash.as_string());
|
||||||
|
if let Some(ref n) = meta.info.name {
|
||||||
|
b.push_str("&dn=");
|
||||||
|
b.push_str(&urlencoding::encode(&n.to_string()))
|
||||||
|
}
|
||||||
|
if let Some(t) = trackers {
|
||||||
|
for tracker in t {
|
||||||
|
b.push_str("&tr=");
|
||||||
|
b.push_str(&urlencoding::encode(tracker.as_str()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b
|
||||||
|
}
|
||||||
|
|
|
||||||
141
src/main.rs
141
src/main.rs
|
|
@ -2,23 +2,25 @@ mod config;
|
||||||
mod format;
|
mod format;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use btracker_fs::public::{Order, Public, Sort};
|
use btracker_fs::public::{Order, Public, Sort, Torrent};
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use librqbit_core::torrent_metainfo::{TorrentMetaV1Owned, torrent_from_bytes};
|
use librqbit_core::{
|
||||||
|
Id20,
|
||||||
|
torrent_metainfo::{TorrentMetaV1Owned, torrent_from_bytes},
|
||||||
|
};
|
||||||
use log::*;
|
use log::*;
|
||||||
use native_tls::{HandshakeError, Identity, TlsAcceptor, TlsStream};
|
use native_tls::{HandshakeError, Identity, TlsAcceptor, TlsStream};
|
||||||
use plurify::Plurify;
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
net::{SocketAddr, TcpListener, TcpStream},
|
net::{SocketAddr, TcpListener, TcpStream},
|
||||||
|
str::FromStr,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
use titanite::*;
|
use titanite::*;
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
if std::env::var("RUST_LOG").is_ok() {
|
if std::env::var("RUST_LOG").is_ok() {
|
||||||
|
|
@ -153,10 +155,10 @@ fn response(
|
||||||
stream: &mut TlsStream<TcpStream>,
|
stream: &mut TlsStream<TcpStream>,
|
||||||
) {
|
) {
|
||||||
debug!("Incoming request from `{peer}` to `{}`", request.url.path());
|
debug!("Incoming request from `{peer}` to `{}`", request.url.path());
|
||||||
|
let p = request.url.path().trim_matches('/');
|
||||||
// try index page
|
// try index page
|
||||||
if request.url.path().trim_end_matches("/").is_empty() {
|
if p.is_empty() {
|
||||||
return send(
|
send(
|
||||||
&match index(
|
&match index(
|
||||||
config,
|
config,
|
||||||
public,
|
public,
|
||||||
|
|
@ -184,16 +186,67 @@ fn response(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
stream,
|
stream,
|
||||||
|result| match result {
|
|result| {
|
||||||
Ok(()) => debug!("Home page request from peer `{peer}`"),
|
if let Err(e) = result {
|
||||||
Err(e) => error!("Internal server error on handle peer `{peer}` request: `{e}`"),
|
error!("Internal server error on handle peer `{peer}` request: `{e}`")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
// try info page
|
// try info page
|
||||||
todo!()
|
else if let Ok(id) = Id20::from_str(p)
|
||||||
|
&& let Some(torrent) = public.torrent(id)
|
||||||
|
{
|
||||||
|
send(
|
||||||
|
&match info(config, torrent) {
|
||||||
|
Ok(data) => response::success::Default {
|
||||||
|
data: data.as_bytes(),
|
||||||
|
meta: response::success::default::Meta {
|
||||||
|
mime: "text/gemini".to_string(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.into_bytes(),
|
||||||
|
Err(e) => {
|
||||||
|
error!("Internal server error on handle peer `{peer}` request: `{e}`");
|
||||||
|
response::failure::temporary::General {
|
||||||
|
message: Some("Internal server error".to_string()),
|
||||||
|
}
|
||||||
|
.into_bytes()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stream,
|
||||||
|
|result| {
|
||||||
|
if let Err(e) = result {
|
||||||
|
error!("Internal server error on handle peer `{peer}` request: `{e}`")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// not found
|
||||||
|
else {
|
||||||
|
warn!(
|
||||||
|
"Requested resource `{}` not found by peer `{peer}`",
|
||||||
|
request.url.as_str()
|
||||||
|
);
|
||||||
|
send(
|
||||||
|
&response::Failure::Permanent(response::failure::Permanent::NotFound(
|
||||||
|
response::failure::permanent::NotFound { message: None },
|
||||||
|
))
|
||||||
|
.into_bytes(),
|
||||||
|
stream,
|
||||||
|
|result| {
|
||||||
|
if let Err(e) = result {
|
||||||
|
error!(
|
||||||
|
"Internal server error on handle peer `{peer}` request `{}`: `{e}`",
|
||||||
|
request.url.as_str()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send(data: &[u8], stream: &mut TlsStream<TcpStream>, callback: impl FnOnce(Result<()>)) {
|
||||||
fn close(stream: &mut TlsStream<TcpStream>) -> Result<()> {
|
fn close(stream: &mut TlsStream<TcpStream>) -> Result<()> {
|
||||||
stream.flush()?;
|
stream.flush()?;
|
||||||
// close connection gracefully
|
// close connection gracefully
|
||||||
|
|
@ -201,8 +254,6 @@ fn close(stream: &mut TlsStream<TcpStream>) -> Result<()> {
|
||||||
stream.shutdown()?;
|
stream.shutdown()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send(data: &[u8], stream: &mut TlsStream<TcpStream>, callback: impl FnOnce(Result<()>)) {
|
|
||||||
callback((|| {
|
callback((|| {
|
||||||
stream.write_all(data)?;
|
stream.write_all(data)?;
|
||||||
close(stream)?;
|
close(stream)?;
|
||||||
|
|
@ -210,7 +261,11 @@ fn send(data: &[u8], stream: &mut TlsStream<TcpStream>, callback: impl FnOnce(Re
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rotes
|
||||||
|
|
||||||
fn index(config: &Config, public: &Public, page: Option<usize>) -> Result<String> {
|
fn index(config: &Config, public: &Public, page: Option<usize>) -> Result<String> {
|
||||||
|
use plurify::Plurify;
|
||||||
|
|
||||||
let (total, torrents) = public.torrents(
|
let (total, torrents) = public.torrents(
|
||||||
None, // @TODO
|
None, // @TODO
|
||||||
Some((Sort::Modified, Order::Desc)),
|
Some((Sort::Modified, Order::Desc)),
|
||||||
|
|
@ -246,13 +301,9 @@ fn index(config: &Config, public: &Public, page: Option<usize>) -> Result<String
|
||||||
b.push(format!(
|
b.push(format!(
|
||||||
"{} • {} • {}\n",
|
"{} • {} • {}\n",
|
||||||
torrent.time.format(&config.date),
|
torrent.time.format(&config.date),
|
||||||
size(&i),
|
format::size(&i),
|
||||||
files(&i),
|
format::files(&i),
|
||||||
))
|
))
|
||||||
/*b.push(format!(
|
|
||||||
"=> {} Magnet\n",
|
|
||||||
magnet(&i, config.tracker.as_ref())
|
|
||||||
))*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b.push("## Navigation\n".into());
|
b.push("## Navigation\n".into());
|
||||||
|
|
@ -283,33 +334,33 @@ fn index(config: &Config, public: &Public, page: Option<usize>) -> Result<String
|
||||||
Ok(b.join("\n"))
|
Ok(b.join("\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn files(meta: &TorrentMetaV1Owned) -> String {
|
fn info(config: &Config, torrent: Torrent) -> Result<String> {
|
||||||
let total = meta.info.files.as_ref().map(|f| f.len()).unwrap_or(1);
|
let i: TorrentMetaV1Owned = torrent_from_bytes(&torrent.bytes)?;
|
||||||
format!("{total} {}", total.plurify(&["file", "files", "files"]))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(meta: &TorrentMetaV1Owned) -> String {
|
let mut b = Vec::new();
|
||||||
format::size(
|
|
||||||
meta.info
|
b.push(format!("# {}\n", config.name));
|
||||||
.files
|
|
||||||
|
b.push(format!(
|
||||||
|
"## {}\n",
|
||||||
|
i.info
|
||||||
|
.name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|files| files.iter().map(|file| file.length).sum::<u64>())
|
.map(|n| n.to_string())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
+ meta.info.length.unwrap_or_default(),
|
));
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn magnet(meta: &TorrentMetaV1Owned, trackers: Option<&Vec<Url>>) -> String {
|
b.push(format!(
|
||||||
let mut b = format!("magnet:?xt=urn:btih:{}", meta.info_hash.as_string());
|
"{} • {} • {}\n",
|
||||||
if let Some(ref n) = meta.info.name {
|
torrent.time.format(&config.date),
|
||||||
b.push_str("&dn=");
|
format::size(&i),
|
||||||
b.push_str(&urlencoding::encode(&n.to_string()))
|
format::files(&i),
|
||||||
}
|
));
|
||||||
if let Some(t) = trackers {
|
|
||||||
for tracker in t {
|
b.push(format!(
|
||||||
b.push_str("&tr=");
|
"=> {} Magnet\n",
|
||||||
b.push_str(&urlencoding::encode(tracker.as_str()))
|
format::magnet(&i, config.tracker.as_ref())
|
||||||
}
|
));
|
||||||
}
|
|
||||||
b
|
Ok(b.join("\n"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue