From 0cd8b54edc09e5d71f4217a73727ef6cf04f281d Mon Sep 17 00:00:00 2001
From: albaintor <118518828+albaintor@users.noreply.github.com>
Date: Sat, 13 Jul 2024 12:29:32 +0200
Subject: [PATCH] Reformat code
---
.github/ISSUE_TEMPLATE/bug_report.yml | 53 ++++
.github/ISSUE_TEMPLATE/config.yml | 11 +
.github/ISSUE_TEMPLATE/feature_request.yml | 25 ++
.github/workflows/build.yml | 146 ++++++++++
.github/workflows/python-code-format.yml | 52 ++++
intg-zidoo/config.py | 2 +
intg-zidoo/const.py | 10 +-
intg-zidoo/discover.py | 34 ++-
intg-zidoo/driver.py | 69 +++--
intg-zidoo/media_player.py | 78 ++---
intg-zidoo/setup_flow.py | 66 ++++-
intg-zidoo/test.py | 48 ---
intg-zidoo/zidooaio.py | 321 +++++++++++++--------
requirements.txt | 6 +-
14 files changed, 664 insertions(+), 257 deletions(-)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml
create mode 100644 .github/ISSUE_TEMPLATE/config.yml
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml
create mode 100644 .github/workflows/build.yml
create mode 100644 .github/workflows/python-code-format.yml
delete mode 100644 intg-zidoo/test.py
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..4502d23
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,53 @@
+name: Bug report
+description: Create a report to help us improve
+title: '
'
+labels: [bug]
+
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Please check the existing issues first to see if the bug has already been recorded.
+ If you have more information about an existing bug, please add it as a comment and don't open a new issue.
+ Thank you!
+ - type: textarea
+ attributes:
+ label: Description
+ description: A clear and concise description of what the bug is.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: How to Reproduce
+ description: Steps to reproduce the behavior.
+ placeholder: |
+ 1. ...
+ 2. ...
+ 3. See error
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Expected behavior
+ description: A clear and concise description of what you expected to happen.
+ validations:
+ required: true
+ - type: input
+ id: intg_version
+ attributes:
+ label: Integration version
+ description: You can find the integration version in driver.json or in the UI under Settings/Integrations
+ placeholder: ex. v0.4.5
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Additional context
+ description: |
+ Add any other context about the problem here. Otherwise you can ignore this section.
+ How has this issue affected you? What are you trying to accomplish?
+ Providing context helps us come up with a solution that is most useful in the real world
+
+ Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..29a982a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,11 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Unfolded Circle Community Forum
+ url: https://unfolded.community/
+ about: Please ask and answer questions here.
+ - name: Unfolded Circle Discord Channel
+ url: https://unfolded.chat/
+ about: Chat with the community and for asking questions.
+ - name: Unfolded Circle Contact Form
+ url: https://unfoldedcircle.com/contact
+ about: Write us a message on our website.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000..a9ae273
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,25 @@
+name: Feature request
+description: Suggest an idea
+title: ''
+labels: [enhancement]
+
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Please check the existing issues first to see if your feature request has already been recorded.
+ - type: textarea
+ attributes:
+ label: Description
+ description: A clear and concise description of what the feature request is about.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Additional context
+ description: |
+ Add any other context or screenshots about the feature request here.
+
+ Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
+ validations:
+ required: false
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..f8b7ed0
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,146 @@
+# GitHub Action to build a self-contained binary of the Android TV Python driver
+---
+name: "Build & Release"
+
+on:
+ push:
+ branches: [main]
+ tags:
+ - v[0-9]+.[0-9]+.[0-9]+*
+ pull_request:
+ branches: [main]
+ types: [opened, synchronize, reopened]
+
+env:
+ INTG_NAME: zidoo
+ HASH_FILENAME: uc-intg-zidoo.hash
+ # Python version to use in the builder image. See https://hub.docker.com/r/unfoldedcircle/r2-pyinstaller for possible versions.
+ PYTHON_VER: 3.11.6-0.2.0
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ # History of 200 should be more than enough to calculate commit count since last release tag.
+ fetch-depth: 200
+
+ - name: Fetch all tags to determine version
+ run: |
+ git fetch origin +refs/tags/*:refs/tags/*
+ echo "VERSION=$(git describe --match "v[0-9]*" --tags HEAD --always)" >> $GITHUB_ENV
+
+ - name: Verify driver.json version for release build
+ if: contains(github.ref, 'tags/v')
+ run: |
+ DRIVER_VERSION="v$(jq .version -r driver.json)"
+ if [ "${{ env.VERSION }}" != "$DRIVER_VERSION" ]; then
+ echo "Version in driver.json ($DRIVER_VERSION) doesn't match git version tag (${{ env.VERSION }})!"
+ exit 1
+ fi
+
+ - name: Prepare
+ run: |
+ sudo apt-get update && sudo apt-get install -y qemu binfmt-support qemu-user-static
+ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
+ echo "Starting pyinstaller build"
+ docker run --rm --name builder \
+ --platform=aarch64 \
+ --user=$(id -u):$(id -g) \
+ -v ${GITHUB_WORKSPACE}:/workspace \
+ docker.io/unfoldedcircle/r2-pyinstaller:${PYTHON_VER} \
+ bash -c \
+ "cd /workspace && \
+ python -m pip install -r requirements.txt && \
+ pyinstaller --clean --onefile --name intg-zidoo intg-zidoo/driver.py"
+
+ - name: Add version
+ run: |
+ mkdir -p artifacts
+ cd artifacts
+ echo ${{ env.VERSION }} > version.txt
+
+ - name: Prepare artifacts
+ shell: bash
+ run: |
+ cp dist/intg-zidoo artifacts/
+ cp driver.json artifacts/
+ cp orange.png artifacts/
+ echo "ARTIFACT_NAME=uc-intg-${{ env.INTG_NAME }}-${{ env.VERSION }}-aarch64" >> $GITHUB_ENV
+
+ - name: Create upload artifact
+ shell: bash
+ run: |
+ tar czvf ${{ env.ARTIFACT_NAME }}.tar.gz -C ${GITHUB_WORKSPACE}/artifacts .
+ ls -lah
+
+ - uses: actions/upload-artifact@v4
+ id: upload_artifact
+ with:
+ name: ${{ env.ARTIFACT_NAME }}
+ path: ${{ env.ARTIFACT_NAME }}.tar.gz
+ if-no-files-found: error
+ retention-days: 3
+
+ release:
+ name: Create Release
+ if: github.ref == 'refs/heads/main' || contains(github.ref, 'tags/v')
+ runs-on: ubuntu-latest
+ needs: [build]
+
+ steps:
+ - name: Download build artifacts
+ uses: actions/download-artifact@v4
+
+ - name: Extract build archives from downloaded files
+ run: |
+ ls -R
+ # extract tar.gz build archives from downloaded artifacts
+ # (wrapped in tar from actions/upload-artifact, then extracted into a directory by actions/download-artifact)
+ for D in *
+ do if [ -d "${D}" ]; then
+ mv $D/* ./
+ fi
+ done;
+
+ # Use a common timestamp for all matrix build artifacts
+ - name: Get timestamp
+ run: |
+ echo "TIMESTAMP=$(date +"%Y%m%d_%H%M%S")" >> $GITHUB_ENV
+
+ # Add timestamp to development builds
+ - name: Create GitHub development build archives
+ if: "!contains(github.ref, 'tags/v')"
+ run: |
+ # append timestamp
+ for filename in *.tar.gz; do mv $filename "$(basename $filename .tar.gz)-${{ env.TIMESTAMP }}.tar.gz"; done;
+ for filename in *.tar.gz; do echo "sha256 `sha256sum $filename`" >> ${{ env.HASH_FILENAME }}; done;
+
+ - name: Create Pre-Release
+ uses: "marvinpinto/action-automatic-releases@latest"
+ if: "!contains(github.ref, 'tags/v')"
+ with:
+ repo_token: "${{ secrets.GITHUB_TOKEN }}"
+ automatic_release_tag: "latest"
+ prerelease: true
+ title: "Development Build"
+ files: |
+ *.tar.gz
+ ${{ env.HASH_FILENAME }}
+
+ - name: Create GitHub release archives
+ if: "contains(github.ref, 'tags/v')"
+ run: |
+ for filename in *.tar.gz; do echo "sha256 `sha256sum $filename`" >> ${{ env.HASH_FILENAME }}; done;
+
+ - name: Create Release
+ uses: "marvinpinto/action-automatic-releases@latest"
+ if: "contains(github.ref, 'tags/v')"
+ with:
+ repo_token: "${{ secrets.GITHUB_TOKEN }}"
+ prerelease: false
+ files: |
+ *.tar.gz
+ ${{ env.HASH_FILENAME }}
diff --git a/.github/workflows/python-code-format.yml b/.github/workflows/python-code-format.yml
new file mode 100644
index 0000000..c14acab
--- /dev/null
+++ b/.github/workflows/python-code-format.yml
@@ -0,0 +1,52 @@
+name: Check Python code formatting
+
+on:
+ push:
+ paths:
+ - 'intg-zidoo/**'
+ - 'requirements.txt'
+ - 'test-requirements.txt'
+ - 'tests/**'
+ - '.github/**/*.yml'
+ - '.pylintrc'
+ - 'pyproject.toml'
+ pull_request:
+ branches: [main]
+ types: [opened, synchronize, reopened]
+
+permissions:
+ contents: read
+
+jobs:
+ test:
+ runs-on: ubuntu-22.04
+
+ name: Check Python code formatting
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.11"
+
+ - name: Install pip
+ run: |
+ python -m pip install --upgrade pip
+
+ - name: Install dependencies
+ run: |
+ if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
+ if [ -f test-requirements.txt ]; then pip install -r test-requirements.txt; fi
+ - name: Analyzing the code with pylint
+ run: |
+ python -m pylint intg-zidoo
+ - name: Lint with flake8
+ run: |
+ python -m flake8 intg-zidoo --count --show-source --statistics
+ - name: Check code formatting with isort
+ run: |
+ python -m isort intg-zidoo/. --check --verbose
+ - name: Check code formatting with black
+ run: |
+ python -m black intg-zidoo --check --diff --verbose --line-length 120
diff --git a/intg-zidoo/config.py b/intg-zidoo/config.py
index 16f104a..d9bfb7c 100644
--- a/intg-zidoo/config.py
+++ b/intg-zidoo/config.py
@@ -40,6 +40,7 @@ def device_from_entity_id(entity_id: str) -> str | None:
class DeviceInstance:
"""Orange TV device configuration."""
+ # pylint: disable = W0622
id: str
name: str
address: str
@@ -47,6 +48,7 @@ class DeviceInstance:
wifi_mac_address: str
def __init__(self, id, name, address, net_mac_address=None, wifi_mac_address=None):
+ """Initialize device instance config."""
self.id = id
self.name = name
self.address = address
diff --git a/intg-zidoo/const.py b/intg-zidoo/const.py
index 2b0de78..13aa59b 100644
--- a/intg-zidoo/const.py
+++ b/intg-zidoo/const.py
@@ -58,7 +58,15 @@
1: MediaType.MUSIC, # music
2: MediaType.VIDEO, # video
# 3: MediaType.IMAGE, # image
- # 4: 'text', # 5: 'apk', # 6: 'pdf', # 7: 'document', # 8: 'spreadsheet', # 9: 'presentation', # 10: 'web', # 11: 'archive' , # 12: 'other'
+ # 4: 'text',
+ # 5: 'apk',
+ # 6: 'pdf',
+ # 7: 'document',
+ # 8: 'spreadsheet',
+ # 9: 'presentation',
+ # 10: 'web',
+ # 11: 'archive' ,
+ # 12: 'other'
1000: MEDIA_TYPE_FILE, # hhd
1001: MEDIA_TYPE_FILE, # usb
1002: MEDIA_TYPE_FILE, # usb
diff --git a/intg-zidoo/discover.py b/intg-zidoo/discover.py
index 1a0c066..c1c9672 100644
--- a/intg-zidoo/discover.py
+++ b/intg-zidoo/discover.py
@@ -1,9 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-"""
-This module implements a discovery function for Orange TV.
-
-"""
+"""This module implements a discovery function for Orange TV."""
import asyncio
import json
@@ -124,9 +121,9 @@ async def async_send_ssdp_broadcast() -> Set[str]:
_LOGGER.debug("Following devices found: %s", urls)
return urls
+
async def async_send_ssdp_broadcast_ip(ip_addr: str) -> Set[str]:
"""Send SSDP broadcast messages to a single IP."""
-
try:
# Ignore 169.254.0.0/16 addresses
if ip_addr.startswith("169.254."):
@@ -138,7 +135,9 @@ async def async_send_ssdp_broadcast_ip(ip_addr: str) -> Set[str]:
# Get asyncio loop
loop = asyncio.get_event_loop()
- transport, protocol = await loop.create_datagram_endpoint(OrangeTVSSDP, sock=sock)
+ transport, protocol = await loop.create_datagram_endpoint(
+ OrangeTVSSDP, sock=sock
+ )
# Wait for the timeout period
await asyncio.sleep(SSDP_MX)
@@ -146,9 +145,12 @@ async def async_send_ssdp_broadcast_ip(ip_addr: str) -> Set[str]:
# Close the connection
transport.close()
- _LOGGER.debug("Got %s results after SSDP queries using ip %s", len(protocol.urls), ip_addr)
+ _LOGGER.debug(
+ "Got %s results after SSDP queries using ip %s", len(protocol.urls), ip_addr
+ )
return protocol.urls
+ # pylint: disable = W0718
except Exception:
return set()
@@ -177,15 +179,23 @@ def evaluate_scpd_xml(url: str, body: str) -> Optional[Dict]:
device_xml = root.find(SCPD_DEVICE)
elif root.find(SCPD_DEVICE).find(SCPD_DEVICELIST) is not None:
for dev in root.find(SCPD_DEVICE).find(SCPD_DEVICELIST):
- if dev.find(SCPD_DEVICETYPE).text in SUPPORTED_DEVICETYPES and dev.find(SCPD_SERIALNUMBER) is not None:
+ if (
+ dev.find(SCPD_DEVICETYPE).text in SUPPORTED_DEVICETYPES
+ and dev.find(SCPD_SERIALNUMBER) is not None
+ ):
device_xml = dev
break
if device_xml is None:
return None
- if device_xml.find(SCPD_PRESENTATIONURL) is not None and device_xml.find(SCPD_PRESENTATIONURL).text != "/":
- device["host"] = urlparse(device_xml.find(SCPD_PRESENTATIONURL).text).hostname
+ if (
+ device_xml.find(SCPD_PRESENTATIONURL) is not None
+ and device_xml.find(SCPD_PRESENTATIONURL).text != "/"
+ ):
+ device["host"] = urlparse(
+ device_xml.find(SCPD_PRESENTATIONURL).text
+ ).hostname
device["presentationURL"] = device_xml.find(SCPD_PRESENTATIONURL).text
else:
device["host"] = urlparse(url).hostname
@@ -201,7 +211,9 @@ def evaluate_scpd_xml(url: str, body: str) -> Optional[Dict]:
ParseError,
UnicodeDecodeError,
) as err:
- _LOGGER.error("Error occurred during evaluation of SCPD XML from URI %s: %s", url, err)
+ _LOGGER.error(
+ "Error occurred during evaluation of SCPD XML from URI %s: %s", url, err
+ )
return None
diff --git a/intg-zidoo/driver.py b/intg-zidoo/driver.py
index 30b977c..3f8ced5 100644
--- a/intg-zidoo/driver.py
+++ b/intg-zidoo/driver.py
@@ -12,20 +12,18 @@
import os
from typing import Any
-import websockets
-from ucapi.api import filter_log_msg_data, IntegrationAPI
-
import config
import media_player
import setup_flow
import ucapi
-
+import ucapi.api_definitions as uc
+import websockets
import zidooaio
from config import device_from_entity_id
-from ucapi.media_player import Attributes as MediaAttr, States
-
+from ucapi.api import IntegrationAPI, filter_log_msg_data
+from ucapi.media_player import Attributes as MediaAttr
+from ucapi.media_player import States
from zidooaio import ZidooRC
-import ucapi.api_definitions as uc
_LOG = logging.getLogger("driver") # avoid having __main__ in log messages
_LOOP = asyncio.get_event_loop()
@@ -76,8 +74,8 @@ async def on_r2_disconnect_cmd():
@api.listens_to(ucapi.Events.ENTER_STANDBY)
async def on_r2_enter_standby() -> None:
- """
- Enter standby notification from Remote Two.
+ """Enter standby notification from Remote Two.
+
Disconnect every ZidooTV instances.
"""
global _R2_IN_STANDBY
@@ -121,14 +119,19 @@ async def on_subscribe_entities(entity_ids: list[str]) -> None:
if device_id in _configured_devices:
device = _configured_devices[device_id]
state = media_player.state_from_device(device.state)
- api.configured_entities.update_attributes(entity_id, {ucapi.media_player.Attributes.STATE: state})
+ api.configured_entities.update_attributes(
+ entity_id, {ucapi.media_player.Attributes.STATE: state}
+ )
continue
device = config.devices.get(device_id)
if device:
_configure_new_device(device, connect=True)
else:
- _LOG.error("Failed to subscribe entity %s: no device configuration found", entity_id)
+ _LOG.error(
+ "Failed to subscribe entity %s: no device configuration found",
+ entity_id,
+ )
@api.listens_to(ucapi.Events.UNSUBSCRIBE_ENTITIES)
@@ -173,7 +176,10 @@ async def on_device_connected(device_id: str):
):
# TODO why STANDBY?
api.configured_entities.update_attributes(
- entity_id, {ucapi.media_player.Attributes.STATE: ucapi.media_player.States.STANDBY}
+ entity_id,
+ {
+ ucapi.media_player.Attributes.STATE: ucapi.media_player.States.STANDBY
+ },
)
@@ -188,7 +194,10 @@ async def on_device_disconnected(avr_id: str):
if configured_entity.entity_type == ucapi.EntityTypes.MEDIA_PLAYER:
api.configured_entities.update_attributes(
- entity_id, {ucapi.media_player.Attributes.STATE: ucapi.media_player.States.UNAVAILABLE}
+ entity_id,
+ {
+ ucapi.media_player.Attributes.STATE: ucapi.media_player.States.UNAVAILABLE
+ },
)
# TODO #20 when multiple devices are supported, the device state logic isn't that simple anymore!
@@ -206,7 +215,10 @@ async def on_avr_connection_error(avr_id: str, message):
if configured_entity.entity_type == ucapi.EntityTypes.MEDIA_PLAYER:
api.configured_entities.update_attributes(
- entity_id, {ucapi.media_player.Attributes.STATE: ucapi.media_player.States.UNAVAILABLE}
+ entity_id,
+ {
+ ucapi.media_player.Attributes.STATE: ucapi.media_player.States.UNAVAILABLE
+ },
)
# TODO #20 when multiple devices are supported, the device state logic isn't that simple anymore!
@@ -217,7 +229,12 @@ async def handle_avr_address_change(avr_id: str, address: str) -> None:
"""Update device configuration with changed IP address."""
device = config.devices.get(avr_id)
if device and device.address != address:
- _LOG.info("Updating IP address of configured AVR %s: %s -> %s", avr_id, device.address, address)
+ _LOG.info(
+ "Updating IP address of configured AVR %s: %s -> %s",
+ avr_id,
+ device.address,
+ address,
+ )
device.address = address
config.devices.update(device)
@@ -275,7 +292,9 @@ def _entities_from_avr(avr_id: str) -> list[str]:
return [f"media_player.{avr_id}"]
-def _configure_new_device(device_config: config.DeviceInstance, connect: bool = True) -> None:
+def _configure_new_device(
+ device_config: config.DeviceInstance, connect: bool = True
+) -> None:
"""
Create and configure a new device.
@@ -302,7 +321,9 @@ def _configure_new_device(device_config: config.DeviceInstance, connect: bool =
_register_available_entities(device_config, device)
-def _register_available_entities(config_device: config.DeviceInstance, device: ZidooRC) -> None:
+def _register_available_entities(
+ config_device: config.DeviceInstance, device: ZidooRC
+) -> None:
"""
Create entities for given receiver device and register them as available entities.
@@ -326,7 +347,9 @@ def on_device_added(device: config.DeviceInstance) -> None:
def on_device_removed(device: config.DeviceInstance | None) -> None:
"""Handle a removed device in the configuration."""
if device is None:
- _LOG.debug("Configuration cleared, disconnecting & removing all configured AVR instances")
+ _LOG.debug(
+ "Configuration cleared, disconnecting & removing all configured AVR instances"
+ )
for configured in _configured_devices.values():
_LOOP.create_task(_async_remove(configured))
_configured_devices.clear()
@@ -349,7 +372,7 @@ async def _async_remove(device: ZidooRC) -> None:
async def patched_broadcast_ws_event(
- self, msg: str, msg_data: dict[str, Any], category: uc.EventCategory
+ self, msg: str, msg_data: dict[str, Any], category: uc.EventCategory
) -> None:
"""
Send the given event-message to all connected WebSocket clients.
@@ -367,6 +390,7 @@ async def patched_broadcast_ws_event(
if _LOG.isEnabledFor(logging.DEBUG):
data_log = json.dumps(data) if filter_log_msg_data(data) else data_dump
+ # pylint: disable = W0212
for websocket in self._clients.copy():
if _LOG.isEnabledFor(logging.DEBUG):
_LOG.debug("[%s] ->: %s", websocket.remote_address, data_log)
@@ -388,19 +412,22 @@ async def main():
logging.getLogger("receiver").setLevel(level)
logging.getLogger("setup_flow").setLevel(level)
- config.devices = config.Devices(api.config_dir_path, on_device_added, on_device_removed)
+ config.devices = config.Devices(
+ api.config_dir_path, on_device_added, on_device_removed
+ )
for device in config.devices.all():
_LOG.debug("UC Zidoo device %s %s", device.id, device.address)
_configure_new_device(device, connect=False)
# _LOOP.create_task(receiver_status_poller())
for device in _configured_devices.values():
- if device.state == States.OFF or device.state == States.UNKNOWN:
+ if device.state in [States.OFF, States.UNKNOWN]:
continue
_LOOP.create_task(device.async_update_data())
_LOOP.create_task(device_status_poller())
# Patched method
+ # pylint: disable = W0212
IntegrationAPI._broadcast_ws_event = patched_broadcast_ws_event
await api.init("driver.json", setup_flow.driver_setup_handler)
diff --git a/intg-zidoo/media_player.py b/intg-zidoo/media_player.py
index 3300ea8..5c4af22 100644
--- a/intg-zidoo/media_player.py
+++ b/intg-zidoo/media_player.py
@@ -11,9 +11,16 @@
import zidooaio
from config import DeviceInstance, create_entity_id
from ucapi import EntityTypes, MediaPlayer, StatusCodes
-from ucapi.media_player import Attributes, Commands, DeviceClasses, Features, States, MediaType, Options
-
-from zidooaio import ZidooRC, ZKEYS
+from ucapi.media_player import (
+ Attributes,
+ Commands,
+ DeviceClasses,
+ Features,
+ MediaType,
+ Options,
+ States,
+)
+from zidooaio import ZKEYS, ZidooRC
_LOG = logging.getLogger(__name__)
@@ -40,7 +47,7 @@
ZKEYS.ZKEY_REPEAT,
ZKEYS.ZKEY_PICTURE_IN_PICTURE,
ZKEYS.ZKEY_SELECT,
- ZKEYS.ZKEY_LIGHT
+ ZKEYS.ZKEY_LIGHT,
]
@@ -103,10 +110,12 @@ def __init__(self, config_device: DeviceInstance, device: ZidooRC):
features,
attributes,
device_class=DeviceClasses.SET_TOP_BOX,
- options={Options.SIMPLE_COMMANDS: SIMPLE_COMMANDS}
+ options={Options.SIMPLE_COMMANDS: SIMPLE_COMMANDS},
)
- async def command(self, cmd_id: str, params: dict[str, Any] | None = None) -> StatusCodes:
+ async def command(
+ self, cmd_id: str, params: dict[str, Any] | None = None
+ ) -> StatusCodes:
"""
Media-player entity command handler.
@@ -116,6 +125,7 @@ async def command(self, cmd_id: str, params: dict[str, Any] | None = None) -> St
:param params: optional command parameters
:return: status code of the command request
"""
+ # pylint: disable = R0915
_LOG.info("Got %s command request: %s %s", self.id, cmd_id, params)
if self._device is None:
@@ -142,65 +152,65 @@ async def command(self, cmd_id: str, params: dict[str, Any] | None = None) -> St
elif cmd_id == Commands.PREVIOUS:
res = await self._device.media_previous_track()
elif cmd_id == Commands.CHANNEL_UP:
- res = await self._device._send_key(ZKEYS.ZKEY_PAGE_UP)
+ res = await self._device.send_key(ZKEYS.ZKEY_PAGE_UP)
elif cmd_id == Commands.CHANNEL_DOWN:
- res = await self._device._send_key(ZKEYS.ZKEY_PAGE_DOWN)
+ res = await self._device.send_key(ZKEYS.ZKEY_PAGE_DOWN)
elif cmd_id == Commands.PLAY_PAUSE:
res = await self._device.media_play_pause()
elif cmd_id == Commands.STOP:
res = await self._device.media_stop()
elif cmd_id == Commands.FAST_FORWARD:
- res = await self._device._send_key(ZKEYS.ZKEY_MEDIA_FORWARDS)
+ res = await self._device.send_key(ZKEYS.ZKEY_MEDIA_FORWARDS)
elif cmd_id == Commands.REWIND:
- res = await self._device._send_key(ZKEYS.ZKEY_MEDIA_BACKWARDS)
+ res = await self._device.send_key(ZKEYS.ZKEY_MEDIA_BACKWARDS)
elif cmd_id == Commands.RECORD:
- res = await self._device._send_key(ZKEYS.ZKEY_RECORD)
+ res = await self._device.send_key(ZKEYS.ZKEY_RECORD)
elif cmd_id == Commands.CURSOR_UP:
- res = await self._device._send_key(ZKEYS.ZKEY_UP)
+ res = await self._device.send_key(ZKEYS.ZKEY_UP)
elif cmd_id == Commands.CURSOR_DOWN:
- res = await self._device._send_key(ZKEYS.ZKEY_DOWN)
+ res = await self._device.send_key(ZKEYS.ZKEY_DOWN)
elif cmd_id == Commands.CURSOR_LEFT:
- res = await self._device._send_key(ZKEYS.ZKEY_LEFT)
+ res = await self._device.send_key(ZKEYS.ZKEY_LEFT)
elif cmd_id == Commands.CURSOR_RIGHT:
- res = await self._device._send_key(ZKEYS.ZKEY_RIGHT)
+ res = await self._device.send_key(ZKEYS.ZKEY_RIGHT)
elif cmd_id == Commands.CURSOR_ENTER:
- res = await self._device._send_key(ZKEYS.ZKEY_OK)
+ res = await self._device.send_key(ZKEYS.ZKEY_OK)
elif cmd_id == Commands.BACK:
- res = await self._device._send_key(ZKEYS.ZKEY_BACK)
+ res = await self._device.send_key(ZKEYS.ZKEY_BACK)
elif cmd_id == Commands.MENU:
- res = await self._device._send_key(ZKEYS.ZKEY_MENU)
+ res = await self._device.send_key(ZKEYS.ZKEY_MENU)
elif cmd_id == Commands.HOME:
- res = await self._device._send_key(ZKEYS.ZKEY_HOME)
+ res = await self._device.send_key(ZKEYS.ZKEY_HOME)
elif cmd_id == Commands.SETTINGS:
- res = await self._device._send_key(ZKEYS.ZKEY_APP_SWITCH)
+ res = await self._device.send_key(ZKEYS.ZKEY_APP_SWITCH)
elif cmd_id == Commands.CONTEXT_MENU:
- res = await self._device._send_key(ZKEYS.ZKEY_POPUP_MENU)
+ res = await self._device.send_key(ZKEYS.ZKEY_POPUP_MENU)
elif cmd_id == Commands.INFO:
- res = await self._device._send_key(ZKEYS.ZKEY_INFO)
+ res = await self._device.send_key(ZKEYS.ZKEY_INFO)
elif cmd_id == Commands.AUDIO_TRACK:
- res = await self._device._send_key(ZKEYS.ZKEY_AUDIO)
+ res = await self._device.send_key(ZKEYS.ZKEY_AUDIO)
elif cmd_id == Commands.SUBTITLE:
- res = await self._device._send_key(ZKEYS.ZKEY_SUBTITLE)
+ res = await self._device.send_key(ZKEYS.ZKEY_SUBTITLE)
elif cmd_id == Commands.DIGIT_0:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_0)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_0)
elif cmd_id == Commands.DIGIT_1:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_1)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_1)
elif cmd_id == Commands.DIGIT_2:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_2)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_2)
elif cmd_id == Commands.DIGIT_3:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_3)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_3)
elif cmd_id == Commands.DIGIT_4:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_4)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_4)
elif cmd_id == Commands.DIGIT_5:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_5)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_5)
elif cmd_id == Commands.DIGIT_6:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_6)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_6)
elif cmd_id == Commands.DIGIT_7:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_7)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_7)
elif cmd_id == Commands.DIGIT_8:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_8)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_8)
elif cmd_id == Commands.DIGIT_9:
- res = await self._device._send_key(ZKEYS.ZKEY_NUM_9)
+ res = await self._device.send_key(ZKEYS.ZKEY_NUM_9)
else:
return StatusCodes.NOT_IMPLEMENTED
diff --git a/intg-zidoo/setup_flow.py b/intg-zidoo/setup_flow.py
index 5e0045c..36a1e9f 100644
--- a/intg-zidoo/setup_flow.py
+++ b/intg-zidoo/setup_flow.py
@@ -11,7 +11,6 @@
import config
import discover
-from zidooaio import ZidooRC
from config import DeviceInstance
from ucapi import (
AbortDriverSetup,
@@ -24,9 +23,12 @@
SetupError,
UserDataResponse,
)
+from zidooaio import ZidooRC
_LOG = logging.getLogger(__name__)
+# pylint: disable = W1405
+
class SetupSteps(IntEnum):
"""Enumeration of setup steps to keep track of user data responses."""
@@ -82,7 +84,10 @@ async def driver_setup_handler(msg: SetupDriver) -> SetupAction:
return await handle_driver_setup(msg)
if isinstance(msg, UserDataResponse):
_LOG.debug(msg)
- if _setup_step == SetupSteps.CONFIGURATION_MODE and "action" in msg.input_values:
+ if (
+ _setup_step == SetupSteps.CONFIGURATION_MODE
+ and "action" in msg.input_values
+ ):
return await handle_configuration_mode(msg)
if _setup_step == SetupSteps.DISCOVER and "address" in msg.input_values:
return await _handle_discovery(msg)
@@ -100,7 +105,9 @@ async def driver_setup_handler(msg: SetupDriver) -> SetupAction:
return SetupError()
-async def handle_driver_setup(_msg: DriverSetupRequest) -> RequestUserInput | SetupError:
+async def handle_driver_setup(
+ _msg: DriverSetupRequest,
+) -> RequestUserInput | SetupError:
"""
Start driver setup.
@@ -120,7 +127,9 @@ async def handle_driver_setup(_msg: DriverSetupRequest) -> RequestUserInput | Se
# get all configured devices for the user to choose from
dropdown_devices = []
for device in config.devices.all():
- dropdown_devices.append({"id": device.id, "label": {"en": f"{device.name} ({device.id})"}})
+ dropdown_devices.append(
+ {"id": device.id, "label": {"en": f"{device.name} ({device.id})"}}
+ )
# TODO #12 externalize language texts
# build user actions, based on available devices
@@ -165,7 +174,12 @@ async def handle_driver_setup(_msg: DriverSetupRequest) -> RequestUserInput | Se
{"en": "Configuration mode", "de": "Konfigurations-Modus"},
[
{
- "field": {"dropdown": {"value": dropdown_devices[0]["id"], "items": dropdown_devices}},
+ "field": {
+ "dropdown": {
+ "value": dropdown_devices[0]["id"],
+ "items": dropdown_devices,
+ }
+ },
"id": "choice",
"label": {
"en": "Configured devices",
@@ -174,7 +188,12 @@ async def handle_driver_setup(_msg: DriverSetupRequest) -> RequestUserInput | Se
},
},
{
- "field": {"dropdown": {"value": dropdown_actions[0]["id"], "items": dropdown_actions}},
+ "field": {
+ "dropdown": {
+ "value": dropdown_actions[0]["id"],
+ "items": dropdown_actions,
+ }
+ },
"id": "action",
"label": {
"en": "Action",
@@ -191,7 +210,9 @@ async def handle_driver_setup(_msg: DriverSetupRequest) -> RequestUserInput | Se
return _user_input_discovery
-async def handle_configuration_mode(msg: UserDataResponse) -> RequestUserInput | SetupComplete | SetupError:
+async def handle_configuration_mode(
+ msg: UserDataResponse,
+) -> RequestUserInput | SetupComplete | SetupError:
"""
Process user data response in a setup process.
@@ -246,6 +267,7 @@ async def _handle_discovery(msg: UserDataResponse) -> RequestUserInput | SetupEr
dropdown_items = []
address = msg.input_values["address"]
+ # pylint: disable = W0718
if address:
_LOG.debug("Starting manual driver setup for %s", address)
try:
@@ -254,7 +276,9 @@ async def _handle_discovery(msg: UserDataResponse) -> RequestUserInput | SetupEr
data = await device.connect()
await device.disconnect()
friendly_name = data["model"]
- dropdown_items.append({"id": address, "label": {"en": f"{friendly_name} [{address}]"}})
+ dropdown_items.append(
+ {"id": address, "label": {"en": f"{friendly_name} [{address}]"}}
+ )
except Exception as ex:
_LOG.error("Cannot connect to manually entered address %s: %s", address, ex)
return SetupError(error_type=IntegrationSetupError.CONNECTION_REFUSED)
@@ -281,7 +305,12 @@ async def _handle_discovery(msg: UserDataResponse) -> RequestUserInput | SetupEr
},
[
{
- "field": {"dropdown": {"value": dropdown_items[0]["id"], "items": dropdown_items}},
+ "field": {
+ "dropdown": {
+ "value": dropdown_items[0]["id"],
+ "items": dropdown_items,
+ }
+ },
"id": "choice",
"label": {
"en": "Choose your Zidoo",
@@ -302,8 +331,11 @@ async def handle_device_choice(msg: UserDataResponse) -> SetupComplete | SetupEr
:param msg: response data from the requested user data
:return: the setup action on how to continue: SetupComplete if a valid AVR device was chosen.
"""
+ # pylint: disable = W0718
host = msg.input_values["choice"]
- _LOG.debug("Chosen Zidoo: %s. Trying to connect and retrieve device information...", host)
+ _LOG.debug(
+ "Chosen Zidoo: %s. Trying to connect and retrieve device information...", host
+ )
try:
# connection check and mac_address extraction for wakeonlan
device = ZidooRC(host, None)
@@ -323,12 +355,20 @@ async def handle_device_choice(msg: UserDataResponse) -> SetupComplete | SetupEr
unique_id = identifier
if unique_id is None:
- _LOG.error("Could not get mac address of host %s: required to create a unique device", host)
+ _LOG.error(
+ "Could not get mac address of host %s: required to create a unique device",
+ host,
+ )
return SetupError(error_type=IntegrationSetupError.OTHER)
config.devices.add(
- DeviceInstance(id=unique_id, name=friendly_name, address=host,
- net_mac_address=net_mac_address, wifi_mac_address=wifi_mac_address)
+ DeviceInstance(
+ id=unique_id,
+ name=friendly_name,
+ address=host,
+ net_mac_address=net_mac_address,
+ wifi_mac_address=wifi_mac_address,
+ )
) # triggers ZidooAVR instance creation
config.devices.store()
diff --git a/intg-zidoo/test.py b/intg-zidoo/test.py
deleted file mode 100644
index df23d4a..0000000
--- a/intg-zidoo/test.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import asyncio
-import json
-import socket
-
-import netifaces
-from ssdp import aio, messages, network
-import socket
-
-from zidooaio import ZidooRC
-
-class MyProtocol(aio.SimpleServiceDiscoveryProtocol):
-
- def response_received(self, response, addr):
- print(response, addr)
-
- def request_received(self, request, addr):
- print(request, addr)
-
-
-# loop = asyncio.get_event_loop()
-# connect = loop.create_datagram_endpoint(MyProtocol, family=socket.AF_INET)
-# transport, protocol = loop.run_until_complete(connect)
-#
-# notify = messages.SSDPRequest('NOTIFY')
-# notify.sendto(transport, (network.MULTICAST_ADDRESS_IPV4, network.PORT))
-#
-# try:
-# loop.run_forever()
-# except KeyboardInterrupt:
-# pass
-#
-# transport.close()
-# loop.close()
-
-# toto = [i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
-# print(*toto, sep=",")
-#
-# ips = []
-# for interface in netifaces.interfaces():
-# addresses = netifaces.ifaddresses(interface)
-# for address in addresses.get(netifaces.AF_INET, []):
-# ips.append(address["addr"])
-# print(*toto, sep=",")
-loop=asyncio.new_event_loop()
-device = ZidooRC("192.168.1.40", loop=loop)
-data = asyncio.run(device.connect())
-asyncio.run(device.disconnect())
-print(json.dumps(data))
diff --git a/intg-zidoo/zidooaio.py b/intg-zidoo/zidooaio.py
index 7929d2d..2234af3 100644
--- a/intg-zidoo/zidooaio.py
+++ b/intg-zidoo/zidooaio.py
@@ -1,5 +1,6 @@
"""
-Zidoo Remote Control API
+Zidoo Remote Control API.
+
By Wizmo
References
oem v1: https://www.zidoo.tv/Support/developer/
@@ -7,25 +8,27 @@
"""
import asyncio
-import logging
import json
+import logging
import socket
import struct
+import urllib.parse
from asyncio import AbstractEventLoop, Lock
-from enum import IntEnum, StrEnum
-from ucapi.media_player import Attributes as MediaAttr
-from aiohttp import ClientError, ClientSession, CookieJar
from datetime import datetime, timedelta
-import urllib.parse
+from enum import IntEnum, StrEnum
+from aiohttp import ClientError, ClientSession, CookieJar
+from config import DeviceInstance
from pyee import AsyncIOEventEmitter
+from ucapi.media_player import Attributes as MediaAttr
from ucapi.media_player import MediaType
from yarl import URL
-from config import DeviceInstance
SCAN_INTERVAL = timedelta(seconds=10)
SCAN_INTERVAL_RAPID = timedelta(seconds=1)
+# pylint: disable = C0302
+
class Events(IntEnum):
"""Internal driver events."""
@@ -59,10 +62,10 @@ class States(IntEnum):
DEFAULT_COUNT = 250 # default list limit
ZCMD_STATUS = "getPlayStatus"
-"""Remote Control Button keys"""
-
class ZKEYS(StrEnum):
+ """List of available keys."""
+
ZKEY_BACK = "Key.Back"
ZKEY_CANCEL = "Key.Cancel"
ZKEY_HOME = "Key.Home"
@@ -124,7 +127,7 @@ class ZKEYS(StrEnum):
ZKEY_APP_SWITCH = "Key.APP.Switch"
-"""Movie Player entry types."""
+# Movie Player entry types
ZTYPE_VIDEO = 0
ZTYPE_MOVIE = 1
ZTYPE_COLLECTION = 2
@@ -224,7 +227,7 @@ class ZKEYS(StrEnum):
}
-class ZidooRC(object):
+class ZidooRC:
"""Zidoo Media Player Remote Control."""
def __init__(
@@ -246,6 +249,7 @@ def __init__(
authorization password key. If not assigned, standard basic auth is used.
"""
self._device_config = device_config
+ self._mac = mac
self._wifi_mac = None
self._ethernet_mac = None
if device_config:
@@ -258,7 +262,7 @@ def __init__(
self.events = AsyncIOEventEmitter(self.event_loop)
self._source_list = None
self._media_type: MediaType | None = None
- self._host = "{}:{}".format(host, CONF_PORT)
+ self._host = f"{host}:{CONF_PORT}"
self._psk = psk
self._session = None
self._cookies = None
@@ -283,10 +287,12 @@ def __init__(
@property
def state(self) -> States:
+ """Return device state."""
return self._state
@property
def media_type(self):
+ """Return current media type."""
return self._media_type
@property
@@ -326,6 +332,7 @@ def media_duration(self):
duration = self._media_info.get("duration")
if duration:
return float(duration) / 1000
+ return None
@property
def media_position(self):
@@ -333,6 +340,7 @@ def media_position(self):
position = self._media_info.get("position")
if position:
return float(position) / 1000
+ return None
@property
def media_image_url(self):
@@ -395,6 +403,7 @@ def _filter_updated_media_info(self, media_info: any, updated_data: any) -> any:
async def async_update_data(self) -> None:
"""Update data callback."""
+ # pylint: disable = R0915,R1702
if not self.is_connected():
await self.connect()
updated_data = {}
@@ -455,13 +464,15 @@ async def async_update_data(self) -> None:
self._media_type = media_type
updated_data[MediaAttr.MEDIA_TYPE] = self._media_type
- except Exception as err: # pylint: disable=broad-except
+ except Exception: # pylint: disable=broad-except
return
if state != self._last_state:
_LOGGER.debug("%s New state (%s)", self._device_config.name, state)
self._last_state = state
- self._update_interval = SCAN_INTERVAL if state == States.OFF else SCAN_INTERVAL_RAPID
+ self._update_interval = (
+ SCAN_INTERVAL if state == States.OFF else SCAN_INTERVAL_RAPID
+ )
updated_data[MediaAttr.STATE] = state
self._state = state
if updated_data:
@@ -469,9 +480,13 @@ async def async_update_data(self) -> None:
def _jdata_build(self, method: str, params: dict = None) -> str:
if params:
- ret = json.dumps({"method": method, "params": [params], "id": 1, "version": "1.0"})
+ ret = json.dumps(
+ {"method": method, "params": [params], "id": 1, "version": "1.0"}
+ )
else:
- ret = json.dumps({"method": method, "params": [], "id": 1, "version": "1.0"})
+ ret = json.dumps(
+ {"method": method, "params": [], "id": 1, "version": "1.0"}
+ )
return ret
async def _init_network(self):
@@ -485,11 +500,11 @@ async def _init_network(self):
for item in data["list"]:
url = urllib.parse.quote(item.get("url"), safe="")
await self._req_json(
- "ZidooFileControl/v2/getFiles?requestCount=100&startIndex=0&sort=0&url={}".format(url)
+ f"ZidooFileControl/v2/getFiles?requestCount=100&startIndex=0&sort=0&url={url}"
)
# gets current song list (and appears to initialize network shared on old devices)
await self.get_music_playlist()
- print("SONG_LIST: {}".format(self._song_list))
+ # print(f"SONG_LIST: {self._song_list}")
# _LOGGER.debug(response)
# await self._req_json("ZidooFileControl/v2/getUpnpDevices")
@@ -513,6 +528,7 @@ async def connect(self) -> json:
# url = "ZidooControlCenter/connect?name={}&uuid={}&tag=0".format(client_name, client_uuid)
# response = await self._req_json(url, log_errors=False)
+ # pylint: disable = W0718
try:
response = await self.get_system_info(log_errors=False)
@@ -569,7 +585,7 @@ def _wakeonlan(self) -> None:
socket_instance.sendto(msg, ("", 9))
socket_instance.close()
- async def _send_key(self, key: str, log_errors: bool = False) -> bool:
+ async def send_key(self, key: str, log_errors: bool = False) -> bool:
"""Async Send Remote Control button command to device.
Parameters
@@ -592,6 +608,7 @@ async def _send_key(self, key: str, log_errors: bool = False) -> bool:
async def _req_json(
self,
url: str,
+ # pylint: disable = W0102
params: dict = {},
log_errors: bool = True,
timeout: int = TIMEOUT,
@@ -614,7 +631,6 @@ async def _req_json(
json
raw API response
"""
-
while max_retries >= 0:
response = await self._send_cmd(url, params, log_errors, timeout)
@@ -658,7 +674,9 @@ async def _send_cmd(
raw API response
"""
if self._session is None:
- self._session = ClientSession(cookie_jar=CookieJar(unsafe=True, quote_cookie=False))
+ self._session = ClientSession(
+ cookie_jar=CookieJar(unsafe=True, quote_cookie=False)
+ )
headers = {}
if self._psk is not None:
@@ -667,7 +685,7 @@ async def _send_cmd(
headers["Cache-Control"] = "no-cache"
headers["Connection"] = "keep-alive"
- url = "http://{}/{}".format(self._host, url)
+ url = f"http://{self._host}/{url}"
try:
response = await self._session.get(
@@ -752,7 +770,9 @@ async def get_playing_info(self) -> json:
async def _get_video_playing_info(self) -> json:
"""Async Get information from built in video player."""
return_value = {}
- response = await self._req_json("ZidooVideoPlay/" + ZCMD_STATUS, log_errors=False, timeout=TIMEOUT_INFO)
+ response = await self._req_json(
+ "ZidooVideoPlay/" + ZCMD_STATUS, log_errors=False, timeout=TIMEOUT_INFO
+ )
if response is not None and response.get("status") == 200:
if response.get("subtitle"):
@@ -789,7 +809,9 @@ async def _get_id_from_uri(self, uri: str) -> int:
movie_id = 0
movie_info = {}
- response = await self._req_json("ZidooPoster/v2/getAggregationOfFile?path={}".format(urllib.parse.quote(uri)))
+ response = await self._req_json(
+ f"ZidooPoster/v2/getAggregationOfFile?path={urllib.parse.quote(uri)}"
+ )
if response:
movie_info["type"] = response.get("type")
@@ -824,8 +846,11 @@ async def _get_id_from_uri(self, uri: str) -> int:
async def _get_music_playing_info(self) -> json:
"""Async Get information from built in Music Player."""
return_value = {}
- response = await self._req_json("ZidooMusicControl/" + ZCMD_STATUS, log_errors=False, timeout=TIMEOUT_INFO)
+ response = await self._req_json(
+ "ZidooMusicControl/" + ZCMD_STATUS, log_errors=False, timeout=TIMEOUT_INFO
+ )
+ # pylint: disable = W1405
if response is not None and response.get("status") == 200:
return_value["status"] = response.get("isPlay")
result = response.get("music")
@@ -836,12 +861,8 @@ async def _get_music_playing_info(self) -> json:
return_value["date"] = result.get("date")
return_value["uri"] = result.get("uri")
return_value["bitrate"] = result.get("bitrate")
- return_value["audio"] = "{}: {} channels {} bits {} Hz".format(
- result.get("extension"),
- result.get("channels"),
- result.get("bits"),
- result.get("SampleRate"),
- )
+ return_value["audio"] = (f"{result.get('extension')}: {result.get('channels')}"
+ f" channels {result.get('bits')} bits {result.get('SampleRate')} Hz")
self._music_id = result.get("id")
self._music_type = result.get("type")
@@ -861,7 +882,9 @@ async def _get_movie_playing_info(self) -> json:
"""Async Get information from built in Movie Player."""
return_value = {}
- response = await self._req_json("ZidooControlCenter/" + ZCMD_STATUS, log_errors=False, timeout=TIMEOUT_INFO)
+ response = await self._req_json(
+ "ZidooControlCenter/" + ZCMD_STATUS, log_errors=False, timeout=TIMEOUT_INFO
+ )
if response is not None and response.get("status") == 200:
if response.get("file"):
@@ -902,7 +925,9 @@ async def get_subtitle_list(self, log_errors=True) -> dict:
dictionary list
"""
return_values = {}
- response = await self._req_json("ZidooVideoPlay/getSubtitleList", log_errors=log_errors)
+ response = await self._req_json(
+ "ZidooVideoPlay/getSubtitleList", log_errors=log_errors
+ )
if response is not None and response.get("status") == 200:
for result in response["subtitles"]:
@@ -921,9 +946,13 @@ async def set_subtitle(self, index: int = None) -> bool:
True if successful
"""
if index is None:
- index = self._next_data(await self.get_subtitle_list(), self._current_subtitle)
+ index = self._next_data(
+ await self.get_subtitle_list(), self._current_subtitle
+ )
- response = await self._req_json("ZidooVideoPlay/setSubtitle?index={}".format(index), log_errors=False)
+ response = await self._req_json(
+ f"ZidooVideoPlay/setSubtitle?index={index}", log_errors=False
+ )
if response is not None and response.get("status") == 200:
self._current_subtitle = index
@@ -959,7 +988,9 @@ async def set_audio(self, index: int = None) -> bool:
if index is None:
index = self._next_data(await self.get_audio_list(), self._current_audio)
- response = await self._req_json("ZidooVideoPlay/setAudio?index={}".format(index), log_errors=False)
+ response = await self._req_json(
+ f"ZidooVideoPlay/setAudio?index={index}", log_errors=False
+ )
if response is not None and response.get("status") == 200:
self._current_audio = index
@@ -987,7 +1018,9 @@ async def get_system_info(self, log_errors=True) -> json:
'ableRemoteBoot': network boot compatible (wol)
'pyapiversion': python api version
"""
- response = await self._req_json("ZidooControlCenter/getModel", log_errors=log_errors, max_retries=0)
+ response = await self._req_json(
+ "ZidooControlCenter/getModel", log_errors=log_errors, max_retries=0
+ )
if response and response.get("status") == 200:
response["pyapiversion"] = VERSION
@@ -1007,7 +1040,7 @@ async def get_power_status(self) -> str:
if response and response.get("status") == 200:
self._power_status = True
- except: # pylint: disable=broad-except
+ except Exception: # pylint: disable=broad-except
pass
if self._power_status is True:
@@ -1016,10 +1049,12 @@ async def get_power_status(self) -> str:
async def get_volume_info(self):
"""Async Get volume info. Not currently supported."""
+ # pylint: disable = W0613
return None
async def set_volume_level(self, volume):
"""Async Set volume level. Not currently supported."""
+ # pylint: disable = W0613
# api_volume = str(int(round(volume * 100)))
return 0
@@ -1032,7 +1067,9 @@ async def get_app_list(self, log_errors=True) -> dict:
"""
return_values = {}
- response = await self._req_json("ZidooControlCenter/Apps/getApps", log_errors=log_errors)
+ response = await self._req_json(
+ "ZidooControlCenter/Apps/getApps", log_errors=log_errors
+ )
if response is not None and response.get("status") == 200:
for result in response["apps"]:
@@ -1054,12 +1091,16 @@ async def start_app(self, app_name: str, log_errors=True) -> bool:
if len(self._app_list) == 0:
self._app_list = await self.get_app_list(log_errors)
if app_name in self._app_list:
- return await self._start_app(self._app_list[app_name], log_errors=log_errors)
+ return await self._start_app(
+ self._app_list[app_name]
+ )
return False
- async def _start_app(self, app_id, log_errors=True) -> bool:
+ async def _start_app(self, app_id) -> bool:
"""Async Start an app by package name."""
- response = await self._req_json("ZidooControlCenter/Apps/openApp?packageName={}".format(app_id))
+ response = await self._req_json(
+ f"ZidooControlCenter/Apps/openApp?packageName={app_id}"
+ )
if response is not None and response.get("status") == 200:
return True
@@ -1092,20 +1133,20 @@ async def get_movie_list(self, filter_type=-1, max_count=DEFAULT_COUNT) -> json:
raw API response if successful
"""
- def byId(e):
+ def by_id(e):
return e["id"]
if filter_type in ZVIDEO_FILTER_TYPES:
- filter_type = ZVIDEO_FILTER_TYPES[filter_type]
+ filter_type = ZVIDEO_FILTER_TYPES.get(filter_type, None)
# v2 http://{{host}}/Poster/v2/getAggregations?type=0&start=0&count=40
response = await self._req_json(
- "ZidooPoster/getVideoList?page=1&pagesize={}&type={}".format(max_count, filter_type)
+ f"ZidooPoster/getVideoList?page=1&pagesize={max_count}&type={filter_type}"
)
if response is not None and response.get("status") == 200:
if filter_type in {10, 11}:
- response["data"].sort(key=byId, reverse=True)
+ response["data"].sort(key=by_id, reverse=True)
return response
async def get_collection_list(self, movie_id) -> json:
@@ -1118,7 +1159,9 @@ async def get_collection_list(self, movie_id) -> json:
json
raw API response if successful
"""
- response = await self._req_json("ZidooPoster/getCollection?id={}".format(movie_id))
+ response = await self._req_json(
+ f"ZidooPoster/getCollection?id={movie_id}"
+ )
if response is not None and response.get("status") == 200:
return response
@@ -1134,7 +1177,7 @@ async def get_movie_details(self, movie_id: int) -> json:
raw API response (no status)
"""
# v1 response = self._req_json("ZidooPoster/getDetail?id={}".format(movie_id))
- response = await self._req_json("Poster/v2/getDetail?id={}".format(movie_id))
+ response = await self._req_json(f"Poster/v2/getDetail?id={movie_id}")
if response is not None: # and response.get("status") == 200:
return response
@@ -1150,7 +1193,7 @@ async def get_episode_list(self, season_id: int) -> json:
raw API episode list if successful
"""
- def byEpisode(e):
+ def by_episode(e):
return e["aggregation"]["episodeNumber"]
response = await self.get_movie_details(season_id)
@@ -1164,7 +1207,7 @@ def byEpisode(e):
episodes = result.get("aggregations")
if episodes is not None:
- episodes.sort(key=byEpisode)
+ episodes.sort(key=by_episode)
return episodes
async def _collection_video_id(self, movie_id: int) -> int:
@@ -1177,7 +1220,9 @@ async def _collection_video_id(self, movie_id: int) -> int:
return result["aggregationId"]
return movie_id
- async def get_music_list(self, music_type: int = 0, music_id: int = None, max_count: int = DEFAULT_COUNT) -> json:
+ async def get_music_list(
+ self, music_type: int = 0, music_id: int = None, max_count: int = DEFAULT_COUNT
+ ) -> json:
"""Async Return list of music.
Parameters
@@ -1191,9 +1236,9 @@ async def get_music_list(self, music_type: int = 0, music_id: int = None, max_co
"""
if music_type == ZMEDIA_TYPE_ARTIST:
return await self._get_artist_list(music_id, max_count)
- elif music_type == ZMEDIA_TYPE_ALBUM:
+ if music_type == ZMEDIA_TYPE_ALBUM:
return await self._get_album_list(music_id, max_count)
- elif music_type == ZMEDIA_TYPE_PLAYLIST:
+ if music_type == ZMEDIA_TYPE_PLAYLIST:
return await self._get_playlist_list(music_id, max_count)
return await self._get_song_list(max_count)
@@ -1207,13 +1252,17 @@ async def _get_song_list(self, max_count: int = DEFAULT_COUNT) -> json:
json
raw API response if successful
"""
- response = await self._req_json("MusicControl/v2/getSingleMusics?start=0&count={}".format(max_count))
+ response = await self._req_json(
+ f"MusicControl/v2/getSingleMusics?start=0&count={max_count}"
+ )
self._song_list = self._get_music_ids(response.get("array"))
if response is not None:
return response
- async def _get_album_list(self, album_id: int = None, max_count: int = DEFAULT_COUNT) -> json:
+ async def _get_album_list(
+ self, album_id: int = None, max_count: int = DEFAULT_COUNT
+ ) -> json:
"""Async Return list of albums or album music.
Parameters
@@ -1227,15 +1276,19 @@ async def _get_album_list(self, album_id: int = None, max_count: int = DEFAULT_C
"""
if album_id:
response = await self._req_json(
- "MusicControl/v2/getAlbumMusics?id={}&start=0&count={}".format(album_id, max_count)
+ f"MusicControl/v2/getAlbumMusics?id={album_id}&start=0&count={max_count}"
)
else:
- response = await self._req_json("MusicControl/v2/getAlbums?start=0&count={}".format(max_count))
+ response = await self._req_json(
+ f"MusicControl/v2/getAlbums?start=0&count={max_count}"
+ )
if response is not None:
return response
- async def _get_artist_list(self, artist_id: int = None, max_count: int = DEFAULT_COUNT) -> json:
+ async def _get_artist_list(
+ self, artist_id: int = None, max_count: int = DEFAULT_COUNT
+ ) -> json:
"""Async Return list of artists or artist music.
Parameters
@@ -1251,10 +1304,12 @@ async def _get_artist_list(self, artist_id: int = None, max_count: int = DEFAULT
"""
if artist_id:
response = await self._req_json(
- "MusicControl/v2/getArtistMusics?id={}&start=0&count={}".format(artist_id, max_count)
+ f"MusicControl/v2/getArtistMusics?id={artist_id}&start=0&count={max_count}"
)
else:
- response = await self._req_json("MusicControl/v2/getArtists?start=0&count={}".format(max_count))
+ response = await self._req_json(
+ f"MusicControl/v2/getArtists?start=0&count={max_count}"
+ )
if response is not None: # and response.get("status") == 200:
return response
@@ -1273,12 +1328,14 @@ async def _get_playlist_list(self, playlist_id=None, max_count=DEFAULT_COUNT):
"""
if playlist_id:
if playlist_id == "playing":
- response = await self._req_json("MusicControl/v2/getPlayQueue?start=0&count={}".format(max_count))
+ response = await self._req_json(
+ f"MusicControl/v2/getPlayQueue?start=0&count={max_count}"
+ )
if response:
self._song_list = self._get_music_ids(response.get("array"))
else:
response = await self._req_json(
- "MusicControl/v2/getSongListMusics?id={}&start=0&count={}".format(playlist_id, max_count)
+ f"MusicControl/v2/getSongListMusics?id={playlist_id}&start=0&count={max_count}"
)
else:
response = await self._req_json(
@@ -1289,7 +1346,9 @@ async def _get_playlist_list(self, playlist_id=None, max_count=DEFAULT_COUNT):
if response is not None:
return response
- async def search_movies(self, query: str, search_type: int = 0, max_count: int = DEFAULT_COUNT) -> json:
+ async def search_movies(
+ self, search_type: int | str = 0, max_count: int = DEFAULT_COUNT
+ ) -> json:
"""Async Return list of video based on query.
Parameters
@@ -1302,11 +1361,11 @@ async def search_movies(self, query: str, search_type: int = 0, max_count: int =
raw API response (no status)
"""
if search_type in ZVIDEO_SEARCH_TYPES:
- search_type = ZVIDEO_SEARCH_TYPES[search_type]
+ search_type = ZVIDEO_SEARCH_TYPES.get(search_type, 0)
# v1 "ZidooPoster/search?q={}&type={}&page=1&pagesize={}".format(query, filter_type, max_count)
response = await self._req_json(
- "Poster/v2/searchAggregation?q={}&type={}&start=0&count={}".format(query, search_type, max_count),
+ f"Poster/v2/searchAggregation?q={max_count}&type={search_type}&start=0&count={max_count}",
timeout=TIMEOUT_SEARCH,
)
@@ -1316,7 +1375,7 @@ async def search_movies(self, query: str, search_type: int = 0, max_count: int =
async def search_music(
self,
query: str,
- search_type: int = 0,
+ search_type: int | str = 0,
max_count: int = DEFAULT_COUNT,
play: bool = False,
) -> json:
@@ -1336,11 +1395,11 @@ async def search_music(
raw API response (no status)
"""
if search_type in ZMUSIC_SEARCH_TYPES:
- search_type = ZMUSIC_SEARCH_TYPES[search_type]
+ search_type = ZMUSIC_SEARCH_TYPES.get(search_type, 0)
if search_type == 1:
return await self._search_album(query, max_count)
- elif search_type == 2:
+ if search_type == 2:
return await self._search_artist(query, max_count)
response = await self._search_song(query, max_count)
if response:
@@ -1360,7 +1419,7 @@ async def _search_song(self, query: str, max_count: int = DEFAULT_COUNT) -> json
raw API response (no status)
"""
response = await self._req_json(
- "MusicControl/v2/searchMusic?key={}&start=0&count={}".format(query, max_count),
+ f"MusicControl/v2/searchMusic?key={query}&start=0&count={max_count}",
timeout=TIMEOUT_SEARCH,
)
@@ -1378,7 +1437,7 @@ async def _search_album(self, query: str, max_count: int = DEFAULT_COUNT) -> jso
raw API response (no status)
"""
response = await self._req_json(
- "MusicControl/v2/searchAlbum?key={}&start=0&count={}".format(query, max_count),
+ f"MusicControl/v2/searchAlbum?key={query}&start=0&count={max_count}",
timeout=TIMEOUT_SEARCH,
)
@@ -1396,7 +1455,7 @@ async def _search_artist(self, query: str, max_count: int = DEFAULT_COUNT) -> js
raw API response (no status)
"""
response = await self._req_json(
- "MusicControl/v2/searchArtist?key={}&start=0&count={}".format(query, max_count),
+ f"MusicControl/v2/searchArtist?key={query}&start=0&count={max_count}",
timeout=TIMEOUT_SEARCH,
)
@@ -1412,9 +1471,8 @@ async def play_file(self, uri: str) -> bool:
Returns
True if successful
"""
- url = "ZidooFileControl/openFile?path={}&videoplaymode={}".format(
- uri, 0
- ) # has issues with parsing for local files
+ url = f"ZidooFileControl/openFile?path={uri}&videoplaymode={0}"
+ # has issues with parsing for local files
response = await self._req_json(url)
@@ -1451,19 +1509,20 @@ async def play_stream(self, uri: str, media_type) -> bool:
Returns
True if successful
"""
+ # pylint: disable = W1405
# take major form mime type
if isinstance(media_type, str) and "/" in media_type:
media_type = media_type.split("/")[0]
if media_type in ZTYPE_MIMETYPE:
- media_type = ZTYPE_MIMETYPE[media_type]
+ media_type = ZTYPE_MIMETYPE.get(media_type)
# the res uri needs to be double quoted to protect keys etc.
# use safe='' in quote to force "/" quoting
uri = urllib.parse.quote(uri, safe="")
- upnp = "upnp://{}/{}?type={}&res={}".format(ZUPNP_SERVERNAME, VERSION, media_type, uri)
- url = "ZidooFileControl/v2/openFile?url={}".format(urllib.parse.quote(upnp, safe=""))
+ upnp = f"upnp://{ZUPNP_SERVERNAME}/{VERSION}?type={media_type}&res={uri}"
+ url = f"ZidooFileControl/v2/openFile?url={urllib.parse.quote(upnp, safe='')}"
_LOGGER.debug("Stream command %s", str(url))
response = await self._req_json(url)
@@ -1487,7 +1546,9 @@ async def play_movie(self, movie_id: int, video_type: int = -1) -> bool:
# print("Video id : {}".format(video_id))
# v2 http://{}/VideoPlay/playVideo?index=0
- response = await self._req_json("ZidooPoster/PlayVideo?id={}&type={}".format(movie_id, video_type))
+ response = await self._req_json(
+ f"ZidooPoster/PlayVideo?id={movie_id}&type={video_type}"
+ )
if response and response.get("status") == 200:
return True
@@ -1499,11 +1560,13 @@ def _get_music_ids(self, data, key="id", sub=None):
for item in data:
result = item.get(sub) if sub else item
if result:
- id = result.get(key)
- ids.append(str(id))
+ _id = result.get(key)
+ ids.append(str(_id))
return ids
- async def play_music(self, media_id: int = None, media_type: int = "music", music_id: int = None) -> bool:
+ async def play_music(
+ self, media_id: int = None, media_type: int = "music", music_id: int = None
+ ) -> bool:
"""Async Play video content by id.
Parameters
@@ -1516,17 +1579,15 @@ async def play_music(self, media_id: int = None, media_type: int = "music", musi
Returns
True if successfull
"""
+ # pylint: disable = W1405
if media_type in ZMUSIC_PLAYLISTTYPE and media_id != "playing":
response = await self._req_json(
- "MusicControl/v2/playMusic?type={}&id={}&musicId={}&music_type=0&trackIndex=1&sort=0".format(
- ZMUSIC_PLAYLISTTYPE[media_type], media_id, music_id
- )
+ f"MusicControl/v2/playMusic?type={ZMUSIC_PLAYLISTTYPE[media_type]}"
+ f"&id={media_id}&musicId={music_id}&music_type=0&trackIndex=1&sort=0"
)
else: # music
response = await self._req_json(
- "MusicControl/v2/playMusics?ids={}&musicId={}&trackIndex=-1".format(
- "%2C".join(self._song_list), music_id
- )
+ f"MusicControl/v2/playMusics?ids={'%2C'.join(self._song_list)}&musicId={music_id}&trackIndex=-1"
)
if response and response.get("status") == 200:
@@ -1558,7 +1619,9 @@ async def get_music_playlist(self, max_count: int = DEFAULT_COUNT) -> json:
Returns
raw api response if successful
"""
- response = await self._req_json("MusicControl/v2/getPlayQueue?start=0&count={}".format(max_count))
+ response = await self._req_json(
+ f"MusicControl/v2/getPlayQueue?start=0&count={max_count}"
+ )
if response is not None:
return response
@@ -1580,7 +1643,9 @@ async def get_file_list(self, uri: str, file_type: int = 0) -> json:
'length': length in ms
'modifyDate': linux date code
"""
- response = await self._req_json("ZidooFileControl/getFileList?path={}&type={}".format(uri, file_type))
+ response = await self._req_json(
+ f"ZidooFileControl/getFileList?path={uri}&type={file_type}"
+ )
if response is not None and response.get("status") == 200:
return response
@@ -1600,7 +1665,9 @@ async def get_host_list(self, uri: str, host_type: int = 1005) -> json:
'length': length in ms
'modifyDate': linux date code
"""
- response = await self._req_json("ZidooFileControl/getHost?path={}&type={}".format(uri, host_type))
+ response = await self._req_json(
+ f"ZidooFileControl/getHost?path={uri}&type={host_type}"
+ )
_LOGGER.debug("zidoo host list: %s", str(response))
return_value = {}
@@ -1618,7 +1685,9 @@ async def get_host_list(self, uri: str, host_type: int = 1005) -> json:
return_value["filelist"] = share_list
return return_value
- def generate_image_url(self, media_id: int, media_type: int, width: int = 400, height: int = None) -> str:
+ def generate_image_url(
+ self, media_id: int, media_type: int, width: int = 400, height: int = None
+ ) -> str:
"""Get link to thumbnail."""
if media_type in ZVIDEO_SEARCH_TYPES:
if height is None:
@@ -1627,9 +1696,14 @@ def generate_image_url(self, media_id: int, media_type: int, width: int = 400, h
if media_type in ZMUSIC_SEARCH_TYPES:
if height is None:
height = width
- return self._generate_music_image_url(media_id, ZMUSIC_SEARCH_TYPES[media_type], width, height)
+ return self._generate_music_image_url(
+ media_id, ZMUSIC_SEARCH_TYPES[media_type], width, height
+ )
+ return None
- def _generate_movie_image_url(self, movie_id: int, width: int = 400, height: int = 600) -> str:
+ def _generate_movie_image_url(
+ self, movie_id: int, width: int = 400, height: int = 600
+ ) -> str:
"""Get link to thumbnail.
Parameters
@@ -1643,11 +1717,14 @@ def _generate_movie_image_url(self, movie_id: int, width: int = 400, height: int
url for image
"""
# http://{}/Poster/v2/getPoster?id=66&w=60&h=30
- url = "http://{}/ZidooPoster/getFile/getPoster?id={}&w={}&h={}".format(self._host, movie_id, width, height)
+ url = f"http://{self._host}/ZidooPoster/getFile/getPoster?id={movie_id}&w={width}&h={height}"
return url
- def _generate_music_image_url(self, music_id: int, music_type: int = 0, width: int = 200, height: int = 200) -> str:
+ # pylint: disable = W0613
+ def _generate_music_image_url(
+ self, music_id: int, music_type: int = 0, width: int = 200, height: int = 200
+ ) -> str:
"""Get link to thumbnail.
Parameters
@@ -1660,13 +1737,9 @@ def _generate_music_image_url(self, music_id: int, music_type: int = 0, width: i
Returns
url for image
"""
- url = "http://{}/ZidooMusicControl/v2/getImage?id={}&music_type={}&type={}&target={}".format(
- self._host,
- music_id,
- ZMUSIC_IMAGETYPE[music_type],
- music_type,
- ZMUSIC_IMAGETARGET[music_type],
- )
+ url = (f"http://{self._host}/ZidooMusicControl/v2/getImage?id={music_id}"
+ f"&music_type={ZMUSIC_IMAGETYPE[music_type]}"
+ f"&type={music_type}&target={ZMUSIC_IMAGETARGET[music_type]}")
return url
@@ -1686,14 +1759,11 @@ def generate_current_image_url(self, width: int = 1080, height: int = 720) -> st
url = None
if self._current_source == ZCONTENT_VIDEO and self._video_id > 0:
- url = "http://{}/ZidooPoster/getFile/getBackdrop?id={}&w={}&h={}".format(
- self._host, self._video_id, width, height
- )
+ url = f"http://{self._host}/ZidooPoster/getFile/getBackdrop?id={self._video_id}&w={width}&h={height}"
if self._current_source == ZCONTENT_MUSIC and self._music_id > 0:
- url = "http://{}/ZidooMusicControl/v2/getImage?id={}&music_type={}&type=4&target=16".format(
- self._host, self._music_id, self._music_type
- )
+ url = (f"http://{self._host}/ZidooMusicControl/v2/getImage?"
+ f"id={self._music_id}&music_type={self._music_type}&type=4&target=16")
# _LOGGER.debug("zidoo getting current image: url-{}".format(url))
return url
@@ -1708,19 +1778,21 @@ async def turn_on(self):
async def turn_off(self, standby=False):
"""Async Turn off media player."""
- return await self._send_key(ZKEYS.ZKEY_POWER_STANDBY if standby else ZKEYS.ZKEY_POWER_OFF)
+ return await self.send_key(
+ ZKEYS.ZKEY_POWER_STANDBY if standby else ZKEYS.ZKEY_POWER_OFF
+ )
async def volume_up(self):
"""Async Volume up the media player."""
- return await self._send_key(ZKEYS.ZKEY_VOLUME_UP)
+ return await self.send_key(ZKEYS.ZKEY_VOLUME_UP)
async def volume_down(self):
"""Async Volume down media player."""
- return await self._send_key(ZKEYS.ZKEY_VOLUME_DOWN)
+ return await self.send_key(ZKEYS.ZKEY_VOLUME_DOWN)
async def mute_volume(self):
"""Async Send mute command."""
- return self._send_key(ZKEYS.ZKEY_MUTE)
+ return self.send_key(ZKEYS.ZKEY_MUTE)
async def media_play_pause(self):
"""Async Send play or Pause command."""
@@ -1728,39 +1800,36 @@ async def media_play_pause(self):
return await self.media_pause()
return await self.media_play()
- async def media_play(self):
+ async def media_play(self) -> any:
"""Async Send play command."""
# self._send_key(ZKEYS.ZKEY_OK)
if self._current_source == ZCONTENT_NONE and self._last_video_path:
return await self.play_file(self._last_video_path)
- elif self._current_source == ZCONTENT_MUSIC:
+ if self._current_source == ZCONTENT_MUSIC:
return await self._req_json("MusicControl/v2/playOrPause")
- return await self._send_key(ZKEYS.ZKEY_MEDIA_PLAY)
+ return await self.send_key(ZKEYS.ZKEY_MEDIA_PLAY)
async def media_pause(self):
"""Async Send media pause command to media player."""
if self._current_source == ZCONTENT_MUSIC:
return await self._req_json("MusicControl/v2/playOrPause")
- else:
- return await self._send_key(ZKEYS.ZKEY_MEDIA_PAUSE)
+ return await self.send_key(ZKEYS.ZKEY_MEDIA_PAUSE)
async def media_stop(self):
"""Async Send media pause command to media player."""
- return await self._send_key(ZKEYS.ZKEY_MEDIA_STOP)
+ return await self.send_key(ZKEYS.ZKEY_MEDIA_STOP)
async def media_next_track(self):
"""Async Send next track command."""
if self._current_source == ZCONTENT_MUSIC:
return await self._req_json("MusicControl/v2/playNext")
- else:
- return await self._send_key(ZKEYS.ZKEY_MEDIA_NEXT)
+ return await self.send_key(ZKEYS.ZKEY_MEDIA_NEXT)
async def media_previous_track(self):
"""Async Send the previous track command."""
if self._current_source == ZCONTENT_MUSIC:
return await self._req_json("MusicControl/v2/playLast")
- else:
- await self._send_key(ZKEYS.ZKEY_MEDIA_PREVIOUS)
+ await self.send_key(ZKEYS.ZKEY_MEDIA_PREVIOUS)
async def set_media_position(self, position):
"""Async Set the current playing position.
@@ -1783,14 +1852,18 @@ async def set_media_position(self, position):
async def _set_movie_position(self, position):
"""Async Set current position for video player."""
- response = await self._req_json("ZidooVideoPlay/seekTo?positon={}".format(int(position)))
+ response = await self._req_json(
+ f"ZidooVideoPlay/seekTo?positon={int(position)}"
+ )
if response is not None and response.get("status") == 200:
return response
async def _set_audio_position(self, position):
"""Async Set current position for music player."""
- response = await self._req_json("ZidooMusicControl/seekTo?time={}".format(int(position)))
+ response = await self._req_json(
+ f"ZidooMusicControl/seekTo?time={int(position)}"
+ )
if response is not None and response.get("status") == 200:
return response
diff --git a/requirements.txt b/requirements.txt
index 957ba97..7dc729e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,6 @@
pyee>=9.0
-ucapi==0.1.7
+ucapi==0.2.0
-logging~=0.4.9.6
-requests~=2.31.0
-ssdp~=1.3.0
-requests~=2.31.0
httpx~=0.27.0
defusedxml~=0.7.1
aiohttp~=3.9.3