mirror of
https://github.com/arabianq/pipewire-soundpad.git
synced 2026-04-28 14:31:23 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 78e0a133b6 | |||
| 7f8b7194b6 | |||
| 302f153b91 | |||
| f87dcb1564 | |||
| d4d16f6ce7 |
Generated
+13
-7
@@ -2655,9 +2655,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "orbclient"
|
name = "orbclient"
|
||||||
version = "0.3.51"
|
version = "0.3.53"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "59aed3b33578edcfa1bc96a321d590d31832b6ad55a26f0313362ce687e9abd6"
|
checksum = "12c6933ddbbd16539a7672e697bb8d41ac3a4e99ac43eeb40c07236bd7fcb2dd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"libredox",
|
"libredox",
|
||||||
@@ -2913,7 +2913,7 @@ checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pwsp"
|
name = "pwsp"
|
||||||
version = "1.7.2"
|
version = "1.7.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -4017,11 +4017,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasip2"
|
name = "wasip2"
|
||||||
version = "1.0.2+wasi-0.2.9"
|
version = "1.0.3+wasi-0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wit-bindgen",
|
"wit-bindgen 0.57.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4030,7 +4030,7 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wit-bindgen",
|
"wit-bindgen 0.51.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4840,6 +4840,12 @@ dependencies = [
|
|||||||
"wit-bindgen-rust-macro",
|
"wit-bindgen-rust-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen"
|
||||||
|
version = "0.57.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen-core"
|
name = "wit-bindgen-core"
|
||||||
version = "0.51.0"
|
version = "0.51.0"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pwsp"
|
name = "pwsp"
|
||||||
version = "1.7.2"
|
version = "1.7.3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["arabian"]
|
authors = ["arabian"]
|
||||||
description = "PWSP lets you play audio files through your microphone. Has both CLI and GUI clients."
|
description = "PWSP lets you play audio files through your microphone. Has both CLI and GUI clients."
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pkgbase = pwsp-bin
|
pkgbase = pwsp-bin
|
||||||
pkgdesc = Lets you play audio files through your microphone (Pre-built binaries)
|
pkgdesc = Lets you play audio files through your microphone (Pre-built binaries)
|
||||||
pkgver = 1.7.2
|
pkgver = 1.7.3
|
||||||
pkgrel = 2
|
pkgrel = 2
|
||||||
url = https://github.com/arabianq/pipewire-soundpad
|
url = https://github.com/arabianq/pipewire-soundpad
|
||||||
arch = x86_64
|
arch = x86_64
|
||||||
@@ -9,8 +9,8 @@ depends = pipewire
|
|||||||
depends = alsa-lib
|
depends = alsa-lib
|
||||||
provides = pwsp
|
provides = pwsp
|
||||||
conflicts = pwsp
|
conflicts = pwsp
|
||||||
source = pwsp-bin-1.7.2.zip :: https://github.com/arabianq/pipewire-soundpad/releases/download/v1.7.2/pwsp-v1.7.2-linux-x64.zip
|
source = pwsp-bin-1.7.3.zip :: https://github.com/arabianq/pipewire-soundpad/releases/download/v1.7.3/pwsp-v1.7.3-linux-x64.zip
|
||||||
source = pipewire-soundpad-1.7.2.tar.gz :: https://github.com/arabianq/pipewire-soundpad/archive/refs/tags/v1.7.2.tar.gz
|
source = pipewire-soundpad-1.7.3.tar.gz :: https://github.com/arabianq/pipewire-soundpad/archive/refs/tags/v1.7.3.tar.gz
|
||||||
sha256sums = SKIP
|
sha256sums = SKIP
|
||||||
sha256sums = SKIP
|
sha256sums = SKIP
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Maintainer: Alexander Tarasov <a.tevg@ya.ru>
|
# Maintainer: Alexander Tarasov <a.tevg@ya.ru>
|
||||||
pkgname=pwsp-bin
|
pkgname=pwsp-bin
|
||||||
_pkgname=pipewire-soundpad
|
_pkgname=pipewire-soundpad
|
||||||
pkgver=1.7.2
|
pkgver=1.7.3
|
||||||
pkgrel=2
|
pkgrel=2
|
||||||
pkgdesc="Lets you play audio files through your microphone (Pre-built binaries)"
|
pkgdesc="Lets you play audio files through your microphone (Pre-built binaries)"
|
||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pkgbase = pwsp
|
pkgbase = pwsp
|
||||||
pkgdesc = Lets you play audio files through your microphone
|
pkgdesc = Lets you play audio files through your microphone
|
||||||
pkgver = 1.7.2
|
pkgver = 1.7.3
|
||||||
pkgrel = 1
|
pkgrel = 1
|
||||||
url = https://github.com/arabianq/pipewire-soundpad
|
url = https://github.com/arabianq/pipewire-soundpad
|
||||||
arch = any
|
arch = any
|
||||||
@@ -10,7 +10,7 @@ pkgbase = pwsp
|
|||||||
makedepends = cargo
|
makedepends = cargo
|
||||||
makedepends = pipewire
|
makedepends = pipewire
|
||||||
makedepends = alsa-lib
|
makedepends = alsa-lib
|
||||||
source = https://github.com/arabianq/pipewire-soundpad/archive/refs/tags/v1.7.2.tar.gz
|
source = https://github.com/arabianq/pipewire-soundpad/archive/refs/tags/v1.7.3.tar.gz
|
||||||
sha256sums = SKIP
|
sha256sums = SKIP
|
||||||
|
|
||||||
pkgname = pwsp
|
pkgname = pwsp
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Maintainer: Alexander Tarasov <a.tevg@ya.ru>
|
# Maintainer: Alexander Tarasov <a.tevg@ya.ru>
|
||||||
pkgsubn=pwsp
|
pkgsubn=pwsp
|
||||||
pkgname=pwsp
|
pkgname=pwsp
|
||||||
pkgver=1.7.2
|
pkgver=1.7.3
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Lets you play audio files through your microphone"
|
pkgdesc="Lets you play audio files through your microphone"
|
||||||
arch=('any')
|
arch=('any')
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ! -f "Cargo.lock" ]; then
|
||||||
|
echo "Error: Cargo.lock not found. Please run this script from the project root."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Downloading flatpak-cargo-generator.py..."
|
||||||
|
curl -sLO https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/cargo/flatpak-cargo-generator.py
|
||||||
|
chmod +x flatpak-cargo-generator.py
|
||||||
|
|
||||||
|
echo "Generating cargo-sources.json..."
|
||||||
|
python3 flatpak-cargo-generator.py Cargo.lock -o packages/flatpak/cargo-sources.json
|
||||||
|
|
||||||
|
echo "Cleaning up..."
|
||||||
|
rm flatpak-cargo-generator.py
|
||||||
|
|
||||||
|
echo "Successfully generated packages/flatpak/cargo-sources.json"
|
||||||
@@ -5,5 +5,5 @@ Exec=pwsp-wrapper.py %u
|
|||||||
Icon=ru.arabianq.pwsp
|
Icon=ru.arabianq.pwsp
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=Audio;Utility;
|
Categories=AudioVideo;Audio;
|
||||||
Keywords=soundpad;pipewire;audio;
|
Keywords=soundpad;pipewire;audio;
|
||||||
|
|||||||
@@ -15,11 +15,17 @@
|
|||||||
<launchable type="desktop-id">ru.arabianq.pwsp.desktop</launchable>
|
<launchable type="desktop-id">ru.arabianq.pwsp.desktop</launchable>
|
||||||
<screenshots>
|
<screenshots>
|
||||||
<screenshot type="default">
|
<screenshot type="default">
|
||||||
<image>
|
<image>https://raw.githubusercontent.com/arabianq/pipewire-soundpad/master/assets/screenshot.png</image>
|
||||||
https://raw.githubusercontent.com/arabianq/pipewire-soundpad/master/assets/screenshot.png</image>
|
|
||||||
</screenshot>
|
</screenshot>
|
||||||
</screenshots>
|
</screenshots>
|
||||||
<url type="homepage">https://pwsp.arabianq.ru</url>
|
<url type="homepage">https://pwsp.arabianq.ru</url>
|
||||||
<developer_name>arabian</developer_name>
|
<url type="bugtracker">https://github.com/arabianq/pipewire-soundpad/issues</url>
|
||||||
|
<url type="vcs-browser">https://github.com/arabianq/pipewire-soundpad</url>
|
||||||
|
<developer id="ru.arabianq">
|
||||||
|
<name>arabian</name>
|
||||||
|
</developer>
|
||||||
|
<releases>
|
||||||
|
<release version="1.7.3" date="2026-04-20" />
|
||||||
|
</releases>
|
||||||
<content_rating type="oars-1.1" />
|
<content_rating type="oars-1.1" />
|
||||||
</component>
|
</component>
|
||||||
@@ -14,10 +14,9 @@ finish-args:
|
|||||||
- --filesystem=xdg-run/pipewire-0
|
- --filesystem=xdg-run/pipewire-0
|
||||||
- --filesystem=xdg-run/pwsp:create
|
- --filesystem=xdg-run/pwsp:create
|
||||||
- --filesystem=xdg-run/app/ru.arabianq.pwsp:create
|
- --filesystem=xdg-run/app/ru.arabianq.pwsp:create
|
||||||
- --filesystem=host
|
- --filesystem=home
|
||||||
- --device=all
|
- --device=all
|
||||||
- --device=dri
|
- --device=dri
|
||||||
- --share=network
|
|
||||||
- --talk-name=org.freedesktop.portal.Desktop
|
- --talk-name=org.freedesktop.portal.Desktop
|
||||||
- --talk-name=org.freedesktop.portal.Documents
|
- --talk-name=org.freedesktop.portal.Documents
|
||||||
|
|
||||||
@@ -30,11 +29,8 @@ build-options:
|
|||||||
modules:
|
modules:
|
||||||
- name: pwsp
|
- name: pwsp
|
||||||
buildsystem: simple
|
buildsystem: simple
|
||||||
build-options:
|
|
||||||
build-args:
|
|
||||||
- --share=network
|
|
||||||
build-commands:
|
build-commands:
|
||||||
- cargo build --release
|
- export CARGO_HOME=$PWD/cargo && cargo build --release --offline
|
||||||
- install -Dm755 target/release/pwsp-daemon /app/bin/pwsp-daemon
|
- install -Dm755 target/release/pwsp-daemon /app/bin/pwsp-daemon
|
||||||
- install -Dm755 target/release/pwsp-cli /app/bin/pwsp-cli
|
- install -Dm755 target/release/pwsp-cli /app/bin/pwsp-cli
|
||||||
- install -Dm755 target/release/pwsp-gui /app/bin/pwsp-gui
|
- install -Dm755 target/release/pwsp-gui /app/bin/pwsp-gui
|
||||||
@@ -45,3 +41,4 @@ modules:
|
|||||||
sources:
|
sources:
|
||||||
- type: dir
|
- type: dir
|
||||||
path: ../../
|
path: ../../
|
||||||
|
- cargo-sources.json
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
%global cargo_install_lib 0
|
%global cargo_install_lib 0
|
||||||
|
|
||||||
Name: pwsp
|
Name: pwsp
|
||||||
Version: 1.7.2
|
Version: 1.7.3
|
||||||
Release: %autorelease
|
Release: %autorelease
|
||||||
Summary: Lets you play audio files through your microphone
|
Summary: Lets you play audio files through your microphone
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -42,10 +42,10 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
lock_file.lock()?;
|
lock_file.lock()?;
|
||||||
|
|
||||||
let socket_path = runtime_dir.join("daemon.sock");
|
let socket_path = runtime_dir.join("daemon.sock");
|
||||||
if let Err(e) = fs::remove_file(&socket_path) {
|
if let Err(e) = fs::remove_file(&socket_path)
|
||||||
if e.kind() != std::io::ErrorKind::NotFound {
|
&& e.kind() != std::io::ErrorKind::NotFound
|
||||||
return Err(e.into());
|
{
|
||||||
}
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let listener = UnixListener::bind(&socket_path)?;
|
let listener = UnixListener::bind(&socket_path)?;
|
||||||
|
|||||||
+23
-28
@@ -196,10 +196,8 @@ impl SoundpadGui {
|
|||||||
ui.add_space(5.0);
|
ui.add_space(5.0);
|
||||||
|
|
||||||
let conflicts = self.app_state.hotkey_config.find_conflicts();
|
let conflicts = self.app_state.hotkey_config.find_conflicts();
|
||||||
let conflict_slots: std::collections::HashSet<String> = conflicts
|
let conflict_slots: std::collections::HashSet<&str> =
|
||||||
.iter()
|
conflicts.into_iter().flat_map(|(a, b)| [a, b]).collect();
|
||||||
.flat_map(|(a, b)| vec![a.clone(), b.clone()])
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let search = self.app_state.hotkey_search_query.to_lowercase();
|
let search = self.app_state.hotkey_search_query.to_lowercase();
|
||||||
|
|
||||||
@@ -266,7 +264,7 @@ impl SoundpadGui {
|
|||||||
for slot in &slots {
|
for slot in &slots {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
// Conflict badge
|
// Conflict badge
|
||||||
if conflict_slots.contains(&slot.slot) {
|
if conflict_slots.contains(slot.slot.as_str()) {
|
||||||
ui.label(
|
ui.label(
|
||||||
RichText::new(ICON_WARNING.codepoint)
|
RichText::new(ICON_WARNING.codepoint)
|
||||||
.color(Color32::from_rgb(255, 165, 0)),
|
.color(Color32::from_rgb(255, 165, 0)),
|
||||||
@@ -609,10 +607,10 @@ impl SoundpadGui {
|
|||||||
.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_text = RichText::new(name.clone());
|
||||||
if let Some(current_dir) = &self.app_state.current_dir {
|
if let Some(current_dir) = &self.app_state.current_dir
|
||||||
if current_dir.eq(&path) {
|
&& current_dir.eq(&path)
|
||||||
dir_button_text = dir_button_text.color(Color32::WHITE);
|
{
|
||||||
}
|
dir_button_text = dir_button_text.color(Color32::WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dir_button =
|
let dir_button =
|
||||||
@@ -645,10 +643,9 @@ impl SoundpadGui {
|
|||||||
ICON_OPEN_IN_BROWSER.codepoint, "Open in File Manager"
|
ICON_OPEN_IN_BROWSER.codepoint, "Open in File Manager"
|
||||||
))
|
))
|
||||||
.clicked()
|
.clicked()
|
||||||
|
&& let Err(e) = opener::open(&path)
|
||||||
{
|
{
|
||||||
if let Err(e) = opener::open(&path) {
|
eprintln!("Failed to open file manager: {}", e);
|
||||||
eprintln!("Failed to open file manager: {}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
@@ -728,10 +725,10 @@ impl SoundpadGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut file_button_text = RichText::new(&file_name);
|
let mut file_button_text = RichText::new(&file_name);
|
||||||
if let Some(current_file) = &self.app_state.selected_file {
|
if let Some(current_file) = &self.app_state.selected_file
|
||||||
if current_file.eq(&entry_path) {
|
&& current_file.eq(&entry_path)
|
||||||
file_button_text = file_button_text.color(Color32::WHITE);
|
{
|
||||||
}
|
file_button_text = file_button_text.color(Color32::WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_button = Button::new(file_button_text).frame(false);
|
let file_button = Button::new(file_button_text).frame(false);
|
||||||
@@ -792,10 +789,9 @@ impl SoundpadGui {
|
|||||||
ICON_OPEN_IN_BROWSER.codepoint, "Show in File Manager"
|
ICON_OPEN_IN_BROWSER.codepoint, "Show in File Manager"
|
||||||
))
|
))
|
||||||
.clicked()
|
.clicked()
|
||||||
|
&& let Err(e) = opener::reveal(&entry_path)
|
||||||
{
|
{
|
||||||
if let Err(e) = opener::reveal(&entry_path) {
|
eprintln!("Failed to open file manager: {}", e);
|
||||||
eprintln!("Failed to open file manager: {}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
@@ -822,15 +818,14 @@ impl SoundpadGui {
|
|||||||
|
|
||||||
fn get_hotkey_badge(&self, path: &PathBuf) -> Option<String> {
|
fn get_hotkey_badge(&self, path: &PathBuf) -> Option<String> {
|
||||||
for slot in &self.app_state.hotkey_config.slots {
|
for slot in &self.app_state.hotkey_config.slots {
|
||||||
if slot.action.name == "play" {
|
if slot.action.name == "play"
|
||||||
if let Some(file_path_str) = slot.action.args.get("file_path") {
|
&& let Some(file_path_str) = slot.action.args.get("file_path")
|
||||||
if Path::new(file_path_str) == path.as_path() {
|
&& Path::new(file_path_str) == path.as_path()
|
||||||
if let Some(chord) = &slot.key_chord {
|
{
|
||||||
return Some(format!("[{}]", chord));
|
if let Some(chord) = &slot.key_chord {
|
||||||
} else {
|
return Some(format!("[{}]", chord));
|
||||||
return Some(format!("[{}]", slot.slot));
|
} else {
|
||||||
}
|
return Some(format!("[{}]", slot.slot));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -192,18 +192,18 @@ impl SoundpadGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Play selected file on Enter
|
// Play selected file on Enter
|
||||||
if self.key_pressed(ctx, Key::Enter) {
|
if self.key_pressed(ctx, Key::Enter)
|
||||||
if let Some(path) = self.app_state.selected_file.clone() {
|
&& let Some(path) = self.app_state.selected_file.clone()
|
||||||
if modifiers.ctrl {
|
{
|
||||||
self.play_file(&path, true);
|
if modifiers.ctrl {
|
||||||
} else if modifiers.shift
|
self.play_file(&path, true);
|
||||||
&& let Some(last_track) = self.audio_player_state.tracks.last()
|
} else if modifiers.shift
|
||||||
{
|
&& let Some(last_track) = self.audio_player_state.tracks.last()
|
||||||
self.stop(Some(last_track.id));
|
{
|
||||||
self.play_file(&path, true);
|
self.stop(Some(last_track.id));
|
||||||
} else {
|
self.play_file(&path, true);
|
||||||
self.play_file(&path, false);
|
} else {
|
||||||
}
|
self.play_file(&path, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ impl SoundpadGui {
|
|||||||
let arrow_down_pressed = self.key_pressed(ctx, Key::ArrowDown);
|
let arrow_down_pressed = self.key_pressed(ctx, Key::ArrowDown);
|
||||||
if modifiers.ctrl && (arrow_up_pressed || arrow_down_pressed) {
|
if modifiers.ctrl && (arrow_up_pressed || arrow_down_pressed) {
|
||||||
if modifiers.shift && !self.app_state.dirs.is_empty() {
|
if modifiers.shift && !self.app_state.dirs.is_empty() {
|
||||||
let mut dirs: Vec<PathBuf> = self.app_state.dirs.iter().cloned().collect();
|
let mut dirs: Vec<PathBuf> = self.app_state.dirs.to_vec();
|
||||||
dirs.sort();
|
dirs.sort();
|
||||||
|
|
||||||
let current_dir_index = self
|
let current_dir_index = self
|
||||||
|
|||||||
+15
-16
@@ -106,7 +106,7 @@ impl AudioPlayer {
|
|||||||
|
|
||||||
fn abort_link_thread(&mut self) {
|
fn abort_link_thread(&mut self) {
|
||||||
if let Some(sender) = &self.input_link_sender {
|
if let Some(sender) = &self.input_link_sender {
|
||||||
if let Ok(_) = sender.send(Terminate {}) {
|
if sender.send(Terminate {}).is_ok() {
|
||||||
println!("Sent terminate signal to input link thread");
|
println!("Sent terminate signal to input link thread");
|
||||||
self.input_link_sender = None;
|
self.input_link_sender = None;
|
||||||
} else {
|
} else {
|
||||||
@@ -117,7 +117,7 @@ impl AudioPlayer {
|
|||||||
|
|
||||||
fn abort_player_link_thread(&mut self) {
|
fn abort_player_link_thread(&mut self) {
|
||||||
if let Some(sender) = &self.player_link_sender {
|
if let Some(sender) = &self.player_link_sender {
|
||||||
if let Ok(_) = sender.send(Terminate {}) {
|
if sender.send(Terminate {}).is_ok() {
|
||||||
println!("Sent terminate signal to player link thread");
|
println!("Sent terminate signal to player link thread");
|
||||||
self.player_link_sender = None;
|
self.player_link_sender = None;
|
||||||
} else {
|
} else {
|
||||||
@@ -254,12 +254,12 @@ impl AudioPlayer {
|
|||||||
pub fn get_volume(&mut self, id: Option<u32>) -> Option<f32> {
|
pub fn get_volume(&mut self, id: Option<u32>) -> Option<f32> {
|
||||||
if let Some(id) = id {
|
if let Some(id) = id {
|
||||||
if let Some(sound) = self.tracks.get_mut(&id) {
|
if let Some(sound) = self.tracks.get_mut(&id) {
|
||||||
return Some(sound.sink.volume());
|
Some(sound.sink.volume())
|
||||||
} else {
|
} else {
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Some(self.volume);
|
Some(self.volume)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,10 +443,10 @@ impl AudioPlayer {
|
|||||||
if let Some(sound) = self.tracks.get(&id) {
|
if let Some(sound) = self.tracks.get(&id) {
|
||||||
let path = sound.path.clone();
|
let path = sound.path.clone();
|
||||||
let handle = tokio::task::spawn_blocking(move || {
|
let handle = tokio::task::spawn_blocking(move || {
|
||||||
if let Ok(file) = fs::File::open(&path) {
|
if let Ok(file) = fs::File::open(&path)
|
||||||
if let Ok(source) = Decoder::try_from(file) {
|
&& let Ok(source) = Decoder::try_from(file)
|
||||||
return Some((id, source));
|
{
|
||||||
}
|
return Some((id, source));
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
});
|
});
|
||||||
@@ -455,13 +455,12 @@ impl AudioPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for handle in restart_futures {
|
for handle in restart_futures {
|
||||||
if let Ok(res) = handle.await {
|
if let Ok(res) = handle.await
|
||||||
if let Some((id, source)) = res {
|
&& let Some((id, source)) = res
|
||||||
if let Some(sound) = self.tracks.get_mut(&id) {
|
&& let Some(sound) = self.tracks.get_mut(&id)
|
||||||
sound.sink.append(source);
|
{
|
||||||
sound.sink.play();
|
sound.sink.append(source);
|
||||||
}
|
sound.sink.play();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -673,7 +673,7 @@ impl Executable for PlayHotkeyCommand {
|
|||||||
if let Some(cmd) = parse_command(&action) {
|
if let Some(cmd) = parse_command(&action) {
|
||||||
cmd.execute().await
|
cmd.execute().await
|
||||||
} else {
|
} else {
|
||||||
Response::new(false, "Unknown command in hotkey slot".to_string())
|
Response::new(false, "Unknown command in hotkey slot")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -13,10 +13,10 @@ impl DaemonConfig {
|
|||||||
pub fn save_to_file(&self) -> Result<(), Box<dyn Error>> {
|
pub fn save_to_file(&self) -> Result<(), Box<dyn Error>> {
|
||||||
let config_path = get_config_path()?.join("daemon.json");
|
let config_path = get_config_path()?.join("daemon.json");
|
||||||
|
|
||||||
if let Some(config_dir) = config_path.parent() {
|
if let Some(config_dir) = config_path.parent()
|
||||||
if !config_path.exists() {
|
&& !config_path.exists()
|
||||||
fs::create_dir_all(config_dir)?;
|
{
|
||||||
}
|
fs::create_dir_all(config_dir)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let config_json = serde_json::to_string_pretty(self)?;
|
let config_json = serde_json::to_string_pretty(self)?;
|
||||||
@@ -68,10 +68,10 @@ impl GuiConfig {
|
|||||||
pub fn save_to_file(&mut self) -> Result<(), Box<dyn Error>> {
|
pub fn save_to_file(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
let config_path = get_config_path()?.join("gui.json");
|
let config_path = get_config_path()?.join("gui.json");
|
||||||
|
|
||||||
if let Some(config_dir) = config_path.parent() {
|
if let Some(config_dir) = config_path.parent()
|
||||||
if !config_path.exists() {
|
&& !config_path.exists()
|
||||||
fs::create_dir_all(config_dir)?;
|
{
|
||||||
}
|
fs::create_dir_all(config_dir)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not save scale factor if user does not want to
|
// Do not save scale factor if user does not want to
|
||||||
@@ -172,7 +172,7 @@ impl HotkeyConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns pairs of slot names that share the same key chord.
|
/// Returns pairs of slot names that share the same key chord.
|
||||||
pub fn find_conflicts(&self) -> Vec<(String, String)> {
|
pub fn find_conflicts(&self) -> Vec<(&str, &str)> {
|
||||||
let mut conflicts = vec![];
|
let mut conflicts = vec![];
|
||||||
let mut chord_map: HashMap<&str, Vec<&str>> = HashMap::new();
|
let mut chord_map: HashMap<&str, Vec<&str>> = HashMap::new();
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ impl HotkeyConfig {
|
|||||||
if slots.len() > 1 {
|
if slots.len() > 1 {
|
||||||
for i in 0..slots.len() {
|
for i in 0..slots.len() {
|
||||||
for j in (i + 1)..slots.len() {
|
for j in (i + 1)..slots.len() {
|
||||||
conflicts.push((slots[i].to_string(), slots[j].to_string()));
|
conflicts.push((slots[i], slots[j]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-6
@@ -1,9 +1,7 @@
|
|||||||
use crate::{
|
use crate::types::{
|
||||||
types::{
|
audio_player::AudioPlayer,
|
||||||
audio_player::AudioPlayer,
|
config::DaemonConfig,
|
||||||
config::DaemonConfig,
|
socket::{MAX_MESSAGE_SIZE, Request, Response},
|
||||||
socket::{MAX_MESSAGE_SIZE, Request, Response},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|||||||
+7
-7
@@ -112,13 +112,13 @@ pub fn start_app_state_thread(audio_player_state_shared: Arc<Mutex<AudioPlayerSt
|
|||||||
let hotkey_res = make_request(Request::get_hotkeys())
|
let hotkey_res = make_request(Request::get_hotkeys())
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
if hotkey_res.status {
|
if hotkey_res.status
|
||||||
if let Ok(config) = serde_json::from_str::<HotkeyConfig>(&hotkey_res.message) {
|
&& let Ok(config) = serde_json::from_str::<HotkeyConfig>(&hotkey_res.message)
|
||||||
let mut guard = audio_player_state_shared
|
{
|
||||||
.lock()
|
let mut guard = audio_player_state_shared
|
||||||
.unwrap_or_else(|e| e.into_inner());
|
.lock()
|
||||||
guard.hotkey_config = Some(config);
|
.unwrap_or_else(|e| e.into_inner());
|
||||||
}
|
guard.hotkey_config = Some(config);
|
||||||
}
|
}
|
||||||
last_hotkey_poll = Instant::now();
|
last_hotkey_poll = Instant::now();
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-22
@@ -9,6 +9,13 @@ use tokio::{
|
|||||||
time::{Duration, timeout},
|
time::{Duration, timeout},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn setup_pipewire_context() -> (MainLoopRc, ContextRc) {
|
||||||
|
pipewire::init();
|
||||||
|
let main_loop = MainLoopRc::new(None).expect("Failed to initialize pipewire main loop");
|
||||||
|
let context = ContextRc::new(&main_loop, None).expect("Failed to create pipewire context");
|
||||||
|
(main_loop, context)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_global_object(
|
fn parse_global_object(
|
||||||
global_object: &GlobalObject<&DictRef>,
|
global_object: &GlobalObject<&DictRef>,
|
||||||
) -> (Option<AudioDevice>, Option<Port>) {
|
) -> (Option<AudioDevice>, Option<Port>) {
|
||||||
@@ -56,20 +63,20 @@ fn parse_global_object(
|
|||||||
(None, None)
|
(None, None)
|
||||||
};
|
};
|
||||||
// Check if the object is a port
|
// Check if the object is a port
|
||||||
} else if props.get("port.direction").is_some() {
|
} else if props.get("port.direction").is_some()
|
||||||
if let (Some(node_id), Some(port_id), Some(port_name)) = (
|
&& let (Some(node_id), Some(port_id), Some(port_name)) = (
|
||||||
props.get("node.id").and_then(|id| id.parse::<u32>().ok()),
|
props.get("node.id").and_then(|id| id.parse::<u32>().ok()),
|
||||||
props.get("port.id").and_then(|id| id.parse::<u32>().ok()),
|
props.get("port.id").and_then(|id| id.parse::<u32>().ok()),
|
||||||
props.get("port.name"),
|
props.get("port.name"),
|
||||||
) {
|
)
|
||||||
let port = Port {
|
{
|
||||||
node_id,
|
let port = Port {
|
||||||
port_id,
|
node_id,
|
||||||
name: port_name.to_string(),
|
port_id,
|
||||||
};
|
name: port_name.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
return (None, Some(port));
|
return (None, Some(port));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, None)
|
(None, None)
|
||||||
@@ -79,9 +86,7 @@ async fn pw_get_global_objects_thread(
|
|||||||
main_sender: mpsc::Sender<(Option<AudioDevice>, Option<Port>)>,
|
main_sender: mpsc::Sender<(Option<AudioDevice>, Option<Port>)>,
|
||||||
pw_receiver: pipewire::channel::Receiver<Terminate>,
|
pw_receiver: pipewire::channel::Receiver<Terminate>,
|
||||||
) {
|
) {
|
||||||
pipewire::init();
|
let (main_loop, context) = setup_pipewire_context();
|
||||||
|
|
||||||
let main_loop = MainLoopRc::new(None).expect("Failed to initialize pipewire main loop");
|
|
||||||
|
|
||||||
// Stop main loop on Terminate message
|
// Stop main loop on Terminate message
|
||||||
let _receiver = pw_receiver.attach(main_loop.loop_(), {
|
let _receiver = pw_receiver.attach(main_loop.loop_(), {
|
||||||
@@ -89,7 +94,6 @@ async fn pw_get_global_objects_thread(
|
|||||||
move |_| _main_loop.quit()
|
move |_| _main_loop.quit()
|
||||||
});
|
});
|
||||||
|
|
||||||
let context = ContextRc::new(&main_loop, None).expect("Failed to create pipewire context");
|
|
||||||
let core = context
|
let core = context
|
||||||
.connect(None)
|
.connect(None)
|
||||||
.expect("Failed to connect to pipewire context");
|
.expect("Failed to connect to pipewire context");
|
||||||
@@ -224,10 +228,7 @@ pub fn create_virtual_mic() -> Result<pipewire::channel::Sender<Terminate>, Box<
|
|||||||
let (pw_sender, pw_receiver) = pipewire::channel::channel::<Terminate>();
|
let (pw_sender, pw_receiver) = pipewire::channel::channel::<Terminate>();
|
||||||
|
|
||||||
let _pw_thread = thread::spawn(move || {
|
let _pw_thread = thread::spawn(move || {
|
||||||
pipewire::init();
|
let (main_loop, context) = setup_pipewire_context();
|
||||||
|
|
||||||
let main_loop = MainLoopRc::new(None).expect("Failed to initialize pipewire main loop");
|
|
||||||
let context = ContextRc::new(&main_loop, None).expect("Failed to create pipewire context");
|
|
||||||
let core = context
|
let core = context
|
||||||
.connect(None)
|
.connect(None)
|
||||||
.expect("Failed to connect to pipewire context");
|
.expect("Failed to connect to pipewire context");
|
||||||
@@ -305,10 +306,7 @@ pub fn create_link(
|
|||||||
let (pw_sender, pw_receiver) = pipewire::channel::channel::<Terminate>();
|
let (pw_sender, pw_receiver) = pipewire::channel::channel::<Terminate>();
|
||||||
|
|
||||||
let _pw_thread = thread::spawn(move || {
|
let _pw_thread = thread::spawn(move || {
|
||||||
pipewire::init();
|
let (main_loop, context) = setup_pipewire_context();
|
||||||
|
|
||||||
let main_loop = MainLoopRc::new(None).expect("Failed to initialize pipewire main loop");
|
|
||||||
let context = ContextRc::new(&main_loop, None).expect("Failed to create pipewire context");
|
|
||||||
let core = context
|
let core = context
|
||||||
.connect(None)
|
.connect(None)
|
||||||
.expect("Failed to connect to pipewire context");
|
.expect("Failed to connect to pipewire context");
|
||||||
|
|||||||
Reference in New Issue
Block a user