tunein-cli 0.5.0

Browse and listen to thousands of radio stations across the globe right from your terminal 🌎 📻 🎵✨
use tunein_cli::{
    api::{
        objects::v1alpha1::{Category, Station, StationLinkDetails},
        tunein::v1alpha1::{
            browse_service_server::BrowseService, BrowseCategoryRequest, BrowseCategoryResponse,
            GetCategoriesRequest, GetCategoriesResponse, GetStationDetailsRequest,
            GetStationDetailsResponse, SearchRequest, SearchResponse,
        },
    },
    provider::radiobrowser::Radiobrowser,
};

use tunein_cli::provider::{tunein::Tunein, Provider};

#[derive(Default)]
pub struct Browse;

#[tonic::async_trait]
impl BrowseService for Browse {
    async fn get_categories(
        &self,
        request: tonic::Request<GetCategoriesRequest>,
    ) -> Result<tonic::Response<GetCategoriesResponse>, tonic::Status> {
        let req = request.into_inner();
        let provider = req.provider.as_deref();

        let client: Box<dyn Provider + Send + Sync> = match provider {
            Some("tunein") => Box::new(Tunein::new()),
            Some("radiobrowser") => Box::new(Radiobrowser::new().await),
            None => Box::new(Tunein::new()),
            _ => {
                return Err(tonic::Status::internal("Unsupported provider"));
            }
        };

        let offset = req.offset.unwrap_or(0);
        let limit = req.limit.unwrap_or(100);
        let result = client
            .categories(offset, limit)
            .await
            .map_err(|e| tonic::Status::internal(e.to_string()))?;

        Ok(tonic::Response::new(GetCategoriesResponse {
            categories: result.into_iter().map(Category::from).collect(),
        }))
    }

    async fn browse_category(
        &self,
        request: tonic::Request<BrowseCategoryRequest>,
    ) -> Result<tonic::Response<BrowseCategoryResponse>, tonic::Status> {
        let req = request.into_inner();
        let category_id = req.category_id;

        let offset = req.offset.unwrap_or(0);
        let limit = req.limit.unwrap_or(100);

        let provider = req.provider.as_deref();

        let client: Box<dyn Provider + Send + Sync> = match provider {
            Some("tunein") => Box::new(Tunein::new()),
            Some("radiobrowser") => Box::new(Radiobrowser::new().await),
            None => Box::new(Tunein::new()),
            _ => {
                return Err(tonic::Status::internal("Unsupported provider"));
            }
        };

        let results = client
            .browse(category_id, offset, limit)
            .await
            .map_err(|e| tonic::Status::internal(e.to_string()))?;

        let categories = results.into_iter().map(Category::from).collect();
        Ok(tonic::Response::new(BrowseCategoryResponse { categories }))
    }

    async fn get_station_details(
        &self,
        request: tonic::Request<GetStationDetailsRequest>,
    ) -> Result<tonic::Response<GetStationDetailsResponse>, tonic::Status> {
        let req = request.into_inner();
        let station_id = req.id;

        let provider = req.provider.as_deref();

        let client: Box<dyn Provider + Send + Sync> = match provider {
            Some("tunein") => Box::new(Tunein::new()),
            Some("radiobrowser") => Box::new(Radiobrowser::new().await),
            None => Box::new(Tunein::new()),
            _ => {
                return Err(tonic::Status::internal("Unsupported provider"));
            }
        };

        let result = client
            .get_station(station_id)
            .await
            .map_err(|e| tonic::Status::internal(e.to_string()))?;

        let station = match result {
            Some(station) => station,
            None => return Err(tonic::Status::internal("No station found")),
        };
        Ok(tonic::Response::new(GetStationDetailsResponse {
            station_link_details: Some(StationLinkDetails::from(station)),
        }))
    }

    async fn search(
        &self,
        request: tonic::Request<SearchRequest>,
    ) -> Result<tonic::Response<SearchResponse>, tonic::Status> {
        let req = request.into_inner();
        let provider = req.provider.as_deref();

        let client: Box<dyn Provider + Send + Sync> = match provider {
            Some("tunein") => Box::new(Tunein::new()),
            Some("radiobrowser") => Box::new(Radiobrowser::new().await),
            None => Box::new(Tunein::new()),
            _ => {
                return Err(tonic::Status::internal("Unsupported provider"));
            }
        };

        let results = client
            .search(req.query)
            .await
            .map_err(|e| tonic::Status::internal(e.to_string()))?;
        let station = results.into_iter().map(Station::from).collect();
        Ok(tonic::Response::new(SearchResponse { station }))
    }
}