mirror of
https://github.com/csd4ni3l/soundboard.git
synced 2026-04-17 16:07:22 +02:00
Compare commits
4 Commits
8d036bca08
...
ff947b57a8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff947b57a8 | ||
|
|
8d21c268c2 | ||
|
|
dff8d5aeff | ||
|
|
4128566048 |
@@ -5,7 +5,8 @@ use rodio::{
|
||||
use serde_json::Value;
|
||||
use std::process::Command;
|
||||
|
||||
const APPS_TO_EXCLUDE: [&str; 1] = ["plasmashell"];
|
||||
const APPS_TO_EXCLUDE: [&str; 7] = ["plasmashell", "pavucontrol", "pipewire", "wireplumber", "kwin_wayland", "kwin_x11", "obs"];
|
||||
const NODE_NAMES_TO_EXCLUDE: [&str; 2] = ["VirtualMicSource", "SoundboardSink"];
|
||||
|
||||
fn pactl_list(sink_type: &str) -> Value {
|
||||
let command_output = Command::new("pactl")
|
||||
@@ -23,21 +24,35 @@ fn pactl_list(sink_type: &str) -> Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_sink_by_index(sink_type: &str, index: String) -> Value {
|
||||
let sinks = pactl_list(sink_type);
|
||||
|
||||
for sink in sinks.as_array().unwrap_or(&vec![]) {
|
||||
if sink["index"]
|
||||
.as_u64()
|
||||
.expect("sink index is not a number")
|
||||
.to_string()
|
||||
== index
|
||||
{
|
||||
return sink.clone();
|
||||
}
|
||||
pub fn get_soundboard_sink_index() -> String {
|
||||
let source_outputs = pactl_list("sinks");
|
||||
source_outputs
|
||||
.as_array()
|
||||
.unwrap_or(&vec![])
|
||||
.iter()
|
||||
.find(|sink| sink["name"] == "SoundboardSink")
|
||||
.and_then(|sink| {
|
||||
Some(sink["index"].to_string())
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
return Value::Null {};
|
||||
pub fn get_default_source() -> String {
|
||||
let sources = pactl_list("sources");
|
||||
|
||||
let command = Command::new("pactl")
|
||||
.args(&["get-default-source"])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let default_source_name = String::from_utf8_lossy(&command.stdout).trim().to_string();
|
||||
|
||||
sources.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|sink|{ sink["name"].as_str() == Some(&default_source_name) })
|
||||
.and_then(|s|{ Some(s["index"].to_string()) })
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn find_soundboard_sinks() -> Vec<Value> {
|
||||
@@ -73,10 +88,11 @@ pub fn list_outputs() -> Vec<(String, String)> {
|
||||
.iter()
|
||||
.filter_map(|sink| {
|
||||
let app_name = sink["properties"]["application.name"].as_str()?;
|
||||
let node_name = sink["properties"]["node.name"].as_str()?;
|
||||
let binary = sink["properties"]["application.process.binary"]
|
||||
.as_str()
|
||||
.unwrap_or("Unknown");
|
||||
if APPS_TO_EXCLUDE.contains(&binary) {
|
||||
if APPS_TO_EXCLUDE.contains(&binary) || NODE_NAMES_TO_EXCLUDE.contains(&node_name) {
|
||||
return None;
|
||||
}
|
||||
let index = sink["index"]
|
||||
@@ -88,9 +104,9 @@ pub fn list_outputs() -> Vec<(String, String)> {
|
||||
.collect();
|
||||
}
|
||||
|
||||
pub fn move_index_to_virtualmic(index: String) {
|
||||
Command::new("pactl")
|
||||
.args(&["move-source-output", index.as_str(), "VirtualMicSource"]) // as_str is needed here as you cannot instantly dereference a growing String (Rust...)
|
||||
pub fn move_output_to_sink(output_index: String, sink_index: String) {
|
||||
let _ = Command::new("pactl")
|
||||
.args(&["move-source-output", output_index.as_str(), sink_index.as_str()]) // as_str is needed here as you cannot instantly dereference a growing String (Rust...)
|
||||
.output()
|
||||
.expect("Failed to execute process");
|
||||
}
|
||||
|
||||
69
src/main.rs
69
src/main.rs
@@ -57,8 +57,7 @@ struct AppState {
|
||||
currently_playing: Vec<PlayingSound>,
|
||||
sound_system: SoundSystem,
|
||||
virt_outputs: Vec<(String, String)>,
|
||||
virt_output_index_switch: String,
|
||||
virt_output_index: String,
|
||||
is_virt_output_used: HashMap<String, bool>,
|
||||
last_virt_output_update: Instant,
|
||||
current_view: String,
|
||||
youtube_downloader_state: YoutubeDownloaderState
|
||||
@@ -156,8 +155,7 @@ fn main() {
|
||||
currently_playing: Vec::new(),
|
||||
sound_system: create_virtual_mic(),
|
||||
virt_outputs: Vec::new(),
|
||||
virt_output_index_switch: String::from("0"),
|
||||
virt_output_index: String::from("999"),
|
||||
is_virt_output_used: HashMap::new(),
|
||||
current_view: "main".to_string(),
|
||||
last_virt_output_update: Instant::now(),
|
||||
youtube_downloader_state: YoutubeDownloaderState {
|
||||
@@ -181,30 +179,29 @@ fn main() {
|
||||
}
|
||||
|
||||
fn update(mut app_state: ResMut<AppState>) {
|
||||
if app_state.last_virt_output_update.elapsed().as_secs_f32() >= 3.0 {
|
||||
#[cfg(target_os = "linux")] {
|
||||
if app_state.last_virt_output_update.elapsed().as_secs_f32() >= 1.5 {
|
||||
app_state.last_virt_output_update = Instant::now();
|
||||
app_state.virt_outputs = list_outputs();
|
||||
let is_virt_output_used = app_state.is_virt_output_used.clone();
|
||||
|
||||
for virt_output in &app_state.virt_outputs.clone() {
|
||||
if !is_virt_output_used.contains_key(&virt_output.1) {
|
||||
app_state.is_virt_output_used.insert(virt_output.1.clone(), false);
|
||||
}
|
||||
|
||||
if app_state.virt_outputs.is_empty() {
|
||||
return;
|
||||
if app_state.is_virt_output_used[&virt_output.1] {
|
||||
linux_lib::move_output_to_sink(virt_output.1.clone(), linux_lib::get_soundboard_sink_index());
|
||||
}
|
||||
else {
|
||||
linux_lib::move_output_to_sink(virt_output.1.clone(), linux_lib::get_default_source());
|
||||
}
|
||||
}
|
||||
|
||||
if !(app_state.virt_output_index == "999".to_string()) {
|
||||
app_state.virt_output_index_switch = app_state.virt_outputs[0].1.clone();
|
||||
}
|
||||
|
||||
if app_state.virt_output_index != app_state.virt_output_index_switch {
|
||||
app_state.virt_output_index = app_state.virt_output_index_switch.clone();
|
||||
#[cfg(target_os = "linux")]
|
||||
linux_lib::move_index_to_virtualmic(app_state.virt_output_index_switch.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn load_system(mut app_state: ResMut<AppState>) {
|
||||
if !app_state.virt_outputs.is_empty() {
|
||||
app_state.virt_output_index_switch = app_state.virt_outputs[0].1.clone();
|
||||
}
|
||||
load_data(&mut app_state);
|
||||
}
|
||||
|
||||
@@ -309,25 +306,22 @@ fn play_sound(file_path: String, app_state: &mut AppState) {
|
||||
app_state.currently_playing.push(playing_sound);
|
||||
}
|
||||
|
||||
fn create_virtual_mic_dropdown(ui: &mut Ui, app_state: &mut ResMut<AppState>, available_width: f32, available_height: f32) {
|
||||
fn create_virtual_mic_ui(ui: &mut Ui, app_state: &mut ResMut<AppState>, available_width: f32, available_height: f32) {
|
||||
#[cfg(target_os = "linux")] {
|
||||
if app_state.is_virt_output_used.len() != 0 {
|
||||
let outputs = app_state.virt_outputs.clone();
|
||||
let output_index = app_state.virt_output_index.clone();
|
||||
let output_sink = linux_lib::get_sink_by_index("source-outputs", output_index);
|
||||
if let Some(app_name) = output_sink["properties"]["application.name"].as_str() {
|
||||
egui::ComboBox::from_id_salt("Virtual Mic Output")
|
||||
.selected_text(app_name.to_string())
|
||||
.width(available_width)
|
||||
.height(available_height / 15.0)
|
||||
.show_ui(ui, |ui| {
|
||||
for output in &outputs {
|
||||
ui.selectable_value(
|
||||
&mut app_state.virt_output_index_switch,
|
||||
output.1.clone(),
|
||||
output.0.clone(),
|
||||
);
|
||||
let current_value = *app_state.is_virt_output_used.get(&output.1).unwrap_or(&false);
|
||||
if ui
|
||||
.add_sized(
|
||||
[available_width, available_height / 30.0],
|
||||
egui::Button::new(format!("{} - {}", output.0.clone(), current_value)),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
*app_state.is_virt_output_used.entry(output.1.clone()).or_insert(false) = !current_value;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
ui.add(egui::Button::new("No apps found to use.".to_string()));
|
||||
@@ -350,7 +344,7 @@ fn main_ui(ctx: &Context, mut app_state: ResMut<AppState>) {
|
||||
let available_width = ui.available_width();
|
||||
let available_height = ui.available_height();
|
||||
ui.label("Virtual Mic Output");
|
||||
create_virtual_mic_dropdown(ui, &mut app_state, available_width, available_height);
|
||||
create_virtual_mic_ui(ui, &mut app_state, available_width, available_height);
|
||||
|
||||
if ui
|
||||
.add_sized(
|
||||
@@ -361,7 +355,6 @@ fn main_ui(ctx: &Context, mut app_state: ResMut<AppState>) {
|
||||
{
|
||||
if let Some(folder) = rfd::FileDialog::new().pick_folder() {
|
||||
if let Some(path_str) = folder.to_str() {
|
||||
println!("Selected: {}", path_str);
|
||||
app_state.json_data.tabs.push(path_str.to_string());
|
||||
std::fs::write(
|
||||
"data.json",
|
||||
@@ -581,7 +574,11 @@ fn draw(mut contexts: EguiContexts, mut app_state: ResMut<AppState>) -> Result {
|
||||
}
|
||||
});
|
||||
|
||||
egui::TopBottomPanel::bottom("currently_playing").show(ctx, |ui| {
|
||||
let window_height = ctx.content_rect().height();
|
||||
|
||||
egui::TopBottomPanel::bottom("currently_playing")
|
||||
.exact_height(window_height * 0.1)
|
||||
.show(ctx, |ui| {
|
||||
ui.vertical(|ui| {
|
||||
for playing_sound in &mut app_state.currently_playing {
|
||||
ui.horizontal(|ui| {
|
||||
|
||||
@@ -2,6 +2,9 @@ use std::{env::current_dir, fs::{File, exists}, io, process::Command};
|
||||
use reqwest;
|
||||
use rfd::{MessageButtons, MessageDialog, MessageDialogResult};
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
pub fn get_yt_dlp_path() -> String {
|
||||
if cfg!(target_os = "windows"){
|
||||
current_dir().expect("Failed to get current working directory").join("bin").join("yt-dlp.exe").to_string_lossy().to_string()
|
||||
@@ -40,10 +43,14 @@ pub fn check_and_download_yt_dlp() {
|
||||
let mut body = reqwest::blocking::get(url).expect("Could not download yt-dlp");
|
||||
let mut out = File::create(get_yt_dlp_path()).expect("failed to create file");
|
||||
io::copy(&mut body, &mut out).expect("failed to copy content");
|
||||
|
||||
#[cfg(unix)]
|
||||
out.set_permissions(PermissionsExt::from_mode(0o755));
|
||||
|
||||
}
|
||||
|
||||
pub fn check_ffmpeg() -> bool{
|
||||
return std::process::Command::new("ffmpeg").spawn().is_ok();
|
||||
return std::process::Command::new("ffmpeg").output().is_ok();
|
||||
}
|
||||
|
||||
pub fn check_and_download_ffmpeg() {
|
||||
|
||||
Reference in New Issue
Block a user