Metadata-Version: 2.4
Name: volumito
Version: 0.1.0
Summary: Python client library and CLI tool for Volumio
Author-email: Alberto Pettarin <alberto@albertopettarin.it>
Maintainer-email: Alberto Pettarin <alberto@albertopettarin.it>
License-Expression: GPL-3.0-or-later
Project-URL: Documentation, https://www.albertopettarin.it/volumito/docs/
Project-URL: Download, https://github.com/pettarin/volumito#installation
Project-URL: Homepage, https://github.com/pettarin/volumito
Project-URL: Release Notes, https://github.com/pettarin/volumito/blob/main/docs/CHANGELOG.md
Project-URL: Source, https://github.com/pettarin/volumito
Project-URL: Tracker, https://github.com/pettarin/volumito/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.4.0
Requires-Dist: colorama>=0.4.6
Requires-Dist: mutagen>=1.47.0
Requires-Dist: packaging>=23.0
Requires-Dist: pydantic>=2.9.0
Requires-Dist: python-mpd2>=3.0.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: requests>=2.31.0
Provides-Extra: scp
Requires-Dist: scp>=0.14.0; extra == "scp"
Provides-Extra: dev
Requires-Dist: volumito[scp]; extra == "dev"
Requires-Dist: build>=1.3.0; extra == "dev"
Requires-Dist: coverage>=7.0.0; extra == "dev"
Requires-Dist: mypy>=1.13.0; extra == "dev"
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: ruff>=0.8.0; extra == "dev"
Requires-Dist: setuptools>=80.9.0; extra == "dev"
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
Requires-Dist: types-requests>=2.31.0; extra == "dev"
Requires-Dist: wheel>=0.45.1; extra == "dev"
Dynamic: license-file

# volumito

Python client library and CLI tool for [Volumio](https://volumio.com/).


## Overview

`volumito` is a Python library and a CLI tool
that allows querying and controlling a
[Volumio](https://volumio.com/)
host.


## Features

- Clean Python API to query the state of a Volumio host and to control it
- Extensive and configurable CLI tool
- AI-generated, Human-reviewed code
- Type-safe implementation with type hints
- Comprehensive unit test coverage (100%)


## Requirements

- Python 3.13 or later
- A package/virtual environment manager tool (e.g., `micromamba`, `conda`, `uv`, etc.)
- A running Volumio host


## Installation

> [!NOTE]
> The examples in the documentation use `micromamba`
> to manage virtual environments; feel free to replace it
> with your favorite tool (`conda`, `uv`, etc.).

### From PyPI (Recommended)

`volumito` is published on PyPI as the same-name package
[volumito](https://pypi.org/project/volumito/)
, and this is the recommended way of installing it for most users.

Only the first time: create a virtual environment,
activate it, and install the latest release of `volumito`
available on PyPI with `pip`:

```bash
$ micromamba create -n volumito_env python=3.13
$ micromamba activate volumito_env

(volumito_env) $ pip install volumito
```

> [!NOTE]
> To use the `volumito scp` and `volumito system execute` commands
> you will need to install the `scp` extra:
> `pip install volumito[scp]`.
> Since those are advanced (and potentially dangerous) commands,
> the `scp` dependency is not installed by default.

You should be able to run the `volumito` CLI tool,
automatically installed in the virtual environment:

```bash
(volumito_env) $ volumito version
volumito, version 0.1.0
```

The next time you want to use `volumito`,
you will only need to activate the existing virtual environment:

```bash
$ micromamba activate volumito_env

(volumito_env) $ volumito version
volumito, version 0.1.0
```

To update `volumito`, use the `-U / --upgrade` option:

```bash
$ micromamba activate volumito_env

(volumito_env) $ pip install volumito --upgrade
```


### From Source

Clone this repository and install from source
in a virtual environment:

```bash
$ git clone https://github.com/pettarin/volumito
$ cd volumito

$ micromamba create -n volumito_env python=3.13
$ micromamba activate volumito_env

(volumito_env) $ pip install -e .
(volumito_env) $ # or
(volumito_env) $ make install-e-this
```

> [!NOTE]
> To use the `volumito scp` and `volumito system execute` commands
> you will need to install the `scp` extra:
> `pip install -e .[scp]` or `make install-e-this-scp`.
> Since those are advanced (and potentially dangerous) commands,
> the `scp` dependency is not installed by default.

You should be able to run the `volumito` CLI tool,
automatically installed in the virtual environment:

```bash
(volumito_env) $ volumito version
volumito, version 0.1.0
```


## Usage

### CLI Usage

The
[CLI Usage](https://github.com/pettarin/volumito/blob/main/docs/cli/INDEX.md)
guide describes all the commands, subcommands, and most of the options
of the CLI tool `volumito`.

Some examples of the commands made available
by the CLI tool `volumito` in the virtual enviroment
where it is installed:

> [!NOTE]
> For the sake of brevity, in the following examples:
> - the `(volumito_env) $` shell prompt is omitted;
> - some commands are shown without their output or with truncated output;
> - several commands and options are not illustrated.
> Consult the
> [CLI Usage](https://github.com/pettarin/volumito/blob/main/docs/cli/INDEX.md)
> for a comprehensive guide of the CLI tool `volumito`.

```bash
# print help/usage messages; it works globally and on commands and subcommands
volumito --help
volumito playback --help

# create a configuration file (you might want to inspect/edit it later)
volumito configuration create -o ~/volumito.yaml
[2026-08-13T13:52:30.130Z] [INFO] Created configuration file "/home/alberto/volumito.yaml"

# print information about the Volumio host
volumito system info
{
    "builddate": "Tue Mar 24 17:20:52 UTC 2026",
    "hardware": "pi",
    "host": "http://192.168.1.122",
    "hwUuid": "<REDACTED>",
    "id": "<REDACTED>",
    "isPremiumDevice": false,
    "isVolumioProduct": false,
    "name": "volumio",
    "os": "12",
    "serviceName": "Volumio",
    "state": {
        "albumart": "https://static.qobuz.com/images/covers/64/04/0639842660464_600.jpg",
        "artist": "Mango",
        "mute": false,
        "status": "play",
        "track": "Nella mia città",
        "volume": 20
    },
    "systemversion": "4.119",
    "type": "device",
    "variant": "volumio"
}

# print the playback status
volumito playback status
{
    "album": "Sirtaki",
    "artist": "Mango",
    "bitdepth": "16 bit",
    "channels": 2,
    "duration": "00:04:34",
    "mute": false,
    "position": 2,
    "samplerate": "44 KHz",
    "seek": "00:00:21.528",
    "status": "play",
    "title": "I giochi del vento sul lago salato",
    "trackType": "qobuz",
    "volume": 20
}

# print the list of tracks currently in the reproduction queue
volumito queue get
[
    {
        "album": "Polvere",
        "artist": "Enrico Ruggeri",
        "duration": "00:03:15",
        "position": 1,
        "title": "Va tutto bene",
        "tracknumber": 1,
        "volumeNumber": 1
    },
    {
        "album": "Polvere",
        "artist": "Enrico Ruggeri",
        "duration": "00:03:56",
        "position": 2,
        "title": "Fuoco sui giocattoli",
        "tracknumber": 2,
        "volumeNumber": 1
    },
    ...
    {
        "album": "La Vie En Rouge",
        "artist": "Enrico Ruggeri",
        "duration": "00:04:49",
        "position": 11,
        "title": "La Bandiera",
        "tracknumber": 3,
        "volumeNumber": 2
    }
]

# print information about the current track,
# with a short format (a subset of all available fields)
volumito track info
{
    "album": "Sirtaki",
    "artist": "Mango",
    "bitdepth": "16 bit",
    "channels": 2,
    "duration": "00:04:34",
    "position": 2,
    "samplerate": "44 KHz",
    "title": "I giochi del vento sul lago salato",
    "trackType": "qobuz"
}

# print information about the current track,
# with all the available fields
volumito track info --fields ALL
{
    "album": "Sirtaki",
    "albumart": "https://static.qobuz.com/images/covers/64/04/0639842660464_600.jpg",
    "artist": "Mango",
    "bitdepth": "16 bit",
    "channels": 2,
    "consume": false,
    "dbVolume": null,
    "disableVolumeControl": false,
    "duration": "00:04:34",
    "mute": false,
    "position": 2,
    "random": false,
    "repeat": false,
    "repeatSingle": false,
    "samplerate": "44 KHz",
    "seek": "00:01:53.135",
    "service": "qobuz",
    "status": "play",
    "stream": "qobuz",
    "title": "I giochi del vento sul lago salato",
    "trackType": "qobuz",
    "updatedb": false,
    "uri": "qobuz://song/2581513",
    "volatile": false,
    "volume": 20
}

# control the playback on the Volumio host
volumito playback play
volumito playback pause
volumito playback stop
volumito playback previous
volumito playback next
volumito playback seek 00:01:02
volumito playback mute
volumito playback unmute
volumito playback volume 80

# print the list of all available playlists
volumito playlist list
[
    "another playlist",
    "my awesome playlist",
    "volumito test playlist"
]

# play the specified playlist, replacing the current queue
volumito playlist play "my awesome playlist"
[2026-08-12T20:14:05.213Z] [INFO] Command 'playplaylist "my awesome playlist"' executed successfully
{
    "album": "Sirtaki",
    "artist": "Mango",
    "bitdepth": "16 bit",
    "channels": 2,
    "duration": "00:06:59",
    "mute": false,
    "position": 1,
    "samplerate": "44.1 kHz",
    "seek": "00:00:01.001",
    "status": "play",
    "title": "Nella mia città",
    "trackType": "qobuz",
    "volume": 30
}
```

### Library Usage

The
[Library Usage](https://github.com/pettarin/volumito/blob/main/docs/LIBRARY_USAGE.md)
document contains the API reference of the Python library `volumito`.

The following is a short example:

```python
from volumito import (
    VolumioHostConfiguration,
    VolumioRESTAPIClient,
)

# replace with your Volumio host
host = VolumioHostConfiguration(host="volumio.local")
client = VolumioRESTAPIClient(host)


# retrieve the system information
info = client.system_info
print(info.name, info.system_version, info.is_premium_device)
# volumio 4.119 False


# retrieve the current playing state
state = client.state
print(state.title, "---", state.artist, "---", state.album)
# Recitando --- Paolo Conte --- Paolo Conte Alla Scala - il Maestro è nell'anima
print(state.status, state.volume, state.seek, state.duration)
# play 49 125029 229
print(state.is_playing, state.is_paused, state.is_stopped)
# True False False

# the payload the Volumio host returned is always available
print(state.raw["trackType"], state.raw["samplerate"])
# qobuz 44.1 kHz

# pause/play/stop the current track (and check the playback status)
client.pause()
print(client.is_paused)
client.play()
print(client.is_playing)
client.stop()
print(client.is_stopped)

# read and control the volume
print(client.volume)
client.volume = 50
client.mute()
print(client.is_muted)
client.unmute()

# print the current queue (which is a sequence of its tracks)
for index, track in enumerate(client.queue, 1):
    print(f"{index}. {track.title} - {track.artist}")
# 1. Aguaplano - Paolo Conte
# 2. Sotto Le Stelle Del Jazz - Paolo Conte
# 3. Come Di - Paolo Conte
# 4. Alle Prese Con Una Verde Milonga - Paolo Conte
# 5. Ratafià - Paolo Conte
# ...

# play the 4th track of the current queue, by track or by position
# (positions start at index zero)
client.play(client.queue[3])
client.play(3)

# read the seek position, then seek to 01:42 (both in seconds)
print(client.seek)
client.seek = 102

# play the previous/next track
client.previous()
client.next()


# list the saved playlists (which are a sequence of their playlists)
for playlist in client.playlists:
    print(playlist.name)
# Jazz Classics
# Rock
# ...

# play one, checking that it exists first
playlist_name = "Jazz Classics"
if playlist_name in client.playlists:
    client.play_playlist(playlist_name)
else:
    print(f"No such playlist: '{playlist_name}'")
```


## Releases And Changelog

The list of releases and their changes is contained
in the
[CHANGELOG](https://github.com/pettarin/volumito/blob/main/docs/CHANGELOG.md)
document.


## Development

Consult the
[DEVELOPMENT](https://github.com/pettarin/volumito/blob/main/docs/DEVELOPMENT.md)
document to learn how to set up a development environment,
run the tests, and browse the project structure.

The
[CONTRIBUTING](https://github.com/pettarin/volumito/blob/main/docs/CONTRIBUTING.md)
document explains how to report issues and propose changes.


## License

This project is licensed under
the GNU General Public License v3.0 or later (GPLv3+).

See the
[LICENSE](https://github.com/pettarin/volumito/blob/main/LICENSE)
file for details.


## Authors

- Alberto Pettarin ([Web](https://www.albertopettarin.it))


## Legal Disclaimers

Volumio and the Volumio logo are registered trademarks of Volumio SRL,
a company registered in Italy (VAT ID: IT07009020483).

Please refer to the
[Volumio Terms Of Service](https://volumio.com/terms-of-service/).

This project and its authors are not affiliated
nor endorsed by Volumio SRL.

