diff --git a/qbittorrent-rs b/qbittorrent-rs index 4c907b9..d0e087a 160000 --- a/qbittorrent-rs +++ b/qbittorrent-rs @@ -1 +1 @@ -Subproject commit 4c907b940e6a4eaeee0c92581b62173d918b054a +Subproject commit d0e087af2b378025416a91085934f396886f3456 diff --git a/src/client/mod.rs b/src/client/mod.rs index 6c7fe1f..1073f71 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,21 +1,27 @@ +pub mod qbittorrent; + use async_trait::async_trait; -use crate::{torrent::{TorrentInfo, TorrentTracker}, error::ClientError}; +use crate::{torrent::{TorrentInfo, TorrentTracker, TorrentUpload}, error::ClientError}; pub type ClientResult = Result; #[async_trait] -pub trait TorrentClient { - async fn login(&self, url: &str, username: &str, password: &str) -> ClientResult<()>; +pub trait TorrentClient<'a> { + async fn login(&mut self, url: &'a str, username: &'a str, password: &'a str) -> ClientResult<()>; async fn get_torrent_list(&self) -> ClientResult>; async fn get_torrent_trackers(&self, torrent: &TorrentInfo) -> ClientResult>; - async fn add_torrent_Tracker(&self, torrent: &TorrentInfo, tracker_url: String) -> ClientResult<()>; - async fn replace_torrent_Tracker(&self, torrent: &TorrentInfo, old_url: String, new_url: String) -> ClientResult<()>; - async fn remove_torrent_Tracker(&self, torrent: &TorrentInfo, tracker_url: String) -> ClientResult<()>; + async fn add_torrent_tracker(&self, torrent: &TorrentInfo, tracker_url: String) -> ClientResult<()>; + async fn replace_torrent_tracker(&self, torrent: &TorrentInfo, old_url: String, new_url: String) -> ClientResult<()>; + async fn remove_torrent_tracker(&self, torrent: &TorrentInfo, tracker_url: String) -> ClientResult<()>; - - async fn add_torrent(&self, torrent: &TorrentInfo) -> ClientResult<()>; + async fn add_torrent(&self, torrent: &TorrentUpload) -> ClientResult<()>; async fn remove_torrent(&self, torrent: &TorrentInfo, delete_files: bool) -> ClientResult<()>; + async fn remove_torrents(&self, torrents: Vec, delete_files: bool) -> ClientResult<()>; + + async fn get_tags(&self) -> ClientResult>; + async fn create_tag(&self, tag: &str) -> ClientResult<()>; + async fn delete_tag(&self, tag: &str) -> ClientResult<()>; } \ No newline at end of file diff --git a/src/client/qbittorrent.rs b/src/client/qbittorrent.rs new file mode 100644 index 0000000..81904c0 --- /dev/null +++ b/src/client/qbittorrent.rs @@ -0,0 +1,144 @@ +use crate::torrent::{TorrentInfo, TorrentTracker, TorrentUpload}; +use super::{TorrentClient, ClientResult}; +use qbittorrent::QBittorrentClient; + +use async_trait::async_trait; + +impl From<&qbittorrent::TorrentInfo> for TorrentInfo { + fn from(torrent: &qbittorrent::TorrentInfo) -> Self { + TorrentInfo { + name: torrent.name.clone(), + trackers: vec![torrent.tracker.clone()], // NOTE: qBittorrent only gives us one tracker. + category: torrent.category.clone(), + tags: torrent.tags.clone(), + hash: torrent.hash.clone(), + } + } +} + +// For some reason I have to implement this twice smh +impl Into for &TorrentInfo { + fn into(self) -> qbittorrent::TorrentInfo { + let mut t = qbittorrent::TorrentInfo::default(); + t.name = self.name.clone(); + t.tracker = self.trackers.first().unwrap_or(&String::new()).clone(); + t.category = self.category.clone(); + t.tags = self.tags.clone(); + t.hash = self.hash.clone(); + + t + } +} + +// For some reason I have to implement this twice smh +impl Into for TorrentInfo { + fn into(self) -> qbittorrent::TorrentInfo { + let mut t = qbittorrent::TorrentInfo::default(); + t.name = self.name.clone(); + t.tracker = self.trackers.first().unwrap_or(&String::new()).clone(); + t.category = self.category.clone(); + t.tags = self.tags.clone(); + t.hash = self.hash.clone(); + + t + } +} + +impl From for TorrentUpload { + fn from(upload: qbittorrent::TorrentUpload) -> Self { + TorrentUpload { + urls: upload.urls, + torrents: upload.torrents, + tags: upload.tags, + category: upload.category, + paused: upload.paused, + } + } +} + +impl Into for &TorrentUpload { + fn into(self) -> qbittorrent::TorrentUpload { + let mut t = qbittorrent::TorrentUpload::default(); + t.urls = self.urls.clone(); + t.torrents = self.torrents.clone(); + t.tags = self.tags.clone(); + t.category = self.category.clone(); + t.paused = self.paused; + + t + } +} + +impl From<&qbittorrent::TorrentTracker> for TorrentTracker { + fn from(tracker: &qbittorrent::TorrentTracker) -> Self { + TorrentTracker { + url: tracker.url.clone(), + status: tracker.status.clone().into(), + message: Some(tracker.message.clone()), + } + } +} + +impl From for crate::torrent::TrackerStatus { + fn from(status: qbittorrent::TrackerStatus) -> Self { + match status { + qbittorrent::TrackerStatus::Disabled => crate::torrent::TrackerStatus::Disabled, + qbittorrent::TrackerStatus::NotContacted => crate::torrent::TrackerStatus::NotContacted, + qbittorrent::TrackerStatus::Working => crate::torrent::TrackerStatus::Working, + qbittorrent::TrackerStatus::Updating => crate::torrent::TrackerStatus::Updating, + qbittorrent::TrackerStatus::NotWorking => crate::torrent::TrackerStatus::NotWorking, + } + } +} + +#[async_trait] +impl<'a> TorrentClient<'a> for QBittorrentClient<'a> { + async fn login(&mut self, url: &'a str, username: &'a str, password: &'a str) -> ClientResult<()> { + Ok(Self::login(&mut self, url, username, password).await?) + } + + async fn get_torrent_list(&self) -> ClientResult> { + Ok(Self::get_torrent_list(self).await?.iter().map(|t| t.into()).collect()) + } + + async fn get_torrent_trackers(&self, torrent: &TorrentInfo) -> ClientResult> { + Ok(Self::get_torrent_trackers(self, &torrent.into()).await?.iter().map(|t| t.into()).collect()) + } + + async fn add_torrent_tracker(&self, torrent: &TorrentInfo, tracker_url: String) -> ClientResult<()> { + Ok(Self::add_torrent_tracker(self, &torrent.into(), tracker_url).await?) + } + + async fn replace_torrent_tracker(&self, torrent: &TorrentInfo, old_url: String, new_url: String) -> ClientResult<()> { + Ok(Self::replace_torrent_tracker(self, &torrent.into(), old_url, new_url).await?) + } + + async fn remove_torrent_tracker(&self, torrent: &TorrentInfo, tracker_url: String) -> ClientResult<()> { + Ok(Self::remove_torrent_tracker(self, &torrent.into(), tracker_url).await?) + } + + async fn add_torrent(&self, torrent: &TorrentUpload) -> ClientResult<()> { + Ok(Self::add_torrent(self, &torrent.into()).await?) + } + + async fn remove_torrent(&self, torrent: &TorrentInfo, delete_files: bool) -> ClientResult<()> { + Ok(Self::remove_torrent(self, &torrent.into(), delete_files).await?) + } + + async fn remove_torrents(&self, torrents: Vec, delete_files: bool) -> ClientResult<()> { + let torrents: Vec = torrents.iter().map(|t| t.into()).collect(); + Ok(Self::remove_torrents(self, torrents, delete_files).await?) + } + + async fn get_tags(&self) -> ClientResult> { + Ok(Self::get_tags(self).await?) + } + + async fn create_tag(&self, tag: &str) -> ClientResult<()> { + Ok(Self::create_tag(self, tag).await?) + } + + async fn delete_tag(&self, tag: &str) -> ClientResult<()> { + Ok(Self::delete_tag(self, tag).await?) + } +} \ No newline at end of file diff --git a/src/torrent.rs b/src/torrent.rs index 4ddfcd4..e6071b7 100644 --- a/src/torrent.rs +++ b/src/torrent.rs @@ -1,6 +1,3 @@ -use qbittorrent::{TorrentInfo as QTorrentInfo, TorrentUpload as QTorrentUpload, - TrackerStatus as QTrackerStatus, TorrentTracker as QTorrentTracker}; - #[derive(Debug, Default)] pub struct TorrentInfo { pub name: String, @@ -10,19 +7,7 @@ pub struct TorrentInfo { pub hash: String, } -impl From for TorrentInfo { - fn from(torrent: QTorrentInfo) -> Self { - TorrentInfo { - name: torrent.name, - trackers: vec![torrent.tracker], // NOTE: qBittorrent only gives us one tracker. - category: torrent.category, - tags: torrent.tags, - hash: torrent.hash, - } - } -} - -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct TorrentUpload { /// URL(s) of the torrent files. pub urls: Vec, @@ -38,15 +23,9 @@ pub struct TorrentUpload { pub paused: Option, } -impl From for TorrentUpload { - fn from(upload: QTorrentUpload) -> Self { - TorrentUpload { - urls: upload.urls, - torrents: upload.torrents, - tags: upload.tags, - category: upload.category, - paused: upload.paused, - } +impl TorrentUpload { + pub fn builder() -> TorrentUploadBuilder { + TorrentUploadBuilder::default() } } @@ -106,6 +85,10 @@ impl TorrentUploadBuilder { self.params.paused = Some(paused); self } + + pub fn build(&self) -> TorrentUpload { + self.params.clone() + } } #[derive(Debug)] @@ -138,26 +121,4 @@ pub enum TrackerStatus { /// Tracker has been contacted, but it is not working (or doesn't send proper replies) NotWorking = 4 -} - -impl From for TorrentTracker { - fn from(tracker: QTorrentTracker) -> Self { - TorrentTracker { - url: tracker.url, - status: tracker.status.into(), - message: Some(tracker.message), - } - } -} - -impl From for TrackerStatus { - fn from(status: QTrackerStatus) -> Self { - match status { - QTrackerStatus::Disabled => TrackerStatus::Disabled, - QTrackerStatus::NotContacted => TrackerStatus::NotContacted, - QTrackerStatus::Working => TrackerStatus::Working, - QTrackerStatus::Updating => TrackerStatus::Updating, - QTrackerStatus::NotWorking => TrackerStatus::NotWorking, - } - } } \ No newline at end of file