1use std::error::Error;
2use std::sync::Arc;
3
4use crate::config::ProxyConfig;
5use crate::optimization::Optimizer;
6
7mod external;
8mod settings;
9
10#[cfg(feature = "torrent-transmission")]
11mod transmission;
12
13pub type StatusCb = Arc<dyn Fn(String) + Send + Sync>;
14pub type ProgressCb = Arc<dyn Fn(f32) + Send + Sync>;
15
16#[derive(Default, Clone)]
17pub struct TorrentCallbacks {
18 pub status: Option<StatusCb>,
19 pub progress: Option<ProgressCb>,
20}
21
22fn emit_status(cb: &TorrentCallbacks, msg: impl Into<String>) {
23 if let Some(f) = &cb.status {
24 f(msg.into());
25 }
26}
27
28fn emit_progress(cb: &TorrentCallbacks, p: f32) {
29 if let Some(f) = &cb.progress {
30 f(p.clamp(0.0, 1.0));
31 }
32}
33
34fn selected_backend() -> String {
38 std::env::var("KGET_TORRENT_BACKEND")
39 .unwrap_or_else(|_| "external".to_string())
40 .to_lowercase()
41}
42
43pub fn download_magnet(
44 magnet: &str,
45 output_dir: &str,
46 quiet: bool,
47 proxy: ProxyConfig,
48 optimizer: Optimizer,
49 cb: TorrentCallbacks,
50) -> Result<(), Box<dyn Error + Send + Sync>> {
51 emit_progress(&cb, 0.0);
52
53 match selected_backend().as_str() {
54 "transmission" => {
55 #[cfg(feature = "torrent-transmission")]
56 {
57 return transmission::download_via_transmission(
58 magnet,
59 output_dir,
60 quiet,
61 proxy,
62 optimizer,
63 cb,
64 );
65 }
66
67 #[cfg(not(feature = "torrent-transmission"))]
68 {
69 emit_status(
70 &cb,
71 "Torrent backend 'transmission' not available (compile with --features torrent-transmission). Falling back to external client.",
72 );
73 }
74 }
75 _ => {}
76 }
77
78 emit_status(
79 &cb,
80 format!(
81 "Opening magnet link in your default torrent client (output folder may be managed by that client): {}",
82 magnet
83 ),
84 );
85
86 external::open_magnet_in_default_client(magnet)?;
87 emit_progress(&cb, 1.0);
88 Ok(())
89}