feat: delete multiple torrents at once

This commit is contained in:
Kristofers Solo 2024-02-21 19:36:51 +02:00
parent b492f1c1fb
commit 429f059c33
3 changed files with 82 additions and 42 deletions

View File

@ -1,20 +1,45 @@
use std::path::Path; use std::path::Path;
use tracing::debug;
use transmission_rpc::types::{Id, Torrent, TorrentAction, TorrentStatus}; use transmission_rpc::types::{Id, Torrent, TorrentAction, TorrentStatus};
use super::Torrents; use super::Torrents;
impl Torrents { impl Torrents {
pub async fn toggle(&mut self, torrent: &Torrent) { pub async fn toggle(&mut self, ids: &Vec<i64>) {
let id = torrent.id().expect("ID not found"); debug!("ID list - {:?}", ids);
let api_ids: Vec<_> = self
.torrents
.iter()
.filter_map(|torrent| {
if let Some(id) = torrent.id {
if ids.contains(&id) {
return torrent.id();
}
}
return None;
})
.collect();
debug!("API ID list - {:?}", api_ids);
for torrent in &self.torrents {
if let Some(id) = torrent.id {
if ids.contains(&id) {
let action = match torrent.status { let action = match torrent.status {
Some(TorrentStatus::Stopped) => TorrentAction::StartNow, Some(TorrentStatus::Stopped) => TorrentAction::Start,
_ => TorrentAction::Stop, _ => TorrentAction::Stop,
}; };
self.client if !api_ids.is_empty() {
.torrent_action(action, vec![id]) if let Err(err) = self.client.torrent_action(action, api_ids.clone()).await
.await {
.expect("Error toggling torrent"); eprintln!("Error toggling torrent: {}", err);
}
}
}
}
}
} }
pub async fn toggle_all(&mut self) { pub async fn toggle_all(&mut self) {
@ -65,16 +90,18 @@ impl Torrents {
Ok(()) Ok(())
} }
pub async fn delete( pub async fn delete(&mut self, ids: &Vec<i64>, delete_local_data: bool) {
&mut self, let api_ids = self
torrent: &Torrent, .torrents
delete_local_data: bool, .iter()
) -> transmission_rpc::types::Result<()> { .filter(|torrent| ids.contains(&torrent.id.unwrap()))
let id = torrent.id().expect("ID not found"); .map(|torrent| torrent.id().unwrap())
.collect();
self.client self.client
.torrent_remove(vec![id], delete_local_data) .torrent_remove(api_ids, delete_local_data)
.await?; .await
Ok(()) .unwrap();
} }
pub async fn rename( pub async fn rename(

View File

@ -3,7 +3,6 @@ mod torrent;
pub mod utils; pub mod utils;
use ratatui::widgets::TableState; use ratatui::widgets::TableState;
use transmission_rpc::types::Torrent;
pub mod action; pub mod action;
mod command; mod command;
@ -119,36 +118,50 @@ impl<'a> App<'a> {
self.show_popup = true; self.show_popup = true;
} }
pub async fn toggle_torrent(&mut self) { pub async fn toggle_torrents(&mut self) {
let torrent = self.selected().expect("Torrent not found"); let ids = &self.selected(false);
self.torrents.toggle(&torrent.clone()).await; self.torrents.toggle(ids).await;
self.close_popup(); self.close_popup();
} }
pub async fn delete(&mut self, delete_local_data: bool) -> transmission_rpc::types::Result<()> { pub async fn delete(&mut self, delete_local_data: bool) {
let torrent = self.selected().expect("Torrent not found"); let ids = &self.selected(false);
self.torrents self.torrents.delete(ids, delete_local_data).await;
.delete(&torrent.clone(), delete_local_data)
.await?;
self.close_popup(); self.close_popup();
Ok(())
} }
pub fn select(&mut self) { pub fn select(&mut self) {
let torrent = self.selected().expect("Torrent not found"); let current_id = *self.selected(true).first().unwrap();
if let Some(id) = torrent.id { if self.torrents.selected.contains(&current_id) {
if self.torrents.selected.contains(&id) { self.torrents.selected.remove(&current_id);
self.torrents.selected.remove(&id);
} else { } else {
self.torrents.selected.insert(id); self.torrents.selected.insert(current_id);
}
} }
self.next(); self.next();
} }
fn selected(&self) -> Option<&Torrent> { fn selected(&self, highlighted: bool) -> Vec<i64> {
let torrents = &self.torrents.torrents;
if self.torrents.selected.is_empty() || highlighted {
let torrent_id = || {
let idx = self.state.selected()?; let idx = self.state.selected()?;
let torrent = self.torrents.torrents.get(idx)?; let torrent = torrents.get(idx)?;
Some(torrent) torrent.id
};
if let Some(id) = torrent_id() {
return vec![id];
}
}
let selected_torrents: Vec<_> = torrents
.iter()
.filter_map(|torrent| {
let id = torrent.id;
if self.torrents.selected.contains(&id?) {
return id;
}
return None;
})
.collect();
selected_torrents
} }
} }

View File

@ -37,12 +37,12 @@ pub async fn update(app: &mut App<'_>, action: Action) -> transmission_rpc::type
Action::PrevTorrent => app.previous(), Action::PrevTorrent => app.previous(),
Action::SwitchTab(x) => app.switch_tab(x as usize), Action::SwitchTab(x) => app.switch_tab(x as usize),
Action::TogglePopup => app.toggle_popup(), Action::TogglePopup => app.toggle_popup(),
Action::ToggleTorrent => app.toggle_torrent().await, Action::ToggleTorrent => app.toggle_torrents().await,
Action::ToggleAll => app.torrents.toggle_all().await, Action::ToggleAll => app.torrents.toggle_all().await,
Action::PauseAll => app.torrents.stop_all().await, Action::PauseAll => app.torrents.stop_all().await,
Action::StartAll => app.torrents.start_all().await, Action::StartAll => app.torrents.start_all().await,
Action::Move => unimplemented!(), Action::Move => unimplemented!(),
Action::Delete(x) => app.delete(x).await?, Action::Delete(x) => app.delete(x).await,
Action::Rename => unimplemented!(), Action::Rename => unimplemented!(),
Action::Select => app.select(), Action::Select => app.select(),
} }