From 26d6630f5b396964efb6df5cf424d536a59e5329 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 6 May 2026 13:07:26 +0200 Subject: 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) --- .zed/tasks.json | 14 +++++++++++++ AGENTS.md | 1 + Cargo.toml | 11 ++++++++++- completions/rsp.bash | 26 +++++++++++++++++++++++++ completions/rsp.fish | 11 +++++++++++ completions/rsp.zsh | 26 +++++++++++++++++++++++++ install.sh | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ rsplayer.service | 12 ++++++++++++ src/audio.rs | 2 +- src/cli.rs | 2 +- 10 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 .zed/tasks.json create mode 100644 completions/rsp.bash create mode 100644 completions/rsp.fish create mode 100644 completions/rsp.zsh create mode 100755 install.sh create mode 100644 rsplayer.service 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 @@ +[ + { + "label": "code coverage", + "command": "cargo tarpaulin", + "show_command": false, + "show_summary": false + }, + { + "label": "run tests", + "command": "cargo test", + "show_command": false, + "show_summary": false + } +] 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: - Database scanning and schema - Shell completion scripts - Systemd service unit +- 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 @@ [package] name = "rsp" version = "0.1.0" -edition = "2021" +edition = "2024" +description = "Rust music player daemon with Unix socket IPC" +license = "GPL-3.0 or later" +repository = "https://github.com/yourusername/rsplayer" +keywords = ["music", "player", "daemon", "audio"] +categories = ["multimedia", "command-line-utilities"] [lib] path = "src/lib.rs" +[[bin]] +name = "rsp" +path = "src/main.rs" + [dependencies] clap = { version = "4.6.1", features = ["derive", "string"] } rusqlite = { 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 @@ +#!/usr/bin/env bash + +_rsp() { + local cur prev words cword + _init_completion || return + + case $prev in + rsp) + COMPREPLY=($(compgen -W "start stop restart play pause resume next previous volume shuffle queue status scan settings" -- "$cur")) + ;; + play) + _filedir + ;; + volume) + COMPREPLY=($(compgen -W "0 10 20 30 40 50 60 70 80 90 100" -- "$cur")) + ;; + shuffle) + COMPREPLY=($(compgen -W "on off album" -- "$cur")) + ;; + settings) + COMPREPLY=($(compgen -W "get set list unset" -- "$cur")) + ;; + esac +} + +complete -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 @@ +# rsp fish completion + +complete -c rsp -n '__fish_use_subcommand' -a 'start stop restart play pause resume next previous volume shuffle queue status scan settings' -d 'Command' + +complete -c rsp -n '__fish_seen_subcommand_from play' -f -d 'Audio file or directory' + +complete -c rsp -n '__fish_seen_subcommand_from volume' -a '0 10 20 30 40 50 60 70 80 90 100' -d 'Volume level' + +complete -c rsp -n '__fish_seen_subcommand_from shuffle' -a 'on off album' -d 'Shuffle mode' + +complete -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 @@ +#compdef rsp + +_rsp() { + _arguments -C \ + '1:command:->cmd' \ + '*::args:->args' + + case $state in + cmd) + _values 'command' \ + 'start' 'stop' 'restart' 'play' 'pause' 'resume' 'next' 'previous' \ + 'volume' 'shuffle' 'queue' 'status' 'scan' 'settings' + ;; + args) + # if first word is "play", complete files/dirs + if [[ $words[1] == play || $words[2] == play ]]; then + _files + else + # default: complete nothing (or you can list other subcommand args) + return 0 + fi + ;; + esac +} + +compdef _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 @@ +#!/bin/bash +set -e + +echo "Building rsplayer in release mode..." +cargo build --release + +echo "Stopping existing daemon..." +systemctl --user stop rsplayer 2>/dev/null || true +rsp stop 2>/dev/null || true + +echo "Installing to /usr/bin/rsp..." +sudo cp target/release/rsp /usr/bin/rsp +sudo chmod +x /usr/bin/rsp + +echo "Installing shell completions for current shell..." +SHELL_NAME=$(basename "$SHELL") + +case "$SHELL_NAME" in + zsh) + sudo mkdir -p /usr/share/zsh/site-functions + sudo cp completions/rsp.zsh /usr/share/zsh/site-functions/_rsp + sudo chmod +x /usr/share/zsh/site-functions/_rsp + echo "Installed completions for $SHELL_NAME" + ;; + bash) + sudo mkdir -p /usr/share/bash-completion/completions + sudo cp completions/rsp.bash /usr/share/bash-completion/completions/rsp + sudo chmod +x /usr/share/bash-completion/completions/rsp + echo "Installed completions for $SHELL_NAME" + ;; + fish) + sudo mkdir -p /usr/share/fish/vendor_completions.d + sudo cp completions/rsp.fish /usr/share/fish/vendor_completions.d/rsp.fish + sudo chmod +x /usr/share/fish/vendor_completions.d/rsp.fish + echo "Installed completions for $SHELL_NAME" + ;; + *) + echo "Unknown shell: $SHELL_NAME, installing no completions..." + ;; +esac + +echo "Installing systemd service..." +mkdir -p ~/.config/systemd/user +cp rsplayer.service ~/.config/systemd/user/ + +if systemctl --user is-active default.target &>/dev/null; then + systemctl --user daemon-reload + echo "To enable auto-start: systemctl --user enable rsplayer" +else + echo "Service installed but not enabled (no user session running)" + echo "To enable later when logged in: systemctl --user enable rsplayer" +fi + +echo "" +echo "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 @@ +[Unit] +Description=rsplayer - Rust music player daemon +After=network.target sound.target + +[Service] +Type=simple +ExecStart=/usr/bin/rsp start +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=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 { pub struct AudioEngine { command_tx: Sender, is_playing: Arc, - current_track: Arc>>, + pub current_track: Arc>>, track_ended: Arc, volume: Arc>, } 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}; use std::path::PathBuf; #[derive(Parser)] -#[command(name = "rsp")] +#[command(name = "rsp", infer_long_args = true)] #[command(about = "Rust music player daemon", long_about = None)] pub struct Cli { #[command(subcommand)] -- cgit v1.2.3