av_stream_info_rust/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
//! This library can analyze a http/https address and check if leads to an audio or a video stream
//! If so, then it will extract information about the stream from its metadata or in case of HLS streams
//! from its master playlist file.
//!
//! # Example
//! ```rust
//! let list = av_stream_info_rust::check("https://example.com/test.m3u", 10, 3, 3);
//! for item in list {
//! println!("{:?}", item);
//! }
//! ```
extern crate hls_m3u8;
#[macro_use]
extern crate log;
extern crate native_tls;
extern crate playlist_decoder;
extern crate reqwest;
extern crate url;
extern crate serde;
extern crate serde_json;
mod decodeerror;
mod lat_long;
mod request;
mod request_error;
mod streamcheck;
mod streamcheckerror;
mod streamcheckresult;
mod streaminfo;
mod http_config;
use std::thread;
use std::time::Duration;
pub use decodeerror::DecodeError;
pub use http_config::extract_from_homepage;
pub use http_config::MetaInfoFile;
pub use lat_long::LatLong;
pub use streamcheckerror::StreamCheckError;
pub use streamcheckresult::StreamCheckResult;
pub use streamcheckresult::UrlType;
pub use streaminfo::StreamInfo;
/// Check url for audio/video stream.
/// # Example
/// ```rust
/// let item = av_stream_info_rust::check_tree("https://example.com/test.m3u", 10, 3, 3, true);
/// println!("{:#?}", item);
/// ```
/// # Arguments
/// * `url` - The url to check
/// * `timeout` - TCP timeout for connect and read in seconds
/// * `max_depth` - How many layers of http redirects or playlists should be followed
/// * `retries` - Retry how many times to find at least one working stream
/// * `early_exit_on_first_ok` - return from checking as early as 1 working stream has been found
pub async fn check_tree(
url: &str,
timeout: u32,
max_depth: u8,
max_retries: u8,
) -> StreamCheckResult {
let mut retries: u8 = 0;
loop {
let mut urllist = vec![url.to_string()];
debug!("Check retry {}", retries);
for depth in 1..max_depth {
debug!("Check depth {}", depth);
for url in urllist.clone() {
debug!("Check url '{}'", url);
let result = streamcheck::check(&url, timeout).await;
if has_ok_result(&result) {
return result;
}
match &result.info {
Ok(info) => match info {
UrlType::Playlist(list) => {
urllist = list.clone();
}
_ => {}
},
_ => {}
};
}
}
retries += 1;
if retries > max_retries {
break;
}
thread::sleep(Duration::from_secs(1));
}
return StreamCheckResult::new(url, Err(StreamCheckError::NoResult()));
}
fn has_ok_result(result: &StreamCheckResult) -> bool {
match &result.info {
Ok(info) => match info {
UrlType::Stream(_) => true,
UrlType::Playlist(_) => false,
},
Err(_) => false,
}
}