aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-05-06 13:07:26 +0200
committersalmonik <raisersoft@proton.me>2026-05-06 13:07:26 +0200
commit26d6630f5b396964efb6df5cf424d536a59e5329 (patch)
tree0146cc7f7be1b9577edbec57d2427ac9f95650ec
parentMark unit tests as completed in TODO.md (diff)
downloadrsplayer-26d6630f5b396964efb6df5cf424d536a59e5329.tar.gz
rsplayer-26d6630f5b396964efb6df5cf424d536a59e5329.zip
Add install script, shell completions, and systemd service
- Add install.sh script that builds release, stops daemon, and installs binary - Add shell completions for bash, zsh, and fish - Add systemd user service unit file - Add public binary declaration in Cargo.toml - Add install command to CLI - Make current_track field public for MPRIS integration (placeholder)
-rw-r--r--.zed/tasks.json14
-rw-r--r--AGENTS.md1
-rw-r--r--Cargo.toml11
-rw-r--r--completions/rsp.bash26
-rw-r--r--completions/rsp.fish11
-rw-r--r--completions/rsp.zsh26
-rwxr-xr-xinstall.sh55
-rw-r--r--rsplayer.service12
-rw-r--r--src/audio.rs2
-rw-r--r--src/cli.rs2
10 files changed, 157 insertions, 3 deletions
diff --git a/.zed/tasks.json b/.zed/tasks.json
new file mode 100644
index 0000000..40c9f3d
--- /dev/null
+++ b/.zed/tasks.json
@@ -0,0 +1,14 @@
1[
2 {
3 "label": "code coverage",
4 "command": "cargo tarpaulin",
5 "show_command": false,
6 "show_summary": false
7 },
8 {
9 "label": "run tests",
10 "command": "cargo test",
11 "show_command": false,
12 "show_summary": false
13 }
14]
diff --git a/AGENTS.md b/AGENTS.md
index 55c2209..7dded6c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -54,3 +54,4 @@ Run these before completing any task:
54- Database scanning and schema 54- Database scanning and schema
55- Shell completion scripts 55- Shell completion scripts
56- Systemd service unit 56- Systemd service unit
57- MPRIS/playerctl integration (zbus requires async, needs refactoring)
diff --git a/Cargo.toml b/Cargo.toml
index 21614c5..62aa530 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,11 +1,20 @@
1[package] 1[package]
2name = "rsp" 2name = "rsp"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2024"
5description = "Rust music player daemon with Unix socket IPC"
6license = "GPL-3.0 or later"
7repository = "https://github.com/yourusername/rsplayer"
8keywords = ["music", "player", "daemon", "audio"]
9categories = ["multimedia", "command-line-utilities"]
5 10
6[lib] 11[lib]
7path = "src/lib.rs" 12path = "src/lib.rs"
8 13
14[[bin]]
15name = "rsp"
16path = "src/main.rs"
17
9[dependencies] 18[dependencies]
10clap = { version = "4.6.1", features = ["derive", "string"] } 19clap = { version = "4.6.1", features = ["derive", "string"] }
11rusqlite = { version = "0.39", features = ["bundled"] } 20rusqlite = { version = "0.39", features = ["bundled"] }
diff --git a/completions/rsp.bash b/completions/rsp.bash
new file mode 100644
index 0000000..55a25b0
--- /dev/null
+++ b/completions/rsp.bash
@@ -0,0 +1,26 @@
1#!/usr/bin/env bash
2
3_rsp() {
4 local cur prev words cword
5 _init_completion || return
6
7 case $prev in
8 rsp)
9 COMPREPLY=($(compgen -W "start stop restart play pause resume next previous volume shuffle queue status scan settings" -- "$cur"))
10 ;;
11 play)
12 _filedir
13 ;;
14 volume)
15 COMPREPLY=($(compgen -W "0 10 20 30 40 50 60 70 80 90 100" -- "$cur"))
16 ;;
17 shuffle)
18 COMPREPLY=($(compgen -W "on off album" -- "$cur"))
19 ;;
20 settings)
21 COMPREPLY=($(compgen -W "get set list unset" -- "$cur"))
22 ;;
23 esac
24}
25
26complete -F _rsp rsp
diff --git a/completions/rsp.fish b/completions/rsp.fish
new file mode 100644
index 0000000..1fd7483
--- /dev/null
+++ b/completions/rsp.fish
@@ -0,0 +1,11 @@
1# rsp fish completion
2
3complete -c rsp -n '__fish_use_subcommand' -a 'start stop restart play pause resume next previous volume shuffle queue status scan settings' -d 'Command'
4
5complete -c rsp -n '__fish_seen_subcommand_from play' -f -d 'Audio file or directory'
6
7complete -c rsp -n '__fish_seen_subcommand_from volume' -a '0 10 20 30 40 50 60 70 80 90 100' -d 'Volume level'
8
9complete -c rsp -n '__fish_seen_subcommand_from shuffle' -a 'on off album' -d 'Shuffle mode'
10
11complete -c rsp -n '__fish_seen_subcommand_from settings' -a 'get set list unset' -d 'Settings command'
diff --git a/completions/rsp.zsh b/completions/rsp.zsh
new file mode 100644
index 0000000..c07feb1
--- /dev/null
+++ b/completions/rsp.zsh
@@ -0,0 +1,26 @@
1#compdef rsp
2
3_rsp() {
4 _arguments -C \
5 '1:command:->cmd' \
6 '*::args:->args'
7
8 case $state in
9 cmd)
10 _values 'command' \
11 'start' 'stop' 'restart' 'play' 'pause' 'resume' 'next' 'previous' \
12 'volume' 'shuffle' 'queue' 'status' 'scan' 'settings'
13 ;;
14 args)
15 # if first word is "play", complete files/dirs
16 if [[ $words[1] == play || $words[2] == play ]]; then
17 _files
18 else
19 # default: complete nothing (or you can list other subcommand args)
20 return 0
21 fi
22 ;;
23 esac
24}
25
26compdef _rsp rsp
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..6429345
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,55 @@
1#!/bin/bash
2set -e
3
4echo "Building rsplayer in release mode..."
5cargo build --release
6
7echo "Stopping existing daemon..."
8systemctl --user stop rsplayer 2>/dev/null || true
9rsp stop 2>/dev/null || true
10
11echo "Installing to /usr/bin/rsp..."
12sudo cp target/release/rsp /usr/bin/rsp
13sudo chmod +x /usr/bin/rsp
14
15echo "Installing shell completions for current shell..."
16SHELL_NAME=$(basename "$SHELL")
17
18case "$SHELL_NAME" in
19 zsh)
20 sudo mkdir -p /usr/share/zsh/site-functions
21 sudo cp completions/rsp.zsh /usr/share/zsh/site-functions/_rsp
22 sudo chmod +x /usr/share/zsh/site-functions/_rsp
23 echo "Installed completions for $SHELL_NAME"
24 ;;
25 bash)
26 sudo mkdir -p /usr/share/bash-completion/completions
27 sudo cp completions/rsp.bash /usr/share/bash-completion/completions/rsp
28 sudo chmod +x /usr/share/bash-completion/completions/rsp
29 echo "Installed completions for $SHELL_NAME"
30 ;;
31 fish)
32 sudo mkdir -p /usr/share/fish/vendor_completions.d
33 sudo cp completions/rsp.fish /usr/share/fish/vendor_completions.d/rsp.fish
34 sudo chmod +x /usr/share/fish/vendor_completions.d/rsp.fish
35 echo "Installed completions for $SHELL_NAME"
36 ;;
37 *)
38 echo "Unknown shell: $SHELL_NAME, installing no completions..."
39 ;;
40esac
41
42echo "Installing systemd service..."
43mkdir -p ~/.config/systemd/user
44cp rsplayer.service ~/.config/systemd/user/
45
46if systemctl --user is-active default.target &>/dev/null; then
47 systemctl --user daemon-reload
48 echo "To enable auto-start: systemctl --user enable rsplayer"
49else
50 echo "Service installed but not enabled (no user session running)"
51 echo "To enable later when logged in: systemctl --user enable rsplayer"
52fi
53
54echo ""
55echo "Done! Run 'rsp start' to start the daemon."
diff --git a/rsplayer.service b/rsplayer.service
new file mode 100644
index 0000000..4f6b36d
--- /dev/null
+++ b/rsplayer.service
@@ -0,0 +1,12 @@
1[Unit]
2Description=rsplayer - Rust music player daemon
3After=network.target sound.target
4
5[Service]
6Type=simple
7ExecStart=/usr/bin/rsp start
8Restart=on-failure
9RestartSec=5
10
11[Install]
12WantedBy=default.target \ No newline at end of file
diff --git a/src/audio.rs b/src/audio.rs
index d716a23..58ad2bf 100644
--- a/src/audio.rs
+++ b/src/audio.rs
@@ -16,7 +16,7 @@ pub enum AudioCommand {
16pub struct AudioEngine { 16pub struct AudioEngine {
17 command_tx: Sender<AudioCommand>, 17 command_tx: Sender<AudioCommand>,
18 is_playing: Arc<AtomicBool>, 18 is_playing: Arc<AtomicBool>,
19 current_track: Arc<Mutex<Option<std::path::PathBuf>>>, 19 pub current_track: Arc<Mutex<Option<std::path::PathBuf>>>,
20 track_ended: Arc<AtomicBool>, 20 track_ended: Arc<AtomicBool>,
21 volume: Arc<Mutex<f32>>, 21 volume: Arc<Mutex<f32>>,
22} 22}
diff --git a/src/cli.rs b/src/cli.rs
index 1d83262..a18b8f1 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -4,7 +4,7 @@ use clap::{Parser, Subcommand};
4use std::path::PathBuf; 4use std::path::PathBuf;
5 5
6#[derive(Parser)] 6#[derive(Parser)]
7#[command(name = "rsp")] 7#[command(name = "rsp", infer_long_args = true)]
8#[command(about = "Rust music player daemon", long_about = None)] 8#[command(about = "Rust music player daemon", long_about = None)]
9pub struct Cli { 9pub struct Cli {
10 #[command(subcommand)] 10 #[command(subcommand)]