Skip to content

Instantly share code, notes, and snippets.

@omer-biz
Created October 19, 2024 17:05
Show Gist options
  • Save omer-biz/2bb509951a4b79f08db1ab3847d9d1f5 to your computer and use it in GitHub Desktop.
Save omer-biz/2bb509951a4b79f08db1ab3847d9d1f5 to your computer and use it in GitHub Desktop.
A minimalistic rewrite of play-with-mpv, cause why not !? Works with the browser extensions by play-with-mpv.
use std::{
path::{Path, PathBuf},
process::Command,
sync::Arc,
thread,
};
use clap::Parser;
use tiny_http::Response;
use url::Url;
fn find_in_path<P>(exe_name: P) -> Option<PathBuf>
where
P: AsRef<Path>,
{
std::env::var_os("PATH").and_then(|paths| {
std::env::split_paths(&paths)
.filter_map(|dir| {
let full_path = dir.join(&exe_name);
if full_path.is_file() {
Some(full_path)
} else {
None
}
})
.next()
})
}
#[derive(Parser)]
struct Args {
/// port to bind to
#[clap(long, default_value = "7531")]
pub port: u16,
/// allow other computers to connect
#[clap(long, default_value = "false")]
pub public: bool,
}
fn main() {
let mpv_path: Arc<Path> = find_in_path("mpv").expect("mpv is not installed").into();
let args = Args::parse();
let host = if args.public { "0.0.0.0" } else { "127.0.0.1" };
let server =
Arc::new(tiny_http::Server::http((host, args.port)).expect("unable to bind to port"));
println!("Listening on {host}:{}", args.port);
let mut handles = vec![];
for _ in 0..4 {
let server = server.clone();
let mpv_path = mpv_path.clone();
handles.push(thread::spawn(move || handle_request(server, mpv_path)));
}
for h in handles {
let _ = h.join();
}
}
fn handle_request(server: Arc<tiny_http::Server>, mpv_path: Arc<Path>) {
for request in server.incoming_requests() {
// at this point you might be asking why ? Why indeed.
let url = Url::parse("http://example.org/")
.expect("if this fails I'm gonna shot myself in the foot for real.");
let params = url.join(request.url()).unwrap();
let pairs = params.query_pairs();
let play_url = pairs
.filter_map(|(k, v)| {
if k == "play_url" {
Some(v.to_string())
} else {
None
}
})
.next();
if let Some(play_url) = play_url {
let mpv_path = mpv_path.clone();
thread::spawn(move || play_video(play_url, mpv_path));
} else {
handle_404(request);
}
}
}
fn play_video(play_url: String, mpv_path: Arc<Path>) {
println!("playing video at: {}", play_url);
Command::new(mpv_path.as_os_str())
.arg(play_url)
.arg("--force-window")
// TODO: These should come from the server.
.arg("--ytdl-format=bestvideo[height=1080]+bestaudio")
.spawn()
.unwrap();
}
fn handle_404(request: tiny_http::Request) {
let response = Response::from_string("not found").with_status_code(404);
let _ = request.respond(response);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment