diff --git a/src/input/youtube.rs b/src/input/youtube.rs new file mode 100644 index 0000000..ab30f58 --- /dev/null +++ b/src/input/youtube.rs @@ -0,0 +1,62 @@ +//! YouTube URL 輸入 + +use anyhow::Result; +use std::process::Command; + +pub struct YouTubeInput { + url: Option, + title: Option, + duration: Option, +} + +impl YouTubeInput { + pub fn new() -> Self { + Self { + url: None, + title: None, + duration: None, + } + } + + pub fn parse(&mut self, url: &str) -> Result { + if !Self::is_youtube_url(url) { + anyhow::bail!("Not a valid YouTube URL"); + } + + self.url = Some(url.to_string()); + + let info = self.get_video_info(url)?; + self.title = Some(info.0); + self.duration = Some(info.1); + + Ok(url.to_string()) + } + + fn is_youtube_url(url: &str) -> bool { + url.contains("youtube.com") || url.contains("youtu.be") + } + + fn get_video_info(&self, url: &str) -> Result<(String, u64)> { + let output = Command::new("yt-dlp") + .args(["--dump-json", "--no-download", url]) + .output()?; + + if !output.status.success() { + anyhow::bail!("Failed to get video info"); + } + + let json: serde_json::Value = serde_json::from_slice(&output.stdout)?; + let title = json["title"].as_str().unwrap_or("Unknown").to_string(); + let duration = json["duration"].as_u64().unwrap_or(0); + + Ok((title, duration)) + } + + pub fn get_title(&self) -> Option<&str> { + self.title.as_deref() + } + + pub fn get_duration(&self) -> Option { + self.duration + } +}