feat: open selected YouTube video in browser
This commit is contained in:
@@ -805,6 +805,52 @@ fn failure(errors: &Receiver<io::Result<String>>, fallback: String) -> Option<Re
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_in_browser(id: &str) -> io::Result<Receiver<Result<(), String>>> {
|
||||
if !valid_video_id(id) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid YouTube video ID",
|
||||
));
|
||||
}
|
||||
let opener = if cfg!(target_os = "macos") {
|
||||
"open"
|
||||
} else {
|
||||
"xdg-open"
|
||||
};
|
||||
let child = isolated_command(OsStr::new(opener))
|
||||
.arg(format!("https://www.youtube.com/watch?v={id}"))
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.map_err(|error| {
|
||||
io::Error::new(
|
||||
error.kind(),
|
||||
format!("Cannot start browser opener: {error}"),
|
||||
)
|
||||
})?;
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
thread::spawn(move || {
|
||||
let result = child
|
||||
.wait_with_output()
|
||||
.map_err(|error| format!("Cannot wait for browser opener: {error}"))
|
||||
.and_then(|output| {
|
||||
if output.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
let error = String::from_utf8_lossy(&output.stderr);
|
||||
Err(format!(
|
||||
"Browser opener exited with {}: {}",
|
||||
output.status,
|
||||
error.trim()
|
||||
))
|
||||
}
|
||||
});
|
||||
let _ = sender.send(result);
|
||||
});
|
||||
Ok(receiver)
|
||||
}
|
||||
|
||||
pub struct PlayerLaunch {
|
||||
player: Child,
|
||||
player_errors: Receiver<io::Result<String>>,
|
||||
@@ -1465,6 +1511,16 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn browser_open_rejects_unsafe_video_ids_before_spawning() {
|
||||
for id in ["", "--help", "jNQXAC9IVRw&list=other", "日本語"] {
|
||||
assert!(matches!(
|
||||
open_in_browser(id),
|
||||
Err(error) if error.kind() == io::ErrorKind::InvalidInput
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn publication_dates_prefer_exact_metadata_and_handle_utc_boundaries_and_invalid_dates() {
|
||||
for feed in [false, true] {
|
||||
|
||||
Reference in New Issue
Block a user