pax_global_header00006660000000000000000000000064141405310740014511gustar00rootroot0000000000000052 comment=d84356f2ca3c368af5e010502e0385b788533c36 OnFreund-PyVolumio-d84356f/000077500000000000000000000000001414053107400155375ustar00rootroot00000000000000OnFreund-PyVolumio-d84356f/.gitignore000066400000000000000000000000541414053107400175260ustar00rootroot00000000000000__pycache__/ *.pyc build/ dist/ *.egg-info/OnFreund-PyVolumio-d84356f/LICENSE000066400000000000000000000020511414053107400165420ustar00rootroot00000000000000MIT License Copyright (c) 2020 On Freund Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.OnFreund-PyVolumio-d84356f/MANIFEST.in000066400000000000000000000000311414053107400172670ustar00rootroot00000000000000include README.md LICENSEOnFreund-PyVolumio-d84356f/README.md000066400000000000000000000010301414053107400170100ustar00rootroot00000000000000# PyVolumio A python interface control [Volumio](https://volumio.org/). ## Installation You can install pyvolumio from [PyPI](https://pypi.org/project/pyvolumio/): pip3 install pyvolumio Python 3.7 and above are supported. ## How to use ```python from pyvolumio import Volumio v = Volumio("", ) # you can also pass in your own session v = Volumio("", , ) info = await v.get_system_info() state = await v.get_state() await v.play() await v.pause() await v.stop() await v.volume_up() ... ```OnFreund-PyVolumio-d84356f/pyvolumio/000077500000000000000000000000001414053107400176025ustar00rootroot00000000000000OnFreund-PyVolumio-d84356f/pyvolumio/__init__.py000066400000000000000000000000611414053107400217100ustar00rootroot00000000000000from .volumio import CannotConnectError, Volumio OnFreund-PyVolumio-d84356f/pyvolumio/volumio.py000066400000000000000000000141431414053107400216510ustar00rootroot00000000000000"""Implementation of a Volumio inteface.""" import aiohttp import asyncio import urllib class Volumio: """A connection to Volumio.""" def __init__(self, host, port, session=None): """Initialize the object.""" self._host = host self._port = port self._created_session = False self._session = session def _init_session(self): if self._session == None: self._session = aiohttp.ClientSession() self._created_session = True async def close(self): """Close the connection.""" if self._created_session and self._session is not None: await self._session.close() self._session = None self._created_session = False async def _post_volumio_msg(self, method, json_payload=None): url = f"http://{self._host}:{self._port}/api/v1/{method}" try: self._init_session() response = await self._session.post(url, json=json_payload) if response.status == 200: return await response.json() else: raise CannotConnectError(response) except aiohttp.client_exceptions.ContentTypeError: # hack to handle methods not supported by older versions return {} except (asyncio.TimeoutError, aiohttp.ClientError) as error: raise CannotConnectError() from error async def _get_volumio_msg(self, method, params=None): url = f"http://{self._host}:{self._port}/api/v1/{method}" try: self._init_session() response = await self._session.get(url, params=params) if response.status == 200: return await response.json() else: raise CannotConnectError(response) except aiohttp.client_exceptions.ContentTypeError: # hack to handle methods not supported by older versions return {} except (asyncio.TimeoutError, aiohttp.ClientError) as error: raise CannotConnectError() from error async def _send_volumio_cmd(self, params): return await self._get_volumio_msg("commands/", params=params) async def get_system_version(self): """Get the systems version.""" response = await self._get_volumio_msg("getSystemVersion") return response.copy() async def get_system_info(self): """Get the systems information.""" response = await self._get_volumio_msg("getSystemInfo") return response.copy() async def get_state(self): """Get the Volumio state.""" response = await self._get_volumio_msg("getState") return response.copy() async def get_playlists(self): """Get available Volumio playlists.""" response = await self._get_volumio_msg("listplaylists") return response.copy() async def next(self): """Send 'next' command to Volumio.""" await self._send_volumio_cmd(params={"cmd": "next"}) async def previous(self): """Send 'previous' command to Volumio.""" await self._send_volumio_cmd(params={"cmd": "prev"}) async def play(self): """Send 'play' command to Volumio.""" await self._send_volumio_cmd(params={"cmd": "play"}) async def repeatAll(self, repeat): """Send 'repeat' command to Volumio.""" await self._send_volumio_cmd(params={"cmd": "repeat", "value": str(repeat).lower()}) async def pause(self): """Send 'pause' command to Volumio.""" await self._send_volumio_cmd(params={"cmd": "pause"}) async def stop(self): """Send 'stop' command to Volumio.""" await self._send_volumio_cmd(params={"cmd": "stop"}) async def set_volume_level(self, volume): """Send volume level to Volumio.""" await self._get_volumio_msg( "commands", params={"cmd": "volume", "volume": volume} ) async def volume_up(self): """Send 'volume up' command to Volumio.""" await self._get_volumio_msg( "commands", params={"cmd": "volume", "volume": "plus"} ) async def volume_down(self): """Send 'volume down' command to Volumio.""" await self._get_volumio_msg( "commands", params={"cmd": "volume", "volume": "minus"} ) async def mute(self): """Send 'mute' command to Volumio.""" await self._get_volumio_msg( "commands", params={"cmd": "volume", "volume": "mute"} ) async def unmute(self): """Send 'unmute' command to Volumio.""" await self._get_volumio_msg( "commands", params={"cmd": "volume", "volume": "unmute"} ) async def set_shuffle(self, shuffle): """Enable/disable shuffle mode.""" await self._get_volumio_msg( "commands", params={"cmd": "random", "value": str(shuffle).lower()} ) async def play_playlist(self, playlist): """Choose an available playlist and play it.""" await self._get_volumio_msg( "commands", params={"cmd": "playplaylist", "name": playlist} ) async def clear_playlist(self): """Clear current playlist.""" await self._send_volumio_cmd(params={"cmd": "clearQueue"}) async def get_queue(self): """Get the current queue.""" return (await self._get_volumio_msg("getQueue")) async def replace_and_play(self, item): """Replace the current content of the queue and play item.""" await self._post_volumio_msg("replaceAndPlay", json_payload=item) async def browse(self, uri=None): """Brose media.""" params = {} if uri is not None: params["uri"] = uri return (await self._get_volumio_msg("browse", params=params))["navigation"] def canonic_url(self, url): """Creates a full url from a potentially relative one.""" if url is None: return if str(url[0:2]).lower() == "ht": return url return urllib.parse.urljoin(f"http://{self._host}:{self._port}", url) class CannotConnectError(Exception): """Exception to indicate an error in connection.""" OnFreund-PyVolumio-d84356f/setup.py000066400000000000000000000064521414053107400172600ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # Note: To use the 'upload' functionality of this file, you must: # $ pipenv install twine --dev import io import os import sys from shutil import rmtree from setuptools import find_packages, setup, Command # Package meta-data. NAME = 'pyvolumio' DESCRIPTION = 'A python library to control Volumio.' URL = 'https://github.com/OnFreund/PyVolumio' EMAIL = 'onfreund@gmail.com' AUTHOR = 'On Freund' REQUIRES_PYTHON = '>=3.7.0' VERSION = '0.1.5' REQUIRED = ['aiohttp'] EXTRAS = {} here = os.path.abspath(os.path.dirname(__file__)) # Import the README and use it as the long-description. # Note: this will only work if 'README.md' is present in your MANIFEST.in file! try: with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: long_description = '\n' + f.read() except FileNotFoundError: long_description = DESCRIPTION # Load the package's __version__.py module as a dictionary. about = {} if not VERSION: project_slug = NAME.lower().replace("-", "_").replace(" ", "_") with open(os.path.join(here, project_slug, '__version__.py')) as f: exec(f.read(), about) else: about['__version__'] = VERSION class UploadCommand(Command): """Support setup.py upload.""" description = 'Build and publish the package.' user_options = [] @staticmethod def status(s): """Prints things in bold.""" print('\033[1m{0}\033[0m'.format(s)) def initialize_options(self): pass def finalize_options(self): pass def run(self): try: self.status('Removing previous builds…') rmtree(os.path.join(here, 'dist')) except OSError: pass self.status('Building Source and Wheel distribution…') os.system('{0} setup.py sdist bdist_wheel'.format(sys.executable)) self.status('Uploading the package to PyPI via Twine…') os.system('twine upload dist/*') self.status('Pushing git tags…') os.system('git tag v{0}'.format(about['__version__'])) os.system('git push --tags') sys.exit() # Where the magic happens: setup( name=NAME, version=about['__version__'], description=DESCRIPTION, long_description=long_description, long_description_content_type='text/markdown', author=AUTHOR, author_email=EMAIL, python_requires=REQUIRES_PYTHON, url=URL, packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]), # If your package is a single module, use this instead of 'packages': # py_modules=['mypackage'], # entry_points={ # 'console_scripts': ['mycli=mymodule:cli'], # }, install_requires=REQUIRED, extras_require=EXTRAS, include_package_data=True, license='MIT', classifiers=[ # Trove classifiers # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy' ], # $ setup.py publish support. cmdclass={ 'upload': UploadCommand, }, )