riva 0.1.0

Provider-agnostic Rust library for extracting normalized media stream metadata from SoundCloud and YouTube via async helpers.
Documentation
use url::Url;

use super::extractor::RivaError;

pub fn normalize_video_id(input: &str) -> Result<String, RivaError> {
    if looks_like_video_id(input) {
        return Ok(input.to_string());
    }

    let normalized = if input.starts_with("http://") || input.starts_with("https://") {
        input.to_string()
    } else {
        format!("https://{input}")
    };

    let url = Url::parse(&normalized).map_err(|_| RivaError::InvalidUrl)?;
    let host = url.host_str().unwrap_or_default();

    if host == "youtu.be" {
        let path = url.path().trim_matches('/');
        if looks_like_video_id(path) {
            return Ok(path.to_string());
        }
        return Err(RivaError::InvalidUrl);
    }

    if host.contains("youtube.") {
        if let Some(id) = url
            .query_pairs()
            .find(|(k, _)| k == "v")
            .map(|(_, v)| v.into_owned())
            .filter(|id| looks_like_video_id(id))
        {
            return Ok(id);
        }

        if let Some(segments) = url.path_segments() {
            let segments: Vec<_> = segments.collect();
            if segments.len() >= 2 {
                match segments[0] {
                    "shorts" | "embed" | "live" | "v" => {
                        if looks_like_video_id(segments[1]) {
                            return Ok(segments[1].to_string());
                        }
                    }
                    _ => {}
                }
            }
        }
    }

    Err(RivaError::InvalidUrl)
}

fn looks_like_video_id(value: &str) -> bool {
    (value.len() == 11 || value.len() == 12)
        && value
            .chars()
            .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
}