magnetease 0.3.1

A library to fetch magnets from the internet
Documentation
//! Magnetease is a library that fetches `Magnet`s from different sources.
//!
//! You can construct [Magnetease] with [Provider]s that you want to search.
//! Examples
//! ```
//! # tokio_test::block_on(async {
//! use magnetease::Magnetease;
//! let magnetease = Magnetease::new();
//! let magnets = magnetease.search("Ubuntu Pro").await;
//! # });
//! ```

mod magnetease;
/// Providers that you can search invidually or within [Magnetease]
pub mod providers;

use std::fmt;

use async_trait::async_trait;
pub use magnetease::Magnetease;
use providers::{Knaben, Nyaa};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use thiserror::Error;

/// Holds the magnet itself in `url` and some metadata along with it.
#[derive(Clone, Debug)]
pub struct Magnet {
    /// The title associated with the magnet link.
    pub title: String,
    /// The URL of the magnet
    pub url: String,
    /// The number of seeders
    pub seeders: u32,
    /// The size of the content in bytes.
    pub bytes: u64,
}

#[derive(Error)]
pub struct MagneteaseError {
    pub kind: MagneteaseErrorKind,
    pub provider: WhichProvider,
}

impl fmt::Debug for MagneteaseError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("MagneteaseError")
            .field("kind", &self.kind)
            .field("provider", &self.provider.name())
            .finish()
    }
}

impl fmt::Display for MagneteaseError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("MagneteaseError")
            .field("kind", &self.kind)
            .field("provider", &self.provider.name())
            .finish()
    }
}

#[derive(Error, Debug)]
pub enum MagneteaseErrorKind {
    #[error(transparent)]
    ConnectionError(#[from] reqwest::Error),
    #[error("couldn't scrape html properly")]
    HtmlError,
}

pub struct MagneteaseResult {
    pub provider: WhichProvider,
    pub magnets: Vec<Magnet>,
}

#[async_trait]
pub trait Provider {
    fn name(&self) -> &'static str;

    fn display_url(&self) -> &'static str;

    fn category(&self) -> ProviderCategory {
        ProviderCategory::General
    }

    async fn search(
        &self,
        client: &Client,
        query: &str,
    ) -> Result<MagneteaseResult, MagneteaseError>;
}

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ProviderCategory {
    General,
    Anime,
}

#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum WhichProvider {
    Knaben,
    Nyaa,
}

impl WhichProvider {
    pub fn all() -> Vec<WhichProvider> {
        vec![WhichProvider::Knaben, WhichProvider::Nyaa]
    }

    pub fn name(&self) -> &'static str {
        match self {
            WhichProvider::Knaben => Knaben.name(),
            WhichProvider::Nyaa => Nyaa.name(),
        }
    }

    pub fn display_url(&self) -> &'static str {
        match self {
            WhichProvider::Knaben => Knaben.display_url(),
            WhichProvider::Nyaa => Nyaa.display_url(),
        }
    }

    pub fn category(&self) -> ProviderCategory {
        match self {
            WhichProvider::Knaben => ProviderCategory::General,
            WhichProvider::Nyaa => ProviderCategory::Anime,
        }
    }

    pub async fn search(
        &self,
        client: &Client,
        query: &str,
    ) -> Result<MagneteaseResult, MagneteaseError> {
        match self {
            WhichProvider::Knaben => Knaben.search(client, query).await,
            WhichProvider::Nyaa => Nyaa.search(client, query).await,
        }
    }
}