Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new PlayContentHandler to abstract Second Swipe #2452

Open
wants to merge 15 commits into
base: future3/develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 93 additions & 12 deletions documentation/builders/cli-client.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,102 @@
# CLI Client
# RPC CLI Client

The CLI (command line interface) client can be used to send [RPC commands](./rpc-commands.md) from command line to Phoniebox.
The Python CLI (Command Line Interface) client can be used to send [RPC commands](./rpc-commands.md) to Phoniebox. It provides an interactive shell with autocompletion and command history, as well as direct command execution.

## Installation
The RPC tool can be found here:

* Install prerequisites: `sudo apt-get install libczmq-dev`
* Change to directory: `cd ~/RPi-Jukebox-RFID/src/cli_client`
* Compile CLI client: `gcc pbc.c -o pbc -lzmq -Wall`
```bash
~/RPi-Jukebox-RFID/src/jukebox/run_rpc_tool.py
```

## Usage

* Get help info: `./pbc -h`
* Example shutdown: `./pbc -p host -o shutdown`
The CLI tool can be used in two modes:

See also [RPC Commands](./rpc-commands.md) reference.
### Interactive Mode

## Reference
```bash
# Start interactive shell
./run_rpc_tool.py

* <https://zeromq.org/>
* <https://www.jsonrpc.org/specification>
# Start with specific connection type
./run_rpc_tool.py --tcp 5555 # TCP connection on port 5555
./run_rpc_tool.py --websocket # WebSocket connection on default port
```

In interactive mode:

- Use TAB for command autocompletion
- Use UP/DOWN arrows for command history
- Type `help` to see available commands
- Type `usage` for detailed usage information
- Press Ctrl-D or type `exit` to quit

### Direct Command Mode

```bash
# Execute single command
./run_rpc_tool.py -c 'command [args...] [key=value...]'

# Examples with positional args:
./run_rpc_tool.py -c 'volume.ctrl.set_volume 50'
./run_rpc_tool.py -c 'player.ctrl.play_content "/music/test.mp3" single'

# Examples with kwargs:
./run_rpc_tool.py -c 'volume.ctrl.set_volume level=50'
./run_rpc_tool.py -c 'player.ctrl.play_content content="/music/test.mp3" content_type=single'
```

## Command Format

Commands support both positional arguments and keyword arguments:

```python
package.plugin.method [arg1] [arg2] [arg3] # Positional args
package.plugin.method [key1=value1] [key2=value2] # Keyword args
```

Arguments can be:

- Numbers (50 or level=50)
- Strings (use quotes for spaces: "my string" or path="my string")
- JSON objects (use single quotes: '{"key":"value"}')
- Hexadecimal numbers (prefix with 0x: 0xFF or value=0xFF)

### Examples

```bash
# Simple commands - both styles work
volume.ctrl.set_volume 50
volume.ctrl.set_volume level=50

system.ctrl.shutdown

# Playing content - positional args
player.ctrl.play_content '{"artist":"Pink Floyd","album":"The Wall"}' album
player.ctrl.play_content "/music/classical" folder true
player.ctrl.play_content "/music/track.mp3" single

# Playing content - keyword args
player.ctrl.play_content content='{"artist":"Pink Floyd","album":"The Wall"}' content_type=album
player.ctrl.play_content content="/music/classical" content_type=folder recursive=true
player.ctrl.play_content content="/music/track.mp3" content_type=single

# Reader-based playback - positional args
player.ctrl.play_from_reader '{"artist":"Pink Floyd","album":"The Wall"}' album false toggle
player.ctrl.play_from_reader "/music/classical" folder true replay

# Reader-based playback - keyword args
player.ctrl.play_from_reader content='{"artist":"Pink Floyd","album":"The Wall"}' content_type=album second_swipe=toggle
player.ctrl.play_from_reader content="/music/classical" content_type=folder recursive=true second_swipe=replay
```

## Features

- Command autocompletion
- Command history
- Support for both positional and keyword arguments
- JSON argument support
- Interactive and direct command modes
- Automatic type conversion (strings, numbers, JSON)
- Connection error handling
- Dynamic command help from server
18 changes: 9 additions & 9 deletions documentation/developers/docstring/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
* [resolve](#misc.simplecolors.resolve)
* [print](#misc.simplecolors.print)
* [components](#components)
* [components.playermpd.playcontentcallback](#components.playermpd.playcontentcallback)
* [PlayContentCallbacks](#components.playermpd.playcontentcallback.PlayContentCallbacks)
* [register](#components.playermpd.playcontentcallback.PlayContentCallbacks.register)
* [run\_callbacks](#components.playermpd.playcontentcallback.PlayContentCallbacks.run_callbacks)
* [components.playermpd.play_content_callback](#components.playermpd.play_content_callback)
* [PlayContentCallbacks](#components.playermpd.play_content_callback.PlayContentCallbacks)
* [register](#components.playermpd.play_content_callback.PlayContentCallbacks.register)
* [run\_callbacks](#components.playermpd.play_content_callback.PlayContentCallbacks.run_callbacks)
* [components.playermpd](#components.playermpd)
* [PlayerMPD](#components.playermpd.PlayerMPD)
* [mpd\_retry\_with\_mutex](#components.playermpd.PlayerMPD.mpd_retry_with_mutex)
Expand Down Expand Up @@ -761,11 +761,11 @@ Use just as a regular print function, but with first parameter as color

# components

<a id="components.playermpd.playcontentcallback"></a>
<a id="components.playermpd.play_content_callback"></a>

# components.playermpd.playcontentcallback
# components.playermpd.play_content_callback

<a id="components.playermpd.playcontentcallback.PlayContentCallbacks"></a>
<a id="components.playermpd.play_content_callback.PlayContentCallbacks"></a>

## PlayContentCallbacks Objects

Expand All @@ -776,7 +776,7 @@ class PlayContentCallbacks(Generic[STATE], CallbackHandler)
Callbacks are executed in various play functions


<a id="components.playermpd.playcontentcallback.PlayContentCallbacks.register"></a>
<a id="components.playermpd.play_content_callback.PlayContentCallbacks.register"></a>

#### register

Expand All @@ -796,7 +796,7 @@ Callback signature is
- `folder`: relativ path to folder to play
- `state`: indicator of the state inside the calling

<a id="components.playermpd.playcontentcallback.PlayContentCallbacks.run_callbacks"></a>
<a id="components.playermpd.play_content_callback.PlayContentCallbacks.run_callbacks"></a>

#### run\_callbacks

Expand Down
5 changes: 2 additions & 3 deletions installation/includes/02_helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ is_debian_based() {
fi
}

_get_debian_version_number() {
get_debian_version_number() {
if [ "$(is_debian_based)" = true ]; then
local debian_version_number=$( . /etc/os-release; printf '%s\n' "$VERSION_ID"; )
echo "$debian_version_number"
Expand All @@ -106,8 +106,7 @@ is_debian_version_at_least() {

_get_boot_file_path() {
local filename="$1"
local is_debian_version_number_at_least_12=$(is_debian_version_at_least 12)
if [ "$(is_debian_version_number_at_least_12)" = true ]; then
if [ "$(is_debian_version_at_least 12)" = true ]; then
echo "/boot/firmware/${filename}"
else
echo "/boot/${filename}"
Expand Down
Loading
Loading