Replaced sequential unwraps on pipewire properties ("node.id", "port.id", "port.name")
with an `if let` and `and_then()` pattern in `src/utils/pipewire.rs`. This provides
safety against daemon crashes when properties are missing or malformed by silently
returning instead of panicking.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Offload synchronous `fs::File::open` and `Decoder::try_from` operations to `tokio::task::spawn_blocking` in `AudioPlayer::update`. This allows the Tokio runtime to process other asynchronous tasks concurrently without being blocked by file I/O operations and audio header decoding during looped playback.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
The daemon was allocating memory based on an unverified length prefix
sent over the unauthenticated Unix socket, potentially allowing a malicious
client to cause an Out-Of-Memory panic (DoS). A 10 MB size limit has been
introduced.
Note: The previously reported `unwrap()` panic on invalid JSON payloads
was already fixed and replaced with a safe `match` block in a prior commit.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Moves the check `if let Some(current_input_name) = &audio_player.input_device_name`
outside the loop over `input_devices` in `GetFullStateCommand::execute`.
By creating two separate loops (one for when an input device name is selected,
and one for when it is not), we eliminate the overhead of evaluating the `Option`
on every single iteration of the `input_devices` array. This effectively unswitches
the loop and avoids repeatedly accessing the `audio_player` struct field.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
In `draw_footer`, the `all_inputs` HashMap was being collected into a Vec
and sorted on every single UI frame (~60 FPS). This caused unnecessary
overhead and allocations.
This commit introduces a cached `all_inputs_sorted` vector in the
`AudioPlayerState` which is populated only when the inputs map changes
during the state sync. `draw_footer` now loops over this pre-sorted
vector directly.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
When the user's daemon.json or gui.json configuration files become corrupted or invalid (e.g. invalid JSON), the application panics as the load_from_file function previously bubbled up the error causing a panic. This fix modifies load_from_file for both DaemonConfig and GuiConfig to catch JSON parsing errors using a match statement and return a Default configuration instead.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Removed the unsafe `.unwrap()` call when attempting to get the parent directory of `config_path` in `DaemonConfig::save_to_file` and `GuiConfig::save_to_file`. Replaced it with an idiomatic `if let Some(config_dir)` check to improve code safety and maintainability.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Replaces `audio_player_state_shared.lock().unwrap()` with `.unwrap_or_else(|e| e.into_inner())` in `src/utils/gui.rs` to allow safe recovery from poisoned locks and avoid application panics.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit addresses a code health issue in `src/gui/input.rs` where an `.is_some()` check was followed by an unsafe `.unwrap()` on `self.app_state.selected_file`.
The logic has been updated to use the idiomatic `if let Some(path) = self.app_state.selected_file.clone()` pattern. The `.clone()` is necessary because the subsequent methods (`self.play_file` and `self.stop`) require a mutable borrow (`&mut self`), which would conflict with an immutable borrow of `self.app_state.selected_file`. This change ensures the code is safe and panic-free while satisfying Rust's borrow checker rules. Behavior remains unchanged.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
- Replaced `.unwrap()` with proper error handling during JSON serialization in `GetStateCommand`, `GetTracksCommand`, and `GetFullStateCommand`.
- Added error handling for malformed client requests in the daemon's main loop.
- Ensured the daemon stays running even if serialization or deserialization fails.
- Handled potential errors from `get_all_devices()`.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Moved the access of `audio_player.input_device_name` outside the loop
in `GetFullStateCommand::execute` to avoid repeated field access and
Option checking during iteration.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Replaced `.to_str().unwrap()` with `.to_string_lossy()` when converting
`PathBuf` to `String` to prevent potential crashes if the path contains
invalid Unicode. This change improves the robustness of both the CLI
and GUI components when handling file paths.
- Modified `src/bin/cli.rs` to safely handle `file_path`.
- Modified `src/gui/mod.rs` to safely handle `path` in `play_file`.
Co-authored-by: arabianq <55220741+arabianq@users.noreply.github.com>
Replaced 6 separate, redundant workflow files (`git-archive.yml`, `git-deb.yml`, `git-flatpak.yml`, `release-archive.yml`, `release-deb.yml`, `release-flatpak.yml`) with 2 consolidated workflows (`build.yml` and `release.yml`).
- Consolidated `.zip` and `.deb` building into a single `linux-build` and `linux-release` job to avoid running `cargo build --release` multiple times.
- Added parallel `flatpak-build` and `flatpak-release` jobs to the respective unified workflows.
- Improved `release.yml` with a `prepare` job that correctly queries and passes the release tag to dependent build jobs.
- Fixed an issue in the `prepare` job where an undefined bash `$GITHUB_TOKEN` was used instead of `${{ secrets.GITHUB_TOKEN }}`.
Co-authored-by: arabianq <55220741+arabianq@users.noreply.github.com>