mirror of
https://gitlab.com/hladislav/radiobrowser-lib-rust.git
synced 2025-04-29 23:34:12 +00:00
added blocking interface
This commit is contained in:
parent
afe64b7795
commit
794aa513ee
10 changed files with 430 additions and 17 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "radiobrowser"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["segler_alex <segler_alex@web.de>"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -15,11 +15,16 @@ repository = "https://gitlab.com/radiobrowser/radiobrowser-lib-rust"
|
|||
async-std = { version = "1.11.0", features = ["attributes", "tokio1"] }
|
||||
async-std-resolver = "0.21.2"
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
futures = { version = "0.3.21" }
|
||||
futures = { version = "0.3.21" }
|
||||
log = { version = "0.4.16" }
|
||||
rand = { version = "0.8.5" }
|
||||
reqwest = { version = "0.11.10", features = ["json"] }
|
||||
serde = { version = "1.0.136", features = ["derive"] }
|
||||
|
||||
[features]
|
||||
default = ["blocking"]
|
||||
blocking = []
|
||||
|
||||
[badges]
|
||||
# The `maintenance` table indicates the status of the maintenance of
|
||||
# the crate. This may be used by a registry, but is currently not
|
||||
|
|
20
src/api.rs
20
src/api.rs
|
@ -1,6 +1,5 @@
|
|||
use crate::external::post_api;
|
||||
use crate::ApiConfig;
|
||||
use crate::ApiCountry;
|
||||
use crate::CountrySearchBuilder;
|
||||
use crate::LanguageSearchBuilder;
|
||||
use crate::StationSearchBuilder;
|
||||
|
@ -13,6 +12,8 @@ use std::error::Error;
|
|||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
|
||||
use log::trace;
|
||||
|
||||
use async_std_resolver::proto::rr::RecordType;
|
||||
use async_std_resolver::proto::xfer::DnsRequestOptions;
|
||||
use async_std_resolver::{config, resolver};
|
||||
|
@ -31,7 +32,8 @@ impl RadioBrowserAPI {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_current_server(&mut self) -> String {
|
||||
fn get_current_server(&mut self) -> String {
|
||||
trace!("get_current_server()");
|
||||
if self.servers.len() > 0 {
|
||||
self.current = self.current % self.servers.len();
|
||||
format!("https://{}", self.servers[self.current])
|
||||
|
@ -40,7 +42,7 @@ impl RadioBrowserAPI {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn post_api<P: DeserializeOwned, A: AsRef<str>>(
|
||||
async fn post_api<P: DeserializeOwned, A: AsRef<str>>(
|
||||
&mut self,
|
||||
endpoint: A,
|
||||
) -> Result<P, Box<dyn Error>> {
|
||||
|
@ -76,16 +78,8 @@ impl RadioBrowserAPI {
|
|||
post_api(self.get_current_server(), endpoint, mapjson).await
|
||||
}
|
||||
|
||||
pub async fn get_countries_filtered<P: AsRef<str>>(
|
||||
&mut self,
|
||||
filter: P,
|
||||
) -> Result<Vec<ApiCountry>, Box<dyn Error>> {
|
||||
Ok(self
|
||||
.post_api(format!("/json/countries/{}", filter.as_ref()))
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn get_servers() -> Result<Vec<String>, Box<dyn Error>> {
|
||||
trace!("get_servers()");
|
||||
let resolver = resolver(
|
||||
config::ResolverConfig::default(),
|
||||
config::ResolverOpts::default(),
|
||||
|
@ -105,7 +99,7 @@ impl RadioBrowserAPI {
|
|||
.collect();
|
||||
|
||||
list.shuffle(&mut thread_rng());
|
||||
println!("Servers: {:?}", list);
|
||||
trace!("Servers: {:?}", list);
|
||||
Ok(list)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/*
|
||||
use futures::join;
|
||||
use radiobrowser::RadioBrowserAPI;
|
||||
use radiobrowser::StationOrder;
|
||||
|
@ -27,3 +28,18 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||
println!("Stations found: {}", stations?.len());
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
|
||||
use radiobrowser::blocking::RadioBrowserAPI;
|
||||
use std::error::Error;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let api = RadioBrowserAPI::new()?;
|
||||
let servers = RadioBrowserAPI::get_servers()?;
|
||||
println!("Servers: {:?}", servers);
|
||||
let countries = api.get_countries().send()?;
|
||||
println!("Countries: {:?}", countries);
|
||||
let stations = api.get_stations().name("jazz").send()?;
|
||||
println!("Stations: {:?}", stations);
|
||||
Ok(())
|
||||
}
|
50
src/blocking/api.rs
Normal file
50
src/blocking/api.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use crate::blocking::stationsearchbuilder::StationSearchBuilder;
|
||||
use crate::blocking::CountrySearchBuilder;
|
||||
use crate::blocking::LanguageSearchBuilder;
|
||||
use crate::blocking::TagSearchBuilder;
|
||||
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RadioBrowserAPI {
|
||||
api: crate::RadioBrowserAPI,
|
||||
}
|
||||
|
||||
use async_std::task;
|
||||
|
||||
impl RadioBrowserAPI {
|
||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
||||
task::block_on(async { crate::RadioBrowserAPI::new().await })
|
||||
.map(|api| RadioBrowserAPI { api })
|
||||
}
|
||||
|
||||
pub fn get_stations(&self) -> StationSearchBuilder {
|
||||
StationSearchBuilder::new(self.api.get_stations())
|
||||
}
|
||||
|
||||
pub fn get_countries(&self) -> CountrySearchBuilder {
|
||||
CountrySearchBuilder::new(self.api.get_countries())
|
||||
}
|
||||
|
||||
pub fn get_languages(&self) -> LanguageSearchBuilder {
|
||||
LanguageSearchBuilder::new(self.api.get_languages())
|
||||
}
|
||||
|
||||
pub fn get_tags(&self) -> TagSearchBuilder {
|
||||
TagSearchBuilder::new(self.api.get_tags())
|
||||
}
|
||||
|
||||
pub fn send<P: AsRef<str>, Q: DeserializeOwned>(
|
||||
&mut self,
|
||||
endpoint: P,
|
||||
mapjson: HashMap<String, String>,
|
||||
) -> Result<Q, Box<dyn Error>> {
|
||||
task::block_on(async { self.api.send(endpoint, mapjson).await })
|
||||
}
|
||||
|
||||
pub fn get_servers() -> Result<Vec<String>, Box<dyn Error>> {
|
||||
task::block_on(async { crate::RadioBrowserAPI::get_servers().await })
|
||||
}
|
||||
}
|
54
src/blocking/countrysearchbuilder.rs
Normal file
54
src/blocking/countrysearchbuilder.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use crate::ApiCountry;
|
||||
use async_std::task;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CountrySearchBuilder {
|
||||
builder: crate::CountrySearchBuilder,
|
||||
}
|
||||
|
||||
impl CountrySearchBuilder {
|
||||
pub fn new(builder: crate::CountrySearchBuilder) -> Self {
|
||||
CountrySearchBuilder { builder }
|
||||
}
|
||||
|
||||
pub fn filter<P: AsRef<str>>(self, filter: P) -> Self {
|
||||
CountrySearchBuilder {
|
||||
builder: self.builder.filter(filter.as_ref().to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn order(self, order: crate::CountryOrder) -> Self {
|
||||
CountrySearchBuilder {
|
||||
builder: self.builder.order(order),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reverse(self, reverse: bool) -> Self {
|
||||
CountrySearchBuilder {
|
||||
builder: self.builder.reverse(reverse),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset<P: AsRef<str>>(self, offset: P) -> Self {
|
||||
CountrySearchBuilder {
|
||||
builder: self.builder.offset(offset),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limit<P: AsRef<str>>(self, limit: P) -> Self {
|
||||
CountrySearchBuilder {
|
||||
builder: self.builder.limit(limit),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hidebroken(self, hidebroken: bool) -> Self {
|
||||
CountrySearchBuilder {
|
||||
builder: self.builder.hidebroken(hidebroken),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(self) -> Result<Vec<ApiCountry>, Box<dyn Error>> {
|
||||
task::block_on(async { self.builder.send().await })
|
||||
}
|
||||
}
|
54
src/blocking/languagesearchbuilder.rs
Normal file
54
src/blocking/languagesearchbuilder.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use crate::ApiLanguage;
|
||||
use async_std::task;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LanguageSearchBuilder {
|
||||
builder: crate::LanguageSearchBuilder,
|
||||
}
|
||||
|
||||
impl LanguageSearchBuilder {
|
||||
pub fn new(builder: crate::LanguageSearchBuilder) -> Self {
|
||||
LanguageSearchBuilder { builder }
|
||||
}
|
||||
|
||||
pub fn filter<P: AsRef<str>>(self, filter: P) -> Self {
|
||||
LanguageSearchBuilder {
|
||||
builder: self.builder.filter(filter.as_ref().to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn order(self, order: crate::LanguageOrder) -> Self {
|
||||
LanguageSearchBuilder {
|
||||
builder: self.builder.order(order),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reverse(self, reverse: bool) -> Self {
|
||||
LanguageSearchBuilder {
|
||||
builder: self.builder.reverse(reverse),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset<P: AsRef<str>>(self, offset: P) -> Self {
|
||||
LanguageSearchBuilder {
|
||||
builder: self.builder.offset(offset),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limit<P: AsRef<str>>(self, limit: P) -> Self {
|
||||
LanguageSearchBuilder {
|
||||
builder: self.builder.limit(limit),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hidebroken(self, hidebroken: bool) -> Self {
|
||||
LanguageSearchBuilder {
|
||||
builder: self.builder.hidebroken(hidebroken),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(self) -> Result<Vec<ApiLanguage>, Box<dyn Error>> {
|
||||
task::block_on(async { self.builder.send().await })
|
||||
}
|
||||
}
|
10
src/blocking/mod.rs
Normal file
10
src/blocking/mod.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
pub mod api;
|
||||
pub mod countrysearchbuilder;
|
||||
pub mod languagesearchbuilder;
|
||||
pub mod stationsearchbuilder;
|
||||
pub mod tagsearchbuilder;
|
||||
|
||||
pub use api::RadioBrowserAPI;
|
||||
pub use countrysearchbuilder::CountrySearchBuilder;
|
||||
pub use languagesearchbuilder::LanguageSearchBuilder;
|
||||
pub use tagsearchbuilder::TagSearchBuilder;
|
154
src/blocking/stationsearchbuilder.rs
Normal file
154
src/blocking/stationsearchbuilder.rs
Normal file
|
@ -0,0 +1,154 @@
|
|||
use crate::structs::ApiStation;
|
||||
use crate::StationOrder;
|
||||
use async_std::task;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StationSearchBuilder {
|
||||
builder: crate::StationSearchBuilder,
|
||||
}
|
||||
|
||||
impl StationSearchBuilder {
|
||||
pub fn new(builder: crate::StationSearchBuilder) -> Self {
|
||||
StationSearchBuilder { builder }
|
||||
}
|
||||
|
||||
pub fn name<P: AsRef<str>>(self, name: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.name(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_exact(self, name_exact: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.name_exact(name_exact),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn country<P: AsRef<str>>(self, country: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.country(country),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn country_exact(self, country_exact: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.country_exact(country_exact),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn countrycode<P: AsRef<str>>(self, countrycode: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.countrycode(countrycode),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state<P: AsRef<str>>(self, state: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.state(state),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state_exact(self, state_exact: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.state_exact(state_exact),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn language<P: AsRef<str>>(self, language: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.language(language),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn language_exact(self, language_exact: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.language_exact(language_exact),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tag<P: AsRef<str>>(self, tag: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.tag(tag),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tag_exact(self, tag_exact: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.tag_exact(tag_exact),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
tagList STRING, STRING, ... OPTIONAL. , a comma-separated list of tag. It can also be an array of string in JSON HTTP POST parameters. All tags in list have to match.
|
||||
*/
|
||||
|
||||
pub fn codec<P: AsRef<str>>(self, codec: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.codec(codec),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bitrate_min<P: AsRef<str>>(self, bitrate_min: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.bitrate_min(bitrate_min),
|
||||
}
|
||||
}
|
||||
pub fn bitrate_max<P: AsRef<str>>(self, bitrate_max: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.bitrate_max(bitrate_max),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_geo_info(self, has_geo_info: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.has_geo_info(has_geo_info),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_extended_info(self, has_extended_info: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.has_extended_info(has_extended_info),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_https(self, is_https: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.is_https(is_https),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn order(self, order: StationOrder) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.order(order),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reverse(self, reverse: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.reverse(reverse),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset<P: AsRef<str>>(self, offset: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.offset(offset),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limit<P: AsRef<str>>(self, limit: P) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.limit(limit),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hidebroken(self, hidebroken: bool) -> Self {
|
||||
StationSearchBuilder {
|
||||
builder: self.builder.hidebroken(hidebroken),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(self) -> Result<Vec<ApiStation>, Box<dyn Error>> {
|
||||
task::block_on(async { self.builder.send().await })
|
||||
}
|
||||
}
|
54
src/blocking/tagsearchbuilder.rs
Normal file
54
src/blocking/tagsearchbuilder.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use crate::ApiTag;
|
||||
use async_std::task;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TagSearchBuilder {
|
||||
builder: crate::TagSearchBuilder,
|
||||
}
|
||||
|
||||
impl TagSearchBuilder {
|
||||
pub fn new(builder: crate::TagSearchBuilder) -> Self {
|
||||
TagSearchBuilder { builder }
|
||||
}
|
||||
|
||||
pub fn filter<P: AsRef<str>>(self, filter: P) -> Self {
|
||||
TagSearchBuilder {
|
||||
builder: self.builder.filter(filter.as_ref().to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn order(self, order: crate::TagOrder) -> Self {
|
||||
TagSearchBuilder {
|
||||
builder: self.builder.order(order),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reverse(self, reverse: bool) -> Self {
|
||||
TagSearchBuilder {
|
||||
builder: self.builder.reverse(reverse),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset<P: AsRef<str>>(self, offset: P) -> Self {
|
||||
TagSearchBuilder {
|
||||
builder: self.builder.offset(offset),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limit<P: AsRef<str>>(self, limit: P) -> Self {
|
||||
TagSearchBuilder {
|
||||
builder: self.builder.limit(limit),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hidebroken(self, hidebroken: bool) -> Self {
|
||||
TagSearchBuilder {
|
||||
builder: self.builder.hidebroken(hidebroken),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(self) -> Result<Vec<ApiTag>, Box<dyn Error>> {
|
||||
task::block_on(async { self.builder.send().await })
|
||||
}
|
||||
}
|
24
src/lib.rs
24
src/lib.rs
|
@ -1,6 +1,23 @@
|
|||
//!
|
||||
//!
|
||||
//! # Example
|
||||
//! # Example blocking
|
||||
//! ```rust
|
||||
//! use radiobrowser::blocking::RadioBrowserAPI;
|
||||
//! use std::error::Error;
|
||||
//!
|
||||
//! fn main() -> Result<(), Box<dyn Error>> {
|
||||
//! let api = RadioBrowserAPI::new()?;
|
||||
//! let servers = RadioBrowserAPI::get_servers()?;
|
||||
//! println!("Servers: {:?}", servers);
|
||||
//! let countries = api.get_countries().send()?;
|
||||
//! println!("Countries: {:?}", countries);
|
||||
//! let stations = api.get_stations().name("jazz").send()?;
|
||||
//! println!("Stations: {:?}", stations);
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Example async
|
||||
//! ```rust
|
||||
//! use std::error::Error;
|
||||
//! use futures::join;
|
||||
|
@ -30,6 +47,8 @@
|
|||
//! ```
|
||||
|
||||
mod api;
|
||||
#[cfg(feature = "blocking")]
|
||||
pub mod blocking;
|
||||
mod external;
|
||||
mod stationsearchbuilder;
|
||||
mod countrysearchbuilder;
|
||||
|
@ -47,5 +66,8 @@ pub use structs::ApiTag;
|
|||
pub use stationsearchbuilder::StationSearchBuilder;
|
||||
pub use stationsearchbuilder::StationOrder;
|
||||
pub use countrysearchbuilder::CountrySearchBuilder;
|
||||
pub use countrysearchbuilder::CountryOrder;
|
||||
pub use languagesearchbuilder::LanguageSearchBuilder;
|
||||
pub use languagesearchbuilder::LanguageOrder;
|
||||
pub use tagsearchbuilder::TagSearchBuilder;
|
||||
pub use tagsearchbuilder::TagOrder;
|
Loading…
Reference in a new issue