mirror of
https://github.com/YGGverse/btracker.git
synced 2026-03-31 17:15:31 +00:00
use shared btracker-fs library
This commit is contained in:
parent
d95cee6c09
commit
f95c9526f2
3 changed files with 12 additions and 187 deletions
16
Cargo.toml
16
Cargo.toml
|
|
@ -11,11 +11,17 @@ repository = "https://github.com/yggverse/btracker"
|
||||||
# homepage = "https://yggverse.github.io"
|
# homepage = "https://yggverse.github.io"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
btracker-fs = { version = "0.1", features = ["public"] }
|
||||||
rocket = "0.5"
|
|
||||||
librqbit-core = "5.0"
|
|
||||||
chrono = { version = "0.4.41", features = ["serde"] }
|
chrono = { version = "0.4.41", features = ["serde"] }
|
||||||
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
|
librqbit-core = "5.0"
|
||||||
|
rand = "0.9"
|
||||||
|
rocket = "0.5"
|
||||||
|
rocket_dyn_templates = { version = "0.2", features = ["tera"] }
|
||||||
url = { version = "2.5", features = ["serde"] }
|
url = { version = "2.5", features = ["serde"] }
|
||||||
urlencoding = "2.1"
|
urlencoding = "2.1"
|
||||||
rocket_dyn_templates = { version = "0.2", features = ["tera"] }
|
|
||||||
rand = "0.9"
|
# development
|
||||||
|
# [patch.crates-io]
|
||||||
|
# btracker-fs = { git = "https://github.com/yggverse/btracker-fs.git" }
|
||||||
|
# btracker-fs = { path = "../btracker-fs" }
|
||||||
|
|
@ -4,14 +4,13 @@ extern crate rocket;
|
||||||
mod config;
|
mod config;
|
||||||
mod feed;
|
mod feed;
|
||||||
mod meta;
|
mod meta;
|
||||||
mod public;
|
|
||||||
mod scraper;
|
mod scraper;
|
||||||
mod torrent;
|
mod torrent;
|
||||||
|
|
||||||
|
use btracker_fs::public::{Order, Public, Sort};
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use feed::Feed;
|
use feed::Feed;
|
||||||
use meta::Meta;
|
use meta::Meta;
|
||||||
use public::{Order, Public, Sort};
|
|
||||||
use rocket::{State, http::Status, response::content::RawXml, serde::Serialize};
|
use rocket::{State, http::Status, response::content::RawXml, serde::Serialize};
|
||||||
use rocket_dyn_templates::{Template, context};
|
use rocket_dyn_templates::{Template, context};
|
||||||
use scraper::{Scrape, Scraper};
|
use scraper::{Scrape, Scraper};
|
||||||
|
|
|
||||||
180
src/public.rs
180
src/public.rs
|
|
@ -1,180 +0,0 @@
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use std::{fs, io::Error, path::PathBuf, time::SystemTime};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
|
||||||
pub enum Sort {
|
|
||||||
#[default]
|
|
||||||
Modified,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
|
||||||
pub enum Order {
|
|
||||||
#[default]
|
|
||||||
Asc,
|
|
||||||
Desc,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Torrent {
|
|
||||||
pub bytes: Vec<u8>,
|
|
||||||
pub time: DateTime<Utc>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Public {
|
|
||||||
default_capacity: usize,
|
|
||||||
pub default_limit: usize,
|
|
||||||
root: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Public {
|
|
||||||
// Constructors
|
|
||||||
|
|
||||||
pub fn init(
|
|
||||||
root: PathBuf,
|
|
||||||
default_limit: usize,
|
|
||||||
default_capacity: usize,
|
|
||||||
) -> Result<Self, String> {
|
|
||||||
if !root.is_dir() {
|
|
||||||
return Err("Public root is not directory".into());
|
|
||||||
}
|
|
||||||
Ok(Self {
|
|
||||||
default_capacity,
|
|
||||||
default_limit,
|
|
||||||
root: root.canonicalize().map_err(|e| e.to_string())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
|
|
||||||
pub fn torrent(&self, info_hash: librqbit_core::Id20) -> Option<Torrent> {
|
|
||||||
let mut p = PathBuf::from(&self.root);
|
|
||||||
p.push(format!("{}.{E}", info_hash.as_string()));
|
|
||||||
Some(Torrent {
|
|
||||||
bytes: fs::read(&p).ok()?,
|
|
||||||
time: p.metadata().ok()?.modified().ok()?.into(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn torrents(
|
|
||||||
&self,
|
|
||||||
keyword: Option<&str>,
|
|
||||||
sort_order: Option<(Sort, Order)>,
|
|
||||||
start: Option<usize>,
|
|
||||||
limit: Option<usize>,
|
|
||||||
) -> Result<(usize, Vec<Torrent>), Error> {
|
|
||||||
let f = self.files(keyword, sort_order)?;
|
|
||||||
let t = f.len();
|
|
||||||
let l = limit.unwrap_or(t);
|
|
||||||
let mut b = Vec::with_capacity(l);
|
|
||||||
for file in f.into_iter().skip(start.unwrap_or_default()).take(l) {
|
|
||||||
b.push(Torrent {
|
|
||||||
bytes: fs::read(file.path)?,
|
|
||||||
time: file.modified.into(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Ok((t, b))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn href(&self, info_hash: &str, path: &str) -> Option<String> {
|
|
||||||
let mut relative = PathBuf::from(info_hash);
|
|
||||||
relative.push(path);
|
|
||||||
|
|
||||||
let mut absolute = PathBuf::from(&self.root);
|
|
||||||
absolute.push(&relative);
|
|
||||||
|
|
||||||
let c = absolute.canonicalize().ok()?;
|
|
||||||
if c.starts_with(&self.root) && c.exists() {
|
|
||||||
Some(relative.to_string_lossy().into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers
|
|
||||||
|
|
||||||
fn files(
|
|
||||||
&self,
|
|
||||||
keyword: Option<&str>,
|
|
||||||
sort_order: Option<(Sort, Order)>,
|
|
||||||
) -> Result<Vec<File>, Error> {
|
|
||||||
let mut files = Vec::with_capacity(self.default_capacity);
|
|
||||||
for dir_entry in fs::read_dir(&self.root)? {
|
|
||||||
let entry = dir_entry?;
|
|
||||||
let path = entry.path();
|
|
||||||
if !path.is_file() || path.extension().is_none_or(|e| e != E) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(k) = keyword
|
|
||||||
&& !k.trim_matches(S).is_empty()
|
|
||||||
&& !librqbit_core::torrent_metainfo::torrent_from_bytes(&fs::read(&path)?)
|
|
||||||
.is_ok_and(|m: librqbit_core::torrent_metainfo::TorrentMetaV1Owned| {
|
|
||||||
k.split(S)
|
|
||||||
.filter(|s| !s.is_empty())
|
|
||||||
.map(|s| s.trim().to_lowercase())
|
|
||||||
.all(|q| {
|
|
||||||
m.info_hash.as_string().to_lowercase().contains(&q)
|
|
||||||
|| m.info
|
|
||||||
.name
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|n| n.to_string().to_lowercase().contains(&q))
|
|
||||||
|| m.comment
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|c| c.to_string().to_lowercase().contains(&q))
|
|
||||||
|| m.created_by
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|c| c.to_string().to_lowercase().contains(&q))
|
|
||||||
|| m.publisher
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|p| p.to_string().to_lowercase().contains(&q))
|
|
||||||
|| m.publisher_url
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|u| u.to_string().to_lowercase().contains(&q))
|
|
||||||
|| m.announce
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|a| a.to_string().to_lowercase().contains(&q))
|
|
||||||
|| m.announce_list.iter().any(|l| {
|
|
||||||
l.iter().any(|a| a.to_string().to_lowercase().contains(&q))
|
|
||||||
})
|
|
||||||
|| m.info.files.as_ref().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().to_lowercase().contains(&q)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
files.push(File {
|
|
||||||
modified: entry.metadata()?.modified()?,
|
|
||||||
path,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if let Some((sort, order)) = sort_order {
|
|
||||||
match sort {
|
|
||||||
Sort::Modified => match order {
|
|
||||||
Order::Asc => files.sort_by(|a, b| a.modified.cmp(&b.modified)),
|
|
||||||
Order::Desc => files.sort_by(|a, b| b.modified.cmp(&a.modified)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local members
|
|
||||||
|
|
||||||
/// Torrent file extension
|
|
||||||
const E: &str = "torrent";
|
|
||||||
|
|
||||||
/// Search keyword separators
|
|
||||||
const S: &[char] = &[
|
|
||||||
'_', '-', ':', ';', ',', '(', ')', '[', ']', '/', '!', '?', ' ', // @TODO make optional
|
|
||||||
];
|
|
||||||
|
|
||||||
struct File {
|
|
||||||
modified: SystemTime,
|
|
||||||
path: PathBuf,
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue