av-stream-info-rust 0.13.2

Analyze a http/https internet address and display information if an audio or video stream has been found. All information is extracted from metainformation.
Documentation
//! 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
//! ```ignore
//! 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 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 external_check_result;

mod http_config;

use std::thread;
use std::time::Duration;

pub use decodeerror::DecodeError;
pub use external_check_result::StreamResult;
pub use http_config::extract_from_homepage_async;
#[cfg(feature = "blocking")]
pub use http_config::extract_from_homepage;
pub use http_config::MetaInfoFile;
pub use lat_long::LatLong;
use streamcheckerror::StreamCheckError;
use streamcheckresult::StreamCheckResult;
pub use streamcheckresult::UrlType;
pub use streaminfo::StreamInfo;

/// Check url for audio/video stream.
/// # Example
/// ```ignore
/// let item = av_stream_info_rust::check("https://example.com/test.m3u", 10, 3, 3);
/// 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
#[cfg(feature = "blocking")]
pub fn check(
    url: &str,
    timeout: u32,
    agent: &str,
    max_depth: u8,
    max_retries: u8,
) -> StreamResult {
    use tokio::runtime::Runtime;
    let rt = Runtime::new().unwrap();
    rt.block_on(async {
        check_async(&url, timeout, agent, max_depth, max_retries).await
    })
}

/// Check url for audio/video stream.
/// # Example
/// ```ignore
/// let item = av_stream_info_rust::check_async("https://example.com/test.m3u", 10, 3, 3).await?;
/// 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
pub async fn check_async(
    url: &str,
    timeout: u32,
    agent: &str,
    max_depth: u8,
    max_retries: u8,
) -> StreamResult {
    let mut retries: u8 = 0;
    let mut log_lines = vec![];
    loop {
        let mut urllist = vec![url.to_string()];
        let mut already_checked = vec![];
        debug!("Check retry {}", retries);
        for depth in 1..max_depth {
            debug!("Check depth {}", depth);
            for url in urllist.clone() {
                if already_checked.contains(&url) {
                    continue;
                }
                debug!("Check url '{}'", url);
                log_lines.push(format!("Checking '{}' (retry {})", url, retries));
                already_checked.push(url.clone());
                let result = streamcheck::check(&mut log_lines, &url, agent, timeout).await;
                match &result.info {
                    Ok(info) => match info {
                        UrlType::Stream(info) => {
                            return StreamResult::new(result.url(), Some(info.to_owned()), log_lines);
                        },
                        _ => {}
                    },
                    _ => {}
                };
                match &result.info {
                    Ok(info) => match info {
                        UrlType::Playlist(list) => {
                            log_lines.push(format!("Found playlist at '{}'", url));
                            for url in list.iter() {
                                log_lines.push(format!("Adding url '{}' to check list", url));
                            }
                            urllist.extend(list.clone());
                            debug!("Urllist updated: {:?}", urllist);
                        }
                        _ => {}
                    },
                    _ => {}
                };
            }
        }
        retries += 1;
        if retries > max_retries {
            break;
        }
        thread::sleep(Duration::from_secs(1));
    }
    return StreamResult::new(url, None, log_lines);
}