From 43562db0804338f2d55dff13439f1165f8dd9d3f Mon Sep 17 00:00:00 2001 From: salmonik Date: Sat, 16 May 2026 12:47:43 +0200 Subject: first public release. --- Cargo.lock | 2 +- Cargo.toml | 4 +- README.md | 53 +++++++++ completions/rsp.bash | 38 +----- completions/rsp.elvish | 224 ------------------------------------ completions/rsp.fish | 37 +++--- completions/rsp.powershell | 280 --------------------------------------------- completions/rsp.zsh | 23 ---- install.sh | 9 -- src/daemon.rs | 32 +++--- src/notification.rs | 8 ++ src/queue.rs | 16 +++ 12 files changed, 115 insertions(+), 611 deletions(-) create mode 100644 README.md delete mode 100644 completions/rsp.elvish delete mode 100644 completions/rsp.powershell diff --git a/Cargo.lock b/Cargo.lock index 923e985..6d359ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2032,7 +2032,7 @@ dependencies = [ [[package]] name = "rsp" -version = "0.8.0" +version = "0.8.1" dependencies = [ "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index 270ea7d..0393d3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "rsp" -version = "0.8.0" +version = "0.8.1" edition = "2024" description = "Rust music player daemon with Unix socket IPC" license = "GPL-3.0 or later" -repository = "https://github.com/yourusername/rsplayer" +repository = "https://codeberg.org/salmonik/RSPlayer" keywords = ["music", "player", "daemon", "audio"] categories = ["multimedia", "command-line-utilities"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..2092f2a --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# RSPlayer is a daemon driven CLI music player with scrobbling written in rust + +## Installation +``` +git clone https://codeberg.org/salmonik/RSPlayer.git +cd RSPlayer +./install.sh +``` + +install.sh will: +compile RSP (make sure you have rust properly installed!) +install shell autocompletions (zsh, bash and fish supported) +install user systemd service and activate it + +## Usage + +configuration is generated at startup in $XDG_CONFIG_HOME/rsplayer/config.toml +most important values there are: +listenbrainz_token (last.fm scrobbling not yet tested) +display_format (supports $ARTIST $ALBUM and $TRACK) +music_paths (for DB usage, still WIP) +scan_interval (same as above) + +all other values can be changed in runtime using commands + +as for commands: +RSP will be installed as rsp, in this fragment, rsp will be ommited + +these commands should only be used in testing or by systemd service: +`start-daemon` Start the daemon +`stop-daemon` Stop the daemon +`restart` Restart the daemon (kill existing and start new) + +these are normal commands: +`play` Play a track, album, or artist +`pause` Pause playback +`resume` Resume playback +`toggle` Toggle play/pause +`stop` Stop playback +`next` Skip to next track +`previous` Skip to previous track +`volume` Set volume (0-100) +`shuffle` Shuffle mode +`queue` Queue management +`status` Show player status +`scan` Scan music paths to populate database +`settings` Settings management +`help` Print this message or the help of the given subcommand(s) + + +## Technical stuff +The main culprit of this player is lack of integration with programs such as playerctl +this is due to the daemon not being asynchronous diff --git a/completions/rsp.bash b/completions/rsp.bash index 1812802..c4e295f 100644 --- a/completions/rsp.bash +++ b/completions/rsp.bash @@ -16,9 +16,6 @@ _rsp() { ",$1") cmd="rsp" ;; - rsp,completions) - cmd="rsp__subcmd__completions" - ;; rsp,help) cmd="rsp__subcmd__help" ;; @@ -70,9 +67,6 @@ _rsp() { rsp,volume) cmd="rsp__subcmd__volume" ;; - rsp__subcmd__help,completions) - cmd="rsp__subcmd__help__subcmd__completions" - ;; rsp__subcmd__help,help) cmd="rsp__subcmd__help__subcmd__help" ;; @@ -173,7 +167,7 @@ _rsp() { case "${cmd}" in rsp) - opts="-h --help start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" + opts="-h --help start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -186,22 +180,8 @@ _rsp() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rsp__subcmd__completions) - opts="-h --help [SHELL]" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; rsp__subcmd__help) - opts="start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" + opts="start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -214,20 +194,6 @@ _rsp() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - rsp__subcmd__help__subcmd__completions) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; rsp__subcmd__help__subcmd__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/completions/rsp.elvish b/completions/rsp.elvish deleted file mode 100644 index 54ccdfe..0000000 --- a/completions/rsp.elvish +++ /dev/null @@ -1,224 +0,0 @@ - -use builtin; -use str; - -set edit:completion:arg-completer[rsp] = {|@words| - fn spaces {|n| - builtin:repeat $n ' ' | str:join '' - } - fn cand {|text desc| - edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc - } - var command = 'rsp' - for word $words[1..-1] { - if (str:has-prefix $word '-') { - break - } - set command = $command';'$word - } - var completions = [ - &'rsp'= { - cand -h 'Print help' - cand --help 'Print help' - cand start-daemon 'Start the daemon' - cand stop-daemon 'Stop the daemon' - cand restart 'Restart the daemon (kill existing and start new)' - cand play 'Play a track, album, or artist' - cand pause 'Pause playback' - cand resume 'Resume playback' - cand toggle 'Toggle play/pause' - cand stop 'Stop playback' - cand next 'Skip to next track' - cand previous 'Skip to previous track' - cand volume 'Set volume (0-100)' - cand shuffle 'Shuffle mode' - cand queue 'Queue management' - cand status 'Show player status' - cand scan 'Scan music paths to populate database' - cand settings 'Settings management' - cand completions 'Generate shell completions (developer only)' - cand help 'Print this message or the help of the given subcommand(s)' - } - &'rsp;start-daemon'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;stop-daemon'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;restart'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;play'= { - cand -i 'Add after current track and skip to it' - cand --now 'Add after current track and skip to it' - cand -n 'Add to queue after current track (don''t skip)' - cand --next 'Add to queue after current track (don''t skip)' - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;pause'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;resume'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;toggle'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;stop'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;next'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;previous'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;volume'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;shuffle'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;queue'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;status'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;scan'= { - cand --paths 'paths' - cand --force 'force' - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;settings'= { - cand -h 'Print help' - cand --help 'Print help' - cand get 'Get a setting value' - cand set 'Set a setting value' - cand list 'List all settings' - cand unset 'Unset a setting' - cand help 'Print this message or the help of the given subcommand(s)' - } - &'rsp;settings;get'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;settings;set'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;settings;list'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;settings;unset'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;settings;help'= { - cand get 'Get a setting value' - cand set 'Set a setting value' - cand list 'List all settings' - cand unset 'Unset a setting' - cand help 'Print this message or the help of the given subcommand(s)' - } - &'rsp;settings;help;get'= { - } - &'rsp;settings;help;set'= { - } - &'rsp;settings;help;list'= { - } - &'rsp;settings;help;unset'= { - } - &'rsp;settings;help;help'= { - } - &'rsp;completions'= { - cand -h 'Print help' - cand --help 'Print help' - } - &'rsp;help'= { - cand start-daemon 'Start the daemon' - cand stop-daemon 'Stop the daemon' - cand restart 'Restart the daemon (kill existing and start new)' - cand play 'Play a track, album, or artist' - cand pause 'Pause playback' - cand resume 'Resume playback' - cand toggle 'Toggle play/pause' - cand stop 'Stop playback' - cand next 'Skip to next track' - cand previous 'Skip to previous track' - cand volume 'Set volume (0-100)' - cand shuffle 'Shuffle mode' - cand queue 'Queue management' - cand status 'Show player status' - cand scan 'Scan music paths to populate database' - cand settings 'Settings management' - cand completions 'Generate shell completions (developer only)' - cand help 'Print this message or the help of the given subcommand(s)' - } - &'rsp;help;start-daemon'= { - } - &'rsp;help;stop-daemon'= { - } - &'rsp;help;restart'= { - } - &'rsp;help;play'= { - } - &'rsp;help;pause'= { - } - &'rsp;help;resume'= { - } - &'rsp;help;toggle'= { - } - &'rsp;help;stop'= { - } - &'rsp;help;next'= { - } - &'rsp;help;previous'= { - } - &'rsp;help;volume'= { - } - &'rsp;help;shuffle'= { - } - &'rsp;help;queue'= { - } - &'rsp;help;status'= { - } - &'rsp;help;scan'= { - } - &'rsp;help;settings'= { - cand get 'Get a setting value' - cand set 'Set a setting value' - cand list 'List all settings' - cand unset 'Unset a setting' - } - &'rsp;help;settings;get'= { - } - &'rsp;help;settings;set'= { - } - &'rsp;help;settings;list'= { - } - &'rsp;help;settings;unset'= { - } - &'rsp;help;completions'= { - } - &'rsp;help;help'= { - } - ] - $completions[$command] -} diff --git a/completions/rsp.fish b/completions/rsp.fish index 265fe37..8764bb9 100644 --- a/completions/rsp.fish +++ b/completions/rsp.fish @@ -41,7 +41,6 @@ complete -c rsp -n "__fish_rsp_needs_command" -f -a "queue" -d 'Queue management complete -c rsp -n "__fish_rsp_needs_command" -f -a "status" -d 'Show player status' complete -c rsp -n "__fish_rsp_needs_command" -f -a "scan" -d 'Scan music paths to populate database' complete -c rsp -n "__fish_rsp_needs_command" -f -a "settings" -d 'Settings management' -complete -c rsp -n "__fish_rsp_needs_command" -f -a "completions" -d 'Generate shell completions (developer only)' complete -c rsp -n "__fish_rsp_needs_command" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rsp -n "__fish_rsp_using_subcommand start-daemon" -s h -l help -d 'Print help' complete -c rsp -n "__fish_rsp_using_subcommand stop-daemon" -s h -l help -d 'Print help' @@ -77,25 +76,23 @@ complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcom complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "list" -d 'List all settings' complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "unset" -d 'Unset a setting' complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c rsp -n "__fish_rsp_using_subcommand completions" -s h -l help -d 'Print help' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "start-daemon" -d 'Start the daemon' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "stop-daemon" -d 'Stop the daemon' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "restart" -d 'Restart the daemon (kill existing and start new)' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "play" -d 'Play a track, album, or artist' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "pause" -d 'Pause playback' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "resume" -d 'Resume playback' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "toggle" -d 'Toggle play/pause' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "stop" -d 'Stop playback' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "next" -d 'Skip to next track' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "previous" -d 'Skip to previous track' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "volume" -d 'Set volume (0-100)' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "shuffle" -d 'Shuffle mode' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "queue" -d 'Queue management' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "status" -d 'Show player status' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "scan" -d 'Scan music paths to populate database' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "settings" -d 'Settings management' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "completions" -d 'Generate shell completions (developer only)' -complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings completions help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "start-daemon" -d 'Start the daemon' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "stop-daemon" -d 'Stop the daemon' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "restart" -d 'Restart the daemon (kill existing and start new)' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "play" -d 'Play a track, album, or artist' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "pause" -d 'Pause playback' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "resume" -d 'Resume playback' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "toggle" -d 'Toggle play/pause' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "stop" -d 'Stop playback' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "next" -d 'Skip to next track' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "previous" -d 'Skip to previous track' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "volume" -d 'Set volume (0-100)' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "shuffle" -d 'Shuffle mode' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "queue" -d 'Queue management' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "status" -d 'Show player status' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "scan" -d 'Scan music paths to populate database' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "settings" -d 'Settings management' +complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start-daemon stop-daemon restart play pause resume toggle stop next previous volume shuffle queue status scan settings help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "get" -d 'Get a setting value' complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "set" -d 'Set a setting value' complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "list" -d 'List all settings' diff --git a/completions/rsp.powershell b/completions/rsp.powershell deleted file mode 100644 index 58db681..0000000 --- a/completions/rsp.powershell +++ /dev/null @@ -1,280 +0,0 @@ - -using namespace System.Management.Automation -using namespace System.Management.Automation.Language - -Register-ArgumentCompleter -Native -CommandName 'rsp' -ScriptBlock { - param($wordToComplete, $commandAst, $cursorPosition) - - $commandElements = $commandAst.CommandElements - $command = @( - 'rsp' - for ($i = 1; $i -lt $commandElements.Count; $i++) { - $element = $commandElements[$i] - if ($element -isnot [StringConstantExpressionAst] -or - $element.StringConstantType -ne [StringConstantType]::BareWord -or - $element.Value.StartsWith('-') -or - $element.Value -eq $wordToComplete) { - break - } - $element.Value - }) -join ';' - - $completions = @(switch ($command) { - 'rsp' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('start-daemon', 'start-daemon', [CompletionResultType]::ParameterValue, 'Start the daemon') - [CompletionResult]::new('stop-daemon', 'stop-daemon', [CompletionResultType]::ParameterValue, 'Stop the daemon') - [CompletionResult]::new('restart', 'restart', [CompletionResultType]::ParameterValue, 'Restart the daemon (kill existing and start new)') - [CompletionResult]::new('play', 'play', [CompletionResultType]::ParameterValue, 'Play a track, album, or artist') - [CompletionResult]::new('pause', 'pause', [CompletionResultType]::ParameterValue, 'Pause playback') - [CompletionResult]::new('resume', 'resume', [CompletionResultType]::ParameterValue, 'Resume playback') - [CompletionResult]::new('toggle', 'toggle', [CompletionResultType]::ParameterValue, 'Toggle play/pause') - [CompletionResult]::new('stop', 'stop', [CompletionResultType]::ParameterValue, 'Stop playback') - [CompletionResult]::new('next', 'next', [CompletionResultType]::ParameterValue, 'Skip to next track') - [CompletionResult]::new('previous', 'previous', [CompletionResultType]::ParameterValue, 'Skip to previous track') - [CompletionResult]::new('volume', 'volume', [CompletionResultType]::ParameterValue, 'Set volume (0-100)') - [CompletionResult]::new('shuffle', 'shuffle', [CompletionResultType]::ParameterValue, 'Shuffle mode') - [CompletionResult]::new('queue', 'queue', [CompletionResultType]::ParameterValue, 'Queue management') - [CompletionResult]::new('status', 'status', [CompletionResultType]::ParameterValue, 'Show player status') - [CompletionResult]::new('scan', 'scan', [CompletionResultType]::ParameterValue, 'Scan music paths to populate database') - [CompletionResult]::new('settings', 'settings', [CompletionResultType]::ParameterValue, 'Settings management') - [CompletionResult]::new('completions', 'completions', [CompletionResultType]::ParameterValue, 'Generate shell completions (developer only)') - [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)') - break - } - 'rsp;start-daemon' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;stop-daemon' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;restart' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;play' { - [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'Add after current track and skip to it') - [CompletionResult]::new('--now', '--now', [CompletionResultType]::ParameterName, 'Add after current track and skip to it') - [CompletionResult]::new('-n', '-n', [CompletionResultType]::ParameterName, 'Add to queue after current track (don''t skip)') - [CompletionResult]::new('--next', '--next', [CompletionResultType]::ParameterName, 'Add to queue after current track (don''t skip)') - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;pause' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;resume' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;toggle' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;stop' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;next' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;previous' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;volume' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;shuffle' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;queue' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;status' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;scan' { - [CompletionResult]::new('--paths', '--paths', [CompletionResultType]::ParameterName, 'paths') - [CompletionResult]::new('--force', '--force', [CompletionResultType]::ParameterName, 'force') - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;settings' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('get', 'get', [CompletionResultType]::ParameterValue, 'Get a setting value') - [CompletionResult]::new('set', 'set', [CompletionResultType]::ParameterValue, 'Set a setting value') - [CompletionResult]::new('list', 'list', [CompletionResultType]::ParameterValue, 'List all settings') - [CompletionResult]::new('unset', 'unset', [CompletionResultType]::ParameterValue, 'Unset a setting') - [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)') - break - } - 'rsp;settings;get' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;settings;set' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;settings;list' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;settings;unset' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;settings;help' { - [CompletionResult]::new('get', 'get', [CompletionResultType]::ParameterValue, 'Get a setting value') - [CompletionResult]::new('set', 'set', [CompletionResultType]::ParameterValue, 'Set a setting value') - [CompletionResult]::new('list', 'list', [CompletionResultType]::ParameterValue, 'List all settings') - [CompletionResult]::new('unset', 'unset', [CompletionResultType]::ParameterValue, 'Unset a setting') - [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)') - break - } - 'rsp;settings;help;get' { - break - } - 'rsp;settings;help;set' { - break - } - 'rsp;settings;help;list' { - break - } - 'rsp;settings;help;unset' { - break - } - 'rsp;settings;help;help' { - break - } - 'rsp;completions' { - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') - break - } - 'rsp;help' { - [CompletionResult]::new('start-daemon', 'start-daemon', [CompletionResultType]::ParameterValue, 'Start the daemon') - [CompletionResult]::new('stop-daemon', 'stop-daemon', [CompletionResultType]::ParameterValue, 'Stop the daemon') - [CompletionResult]::new('restart', 'restart', [CompletionResultType]::ParameterValue, 'Restart the daemon (kill existing and start new)') - [CompletionResult]::new('play', 'play', [CompletionResultType]::ParameterValue, 'Play a track, album, or artist') - [CompletionResult]::new('pause', 'pause', [CompletionResultType]::ParameterValue, 'Pause playback') - [CompletionResult]::new('resume', 'resume', [CompletionResultType]::ParameterValue, 'Resume playback') - [CompletionResult]::new('toggle', 'toggle', [CompletionResultType]::ParameterValue, 'Toggle play/pause') - [CompletionResult]::new('stop', 'stop', [CompletionResultType]::ParameterValue, 'Stop playback') - [CompletionResult]::new('next', 'next', [CompletionResultType]::ParameterValue, 'Skip to next track') - [CompletionResult]::new('previous', 'previous', [CompletionResultType]::ParameterValue, 'Skip to previous track') - [CompletionResult]::new('volume', 'volume', [CompletionResultType]::ParameterValue, 'Set volume (0-100)') - [CompletionResult]::new('shuffle', 'shuffle', [CompletionResultType]::ParameterValue, 'Shuffle mode') - [CompletionResult]::new('queue', 'queue', [CompletionResultType]::ParameterValue, 'Queue management') - [CompletionResult]::new('status', 'status', [CompletionResultType]::ParameterValue, 'Show player status') - [CompletionResult]::new('scan', 'scan', [CompletionResultType]::ParameterValue, 'Scan music paths to populate database') - [CompletionResult]::new('settings', 'settings', [CompletionResultType]::ParameterValue, 'Settings management') - [CompletionResult]::new('completions', 'completions', [CompletionResultType]::ParameterValue, 'Generate shell completions (developer only)') - [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)') - break - } - 'rsp;help;start-daemon' { - break - } - 'rsp;help;stop-daemon' { - break - } - 'rsp;help;restart' { - break - } - 'rsp;help;play' { - break - } - 'rsp;help;pause' { - break - } - 'rsp;help;resume' { - break - } - 'rsp;help;toggle' { - break - } - 'rsp;help;stop' { - break - } - 'rsp;help;next' { - break - } - 'rsp;help;previous' { - break - } - 'rsp;help;volume' { - break - } - 'rsp;help;shuffle' { - break - } - 'rsp;help;queue' { - break - } - 'rsp;help;status' { - break - } - 'rsp;help;scan' { - break - } - 'rsp;help;settings' { - [CompletionResult]::new('get', 'get', [CompletionResultType]::ParameterValue, 'Get a setting value') - [CompletionResult]::new('set', 'set', [CompletionResultType]::ParameterValue, 'Set a setting value') - [CompletionResult]::new('list', 'list', [CompletionResultType]::ParameterValue, 'List all settings') - [CompletionResult]::new('unset', 'unset', [CompletionResultType]::ParameterValue, 'Unset a setting') - break - } - 'rsp;help;settings;get' { - break - } - 'rsp;help;settings;set' { - break - } - 'rsp;help;settings;list' { - break - } - 'rsp;help;settings;unset' { - break - } - 'rsp;help;completions' { - break - } - 'rsp;help;help' { - break - } - }) - - $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | - Sort-Object -Property ListItemText -} diff --git a/completions/rsp.zsh b/completions/rsp.zsh index e8da3d7..dd24572 100644 --- a/completions/rsp.zsh +++ b/completions/rsp.zsh @@ -209,13 +209,6 @@ esac ;; esac ;; -(completions) -_arguments "${_arguments_options[@]}" : \ -'-h[Print help]' \ -'--help[Print help]' \ -'::shell -- Shell to generate (bash, zsh, fish, elvish, powershell) If not specified, generates all completion files:_default' \ -&& ret=0 -;; (help) _arguments "${_arguments_options[@]}" : \ ":: :_rsp__subcmd__help_commands" \ @@ -320,10 +313,6 @@ _arguments "${_arguments_options[@]}" : \ ;; esac ;; -(completions) -_arguments "${_arguments_options[@]}" : \ -&& ret=0 -;; (help) _arguments "${_arguments_options[@]}" : \ && ret=0 @@ -356,16 +345,10 @@ _rsp_commands() { 'status:Show player status' \ 'scan:Scan music paths to populate database' \ 'settings:Settings management' \ -'completions:Generate shell completions (developer only)' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rsp commands' commands "$@" } -(( $+functions[_rsp__subcmd__completions_commands] )) || -_rsp__subcmd__completions_commands() { - local commands; commands=() - _describe -t commands 'rsp completions commands' commands "$@" -} (( $+functions[_rsp__subcmd__help_commands] )) || _rsp__subcmd__help_commands() { local commands; commands=( @@ -385,16 +368,10 @@ _rsp__subcmd__help_commands() { 'status:Show player status' \ 'scan:Scan music paths to populate database' \ 'settings:Settings management' \ -'completions:Generate shell completions (developer only)' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'rsp help commands' commands "$@" } -(( $+functions[_rsp__subcmd__help__subcmd__completions_commands] )) || -_rsp__subcmd__help__subcmd__completions_commands() { - local commands; commands=() - _describe -t commands 'rsp help completions commands' commands "$@" -} (( $+functions[_rsp__subcmd__help__subcmd__help_commands] )) || _rsp__subcmd__help__subcmd__help_commands() { local commands; commands=() diff --git a/install.sh b/install.sh index 3133601..872118c 100755 --- a/install.sh +++ b/install.sh @@ -48,15 +48,6 @@ case "$shell_name" in cp "$SCRIPT_DIR/completions/rsp.fish" "$dest" echo " → Fish completions: $dest" ;; - elvish) - dest="$HOME/.config/elvish/rc.d/rsp.elvish" - mkdir -p "$(dirname "$dest")" - cp "$SCRIPT_DIR/completions/rsp.elvish" "$dest" - echo " → Elvish completions: $dest" - ;; - powershell) - echo " → PowerShell: source \"$SCRIPT_DIR/completions/rsp.powershell\" from your profile" - ;; *) echo " → Unrecognized shell '$shell_name'; completion files are in $SCRIPT_DIR/completions/" ;; diff --git a/src/daemon.rs b/src/daemon.rs index 06b925e..59fc3d8 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -544,10 +544,10 @@ fn process_command( ); let result = match temp_scrobbler.validate_listenbrainz_token() { Ok(Some(user)) => { - notification::notify_change(&format!( - "Logged in to ListenBrainz as {}", - user - )); + notification::notify( + "RSPlayer scrobbler login", + &format!("Logged in to ListenBrainz as {}", user), + ); format!("ListenBrainz token valid (user: {})\n", user) } Ok(None) => { @@ -779,19 +779,19 @@ fn process_command( for file in &files { q.add_track(file.clone()); } - if was_empty - && !was_playing - && let Some(track) = q.current() - { - audio.play(track.path.clone()); - send_now_playing(scrobbler, track); - if let Ok(mut s) = scrobble_state.lock() { - s.start(track.clone()); + if was_empty && !was_playing { + q.shuffle_initial(); + if let Some(track) = q.current() { + audio.play(track.path.clone()); + send_now_playing(scrobbler, track); + if let Ok(mut s) = scrobble_state.lock() { + s.start(track.clone()); + } + let fmt = Config::load() + .ok() + .and_then(|c| c.display_format.clone()); + notification::notify_track(track, fmt.as_deref()); } - let fmt = Config::load() - .ok() - .and_then(|c| c.display_format.clone()); - notification::notify_track(track, fmt.as_deref()); } format!("Queued {} tracks from: {}\n", files.len(), path_str) } diff --git a/src/notification.rs b/src/notification.rs index df9c622..2c8d80f 100644 --- a/src/notification.rs +++ b/src/notification.rs @@ -45,3 +45,11 @@ pub fn notify_error(context: &str) { .appname("RSPlayer") .show(); } + +pub fn notify(summary: &str, body: &str) { + let _ = notify_rust::Notification::new() + .summary(summary) + .body(body) + .appname("RSPlayer") + .show(); +} diff --git a/src/queue.rs b/src/queue.rs index 8f98173..26aeb8b 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -385,6 +385,22 @@ impl Queue { &self.shuffled_indices } + pub fn shuffle_initial(&mut self) { + if self.position != 0 || self.tracks.len() <= 1 { + return; + } + let mut rng = rand::rng(); + match self.shuffle { + ShuffleMode::All => { + self.shuffled_indices.shuffle(&mut rng); + } + ShuffleMode::Album => { + self.shuffle_album_range(0..self.tracks.len(), &mut rng); + } + ShuffleMode::None => {} + } + } + pub fn clear(&mut self) { self.tracks.clear(); self.position = 0; -- cgit v1.2.3