dev #1
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
23
.woodpecker.yml
Normal file
23
.woodpecker.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
when:
|
||||||
|
event: [push, pull_request]
|
||||||
|
image: ghcr.io/13hannes11/gtk4-rs-docker:latest-appimage
|
||||||
|
commands:
|
||||||
|
- cargo update
|
||||||
|
- cargo build
|
||||||
|
- cargo test
|
||||||
|
- echo "Done building!"
|
||||||
|
gzip:
|
||||||
|
when:
|
||||||
|
event: [push]
|
||||||
|
image: rust:latest
|
||||||
|
commands:
|
||||||
|
- mkdir ../artifact
|
||||||
|
- mv target/debug ../artifact
|
||||||
|
- tar -c -z -v -f gtubek-dev.tar.gz ../artifact
|
||||||
|
#upload:
|
||||||
|
#when:
|
||||||
|
#event: [push]
|
||||||
|
#image:
|
||||||
|
|
20
Cargo.toml
Normal file
20
Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "gtubek"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
gtk = { version = "0.4.8", package = "gtk4" }
|
||||||
|
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
|
10
inv.rs
10
inv.rs
@ -1,10 +0,0 @@
|
|||||||
use invidious::reqwest::blocking::Client;
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
let client = Client::new(String::from("https://vid.puffyan.us"));
|
|
||||||
let search_results = client.search(Some("q=rust programming"))?.items;
|
|
||||||
let video = client.video("5C_HPTJg5ek", None)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
52
main.rs
52
main.rs
@ -1,52 +0,0 @@
|
|||||||
use adw::Application;
|
|
||||||
use std::time::Duration;
|
|
||||||
use gtk::Video;
|
|
||||||
use gtk::gio;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::path::Path;
|
|
||||||
use gtk::prelude::*;
|
|
||||||
use gtk::{self, ApplicationWindow, Button, prelude::*};
|
|
||||||
use invidious::reqwest::blocking::functions::video;
|
|
||||||
mod inv;
|
|
||||||
|
|
||||||
|
|
||||||
const APP_ID: &str = "org.gtk_rs.MainEventLoop1";
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Create a new application
|
|
||||||
let app = Application::builder().application_id(APP_ID).build();
|
|
||||||
|
|
||||||
// Connect to "activate" signal of `app`
|
|
||||||
app.connect_activate(build_ui);
|
|
||||||
|
|
||||||
print!("{}: {}", video.title, video.author);
|
|
||||||
|
|
||||||
// Run the application
|
|
||||||
app.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_ui(app: &Application) {
|
|
||||||
// Create a button
|
|
||||||
let button = Button::builder()
|
|
||||||
.label("Press me!")
|
|
||||||
.margin_top(12)
|
|
||||||
.margin_bottom(12)
|
|
||||||
.margin_start(12)
|
|
||||||
.margin_end(12)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
|
|
||||||
let video = Video::for_file(Some(&gio::File::for_path("/home/midou/Vidéos/miui.mp4")));
|
|
||||||
|
|
||||||
|
|
||||||
// Create a window
|
|
||||||
let window = ApplicationWindow::builder()
|
|
||||||
.application(app)
|
|
||||||
.title("My GTK App")
|
|
||||||
.child(&button)
|
|
||||||
.child(&video)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Present window
|
|
||||||
window.present();
|
|
||||||
}
|
|
12
src/inv.rs
Normal file
12
src/inv.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use invidious::reqwest::blocking::Client;
|
||||||
|
use std::error::Error;
|
||||||
|
//use serde::{Deserialize, Serialize};
|
||||||
|
//use serde_json::Result;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn inv() -> Result<String, Box<dyn Error>> {
|
||||||
|
let client = Client::new(String::from("https://invidious.projectsegfau.lt"));
|
||||||
|
let output = &client.video("5C_HPTJg5ek", None)?.format_streams[2].url;
|
||||||
|
println!("{}", output);
|
||||||
|
Ok(output.to_string())
|
||||||
|
}
|
180
src/main.rs
Normal file
180
src/main.rs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
use adw::Application;
|
||||||
|
use std::time::Duration;
|
||||||
|
use gtk::Video;
|
||||||
|
use gtk::gio;
|
||||||
|
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 gst::prelude::*;
|
||||||
|
use std::io::Write;
|
||||||
|
use anyhow::Error;
|
||||||
|
use crate::inv::*;
|
||||||
|
mod inv;
|
||||||
|
|
||||||
|
|
||||||
|
const APP_ID: &str = "org.gtk_rs.MainEventLoop1";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Create a new application
|
||||||
|
let app = Application::builder().application_id(APP_ID).build();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn build_ui(app: &Application) {
|
||||||
|
// Create a button
|
||||||
|
let button = Button::builder()
|
||||||
|
.label("Press me!")
|
||||||
|
.icon_name("fingerprint-authentication-symbolic")
|
||||||
|
.valign(Fill)
|
||||||
|
.vexpand(true)
|
||||||
|
.margin_top(12)
|
||||||
|
.margin_bottom(12)
|
||||||
|
.margin_start(12)
|
||||||
|
.margin_end(12)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
//button.connect_clicked(move |_| trig_play());
|
||||||
|
|
||||||
|
|
||||||
|
let video = Video::for_file(Some(&gio::File::for_path("/home/midou/Vidéos/miui.mp4")));
|
||||||
|
//let output = inv::inv();
|
||||||
|
|
||||||
|
//let video = Video::for_media_stream(Some(&output));
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Set a listBox
|
||||||
|
let listbox = ListBox::builder()
|
||||||
|
.child(&video)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set a box
|
||||||
|
let boxy = Box::new(Orientation::Vertical, 0);
|
||||||
|
boxy.append(&video);
|
||||||
|
boxy.append(&button);
|
||||||
|
|
||||||
|
// Then make the window scrollable
|
||||||
|
let scrolled_window = ScrolledWindow::builder()
|
||||||
|
// .hscrollbar_policy(PolicyType::Never) // Disable horizontal scrolling
|
||||||
|
// .hscrollbar_policy()
|
||||||
|
.min_content_width(360)
|
||||||
|
.child(&boxy)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Create a window
|
||||||
|
let window = ApplicationWindow::builder()
|
||||||
|
.application(app)
|
||||||
|
.default_width(1280)
|
||||||
|
.default_height(720)
|
||||||
|
.title("My GTK App")
|
||||||
|
.child(&scrolled_window)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Present window
|
||||||
|
window.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
//fn trig_play() {
|
||||||
|
// let trigger =
|
||||||
|
//}
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user