From 95f5a322f65ddac905ba9a2a47088ebd8f5e53cb Mon Sep 17 00:00:00 2001 From: Igor Katson Date: Thu, 7 Nov 2024 19:35:02 +0000 Subject: [PATCH] [feature] support 40-byte infohash (not a magnet) as a way to add torrents --- crates/librqbit/src/http_api.rs | 10 +++++++++- crates/librqbit/src/session.rs | 5 ++++- crates/librqbit_core/src/magnet.rs | 10 ++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/librqbit/src/http_api.rs b/crates/librqbit/src/http_api.rs index 69744ad8a..e7f302f96 100644 --- a/crates/librqbit/src/http_api.rs +++ b/crates/librqbit/src/http_api.rs @@ -10,6 +10,7 @@ use futures::{FutureExt, TryStreamExt}; use http::{HeaderMap, HeaderValue, StatusCode}; use itertools::Itertools; +use librqbit_core::magnet::Magnet; use serde::{Deserialize, Serialize}; use std::io::SeekFrom; use std::net::SocketAddr; @@ -118,6 +119,12 @@ impl HttpApi { let is_url = params.is_url; let opts = params.into_add_torrent_options(); let data = data.to_vec(); + let maybe_magnet = |data: &[u8]| -> bool { + std::str::from_utf8(data) + .ok() + .and_then(|s| Magnet::parse(s).ok()) + .is_some() + }; let add = match is_url { Some(true) => AddTorrent::Url( String::from_utf8(data) @@ -129,7 +136,8 @@ impl HttpApi { // Guess the format. None if SUPPORTED_SCHEMES .iter() - .any(|s| data.starts_with(s.as_bytes())) => + .any(|s| data.starts_with(s.as_bytes())) + || maybe_magnet(&data) => { AddTorrent::Url( String::from_utf8(data) diff --git a/crates/librqbit/src/session.rs b/crates/librqbit/src/session.rs index 272383928..edd24cd63 100644 --- a/crates/librqbit/src/session.rs +++ b/crates/librqbit/src/session.rs @@ -334,6 +334,9 @@ impl<'a> AddTorrent<'a> { if SUPPORTED_SCHEMES.iter().any(|s| path.starts_with(s)) { return Ok(Self::Url(Cow::Borrowed(path))); } + if path.len() == 40 && !Path::new(path).exists() && Magnet::parse(path).is_ok() { + return Ok(Self::Url(Cow::Borrowed(path))); + } Self::from_local_filename(path) } @@ -884,7 +887,7 @@ impl Session { // So we must discover at least one peer and connect to it to be able to proceed further. let add_res = match add { - AddTorrent::Url(magnet) if magnet.starts_with("magnet:") => { + AddTorrent::Url(magnet) if magnet.starts_with("magnet:") || magnet.len() == 40 => { let magnet = Magnet::parse(&magnet) .context("provided path is not a valid magnet URL")?; let info_hash = magnet diff --git a/crates/librqbit_core/src/magnet.rs b/crates/librqbit_core/src/magnet.rs index 443440448..2a3d35a4f 100644 --- a/crates/librqbit_core/src/magnet.rs +++ b/crates/librqbit_core/src/magnet.rs @@ -35,6 +35,16 @@ impl Magnet { /// Parse a magnet link. pub fn parse(url: &str) -> anyhow::Result { + if url.len() == 40 { + if let Ok(id20) = Id20::from_str(url) { + return Ok(Magnet { + id20: Some(id20), + id32: None, + trackers: vec![], + select_only: None, + }); + } + } let url = url::Url::parse(url).context("magnet link must be a valid URL")?; if url.scheme() != "magnet" { anyhow::bail!("expected scheme magnet");