Check if a search result is a torrent we can cross seed,
This commit is contained in:
parent
507b0e0594
commit
9a7d08cb81
|
@ -45,6 +45,17 @@ dependencies = [
|
||||||
"tokio 1.19.2",
|
"tokio 1.19.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-recursion"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atom_syndication"
|
name = "atom_syndication"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -191,6 +202,7 @@ name = "cross-seed"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argmap",
|
"argmap",
|
||||||
|
"async-recursion",
|
||||||
"bytes 1.1.0",
|
"bytes 1.1.0",
|
||||||
"figment",
|
"figment",
|
||||||
"futures 0.3.21",
|
"futures 0.3.21",
|
||||||
|
@ -820,8 +832,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "magnet-url"
|
name = "magnet-url"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/SeanOMik/magnet-url-rs.git?branch=main#9e1bf9a9a85e83b99b10c8475b0a4a10e6d897e8"
|
||||||
checksum = "ac3b4c4004e88aca00cc0c60782e5642c8fc628deca19e530ce58aa76e737d74"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"regex",
|
"regex",
|
||||||
|
|
|
@ -13,12 +13,13 @@ futures = "0.3.21"
|
||||||
toml = "0.5.9"
|
toml = "0.5.9"
|
||||||
lava_torrent = "0.7.0" # https://docs.rs/lava_torrent/0.7.0/lava_torrent/
|
lava_torrent = "0.7.0" # https://docs.rs/lava_torrent/0.7.0/lava_torrent/
|
||||||
torznab = "0.7.2" # https://docs.rs/torznab/0.7.2/torznab/
|
torznab = "0.7.2" # https://docs.rs/torznab/0.7.2/torznab/
|
||||||
magnet-url = "2.0.0"
|
magnet-url = { git = "https://github.com/SeanOMik/magnet-url-rs.git", branch = "main" }
|
||||||
serde_with = "1.14.0"
|
serde_with = "1.14.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
figment = { version = "0.10", features = ["toml", "env"] }
|
figment = { version = "0.10", features = ["toml", "env"] }
|
||||||
wild = "2.0.4"
|
wild = "2.0.4"
|
||||||
argmap = "1.1.2"
|
argmap = "1.1.2"
|
||||||
|
async-recursion = "1.0.0"
|
||||||
|
|
||||||
reqwest = {version = "0.11", default_features = false, features = ["gzip", "json", "rustls-tls"]}
|
reqwest = {version = "0.11", default_features = false, features = ["gzip", "json", "rustls-tls"]}
|
||||||
urlencoding = "2.1.0"
|
urlencoding = "2.1.0"
|
||||||
|
|
48
src/main.rs
48
src/main.rs
|
@ -8,7 +8,7 @@ use tracing::{info, Level, debug};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use lava_torrent::torrent::v1::Torrent;
|
use lava_torrent::torrent::v1::{Torrent, AnnounceList};
|
||||||
|
|
||||||
use crate::torznab::{GenericSearchParameters, SearchFunction};
|
use crate::torznab::{GenericSearchParameters, SearchFunction};
|
||||||
use crate::torznab::search_parameters::{GenericSearchParametersBuilder, MovieSearchParametersBuilder};
|
use crate::torznab::search_parameters::{GenericSearchParametersBuilder, MovieSearchParametersBuilder};
|
||||||
|
@ -46,7 +46,7 @@ async fn main() {
|
||||||
|
|
||||||
// Get config and debug the torrents
|
// Get config and debug the torrents
|
||||||
let config = Config::new();
|
let config = Config::new();
|
||||||
info!("Searching torrents in: {}", config.torrents_path_str());
|
info!("Searching for torrents in: {}", config.torrents_path_str());
|
||||||
|
|
||||||
let mut indexers = config.indexers.clone();
|
let mut indexers = config.indexers.clone();
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ async fn main() {
|
||||||
debug!(" Can Search: {:?}", indexer.client.as_ref().unwrap().capabilities.searching_capabilities);
|
debug!(" Can Search: {:?}", indexer.client.as_ref().unwrap().capabilities.searching_capabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log the amount of torrents.
|
||||||
let torrent_files = read_torrents(config.torrents_path()).unwrap();
|
let torrent_files = read_torrents(config.torrents_path()).unwrap();
|
||||||
info!("Found {} torrents", torrent_files.len());
|
info!("Found {} torrents", torrent_files.len());
|
||||||
|
|
||||||
|
@ -77,6 +78,8 @@ async fn main() {
|
||||||
let torrent = Arc::new(torrent);
|
let torrent = Arc::new(torrent);
|
||||||
|
|
||||||
for indexer in indexers.iter() {
|
for indexer in indexers.iter() {
|
||||||
|
info!("Checking for \"{}\"", torrent.name);
|
||||||
|
|
||||||
let mut indexer = Arc::clone(indexer);
|
let mut indexer = Arc::clone(indexer);
|
||||||
let torrent = Arc::clone(&torrent);
|
let torrent = Arc::clone(&torrent);
|
||||||
indexer_handles.push(tokio::spawn(async move {
|
indexer_handles.push(tokio::spawn(async move {
|
||||||
|
@ -88,7 +91,46 @@ async fn main() {
|
||||||
.build();
|
.build();
|
||||||
let results = client.search(SearchFunction::Search, generic).await.unwrap();
|
let results = client.search(SearchFunction::Search, generic).await.unwrap();
|
||||||
|
|
||||||
//println!("Results: {:?}", results);
|
// The first result should be the correct one.
|
||||||
|
if let Some(result) = results.first() {
|
||||||
|
let found_torrent = result.download_torrent().await.unwrap();
|
||||||
|
|
||||||
|
if let Some(found_announces) = &found_torrent.announce_list {
|
||||||
|
// Some urls can be encoded so we need to decode to compare them.
|
||||||
|
let found_announces: Vec<Vec<String>> = found_announces.iter()
|
||||||
|
.map(|a_list| a_list.iter().map(|a| urlencoding::decode(a).unwrap().to_string()).collect::<Vec<String>>())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if let Some(torrent_announces) = &torrent.announce_list {
|
||||||
|
let mut found_announces_flat: Vec<&String> = Vec::new();
|
||||||
|
for i in found_announces.iter() {
|
||||||
|
for j in i.iter() {
|
||||||
|
found_announces_flat.push(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut flat_announces: Vec<&String> = Vec::new();
|
||||||
|
for i in torrent_announces.iter() {
|
||||||
|
for j in i.iter() {
|
||||||
|
flat_announces.push(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the announce urls from the found torrent are in the one
|
||||||
|
// that is on the file system.
|
||||||
|
let mut in_tracker = true;
|
||||||
|
for found_url in found_announces_flat.iter() {
|
||||||
|
in_tracker = in_tracker && flat_announces.contains(found_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !in_tracker {
|
||||||
|
info!("Found a cross-seedable torrent for {}", found_torrent.name);
|
||||||
|
} else {
|
||||||
|
debug!("Found the torrent in its original indexer, skipping...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
panic!("idfk");
|
panic!("idfk");
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ClientError {
|
pub enum ClientError {
|
||||||
HttpError(reqwest::Error),
|
HttpError(reqwest::Error),
|
||||||
SearchResultError(super::ResultError)
|
SearchResultError(super::ResultError),
|
||||||
|
InvalidRedirect,
|
||||||
|
TorrentError(lava_torrent::LavaTorrentError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<reqwest::Error> for ClientError {
|
impl From<reqwest::Error> for ClientError {
|
||||||
|
@ -14,4 +16,10 @@ impl From<super::ResultError> for ClientError {
|
||||||
fn from(e: super::ResultError) -> Self {
|
fn from(e: super::ResultError) -> Self {
|
||||||
ClientError::SearchResultError(e)
|
ClientError::SearchResultError(e)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lava_torrent::LavaTorrentError> for ClientError {
|
||||||
|
fn from(e: lava_torrent::LavaTorrentError) -> Self {
|
||||||
|
ClientError::TorrentError(e)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,15 +1,21 @@
|
||||||
|
use lava_torrent::torrent::v1::Torrent;
|
||||||
use rss::Item;
|
use rss::Item;
|
||||||
|
|
||||||
|
use async_recursion::async_recursion;
|
||||||
|
|
||||||
|
use super::ClientError;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ResultError {
|
pub enum ResultError {
|
||||||
MissingTitle,
|
MissingTitle,
|
||||||
MissingLink,
|
MissingLink,
|
||||||
|
InvalidRedirect,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct TorrentResult {
|
pub struct TorrentResult {
|
||||||
name: String,
|
pub name: String,
|
||||||
link: String,
|
pub link: String,
|
||||||
/* size: u64,
|
/* size: u64,
|
||||||
categories: Vec<u32>, */
|
categories: Vec<u32>, */
|
||||||
}
|
}
|
||||||
|
@ -28,6 +34,40 @@ impl TorrentResult {
|
||||||
categories, */
|
categories, */
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_recursion]
|
||||||
|
async fn download_impl(&self, client: &reqwest::Client, url: &str) -> Result<Torrent, ClientError> {
|
||||||
|
let res = client
|
||||||
|
.get(&self.link)
|
||||||
|
.send().await?;
|
||||||
|
|
||||||
|
if res.status() == 301 {
|
||||||
|
let headers = res.headers();
|
||||||
|
if let Some(location) = headers.get(reqwest::header::LOCATION) {
|
||||||
|
let location = location.to_str().unwrap();
|
||||||
|
|
||||||
|
self.download_impl(client, location).await
|
||||||
|
} else {
|
||||||
|
Err(ClientError::InvalidRedirect)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let bytes = res.bytes().await?;
|
||||||
|
|
||||||
|
if url.starts_with("magnet:?") {
|
||||||
|
let magnet = magnet_url::Magnet::new(url).unwrap();
|
||||||
|
|
||||||
|
todo!() // TODO
|
||||||
|
} else {
|
||||||
|
let torrent = Torrent::read_from_bytes(bytes)?;
|
||||||
|
|
||||||
|
Ok(torrent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn download_torrent(&self) -> Result<Torrent, ClientError> {
|
||||||
|
self.download_impl(&reqwest::Client::default(), &self.link).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* impl<'a> From<Item> for TorrentResult<'a> {
|
/* impl<'a> From<Item> for TorrentResult<'a> {
|
||||||
|
|
Loading…
Reference in New Issue