qbt-rs/src/utils.rs

87 lines
3.0 KiB
Rust

use snafu::prelude::*;
use imdl::infohash::Infohash;
use imdl::input::Input;
use imdl::input_target::InputTarget;
use imdl::magnet_link::MagnetLink;
use imdl::metainfo::Metainfo;
use imdl::torrent_summary::TorrentSummary;
use std::path::Path;
use std::net::TcpListener;
use crate::error::{Error, InvalidMagnetSnafu as InvalidMagnet, InvalidTorrentSnafu as InvalidTorrent, FailedToReadFileSnafu as FailedToReadFile, OtherTorrentSnafu as OtherTorrentError};
/// Helper method for imdl functions which expect an imdl::Input type
pub fn input_path<T: AsRef<Path>>(path: T) -> Result<Input, Error> {
let path = path.as_ref();
let absolute = path.canonicalize().context(FailedToReadFile { path: path.to_path_buf() })?;
let data = std::fs::read(absolute).context(FailedToReadFile { path: path.to_path_buf() })?;
Ok(Input::new(
InputTarget::Path(path.to_path_buf()),
data
))
}
/// Extracts the infohash of a magnet link
pub fn magnet_hash<T: AsRef<str>>(magnet: T) -> Result<String, Error> {
let magnet = magnet.as_ref();
let magnet = MagnetLink::parse(magnet).context(InvalidMagnet { magnet: magnet.to_string() })?;
let bytes = magnet.infohash.inner.bytes.clone();
let mut s = String::new();
for byte in bytes {
s.push_str(&format!("{:02x}", byte));
}
Ok(s)
}
/// Extracts the name of a magnet link
pub fn magnet_name<T: AsRef<str>>(magnet: T) -> Result<Option<String>, Error> {
let magnet = magnet.as_ref();
let magnet = MagnetLink::parse(magnet).context(InvalidMagnet { magnet })?;
Ok(magnet.name)
}
/// Extracts the infohash of a torrent file
pub fn torrent_hash<T: AsRef<Path>>(torrent: T) -> Result<String, Error> {
let torrent = torrent.as_ref();
let input = input_path(torrent)?;
let summary = TorrentSummary::from_input(&input).context(InvalidTorrent { torrent })?;
Ok(summary.torrent_summary_data().info_hash)
}
/// Extracts the name of a torrent file
pub fn torrent_name<T: AsRef<Path>>(torrent: T) -> Result<String, Error> {
let torrent = torrent.as_ref();
let input = input_path(torrent)?;
let summary = TorrentSummary::from_input(&input).context(InvalidTorrent { torrent })?;
Ok(summary.torrent_summary_data().name)
}
/// Turns a torrent file into a magnet link
pub fn torrent_to_magnet<T: AsRef<Path>>(torrent: T) -> Result<String, Error> {
let torrent = torrent.as_ref();
let input = input_path(torrent)?;
let infohash = Infohash::from_input(&input).context(InvalidTorrent { torrent })?;
let metainfo = Metainfo::from_input(&input).context(InvalidTorrent { torrent })?;
let mut link = MagnetLink::with_infohash(infohash);
link.set_name(&metainfo.info.name);
for result in metainfo.trackers() {
let result = result.context(OtherTorrentError { torrent })?;
link.add_tracker(result);
}
Ok(link.to_url().to_string())
}
// Fallible: only used in tests
#[allow(dead_code)]
pub fn find_free_port() -> u16 {
let bind = TcpListener::bind("127.0.0.1:0").unwrap();
bind.local_addr().unwrap().port()
}