diff --git a/docs/conf.py b/docs/conf.py index ba45e19..83e0082 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,9 +3,7 @@ # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html - # -- Path setup -------------------------------------------------------------- - # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -13,50 +11,43 @@ # import os # import sys # sys.path.insert(0, os.path.abspath('.')) - # -- Project information ----------------------------------------------------- -project = 'librespot-python' -copyright = '2021, kokarare1212' -author = 'kokarare1212' - +project = "librespot-python" +copyright = "2021, kokarare1212" +author = "kokarare1212" # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ - 'recommonmark' -] +extensions = ["recommonmark"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - +html_static_path = ["_static"] # -- Markdown ---------------------------------------------------------------- -source_suffix = ['.rst', '.md'] +source_suffix = [".rst", ".md"] source_parsers = { - '.md': 'recommonmark.parser.CommonMarkParser', + ".md": "recommonmark.parser.CommonMarkParser", } - diff --git a/librespot/metadata/AlbumId.py b/librespot/metadata/AlbumId.py index c5b2872..894b9b6 100644 --- a/librespot/metadata/AlbumId.py +++ b/librespot/metadata/AlbumId.py @@ -1,9 +1,11 @@ from __future__ import annotations -from librespot.common import Base62, Utils -from librespot.metadata import SpotifyId import re +from librespot.common import Base62 +from librespot.common import Utils +from librespot.metadata import SpotifyId + class AlbumId(SpotifyId.SpotifyId): _PATTERN = re.compile(r"spotify:album:(.{22})") @@ -25,8 +27,7 @@ class AlbumId(SpotifyId.SpotifyId): @staticmethod def from_base62(base62: str) -> AlbumId: - return AlbumId( - Utils.bytes_to_hex(AlbumId._BASE62.decode(base62, 16))) + return AlbumId(Utils.bytes_to_hex(AlbumId._BASE62.decode(base62, 16))) @staticmethod def from_hex(hex_str: str) -> AlbumId: diff --git a/librespot/metadata/ArtistId.py b/librespot/metadata/ArtistId.py index 1c30128..0eb0513 100644 --- a/librespot/metadata/ArtistId.py +++ b/librespot/metadata/ArtistId.py @@ -1,8 +1,11 @@ from __future__ import annotations -from librespot.common import Base62, Utils -from librespot.metadata import SpotifyId + import re +from librespot.common import Base62 +from librespot.common import Utils +from librespot.metadata import SpotifyId + class ArtistId(SpotifyId.SpotifyId): _PATTERN = re.compile("spotify:artist:(.{22})") @@ -18,15 +21,14 @@ class ArtistId(SpotifyId.SpotifyId): if matcher is not None: artist_id = matcher.group(1) return ArtistId( - Utils.bytes_to_hex(ArtistId._BASE62.decode( - artist_id, 16))) + Utils.bytes_to_hex(ArtistId._BASE62.decode(artist_id, 16))) else: raise TypeError("Not a Spotify artist ID: {}".format(uri)) @staticmethod def from_base62(base62: str) -> ArtistId: - return ArtistId( - Utils.bytes_to_hex(ArtistId._BASE62.decode(base62, 16))) + return ArtistId(Utils.bytes_to_hex(ArtistId._BASE62.decode(base62, + 16))) @staticmethod def from_hex(hex_str: str) -> ArtistId: diff --git a/librespot/metadata/ShowId.py b/librespot/metadata/ShowId.py index d6c2a7f..3678926 100644 --- a/librespot/metadata/ShowId.py +++ b/librespot/metadata/ShowId.py @@ -1,8 +1,11 @@ from __future__ import annotations -from librespot.common import Base62, Utils -from librespot.metadata import SpotifyId + import re +from librespot.common import Base62 +from librespot.common import Utils +from librespot.metadata import SpotifyId + class ShowId(SpotifyId.SpotifyId): _PATTERN = re.compile("spotify:show:(.{22})") @@ -24,8 +27,7 @@ class ShowId(SpotifyId.SpotifyId): @staticmethod def from_base62(base62: str) -> ShowId: - return ShowId( - Utils.bytes_to_hex(ShowId._BASE62.decode(base62, 16))) + return ShowId(Utils.bytes_to_hex(ShowId._BASE62.decode(base62, 16))) @staticmethod def from_hex(hex_str: str) -> ShowId: diff --git a/librespot/metadata/TrackId.py b/librespot/metadata/TrackId.py index 69fb6a2..fa29b2d 100644 --- a/librespot/metadata/TrackId.py +++ b/librespot/metadata/TrackId.py @@ -1,8 +1,10 @@ from __future__ import annotations + +import re + from librespot.common import Utils from librespot.metadata import SpotifyId from librespot.metadata.PlayableId import PlayableId -import re class TrackId(PlayableId, SpotifyId): @@ -18,15 +20,14 @@ class TrackId(PlayableId, SpotifyId): if search is not None: track_id = search.group(1) return TrackId( - Utils.bytes_to_hex(PlayableId.BASE62.decode( - track_id, 16))) + Utils.bytes_to_hex(PlayableId.BASE62.decode(track_id, 16))) else: raise RuntimeError("Not a Spotify track ID: {}".format(uri)) @staticmethod def from_base62(base62: str) -> TrackId: - return TrackId( - Utils.bytes_to_hex(PlayableId.BASE62.decode(base62, 16))) + return TrackId(Utils.bytes_to_hex(PlayableId.BASE62.decode(base62, + 16))) @staticmethod def from_hex(hex_str: str) -> TrackId: diff --git a/librespot/player/Player.py b/librespot/player/Player.py index 6e34420..20e5d12 100644 --- a/librespot/player/Player.py +++ b/librespot/player/Player.py @@ -1,14 +1,17 @@ from __future__ import annotations + +import logging +import sched +import time + from librespot.core.Session import Session -from librespot.player import PlayerConfiguration, StateWrapper +from librespot.player import PlayerConfiguration +from librespot.player import StateWrapper from librespot.player.metrics import PlaybackMetrics from librespot.player.mixing import AudioSink from librespot.player.playback.PlayerSession import PlayerSession from librespot.player.state.DeviceStateHandler import DeviceStateHandler from librespot.standard.Closeable import Closeable -import logging -import sched -import time class Player(Closeable, PlayerSession.Listener, AudioSink.Listener): @@ -34,7 +37,8 @@ class Player(Closeable, PlayerSession.Listener, AudioSink.Listener): self._init_state() def _init_state(self): - self._state = StateWrapper.StateWrapper(self._session, self, self._conf) + self._state = StateWrapper.StateWrapper(self._session, self, + self._conf) class Anonymous(DeviceStateHandler.Listener): _player: Player = None @@ -45,8 +49,13 @@ class Player(Closeable, PlayerSession.Listener, AudioSink.Listener): def ready(self) -> None: pass - def command(self, endpoint: DeviceStateHandler.Endpoint, data: DeviceStateHandler.CommandBody) -> None: - self._player._LOGGER.debug("Received command: {}".format(endpoint)) + def command( + self, + endpoint: DeviceStateHandler.Endpoint, + data: DeviceStateHandler.CommandBody, + ) -> None: + self._player._LOGGER.debug( + "Received command: {}".format(endpoint)) self._deviceStateListener = Anonymous(self) self._state.add_listener(self._deviceStateListener) diff --git a/librespot/player/StateWrapper.py b/librespot/player/StateWrapper.py index f46f768..56785a6 100644 --- a/librespot/player/StateWrapper.py +++ b/librespot/player/StateWrapper.py @@ -1,10 +1,15 @@ from __future__ import annotations + from librespot.core import Session from librespot.dealer import DealerClient -from librespot.player import Player, PlayerConfiguration +from librespot.player import Player +from librespot.player import PlayerConfiguration from librespot.player.state import DeviceStateHandler from librespot.proto import Connect -from librespot.proto.Player import ContextPlayerOptions, PlayerState, Restrictions, Suppressions +from librespot.proto.Player import ContextPlayerOptions +from librespot.proto.Player import PlayerState +from librespot.proto.Player import Restrictions +from librespot.proto.Player import Suppressions class StateWrapper(DeviceStateHandler.Listener, DealerClient.MessageListener): @@ -21,29 +26,32 @@ class StateWrapper(DeviceStateHandler.Listener, DealerClient.MessageListener): self._state = self._init_state() self._device.add_listener(self) - self._session.dealer().add_message_listener(self, "spotify:user:attributes:update", "hm://playlist/", "hm://collection/collection/" + self._session.username() + "/json") + self._session.dealer().add_message_listener( + self, + "spotify:user:attributes:update", + "hm://playlist/", + "hm://collection/collection/" + self._session.username() + "/json", + ) def _init_state(self) -> PlayerState: return PlayerState( playback_speed=1.0, suppressions=Suppressions(), context_restrictions=Restrictions(), - options=ContextPlayerOptions( - repeating_context=False, - shuffling_context=False, - repeating_track=False - ), + options=ContextPlayerOptions(repeating_context=False, + shuffling_context=False, + repeating_track=False), position_as_of_timestamp=0, position=0, - is_playing=False + is_playing=False, ) def add_listener(self, listener: DeviceStateHandler.Listener): self._device.add_listener(listener) def ready(self) -> None: - self._device.update_state(Connect.PutStateReason.NEW_DEVICE, 0, self._state) + self._device.update_state(Connect.PutStateReason.NEW_DEVICE, 0, + self._state) - def on_message(self, uri: str, headers: dict[str, str], - payload: bytes): + def on_message(self, uri: str, headers: dict[str, str], payload: bytes): pass diff --git a/librespot/player/mixing/AudioSink.py b/librespot/player/mixing/AudioSink.py index 5e4234b..716c68e 100644 --- a/librespot/player/mixing/AudioSink.py +++ b/librespot/player/mixing/AudioSink.py @@ -1,9 +1,11 @@ from __future__ import annotations + from librespot.player import PlayerConfiguration class AudioSink: - def __init__(self, conf: PlayerConfiguration, listener: AudioSink.Listener): + def __init__(self, conf: PlayerConfiguration, + listener: AudioSink.Listener): pass class Listener: diff --git a/librespot/player/state/DeviceStateHandler.py b/librespot/player/state/DeviceStateHandler.py index 32216f6..71b8fe1 100644 --- a/librespot/player/state/DeviceStateHandler.py +++ b/librespot/player/state/DeviceStateHandler.py @@ -1,8 +1,5 @@ from __future__ import annotations -from librespot.common import Utils -from librespot.core import Session -from librespot.player import PlayerConfiguration -from librespot.proto import Connect, Player + import base64 import concurrent.futures import enum @@ -11,6 +8,12 @@ import time import typing import urllib.parse +from librespot.common import Utils +from librespot.core import Session +from librespot.player import PlayerConfiguration +from librespot.proto import Connect +from librespot.proto import Player + class DeviceStateHandler: _LOGGER: logging = logging.getLogger(__name__) @@ -18,7 +21,8 @@ class DeviceStateHandler: _deviceInfo: Connect.DeviceInfo = None _listeners: list[DeviceStateHandler.Listener] = list() _putState: Connect.PutStateRequest = None - _putStateWorker: concurrent.futures.ThreadPoolExecutor = concurrent.futures.ThreadPoolExecutor() + _putStateWorker: concurrent.futures.ThreadPoolExecutor = ( + concurrent.futures.ThreadPoolExecutor()) _connectionId: str = None def __init__(self, session: Session, player, conf: PlayerConfiguration): @@ -29,10 +33,10 @@ class DeviceStateHandler: def _update_connection_id(self, newer: str) -> None: newer = urllib.parse.unquote(newer, "UTF-8") - if self._connectionId is None or \ - self._connectionId != newer: + if self._connectionId is None or self._connectionId != newer: self._connectionId = newer - self._LOGGER.debug("Updated Spotify-Connection-Id: {}".format(self._connectionId)) + self._LOGGER.debug("Updated Spotify-Connection-Id: {}".format( + self._connectionId)) self._notify_ready() def add_listener(self, listener: DeviceStateHandler.Listener): @@ -42,7 +46,12 @@ class DeviceStateHandler: for listener in self._listeners: listener.ready() - def update_state(self, reason: Connect.PutStateReason, player_time: int, state: Player.PlayerState): + def update_state( + self, + reason: Connect.PutStateReason, + player_time: int, + state: Player.PlayerState, + ): if self._connectionId is None: raise TypeError() @@ -61,7 +70,9 @@ class DeviceStateHandler: def _put_connect_state(self, req: Connect.PutStateRequest): self._session.api().put_connect_state(self._connectionId, req) self._LOGGER.info("Put state. ts: {}, connId: {}, reason: {}".format( - req.client_side_timestamp, Utils.truncate_middle(self._connectionId, 10), req.put_state_reason + req.client_side_timestamp, + Utils.truncate_middle(self._connectionId, 10), + req.put_state_reason, )) class Endpoint(enum.Enum): @@ -76,7 +87,11 @@ class DeviceStateHandler: def ready(self) -> None: pass - def command(self, endpoint: DeviceStateHandler.Endpoint, data: DeviceStateHandler.CommandBody) -> None: + def command( + self, + endpoint: DeviceStateHandler.Endpoint, + data: DeviceStateHandler.CommandBody, + ) -> None: pass def volume_changed(self) -> None: