oshit is taht

main
Bel LaPointe 2023-12-28 00:27:43 -05:00
parent 3f7004cc06
commit 53714ead7c
2 changed files with 96 additions and 52 deletions

View File

@ -9,6 +9,6 @@ edition = "2021"
dioxus = "0.4.3" dioxus = "0.4.3"
lib = { path = "../src-lib" } lib = { path = "../src-lib" }
base64 = "0.21.5" base64 = "0.21.5"
#dioxus-web = "0.4.3"
opener = "0.6.1" opener = "0.6.1"
#dioxus-web = "0.4.3"
dioxus-desktop = "0.4.3" dioxus-desktop = "0.4.3"

View File

@ -3,6 +3,8 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use lib; use lib;
use base64::{engine::general_purpose, Engine as _}; use base64::{engine::general_purpose, Engine as _};
use core::cmp::Ordering;
use std::str::FromStr;
fn main() { fn main() {
// launch the dioxus app in a webview // launch the dioxus app in a webview
@ -17,20 +19,30 @@ fn App(cx: Scope) -> Element {
let status = use_state(cx, String::new); let status = use_state(cx, String::new);
cx.render(rsx! { cx.render(rsx! {
header { header {
h1 { "home-video-blue-extractinator" } style { "
body {{
max-width: 600pt;
margin: auto;
}}
label {{
display: block;
}}
label:has(input[type=checkbox]:checked) {{
background-color: lightgreen;
}}
" }
} }
main { main {
rsx! { rsx! {
h1 { "home-video-blue-extractinator" }
div { div {
input { input {
r#type: "file", r#type: "file",
onchange: |evt| { onchange: |evt| {
to_owned![file]; to_owned![file];
async move { if let Some(file_engine) = &evt.files {
if let Some(file_engine) = &evt.files { for f in &file_engine.files() {
for f in &file_engine.files() { file.set(f.clone());
file.set(f.clone());
}
} }
} }
}, },
@ -38,7 +50,7 @@ fn App(cx: Scope) -> Element {
p { file.get().clone() } p { file.get().clone() }
} }
div { div {
input { r#type: "button", value: "analyze", disabled: file.get().len() == 0, onclick: move |evt| { input { r#type: "button", value: "analyze", disabled: file.get().len() == 0, onclick: |evt| {
to_owned![file]; to_owned![file];
to_owned![analysis]; to_owned![analysis];
to_owned![status]; to_owned![status];
@ -49,20 +61,13 @@ fn App(cx: Scope) -> Element {
} else { } else {
status.set(format!( status.set(format!(
"found {} clips to keep and {} clips to drop", "found {} clips to keep and {} clips to drop",
analyzed.with_content.len(), analyzed.result.iter().filter(|x| x.has_content).count(),
analyzed.without_content.len(), analyzed.result.iter().filter(|x| !x.has_content).count(),
)); ));
} }
analysis.set(analyzed); analysis.set(analyzed);
} }
}} }}
input { r#type: "button", value: "clipify", disabled: file.get().len() == 0, onclick: move |evt| {
to_owned![file];
to_owned![status];
async move {
status.set(clipify(file.get().clone()));
}
}}
} }
div { div {
br {} br {}
@ -70,28 +75,43 @@ fn App(cx: Scope) -> Element {
br {} br {}
} }
div { div {
h3 { "Clips to Keep" } h3 { "Content Spans" }
div { form {
analysis.get().with_content.iter().map(|a| { onsubmit: |evt| {
rsx! { let content_spans: Vec<_> = evt.values.iter()
p { .filter(|kv| kv.1.len() > 0)
"{a.start}..{a.stop}: " .map(|kv| {
br {} let span_str = kv.0;
img { src: "data:image/png;base64, {a.screenshot}" } let idx = span_str.find("..").unwrap();
} lib::video::ContentSpan{
start: f32::from_str(&span_str[0..idx]).unwrap(),
stop: f32::from_str(&span_str[idx+2..span_str.len()]).unwrap(),
}
})
.collect();
status.set(format!("clipifying {:?}", content_spans));
let file = file.get().clone();
to_owned![status];
async move {
let f = clipify(file, content_spans).await;
status.set(f);
} }
}) },
} input { r#type: "submit", value: "clipify selected spans", disabled: file.get().len() == 0 }
} hr {}
div { analysis.get().result.iter().map(|a| {
h3 { "Clips to Remove" }
div {
analysis.get().without_content.iter().map(|a| {
rsx! { rsx! {
p { div {
"{a.start}..{a.stop}: " label {
br {} input {
img { src: "data:image/png;base64, {a.screenshot}" } r#type: "checkbox",
checked: a.has_content,
name: "{a.start}..{a.stop}",
}
"{a.start}..{a.stop}: "
br {}
img { src: "data:image/png;base64, {a.screenshot}" }
}
} }
} }
}) })
@ -103,25 +123,25 @@ fn App(cx: Scope) -> Element {
} }
struct Analysis { struct Analysis {
with_content: Vec<Analyzed>, result: Vec<Analyzed>,
without_content: Vec<Analyzed>,
err: String, err: String,
} }
impl Analysis { impl Analysis {
fn new() -> Self { fn new() -> Self {
Self{ Self{
with_content: vec![], result: vec![],
without_content: vec![],
err: "".to_string(), err: "".to_string(),
} }
} }
} }
#[derive(Clone)]
struct Analyzed { struct Analyzed {
start: String, start: String,
stop: String, stop: String,
screenshot: String, screenshot: String,
has_content: bool,
} }
fn analyze(file: String) -> Analysis { fn analyze(file: String) -> Analysis {
@ -129,8 +149,7 @@ fn analyze(file: String) -> Analysis {
//let content_spans: Result<Vec<lib::video::ContentSpan>, String> = Ok(vec![lib::video::ContentSpan{start: 0.5, stop: 20.2}]); //let content_spans: Result<Vec<lib::video::ContentSpan>, String> = Ok(vec![lib::video::ContentSpan{start: 0.5, stop: 20.2}]);
if content_spans.is_err() { if content_spans.is_err() {
return Analysis{ return Analysis{
with_content: vec![], result: vec![],
without_content: vec![],
err: format!("failed to analyze {}: {}", file, content_spans.err().unwrap()), err: format!("failed to analyze {}: {}", file, content_spans.err().unwrap()),
}; };
} }
@ -155,26 +174,51 @@ fn analyze(file: String) -> Analysis {
screenshot: match lib::video::screenshot_png(&file, ts) { screenshot: match lib::video::screenshot_png(&file, ts) {
Ok(png) => general_purpose::STANDARD.encode(&png), Ok(png) => general_purpose::STANDARD.encode(&png),
Err(_) => a_png.to_string(), Err(_) => a_png.to_string(),
} },
has_content: false,
} }
}; };
let mut result = vec![];
content_spans.iter()
.map(screenshot)
.map(|x| {
let mut x = x.clone();
x.has_content = true;
x
})
.for_each(|x| result.push(x));
non_content_spans.iter()
.map(screenshot)
.for_each(|x| result.push(x));
result.sort_by(|x, y| x.start.partial_cmp(&y.start).unwrap());
Analysis{ Analysis{
with_content: content_spans.iter().map(screenshot).collect(), result: result,
without_content: non_content_spans.iter().map(screenshot).collect(),
err: "".to_string(), err: "".to_string(),
} }
} }
fn clipify(file: String) -> String { async fn clipify(file: String, content_spans: Vec<lib::video::ContentSpan>) -> String {
match lib::clipify(&file.to_string()) { let d = format!("{}.d", &file);
Ok(path) => { match content_spans.iter()
match opener::open(path.clone()) { .map(|content_span| {
Ok(_) => path, lib::video::clip(
&format!("{}/{}.mp4", &d, content_span.start),
&file,
*content_span,
)
})
.filter(|x| x.is_err())
.map(|x| x.err().unwrap())
.nth(0) {
Some(err_msg) => err_msg,
None => {
match opener::open(d.clone()) {
Ok(_) => d,
Err(msg) => format!("failed to open clipify result: {}", msg), Err(msg) => format!("failed to open clipify result: {}", msg),
} }
}, },
Err(msg) => msg,
} }
} }