diff options
| -rw-r--r-- | .zed/tasks.json | 14 | ||||
| -rw-r--r-- | AGENTS.md | 1 | ||||
| -rw-r--r-- | Cargo.toml | 11 | ||||
| -rw-r--r-- | completions/rsp.bash | 26 | ||||
| -rw-r--r-- | completions/rsp.fish | 11 | ||||
| -rw-r--r-- | completions/rsp.zsh | 26 | ||||
| -rwxr-xr-x | install.sh | 55 | ||||
| -rw-r--r-- | rsplayer.service | 12 | ||||
| -rw-r--r-- | src/audio.rs | 2 | ||||
| -rw-r--r-- | src/cli.rs | 2 |
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 | ] | ||
| @@ -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) | ||
| @@ -1,11 +1,20 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "rsp" | 2 | name = "rsp" |
| 3 | version = "0.1.0" | 3 | version = "0.1.0" |
| 4 | edition = "2021" | 4 | edition = "2024" |
| 5 | description = "Rust music player daemon with Unix socket IPC" | ||
| 6 | license = "GPL-3.0 or later" | ||
| 7 | repository = "https://github.com/yourusername/rsplayer" | ||
| 8 | keywords = ["music", "player", "daemon", "audio"] | ||
| 9 | categories = ["multimedia", "command-line-utilities"] | ||
| 5 | 10 | ||
| 6 | [lib] | 11 | [lib] |
| 7 | path = "src/lib.rs" | 12 | path = "src/lib.rs" |
| 8 | 13 | ||
| 14 | [[bin]] | ||
| 15 | name = "rsp" | ||
| 16 | path = "src/main.rs" | ||
| 17 | |||
| 9 | [dependencies] | 18 | [dependencies] |
| 10 | clap = { version = "4.6.1", features = ["derive", "string"] } | 19 | clap = { version = "4.6.1", features = ["derive", "string"] } |
| 11 | rusqlite = { version = "0.39", features = ["bundled"] } | 20 | 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 @@ | |||
| 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 | |||
| 26 | 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 @@ | |||
| 1 | # rsp fish completion | ||
| 2 | |||
| 3 | complete -c rsp -n '__fish_use_subcommand' -a 'start stop restart play pause resume next previous volume shuffle queue status scan settings' -d 'Command' | ||
| 4 | |||
| 5 | complete -c rsp -n '__fish_seen_subcommand_from play' -f -d 'Audio file or directory' | ||
| 6 | |||
| 7 | complete -c rsp -n '__fish_seen_subcommand_from volume' -a '0 10 20 30 40 50 60 70 80 90 100' -d 'Volume level' | ||
| 8 | |||
| 9 | complete -c rsp -n '__fish_seen_subcommand_from shuffle' -a 'on off album' -d 'Shuffle mode' | ||
| 10 | |||
| 11 | 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 @@ | |||
| 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 | |||
| 26 | 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 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | set -e | ||
| 3 | |||
| 4 | echo "Building rsplayer in release mode..." | ||
| 5 | cargo build --release | ||
| 6 | |||
| 7 | echo "Stopping existing daemon..." | ||
| 8 | systemctl --user stop rsplayer 2>/dev/null || true | ||
| 9 | rsp stop 2>/dev/null || true | ||
| 10 | |||
| 11 | echo "Installing to /usr/bin/rsp..." | ||
| 12 | sudo cp target/release/rsp /usr/bin/rsp | ||
| 13 | sudo chmod +x /usr/bin/rsp | ||
| 14 | |||
| 15 | echo "Installing shell completions for current shell..." | ||
| 16 | SHELL_NAME=$(basename "$SHELL") | ||
| 17 | |||
| 18 | case "$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 | ;; | ||
| 40 | esac | ||
| 41 | |||
| 42 | echo "Installing systemd service..." | ||
| 43 | mkdir -p ~/.config/systemd/user | ||
| 44 | cp rsplayer.service ~/.config/systemd/user/ | ||
| 45 | |||
| 46 | if systemctl --user is-active default.target &>/dev/null; then | ||
| 47 | systemctl --user daemon-reload | ||
| 48 | echo "To enable auto-start: systemctl --user enable rsplayer" | ||
| 49 | else | ||
| 50 | echo "Service installed but not enabled (no user session running)" | ||
| 51 | echo "To enable later when logged in: systemctl --user enable rsplayer" | ||
| 52 | fi | ||
| 53 | |||
| 54 | echo "" | ||
| 55 | 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 @@ | |||
| 1 | [Unit] | ||
| 2 | Description=rsplayer - Rust music player daemon | ||
| 3 | After=network.target sound.target | ||
| 4 | |||
| 5 | [Service] | ||
| 6 | Type=simple | ||
| 7 | ExecStart=/usr/bin/rsp start | ||
| 8 | Restart=on-failure | ||
| 9 | RestartSec=5 | ||
| 10 | |||
| 11 | [Install] | ||
| 12 | 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 { | |||
| 16 | pub struct AudioEngine { | 16 | pub 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 | } |
| @@ -4,7 +4,7 @@ use clap::{Parser, Subcommand}; | |||
| 4 | use std::path::PathBuf; | 4 | use 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)] |
| 9 | pub struct Cli { | 9 | pub struct Cli { |
| 10 | #[command(subcommand)] | 10 | #[command(subcommand)] |
