mirror of
https://gitlab.com/hladislav/radiobrowser-lib-rust.git
synced 2025-04-29 23:34:12 +00:00
added station actions
This commit is contained in:
parent
5ba1aa492e
commit
adf4c5a49f
9 changed files with 255 additions and 51 deletions
12
Cargo.toml
12
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "radiobrowser"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["segler_alex <segler_alex@web.de>"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -16,15 +16,19 @@ 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" }
|
||||
log = { version = "0.4.16" }
|
||||
log = { version = "0.4.17" }
|
||||
rand = { version = "0.8.5" }
|
||||
reqwest = { version = "0.11.10", features = ["json"] }
|
||||
serde = { version = "1.0.136", features = ["derive"] }
|
||||
serde = { version = "1.0.137", features = ["derive"] }
|
||||
|
||||
[features]
|
||||
default = ["blocking"]
|
||||
default = []
|
||||
blocking = []
|
||||
|
||||
[[bin]]
|
||||
name = "test"
|
||||
required-features = ["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
|
||||
|
|
37
README.md
37
README.md
|
@ -1,12 +1,45 @@
|
|||
# Radiobrowser Lib Rust
|
||||
Client library for radio-browser.info and other radio-browser-rust servers
|
||||
|
||||
## Getting started
|
||||
## Features
|
||||
- [x] Async / Blocking API
|
||||
- [x] Clean query api with builder pattern
|
||||
- [x] Countries, languages, tags, stations, serverconfig
|
||||
- [x] Server statistics
|
||||
- [x] Station actions: click, vote
|
||||
- [ ] Add streams
|
||||
|
||||
## Getting started (Blocking)
|
||||
### Example:
|
||||
It needs to have the feature "blocking" enabled.
|
||||
Cargo.toml entry:
|
||||
```toml
|
||||
radiobrowser = { version = "*", features = ["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 status = RadioBrowserAPI::get_server_status()?;
|
||||
println!("Status: {:?}", status);
|
||||
let countries = api.get_countries().send()?;
|
||||
println!("Countries: {:?}", countries);
|
||||
let stations = api.get_stations().name("jazz").send()?;
|
||||
println!("Stations: {:?}", stations);
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Getting started (Async)
|
||||
Cargo.toml entry
|
||||
```toml
|
||||
radiobrowser = "*"
|
||||
```
|
||||
Example:
|
||||
### Example:
|
||||
```rust
|
||||
use radiobrowser::RadioBrowserAPI;
|
||||
use radiobrowser::StationOrder;
|
||||
|
|
35
src/api.rs
35
src/api.rs
|
@ -1,3 +1,6 @@
|
|||
use crate::ApiStationClickResult;
|
||||
use crate::ApiStationVoteResult;
|
||||
use crate::ApiStatus;
|
||||
use crate::external::post_api;
|
||||
use crate::ApiConfig;
|
||||
use crate::CountrySearchBuilder;
|
||||
|
@ -18,6 +21,21 @@ use async_std_resolver::proto::rr::RecordType;
|
|||
use async_std_resolver::proto::xfer::DnsRequestOptions;
|
||||
use async_std_resolver::{config, resolver};
|
||||
|
||||
|
||||
/// RadioBrowser client for async communication
|
||||
///
|
||||
/// It uses crate:async_std
|
||||
///
|
||||
/// Example
|
||||
/// ```rust
|
||||
/// use std::error::Error;
|
||||
/// use radiobrowser::RadioBrowserAPI;
|
||||
/// #[async_std::main]
|
||||
/// async fn main() -> Result<(), Box<dyn Error>> {
|
||||
/// let mut api = RadioBrowserAPI::new().await?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RadioBrowserAPI {
|
||||
servers: Vec<String>,
|
||||
|
@ -25,6 +43,9 @@ pub struct RadioBrowserAPI {
|
|||
}
|
||||
|
||||
impl RadioBrowserAPI {
|
||||
/// Create a new instance of a radiobrowser api client.
|
||||
/// It will fetch a list of radiobrowser server with get_servers()
|
||||
/// and save it internally.
|
||||
pub async fn new() -> Result<Self, Box<dyn Error>> {
|
||||
Ok(RadioBrowserAPI {
|
||||
servers: RadioBrowserAPI::get_servers().await?,
|
||||
|
@ -54,6 +75,20 @@ impl RadioBrowserAPI {
|
|||
Ok(self.post_api("/json/config").await?)
|
||||
}
|
||||
|
||||
pub async fn get_server_status(&mut self) -> Result<ApiStatus, Box<dyn Error>> {
|
||||
Ok(self.post_api("/json/stats").await?)
|
||||
}
|
||||
|
||||
/// Add a click to a station found by stationuuid
|
||||
pub async fn station_click<P: AsRef<str>>(&mut self, stationuuid: P) -> Result<ApiStationClickResult, Box<dyn Error>> {
|
||||
Ok(self.post_api(format!("/json/url/{}",stationuuid.as_ref())).await?)
|
||||
}
|
||||
|
||||
/// Add a vote to a station found by a stationuuid
|
||||
pub async fn station_vote<P: AsRef<str>>(&mut self, stationuuid: P) -> Result<ApiStationVoteResult, Box<dyn Error>> {
|
||||
Ok(self.post_api(format!("/json/vote/{}",stationuuid.as_ref())).await?)
|
||||
}
|
||||
|
||||
pub fn get_stations(&self) -> StationSearchBuilder {
|
||||
StationSearchBuilder::new(self.clone())
|
||||
}
|
||||
|
|
38
src/bin/test-async.rs
Normal file
38
src/bin/test-async.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use futures::join;
|
||||
use radiobrowser::RadioBrowserAPI;
|
||||
use radiobrowser::StationOrder;
|
||||
use std::error::Error;
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut api = RadioBrowserAPI::new().await?;
|
||||
let countries = api.get_countries().send();
|
||||
let languages = api.get_languages().send();
|
||||
let tags = api.get_tags().filter("jazz").send();
|
||||
let stations = api
|
||||
.get_stations()
|
||||
.name("jazz")
|
||||
.reverse(true)
|
||||
.order(StationOrder::Clickcount)
|
||||
.send();
|
||||
let mut api2 = api.clone();
|
||||
let config = api.get_server_config();
|
||||
let stats = api2.get_server_status();
|
||||
let (stations, config, countries, languages, tags, stats) = join!(stations, config, countries, languages, tags, stats);
|
||||
|
||||
println!("Config: {:#?}", config?);
|
||||
println!("Status: {:#?}", stats?);
|
||||
println!("Countries found: {}", countries?.len());
|
||||
println!("Languages found: {}", languages?.len());
|
||||
let tags = tags?;
|
||||
println!("Tags found: {}", tags.len());
|
||||
println!("{:?}", tags);
|
||||
let stations = stations?;
|
||||
println!("Stations found: {}", stations.len());
|
||||
|
||||
let vote_result = api.station_vote(&stations[0].stationuuid).await?;
|
||||
println!("Stations voted result: {:?}", vote_result);
|
||||
let click_result = api.station_click(&stations[0].stationuuid).await?;
|
||||
println!("Stations clicked result: {:?}", click_result);
|
||||
Ok(())
|
||||
}
|
|
@ -1,45 +1,21 @@
|
|||
/*
|
||||
use futures::join;
|
||||
use radiobrowser::RadioBrowserAPI;
|
||||
use radiobrowser::StationOrder;
|
||||
use std::error::Error;
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut api = RadioBrowserAPI::new().await?;
|
||||
let countries = api.get_countries().send();
|
||||
let languages = api.get_languages().send();
|
||||
let tags = api.get_tags().filter("jazz").send();
|
||||
let stations = api
|
||||
.get_stations()
|
||||
.name("jazz")
|
||||
.reverse(true)
|
||||
.order(StationOrder::Clickcount)
|
||||
.send();
|
||||
let config = api.get_server_config();
|
||||
let (stations, config, countries, languages, tags) = join!(stations, config, countries, languages, tags);
|
||||
|
||||
println!("Config: {:#?}", config?);
|
||||
println!("Countries found: {}", countries?.len());
|
||||
println!("Languages found: {}", languages?.len());
|
||||
let tags = tags?;
|
||||
println!("Tags found: {}", tags.len());
|
||||
println!("{:?}", tags);
|
||||
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 mut api = RadioBrowserAPI::new()?;
|
||||
let servers = RadioBrowserAPI::get_servers()?;
|
||||
println!("Servers: {:?}", servers);
|
||||
let status = api.get_server_status()?;
|
||||
println!("Status: {:#?}", status);
|
||||
let config = api.get_server_config()?;
|
||||
println!("Config: {:#?}", config);
|
||||
let countries = api.get_countries().send()?;
|
||||
println!("Countries: {:?}", countries);
|
||||
println!("Countries: {:?}", countries.len());
|
||||
let stations = api.get_stations().name("jazz").send()?;
|
||||
println!("Stations: {:?}", stations);
|
||||
println!("Stations with name containing 'jazz': {:?}", stations.len());
|
||||
let vote_result = api.station_vote(&stations[0].stationuuid)?;
|
||||
println!("Stations voted result: {:?}", vote_result);
|
||||
let click_result = api.station_click(&stations[0].stationuuid)?;
|
||||
println!("Stations clicked result: {:?}", click_result);
|
||||
Ok(())
|
||||
}
|
|
@ -2,6 +2,10 @@ use crate::blocking::stationsearchbuilder::StationSearchBuilder;
|
|||
use crate::blocking::CountrySearchBuilder;
|
||||
use crate::blocking::LanguageSearchBuilder;
|
||||
use crate::blocking::TagSearchBuilder;
|
||||
use crate::ApiStationClickResult;
|
||||
use crate::ApiStationVoteResult;
|
||||
use crate::ApiStatus;
|
||||
use crate::ApiConfig;
|
||||
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::collections::HashMap;
|
||||
|
@ -20,6 +24,24 @@ impl RadioBrowserAPI {
|
|||
.map(|api| RadioBrowserAPI { api })
|
||||
}
|
||||
|
||||
pub fn get_server_status(&mut self) -> Result<ApiStatus, Box<dyn Error>> {
|
||||
task::block_on(async { self.api.get_server_status().await })
|
||||
}
|
||||
|
||||
pub fn get_server_config(&mut self) -> Result<ApiConfig, Box<dyn Error>> {
|
||||
task::block_on(async { self.api.get_server_config().await })
|
||||
}
|
||||
|
||||
/// Add a click to a station found by stationuuid
|
||||
pub fn station_click<P: AsRef<str>>(&mut self, stationuuid: P) -> Result<ApiStationClickResult, Box<dyn Error>> {
|
||||
task::block_on(async { self.api.station_click(stationuuid).await })
|
||||
}
|
||||
|
||||
/// Add a vote to a station found by a stationuuid
|
||||
pub fn station_vote<P: AsRef<str>>(&mut self, stationuuid: P) -> Result<ApiStationVoteResult, Box<dyn Error>> {
|
||||
task::block_on(async { self.api.station_vote(stationuuid).await })
|
||||
}
|
||||
|
||||
pub fn get_stations(&self) -> StationSearchBuilder {
|
||||
StationSearchBuilder::new(self.api.get_stations())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
pub mod api;
|
||||
pub mod countrysearchbuilder;
|
||||
pub mod languagesearchbuilder;
|
||||
pub mod stationsearchbuilder;
|
||||
pub mod tagsearchbuilder;
|
||||
mod api;
|
||||
mod countrysearchbuilder;
|
||||
mod languagesearchbuilder;
|
||||
mod stationsearchbuilder;
|
||||
mod tagsearchbuilder;
|
||||
|
||||
pub use api::RadioBrowserAPI;
|
||||
pub use countrysearchbuilder::CountrySearchBuilder;
|
||||
pub use languagesearchbuilder::LanguageSearchBuilder;
|
||||
pub use tagsearchbuilder::TagSearchBuilder;
|
||||
pub use stationsearchbuilder::StationSearchBuilder;
|
|
@ -51,6 +51,7 @@
|
|||
//! ```
|
||||
|
||||
mod api;
|
||||
#[doc()]
|
||||
#[cfg(feature = "blocking")]
|
||||
pub mod blocking;
|
||||
mod external;
|
||||
|
@ -66,7 +67,13 @@ pub use structs::ApiCountry;
|
|||
pub use structs::ApiLanguage;
|
||||
pub use structs::ApiStation;
|
||||
pub use structs::ApiStreamingServer;
|
||||
pub use structs::ApiStationClick;
|
||||
pub use structs::ApiStationHistory;
|
||||
pub use structs::ApiTag;
|
||||
pub use structs::ApiStatus;
|
||||
pub use structs::ApiStationAddResult;
|
||||
pub use structs::ApiStationClickResult;
|
||||
pub use structs::ApiStationVoteResult;
|
||||
pub use stationsearchbuilder::StationSearchBuilder;
|
||||
pub use stationsearchbuilder::StationOrder;
|
||||
pub use countrysearchbuilder::CountrySearchBuilder;
|
||||
|
|
|
@ -1,7 +1,48 @@
|
|||
use serde::Deserialize;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Radiobrowser status and statistical information of single server.
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiStatus {
|
||||
pub supported_version: u32,
|
||||
pub software_version: Option<String>,
|
||||
pub status: String,
|
||||
pub stations: u64,
|
||||
pub stations_broken: u64,
|
||||
pub tags: u64,
|
||||
pub clicks_last_hour: u64,
|
||||
pub clicks_last_day: u64,
|
||||
pub languages: u64,
|
||||
pub countries: u64,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiStationAddResult {
|
||||
pub ok: bool,
|
||||
pub message: String,
|
||||
pub uuid: String,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiStationVoteResult {
|
||||
pub ok: bool,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiStationClickResult {
|
||||
pub ok: bool,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiCodec {
|
||||
name: String,
|
||||
stationcount: u64,
|
||||
}
|
||||
|
||||
/// A single station entry
|
||||
#[derive(PartialEq, Deserialize, Debug)]
|
||||
pub struct ApiStation {
|
||||
pub changeuuid: String,
|
||||
|
@ -42,6 +83,51 @@ pub struct ApiStation {
|
|||
pub has_extended_info: Option<bool>,
|
||||
}
|
||||
|
||||
/// A single historical entry for a station
|
||||
#[derive(PartialEq, Deserialize, Debug)]
|
||||
pub struct ApiStationHistory {
|
||||
pub changeuuid: String,
|
||||
pub stationuuid: String,
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
pub homepage: String,
|
||||
pub favicon: String,
|
||||
pub tags: String,
|
||||
pub country: String,
|
||||
pub countrycode: String,
|
||||
pub state: String,
|
||||
pub language: String,
|
||||
pub languagecodes: Option<String>,
|
||||
pub votes: i32,
|
||||
pub lastchangetime: String,
|
||||
pub lastchangetime_iso8601: Option<DateTime<Utc>>,
|
||||
pub geo_lat: Option<f64>,
|
||||
pub geo_long: Option<f64>,
|
||||
}
|
||||
|
||||
/// A click event for a station
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiStationClick {
|
||||
pub stationuuid: String,
|
||||
pub clickuuid: String,
|
||||
pub clicktimestamp_iso8601: Option<DateTime<Utc>>,
|
||||
pub clicktimestamp: String,
|
||||
}
|
||||
|
||||
/// A single step of a check action for a station
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiStationCheckStep {
|
||||
pub stepuuid: String,
|
||||
pub parent_stepuuid: Option<String>,
|
||||
pub checkuuid: String,
|
||||
pub stationuuid: String,
|
||||
pub url: String,
|
||||
pub urltype: Option<String>,
|
||||
pub error: Option<String>,
|
||||
pub creation_iso8601: DateTime<Utc>,
|
||||
}
|
||||
|
||||
/// A single country
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiCountry {
|
||||
pub name: String,
|
||||
|
@ -49,6 +135,7 @@ pub struct ApiCountry {
|
|||
pub stationcount: u32,
|
||||
}
|
||||
|
||||
/// A single language
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiLanguage {
|
||||
pub name: String,
|
||||
|
@ -56,13 +143,14 @@ pub struct ApiLanguage {
|
|||
pub stationcount: u32,
|
||||
}
|
||||
|
||||
/// A single tag
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiTag {
|
||||
pub name: String,
|
||||
pub stationcount: u32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Deserialize, Debug)]
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiStreamingServer {
|
||||
pub uuid: String,
|
||||
pub url: String,
|
||||
|
@ -71,7 +159,7 @@ pub struct ApiStreamingServer {
|
|||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Deserialize, Debug)]
|
||||
pub struct ApiConfig {
|
||||
pub check_enabled: bool,
|
||||
pub prometheus_exporter_enabled: bool,
|
||||
|
|
Loading…
Reference in a new issue