rqbit/crates/librqbit/README.md
2023-11-15 20:21:30 +01:00

Symbolic link
5.1 KiB

librqbit

A torrent library 100% written in rust

Basic example

This is a simple program on how to use this library
This program will just download a simple torrent file with a Magnet link

use std::error::Error;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use librqbit::Magnet;
use librqbit::session::{AddTorrentResponse, ListOnlyResponse, ManagedTorrentState, Session};
use librqbit::spawn_utils::BlockingSpawner;
use size_format::SizeFormatterBinary as SF;
use tokio::spawn;

const MAGNET_LINK: &str = "magnet:?..."; // Put your magnet link here

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>>{

    let spawner = BlockingSpawner::new(false);

    // This function will print the torrent properties every 1s
    let stats_printer = |session: Arc<Session>| async move {
        loop {
            session.with_torrents(|torrents| {
                for (idx, torrent) in torrents.iter().enumerate() {
                    match &torrent.state {
                        ManagedTorrentState::Initializing => {
                            println!("[{}] initializing", idx);
                        },
                        ManagedTorrentState::Running(handle) => {
                            let peer_stats = handle.torrent_state().peer_stats_snapshot();
                            let stats = handle.torrent_state().stats_snapshot();
                            let speed = handle.speed_estimator();
                            let total = stats.total_bytes;
                            let progress = stats.total_bytes - stats.remaining_bytes;
                            let downloaded_pct = if stats.remaining_bytes == 0 {
                                100f64
                            } else {
                                (progress as f64 / total as f64) * 100f64
                            };
                            println!(
                                "[{}]: {:.2}% ({:.2}), down speed {:.2} MiB/s, fetched {}, remaining {:.2} of {:.2}, uploaded {:.2}, peers: {{live: {}, connecting: {}, queued: {}, seen: {}}}",
                                idx,
                                downloaded_pct,
                                SF::new(progress),
                                speed.download_mbps(),
                                SF::new(stats.fetched_bytes),
                                SF::new(stats.remaining_bytes),
                                SF::new(total),
                                SF::new(stats.uploaded_bytes),
                                peer_stats.live,
                                peer_stats.connecting,
                                peer_stats.queued,
                                peer_stats.seen,
                            );
                        },
                    }
                }
            });
            tokio::time::sleep(Duration::from_secs(1)).await;
        }
    };

    // Create the torrent session, one session can have more than one torrent at the same time
    let session = Arc::new(
        Session::new(PathBuf::from("C:\\Anime"), spawner).await?
    );

    // Spawn the properties printer function
    spawn(stats_printer(session.clone()));

    // Add the magnet link to the torrent session, you don't have to specify if it's an url or magnet,
    // the library will recognize automatically for you
    let handle = match session.add_torrent(MAGNET_LINK, None).await {
        Ok(v) => match v {
            AddTorrentResponse::AlreadyManaged(handle) => {
                println!(
                    "torrent {:?} is already managed, downloaded to {:?}",
                    handle.info_hash, handle.output_folder
                );
                Err(())
            }
            AddTorrentResponse::ListOnly(ListOnlyResponse {
                                             info_hash: _,
                                             info,
                                             only_files,
                                         }) => {
                for (idx, (filename, len)) in
                info.iter_filenames_and_lengths()?.enumerate()
                {
                    let included = match &only_files {
                        Some(files) => files.contains(&idx),
                        None => true,
                    };
                    println!(
                        "File {}, size {}{}",
                        filename.to_string()?,
                        SF::new(len),
                        if included { "" } else { ", will skip" }
                    )
                }
                Err(())
            }
            AddTorrentResponse::Added(handle) => {
                Ok(handle)
            }
        }
        Err(err) => {
            eprintln!("error adding {}: {:?}", MAGNET_LINK, err);
            Err(())
        }
    };

    // Wait until the session complete the torrent download and terminate
    let _ = match handle {
        Ok(h) => h.wait_until_completed().await?,
        _ => {},
    };

    Ok(())
}