mirror of
https://github.com/arabianq/pipewire-soundpad.git
synced 2026-06-19 20:23:33 +00:00
Compare commits
7 Commits
v1.9.1
...
dac9d53cef
| Author | SHA1 | Date | |
|---|---|---|---|
| dac9d53cef | |||
| 9da3799cd3 | |||
| d66369884c | |||
| 5e47e7d6fb | |||
| 695c83c9e6 | |||
| 798a6d1887 | |||
| bb18175a30 |
Generated
+677
-156
File diff suppressed because it is too large
Load Diff
+5
-2
@@ -36,14 +36,14 @@ rfd = { version = "0.17.2", default-features = false, features = [
|
|||||||
|
|
||||||
] }
|
] }
|
||||||
opener = { version = "0.8.4", features = ["reveal"] }
|
opener = { version = "0.8.4", features = ["reveal"] }
|
||||||
system-fonts = "0.1.0"
|
system-fonts = "0.1.1"
|
||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
rustix = { version = "1.1.4", features = ["process"] }
|
rustix = { version = "1.1.4", features = ["process"] }
|
||||||
|
|
||||||
rust-i18n = "4.0.0"
|
rust-i18n = "4.0.0"
|
||||||
sys-locale = "0.3.2"
|
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-all",
|
||||||
"symphonia-libopus",
|
"symphonia-libopus",
|
||||||
"playback",
|
"playback",
|
||||||
@@ -64,6 +64,9 @@ egui_extras = "0.34.1"
|
|||||||
egui_material_icons = "0.6.0"
|
egui_material_icons = "0.6.0"
|
||||||
egui_dnd = "0.15.0"
|
egui_dnd = "0.15.0"
|
||||||
|
|
||||||
|
reqwest = "0.13.4"
|
||||||
|
percent-encoding = "2.3.2"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "pwsp-daemon"
|
name = "pwsp-daemon"
|
||||||
path = "src/bin/daemon.rs"
|
path = "src/bin/daemon.rs"
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=PWSP (Soundpad)
|
Name=PWSP (Soundpad)
|
||||||
Comment=Let's you play audio files through you microphone
|
Comment=Let's you play audio files through you microphone
|
||||||
Exec=pwsp-gui %u
|
Exec=/usr/bin/pwsp-gui %u
|
||||||
Icon=pwsp
|
Icon=pwsp
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=Audio
|
Categories=Audio
|
||||||
|
MimeType=x-scheme-handler/soundpad;
|
||||||
@@ -195,6 +195,50 @@ kz = "GUI нұсқасы: %{version}"
|
|||||||
he = "גרסת ממשק משתמש: %{version}"
|
he = "גרסת ממשק משתמש: %{version}"
|
||||||
pt-BR = "Versão da GUI: %{version}"
|
pt-BR = "Versão da GUI: %{version}"
|
||||||
|
|
||||||
|
[gui.settings.theme.label]
|
||||||
|
en = "Color Scheme"
|
||||||
|
ru = "Цветовая схема"
|
||||||
|
es = "Esquema de color"
|
||||||
|
fr = "Schéma de couleurs"
|
||||||
|
zh = "配色方案"
|
||||||
|
ar = "نظام الألوان"
|
||||||
|
kz = "Түс схемасы"
|
||||||
|
he = "ערכת צבעים"
|
||||||
|
pt-BR = "Esquema de cores"
|
||||||
|
|
||||||
|
[gui.settings.theme.system]
|
||||||
|
en = "System"
|
||||||
|
ru = "Системная"
|
||||||
|
es = "Sistema"
|
||||||
|
fr = "Système"
|
||||||
|
zh = "系统"
|
||||||
|
ar = "النظام"
|
||||||
|
kz = "Жүйе"
|
||||||
|
he = "מערכת"
|
||||||
|
pt-BR = "Sistema"
|
||||||
|
|
||||||
|
[gui.settings.theme.light]
|
||||||
|
en = "Light"
|
||||||
|
ru = "Светлая"
|
||||||
|
es = "Claro"
|
||||||
|
fr = "Clair"
|
||||||
|
zh = "浅色"
|
||||||
|
ar = "فاتح"
|
||||||
|
kz = "Жарық"
|
||||||
|
he = "בהיר"
|
||||||
|
pt-BR = "Claro"
|
||||||
|
|
||||||
|
[gui.settings.theme.dark]
|
||||||
|
en = "Dark"
|
||||||
|
ru = "Тёмная"
|
||||||
|
es = "Oscuro"
|
||||||
|
fr = "Sombre"
|
||||||
|
zh = "暗色"
|
||||||
|
ar = "داكن"
|
||||||
|
kz = "Қараңғы"
|
||||||
|
he = "כהה"
|
||||||
|
pt-BR = "Escuro"
|
||||||
|
|
||||||
# ----------------
|
# ----------------
|
||||||
# Hotkeys
|
# Hotkeys
|
||||||
# ----------------
|
# ----------------
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ package() {
|
|||||||
install -Dm755 "${srcdir}/pwsp-gui" "${pkgdir}/usr/bin/pwsp-gui"
|
install -Dm755 "${srcdir}/pwsp-gui" "${pkgdir}/usr/bin/pwsp-gui"
|
||||||
|
|
||||||
install -Dm644 "$_srcsrc/assets/pwsp-gui.desktop" "${pkgdir}/usr/share/applications/pwsp-gui.desktop"
|
install -Dm644 "$_srcsrc/assets/pwsp-gui.desktop" "${pkgdir}/usr/share/applications/pwsp-gui.desktop"
|
||||||
install -Dm644 "$_srcsrc/assets/icon.png" "${pkgdir}/usr/share/icons/hicolor/256x256/apps/icon.png"
|
install -Dm644 "$_srcsrc/assets/icon.png" "${pkgdir}/usr/share/icons/hicolor/256x256/apps/pwsp.png"
|
||||||
install -Dm644 "$_srcsrc/assets/pwsp-daemon.service" "${pkgdir}/usr/lib/systemd/user/pwsp-daemon.service"
|
install -Dm644 "$_srcsrc/assets/pwsp-daemon.service" "${pkgdir}/usr/lib/systemd/user/pwsp-daemon.service"
|
||||||
|
|
||||||
install -Dm644 "$_srcsrc/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
install -Dm644 "$_srcsrc/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
pkgbase = pwsp
|
pkgbase = pwsp
|
||||||
pkgdesc = Lets you play audio files through your microphone
|
pkgdesc = Lets you play audio files through your microphone
|
||||||
pkgver = 1.9.1
|
pkgver = 1.9.1
|
||||||
pkgrel = 1
|
pkgrel = 2
|
||||||
url = https://github.com/arabianq/pipewire-soundpad
|
url = https://github.com/arabianq/pipewire-soundpad
|
||||||
arch = any
|
arch = any
|
||||||
license = MIT
|
license = MIT
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
pkgsubn=pwsp
|
pkgsubn=pwsp
|
||||||
pkgname=pwsp
|
pkgname=pwsp
|
||||||
pkgver=1.9.1
|
pkgver=1.9.1
|
||||||
pkgrel=1
|
pkgrel=2
|
||||||
pkgdesc="Lets you play audio files through your microphone"
|
pkgdesc="Lets you play audio files through your microphone"
|
||||||
arch=('any')
|
arch=('any')
|
||||||
url="https://github.com/arabianq/pipewire-soundpad"
|
url="https://github.com/arabianq/pipewire-soundpad"
|
||||||
@@ -41,7 +41,7 @@ package() {
|
|||||||
install -Dm755 "target/release/pwsp-gui" "${pkgdir}/usr/bin/pwsp-gui"
|
install -Dm755 "target/release/pwsp-gui" "${pkgdir}/usr/bin/pwsp-gui"
|
||||||
|
|
||||||
install -Dm644 "assets/pwsp-gui.desktop" "${pkgdir}/usr/share/applications/pwsp-gui.desktop"
|
install -Dm644 "assets/pwsp-gui.desktop" "${pkgdir}/usr/share/applications/pwsp-gui.desktop"
|
||||||
install -Dm644 "assets/icon.png" "${pkgdir}/usr/share/icons/hicolor/256x256/apps/icon.png"
|
install -Dm644 "assets/icon.png" "${pkgdir}/usr/share/icons/hicolor/256x256/apps/pwsp.png"
|
||||||
|
|
||||||
install -Dm644 "assets/pwsp-daemon.service" "${pkgdir}/usr/lib/systemd/user/pwsp-daemon.service"
|
install -Dm644 "assets/pwsp-daemon.service" "${pkgdir}/usr/lib/systemd/user/pwsp-daemon.service"
|
||||||
}
|
}
|
||||||
|
|||||||
+843
-297
File diff suppressed because one or more lines are too long
@@ -2,21 +2,26 @@
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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(
|
parser = argparse.ArgumentParser(
|
||||||
prog="PWSP Flatpak",
|
prog="PWSP Flatpak", add_help=True, exit_on_error=True
|
||||||
add_help=True,
|
|
||||||
exit_on_error=True
|
|
||||||
)
|
)
|
||||||
subparsers = parser.add_subparsers(dest="command")
|
subparsers = parser.add_subparsers(dest="command")
|
||||||
|
|
||||||
cli_parser = subparsers.add_parser("cli", add_help=False, prefix_chars=" ")
|
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_parser = subparsers.add_parser("daemon", add_help=True)
|
||||||
daemon_group = daemon_parser.add_mutually_exclusive_group(required=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")
|
daemon_group.add_argument("--kill", action="store_true", help="Kill pwsp-daemon")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ Terminal=false
|
|||||||
Type=Application
|
Type=Application
|
||||||
Categories=AudioVideo;Audio;
|
Categories=AudioVideo;Audio;
|
||||||
Keywords=soundpad;pipewire;audio;
|
Keywords=soundpad;pipewire;audio;
|
||||||
|
MimeType=x-scheme-handler/soundpad;
|
||||||
+19
-2
@@ -1,14 +1,31 @@
|
|||||||
use crate::gui::SoundpadGui;
|
use crate::gui::SoundpadGui;
|
||||||
use eframe::{App, Frame as EFrame};
|
use eframe::{App, Frame as EFrame};
|
||||||
use egui::{CentralPanel, Context};
|
use egui::{CentralPanel, Context, ThemePreference};
|
||||||
use pwsp::{
|
use pwsp::{
|
||||||
types::socket::Request,
|
types::{config::PreferredTheme, socket::Request},
|
||||||
utils::{daemon::get_daemon_config, gui::make_request_async},
|
utils::{daemon::get_daemon_config, gui::make_request_async},
|
||||||
};
|
};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
impl App for SoundpadGui {
|
impl App for SoundpadGui {
|
||||||
fn logic(&mut self, ctx: &Context, _frame: &mut EFrame) {
|
fn logic(&mut self, ctx: &Context, _frame: &mut EFrame) {
|
||||||
|
// Update theme
|
||||||
|
let current_theme = match ctx.options(|r| r.theme_preference) {
|
||||||
|
ThemePreference::System => PreferredTheme::System,
|
||||||
|
ThemePreference::Light => PreferredTheme::Light,
|
||||||
|
ThemePreference::Dark => PreferredTheme::Dark,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.config.preferred_theme.eq(¤t_theme) {
|
||||||
|
ctx.options_mut(|w| {
|
||||||
|
w.theme_preference = match self.config.preferred_theme {
|
||||||
|
PreferredTheme::System => ThemePreference::System,
|
||||||
|
PreferredTheme::Light => ThemePreference::Light,
|
||||||
|
PreferredTheme::Dark => ThemePreference::Dark,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Remove directories
|
// Remove directories
|
||||||
for path in self.app_state.dirs_to_remove.drain() {
|
for path in self.app_state.dirs_to_remove.drain() {
|
||||||
self.app_state.dirs.retain(|x| x != &path);
|
self.app_state.dirs.retain(|x| x != &path);
|
||||||
|
|||||||
@@ -76,16 +76,16 @@ impl SoundpadGui {
|
|||||||
.map(|s| s.to_string_lossy().to_string())
|
.map(|s| s.to_string_lossy().to_string())
|
||||||
.unwrap_or_else(|| path.to_string_lossy().to_string());
|
.unwrap_or_else(|| path.to_string_lossy().to_string());
|
||||||
|
|
||||||
let mut dir_button_text = RichText::new(name.clone());
|
let mut dir_button =
|
||||||
|
Button::new(RichText::new(name.clone()).atom_max_width(area_size.x))
|
||||||
|
.frame(false);
|
||||||
|
|
||||||
if let Some(current_dir) = &self.app_state.current_dir
|
if let Some(current_dir) = &self.app_state.current_dir
|
||||||
&& current_dir.eq(&*path)
|
&& current_dir.eq(&*path)
|
||||||
{
|
{
|
||||||
dir_button_text = dir_button_text.color(Color32::WHITE);
|
dir_button = dir_button.selected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dir_button =
|
|
||||||
Button::new(dir_button_text.atom_max_width(area_size.x)).frame(false);
|
|
||||||
|
|
||||||
let dir_button_response = ui.add(dir_button);
|
let dir_button_response = ui.add(dir_button);
|
||||||
if dir_button_response.clicked() {
|
if dir_button_response.clicked() {
|
||||||
dir_to_open = Some(path.clone());
|
dir_to_open = Some(path.clone());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::gui::SoundpadGui;
|
use crate::gui::SoundpadGui;
|
||||||
use egui::{Button, CollapsingHeader, Color32, FontFamily, Label, RichText, Slider, Ui};
|
use egui::{Button, CollapsingHeader, FontFamily, Label, RichText, Slider, Ui};
|
||||||
use egui_material_icons::icons::*;
|
use egui_material_icons::icons::*;
|
||||||
use pwsp::types::{audio_player::TrackInfo, gui::AppState};
|
use pwsp::types::{audio_player::TrackInfo, gui::AppState};
|
||||||
use pwsp::utils::gui::format_time_pair;
|
use pwsp::utils::gui::format_time_pair;
|
||||||
@@ -32,7 +32,6 @@ impl SoundpadGui {
|
|||||||
.to_str()
|
.to_str()
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
)
|
)
|
||||||
.color(Color32::WHITE)
|
|
||||||
.family(FontFamily::Monospace),
|
.family(FontFamily::Monospace),
|
||||||
)
|
)
|
||||||
.default_open(true)
|
.default_open(true)
|
||||||
|
|||||||
@@ -146,32 +146,28 @@ impl SoundpadGui {
|
|||||||
ui.label(
|
ui.label(
|
||||||
RichText::new(t!("gui.hotkeys.column_slot"))
|
RichText::new(t!("gui.hotkeys.column_slot"))
|
||||||
.strong()
|
.strong()
|
||||||
.monospace()
|
.monospace(),
|
||||||
.color(Color32::LIGHT_GRAY),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
header.col(|ui| {
|
header.col(|ui| {
|
||||||
ui.label(
|
ui.label(
|
||||||
RichText::new(t!("gui.hotkeys.column_sound"))
|
RichText::new(t!("gui.hotkeys.column_sound"))
|
||||||
.strong()
|
.strong()
|
||||||
.monospace()
|
.monospace(),
|
||||||
.color(Color32::LIGHT_GRAY),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
header.col(|ui| {
|
header.col(|ui| {
|
||||||
ui.label(
|
ui.label(
|
||||||
RichText::new(t!("gui.hotkeys.column_key_chord"))
|
RichText::new(t!("gui.hotkeys.column_key_chord"))
|
||||||
.strong()
|
.strong()
|
||||||
.monospace()
|
.monospace(),
|
||||||
.color(Color32::LIGHT_GRAY),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
header.col(|ui| {
|
header.col(|ui| {
|
||||||
ui.label(
|
ui.label(
|
||||||
RichText::new(t!("gui.hotkeys.column_actions"))
|
RichText::new(t!("gui.hotkeys.column_actions"))
|
||||||
.strong()
|
.strong()
|
||||||
.monospace()
|
.monospace(),
|
||||||
.color(Color32::LIGHT_GRAY),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -180,10 +176,7 @@ impl SoundpadGui {
|
|||||||
body.row(30.0, |mut row| {
|
body.row(30.0, |mut row| {
|
||||||
row.col(|_| {});
|
row.col(|_| {});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(
|
ui.label(RichText::new(t!("gui.hotkeys.no_hotkeys_configured")));
|
||||||
RichText::new(t!("gui.hotkeys.no_hotkeys_configured"))
|
|
||||||
.color(Color32::GRAY),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
row.col(|_| {});
|
row.col(|_| {});
|
||||||
row.col(|_| {});
|
row.col(|_| {});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::gui::SoundpadGui;
|
use crate::gui::SoundpadGui;
|
||||||
use egui::{Align, Button, Color32, Layout, RichText, Ui};
|
use egui::{Align, Button, Color32, ComboBox, Layout, RichText, Ui};
|
||||||
use egui_material_icons::icons::ICON_ARROW_BACK;
|
use egui_material_icons::icons::ICON_ARROW_BACK;
|
||||||
|
use pwsp::types::config::PreferredTheme;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
impl SoundpadGui {
|
impl SoundpadGui {
|
||||||
@@ -53,6 +54,40 @@ impl SoundpadGui {
|
|||||||
}
|
}
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
// ---------- Selectors -----------
|
||||||
|
let mut selected_theme = self.config.preferred_theme.clone();
|
||||||
|
ComboBox::from_label(t!("gui.settings.theme.label"))
|
||||||
|
.selected_text(match self.config.preferred_theme {
|
||||||
|
PreferredTheme::System => t!("gui.settings.theme.system"),
|
||||||
|
PreferredTheme::Light => t!("gui.settings.theme.light"),
|
||||||
|
PreferredTheme::Dark => t!("gui.settings.theme.dark"),
|
||||||
|
})
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
ui.selectable_value(
|
||||||
|
&mut selected_theme,
|
||||||
|
PreferredTheme::System,
|
||||||
|
t!("gui.settings.theme.system"),
|
||||||
|
);
|
||||||
|
ui.selectable_value(
|
||||||
|
&mut selected_theme,
|
||||||
|
PreferredTheme::Light,
|
||||||
|
t!("gui.settings.theme.light"),
|
||||||
|
);
|
||||||
|
ui.selectable_value(
|
||||||
|
&mut selected_theme,
|
||||||
|
PreferredTheme::Dark,
|
||||||
|
t!("gui.settings.theme.dark"),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if selected_theme != self.config.preferred_theme {
|
||||||
|
self.config.preferred_theme = selected_theme;
|
||||||
|
self.config.save_to_file().ok();
|
||||||
|
}
|
||||||
|
// --------------------------------
|
||||||
|
|
||||||
ui.with_layout(Layout::bottom_up(Align::Min), |ui| {
|
ui.with_layout(Layout::bottom_up(Align::Min), |ui| {
|
||||||
ui.label(t!(
|
ui.label(t!(
|
||||||
"gui.settings.version",
|
"gui.settings.version",
|
||||||
|
|||||||
+48
-2
@@ -1,7 +1,9 @@
|
|||||||
mod gui;
|
mod gui;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
|
use pwsp::utils::gui::ensure_pwsp_audio_dir;
|
||||||
use rust_i18n::i18n;
|
use rust_i18n::i18n;
|
||||||
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
i18n!("locales", fallback = "en");
|
i18n!("locales", fallback = "en");
|
||||||
|
|
||||||
@@ -10,5 +12,49 @@ async fn main() -> Result<()> {
|
|||||||
let locale = sys_locale::get_locale().unwrap_or(String::from("en-US"));
|
let locale = sys_locale::get_locale().unwrap_or(String::from("en-US"));
|
||||||
rust_i18n::set_locale(&locale);
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -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 anyhow::Result;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, fs, path::PathBuf};
|
use std::{collections::HashMap, fs, path::PathBuf};
|
||||||
@@ -35,6 +38,13 @@ impl DaemonConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum PreferredTheme {
|
||||||
|
System,
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct GuiConfig {
|
pub struct GuiConfig {
|
||||||
@@ -47,6 +57,8 @@ pub struct GuiConfig {
|
|||||||
pub pause_on_exit: bool,
|
pub pause_on_exit: bool,
|
||||||
|
|
||||||
pub dirs: Vec<PathBuf>,
|
pub dirs: Vec<PathBuf>,
|
||||||
|
|
||||||
|
pub preferred_theme: PreferredTheme,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GuiConfig {
|
impl Default for GuiConfig {
|
||||||
@@ -60,7 +72,9 @@ impl Default for GuiConfig {
|
|||||||
save_scale_factor: false,
|
save_scale_factor: false,
|
||||||
pause_on_exit: false,
|
pause_on_exit: false,
|
||||||
|
|
||||||
dirs: vec![],
|
dirs: vec![ensure_pwsp_audio_dir()],
|
||||||
|
|
||||||
|
preferred_theme: PreferredTheme::System,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use std::{
|
use std::{
|
||||||
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
time::Instant,
|
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 {
|
pub fn format_time_pair(position: f32, duration: f32) -> String {
|
||||||
fn format_time(seconds: f32) -> String {
|
fn format_time(seconds: f32) -> String {
|
||||||
let total_seconds = seconds.round() as u32;
|
let total_seconds = seconds.round() as u32;
|
||||||
|
|||||||
Reference in New Issue
Block a user