Compare commits

...

4 Commits

Author SHA1 Message Date
arabianq dac9d53cef deps: update cargo-sources.json 2026-05-28 01:09:33 +03:00
arabianq 9da3799cd3 cargo update 2026-05-28 01:08:52 +03:00
arabianq d66369884c deps: update rodio 2026-05-28 01:08:13 +03:00
Tarasov Aleksandr 5e47e7d6fb feat(gui): support for soundpad:// uri (#123)
* feat(gui): support for soundpad:// uri

* fix: flatpak

* do not open gui when downloading file
2026-05-28 00:58:03 +03:00
9 changed files with 1604 additions and 466 deletions
Generated
+677 -156
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -43,7 +43,7 @@ rustix = { version = "1.1.4", features = ["process"] }
rust-i18n = "4.0.0"
sys-locale = "0.3.2"
rodio = { git = "https://github.com/arabianq/rodio.git", rev = "1a08f281c352622bd82b87b8731585245802d9cf", default-features = false, features = [
rodio = { git = "https://github.com/arabianq/rodio.git", rev = "33afba2a2d97bb730eb6537f09d2b3815bff0f33", default-features = false, features = [
"symphonia-all",
"symphonia-libopus",
"playback",
@@ -64,6 +64,9 @@ egui_extras = "0.34.1"
egui_material_icons = "0.6.0"
egui_dnd = "0.15.0"
reqwest = "0.13.4"
percent-encoding = "2.3.2"
[[bin]]
name = "pwsp-daemon"
path = "src/bin/daemon.rs"
+2 -1
View File
@@ -1,8 +1,9 @@
[Desktop Entry]
Name=PWSP (Soundpad)
Comment=Let's you play audio files through you microphone
Exec=pwsp-gui %u
Exec=/usr/bin/pwsp-gui %u
Icon=pwsp
Terminal=false
Type=Application
Categories=Audio
MimeType=x-scheme-handler/soundpad;
File diff suppressed because one or more lines are too long
+10 -5
View File
@@ -2,21 +2,26 @@
import argparse
import subprocess
import sys
if __name__ == "__main__":
if len(sys.argv) == 2 and sys.argv[1].startswith("soundpad://"):
subprocess.Popen(["pwsp-gui", sys.argv[1]])
sys.exit(0)
parser = argparse.ArgumentParser(
prog="PWSP Flatpak",
add_help=True,
exit_on_error=True
prog="PWSP Flatpak", add_help=True, exit_on_error=True
)
subparsers = parser.add_subparsers(dest="command")
cli_parser = subparsers.add_parser("cli", add_help=False, prefix_chars=" ")
cli_parser.add_argument("args", nargs=argparse.REMAINDER, help="Arguments for pwsp-cli")
cli_parser.add_argument(
"args", nargs=argparse.REMAINDER, help="Arguments for pwsp-cli"
)
daemon_parser = subparsers.add_parser("daemon", add_help=True)
daemon_group = daemon_parser.add_mutually_exclusive_group(required=True)
daemon_group.add_argument("--start", action="store_true", help="Start pwps-daemon")
daemon_group.add_argument("--start", action="store_true", help="Start pwsp-daemon")
daemon_group.add_argument("--kill", action="store_true", help="Kill pwsp-daemon")
args = parser.parse_args()
@@ -7,3 +7,4 @@ Terminal=false
Type=Application
Categories=AudioVideo;Audio;
Keywords=soundpad;pipewire;audio;
MimeType=x-scheme-handler/soundpad;
+48 -2
View File
@@ -1,7 +1,9 @@
mod gui;
use anyhow::Result;
use anyhow::{Context, Result};
use pwsp::utils::gui::ensure_pwsp_audio_dir;
use rust_i18n::i18n;
use std::{env, path::PathBuf};
i18n!("locales", fallback = "en");
@@ -10,5 +12,49 @@ async fn main() -> Result<()> {
let locale = sys_locale::get_locale().unwrap_or(String::from("en-US"));
rust_i18n::set_locale(&locale);
gui::run().await
let args = env::args().skip(1).collect::<Vec<String>>();
if let Some(uri) = args.first() {
match download_audio_from_url(uri).await {
Ok(path) => println!("Successfully downloaded to: {:?}", path),
Err(e) => eprintln!("Error downloading file: {}", e),
}
} else {
gui::run().await?;
}
Ok(())
}
async fn download_audio_from_url(uri: &str) -> Result<PathBuf> {
let prefix = "soundpad://sound/url/";
let target_url = uri
.strip_prefix(prefix)
.ok_or_else(|| anyhow::anyhow!("URI does not containt an expected prefix: {}", prefix))?;
let file_name_encoded = target_url
.split('/')
.next_back()
.unwrap_or("downloaded_audio.mp3");
let file_name = percent_encoding::percent_decode_str(file_name_encoded)
.decode_utf8()
.unwrap_or_else(|_| file_name_encoded.into())
.into_owned();
let save_path = ensure_pwsp_audio_dir().join(file_name);
let response = reqwest::get(target_url)
.await?
.error_for_status()
.context("Failed to fetch file")?;
let bytes = response.bytes().await?;
tokio::fs::write(&save_path, bytes)
.await
.context("Failed to save file to disk")?;
Ok(save_path)
}
+5 -2
View File
@@ -1,4 +1,7 @@
use crate::{types::socket::Request, utils::config::get_config_path};
use crate::{
types::socket::Request,
utils::{config::get_config_path, gui::ensure_pwsp_audio_dir},
};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fs, path::PathBuf};
@@ -69,7 +72,7 @@ impl Default for GuiConfig {
save_scale_factor: false,
pause_on_exit: false,
dirs: vec![],
dirs: vec![ensure_pwsp_audio_dir()],
preferred_theme: PreferredTheme::System,
}
+12
View File
@@ -9,6 +9,7 @@ use crate::{
};
use anyhow::{Result, anyhow};
use std::{
path::PathBuf,
sync::{Arc, Mutex},
time::Instant,
};
@@ -36,6 +37,17 @@ pub fn make_request_async(request: Request) {
});
}
pub fn ensure_pwsp_audio_dir() -> PathBuf {
let audio_dir = dirs::audio_dir().unwrap_or("~/Music".into());
let pwsp_audio_dir = audio_dir.join("PWSP");
if !pwsp_audio_dir.exists() {
std::fs::create_dir_all(&pwsp_audio_dir).ok();
}
pwsp_audio_dir
}
pub fn format_time_pair(position: f32, duration: f32) -> String {
fn format_time(seconds: f32) -> String {
let total_seconds = seconds.round() as u32;