use reqwest::Url;
pub fn get_youtube_api_key() -> Option<String> {
std::env::var("TRIMSEC_YOUTUBE_KEY").ok()
}
#[derive(Debug, PartialEq)]
pub struct YoutubeId {
pub id: String,
pub is_playlist: bool,
}
pub fn get_youtube_id(link: &str) -> Option<YoutubeId> {
let mut is_playlist = false;
if let Ok(parsed_url) = Url::parse(link) {
if !parsed_url
.host_str()
.is_some_and(|f| f == "www.youtube.com" || f == "youtube.com" || f == "youtu.be")
{
return None;
}
let query_search = |q: &str, ptr: &str| {
q.split('&')
.find(|p| p.starts_with(ptr))
.map(|p| p.trim_start_matches(ptr).to_string())
};
let id: Option<String> = if parsed_url.path().starts_with("/shorts/")
|| parsed_url.path().starts_with("/embed/")
{
parsed_url
.path_segments()
.and_then(|f| f.last())
.map(|s| s.to_string())
} else if parsed_url.path().starts_with("/watch") {
parsed_url.query().and_then(|q| {
if q.contains("list=") {
let listsearch = query_search(q, "list=");
if listsearch.is_none() || listsearch.clone().is_some_and(|f| f.is_empty()) {
query_search(q, "v=")
} else {
is_playlist = true;
listsearch
}
} else {
query_search(q, "v=")
}
})
} else if parsed_url.path().starts_with("/playlist") {
is_playlist = true;
parsed_url.query().and_then(|q| query_search(q, "list="))
} else if parsed_url.host_str().is_some_and(|f| f == "youtu.be") {
Some(parsed_url.path().trim_start_matches("/").to_string())
} else {
return None;
};
if id == Some("".to_string()) {
None
} else if let Some(id) = id {
Some(YoutubeId { id, is_playlist })
} else {
None
}
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_id_splitter() {
assert_eq!(get_youtube_id("test-driven-development"), None);
assert_eq!(
get_youtube_id("https://www.youtube.com/embed/ZNYRjxJ3sdY"),
Some(YoutubeId {
id: "ZNYRjxJ3sdY".to_string(),
is_playlist: false
})
);
assert_eq!(
get_youtube_id("https://www.youtube.com/shorts/ZNYRjxJ3sdY"),
Some(YoutubeId {
id: "ZNYRjxJ3sdY".to_string(),
is_playlist: false
})
);
assert_eq!(
get_youtube_id("https://www.youtube.com/watch?v=ZNYRjxJ3sdY"),
Some(YoutubeId {
id: "ZNYRjxJ3sdY".to_string(),
is_playlist: false
})
);
assert_eq!(
get_youtube_id(
"https://www.youtube.com/playlist?list=PLHXZ9OQGMqxersk8fUxiUMSIx0DBqsKZS"
),
Some(YoutubeId {
id: "PLHXZ9OQGMqxersk8fUxiUMSIx0DBqsKZS".to_string(),
is_playlist: true
})
);
assert_eq!(
get_youtube_id("https://www.youtube.com/playlist?list="),
None
);
assert_eq!(get_youtube_id("https://www.youtube.com/watch?v="), None,);
assert_eq!(
get_youtube_id(
"https://www.youtube.com/watch?v=rdXw7Ps9vxc&list=PLHXZ9OQGMqxersk8fUxiUMSIx0DBqsKZS"
),
Some(YoutubeId {
id: "PLHXZ9OQGMqxersk8fUxiUMSIx0DBqsKZS".to_string(),
is_playlist: true
})
);
assert_eq!(
get_youtube_id("https://www.youtube.com/watch?v=rdXw7Ps9vxc&list="),
Some(YoutubeId {
id: "rdXw7Ps9vxc".to_string(),
is_playlist: false
})
);
assert_eq!(
get_youtube_id("https://youtu.be/sEWIDdQKWgc?si=Ywu5MycwAaZ4cZ3t"),
Some(YoutubeId {
id: "sEWIDdQKWgc".to_string(),
is_playlist: false
})
);
assert_eq!(
get_youtube_id("https://youtu.be/?si=Ywu5MycwAaZ4cZ3t"),
None,
);
assert_eq!(get_youtube_id("https://youtu.be/"), None,);
assert_eq!(
get_youtube_id("https://www.youtube.com/watch?v=&list="),
None,
)
}
}