diff --git a/Cargo.toml b/Cargo.toml index 59fb934..73bd3e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,10 @@ adw = { version = "0.1.1", package = "libadwaita" } invidious = "0.3.2" gtk-ui-builder = "0.2.0" serde_json = "1.0" +gst = { version = "0.18.8", package = "gstreamer" } +anyhow = "1.0.65" +glib = "0.15.12" +gst-plugin-reqwest = "0.8.0" [profile.release] strip = true \ No newline at end of file diff --git a/src/inv.rs b/src/inv.rs index 506f205..f795182 100644 --- a/src/inv.rs +++ b/src/inv.rs @@ -3,11 +3,10 @@ use std::error::Error; //use serde::{Deserialize, Serialize}; //use serde_json::Result; -pub fn inv() -> Result<(), Box> { + +pub fn inv() -> Result> { let client = Client::new(String::from("https://invidious.projectsegfau.lt")); - let search_results = client.search(Some("q=rust programming"))?.items; - let video = client.video("5C_HPTJg5ek", None)?; - //println!("{:?}", video); - println!("{:?}", video.format_streams[2].url); - Ok(()) + let output = &client.video("5C_HPTJg5ek", None)?.format_streams[2].url; + println!("{}", output); + Ok(output.to_string()) } diff --git a/src/main.rs b/src/main.rs index 2a08447..06d28ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,10 @@ use std::fs::File; use std::path::Path; use gtk::prelude::*; use gtk::{self, ApplicationWindow, Button, prelude::*, ListBox, FlowBox, PolicyType, ScrolledWindow, Box, Orientation, Align::*}; -use crate::inv::inv; +use gst::prelude::*; +use std::io::Write; +use anyhow::Error; +use crate::inv::*; mod inv; @@ -19,9 +22,15 @@ fn main() { // Connect to "activate" signal of `app` app.connect_activate(build_ui); - //print!("{:?}", output); // Run the application + match VidPlayer() { + Ok(_) => {} + Err(err) => eprintln!("Failed: {}", err), + } + + + app.run(); } @@ -84,4 +93,88 @@ fn build_ui(app: &Application) { //fn trig_play() { // let trigger = -//} \ No newline at end of file +//} + +use gst::prelude::*; + +fn VidPlayer() -> Result<(), Error> { + // Initialize GStreamer + gst::init()?; + + // Build the pipeline + //let uri = + //"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm"; + let uri = inv().unwrap(); + println!("{:?}", uri); + let pipeline = gst::parse_launch(&format!("playbin uri={:?}", uri))?; + + // Start playing + let res = pipeline.set_state(gst::State::Playing)?; + let is_live = res == gst::StateChangeSuccess::NoPreroll; + + let main_loop = glib::MainLoop::new(None, false); + let main_loop_clone = main_loop.clone(); + let pipeline_weak = pipeline.downgrade(); + let bus = pipeline.bus().expect("Pipeline has no bus"); + bus.add_watch(move |_, msg| { + let pipeline = match pipeline_weak.upgrade() { + Some(pipeline) => pipeline, + None => return glib::Continue(true), + }; + let main_loop = &main_loop_clone; + match msg.view() { + gst::MessageView::Error(err) => { + println!( + "Error from {:?}: {} ({:?})", + err.src().map(|s| s.path_string()), + err.error(), + err.debug() + ); + let _ = pipeline.set_state(gst::State::Ready); + main_loop.quit(); + } + gst::MessageView::Eos(..) => { + // end-of-stream + let _ = pipeline.set_state(gst::State::Ready); + main_loop.quit(); + } + gst::MessageView::Buffering(buffering) => { + // If the stream is live, we do not care about buffering + if is_live { + return glib::Continue(true); + } + + let percent = buffering.percent(); + print!("Buffering ({}%)\r", percent); + match std::io::stdout().flush() { + Ok(_) => {} + Err(err) => eprintln!("Failed: {}", err), + }; + + // Wait until buffering is complete before start/resume playing + if percent < 100 { + let _ = pipeline.set_state(gst::State::Paused); + } else { + let _ = pipeline.set_state(gst::State::Playing); + } + } + gst::MessageView::ClockLost(_) => { + // Get a new clock + let _ = pipeline.set_state(gst::State::Paused); + let _ = pipeline.set_state(gst::State::Playing); + } + _ => (), + } + glib::Continue(true) + }) + .expect("Failed to add bus watch"); + + main_loop.run(); + + bus.remove_watch()?; + pipeline.set_state(gst::State::Null)?; + + Ok(()) +} + +