Restyled by black
This commit is contained in:
20
docs/conf.py
20
docs/conf.py
@@ -16,41 +16,41 @@
|
|||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = 'librespot-python'
|
project = "librespot-python"
|
||||||
copyright = '2021, kokarare1212'
|
copyright = "2021, kokarare1212"
|
||||||
author = 'kokarare1212'
|
author = "kokarare1212"
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = ['recommonmark']
|
extensions = ["recommonmark"]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# 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
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
# This pattern also affects html_static_path and html_extra_path.
|
# 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 -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# 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,
|
# 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,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ['_static']
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
# -- Markdown ----------------------------------------------------------------
|
# -- Markdown ----------------------------------------------------------------
|
||||||
|
|
||||||
source_suffix = ['.rst', '.md']
|
source_suffix = [".rst", ".md"]
|
||||||
|
|
||||||
source_parsers = {
|
source_parsers = {
|
||||||
'.md': 'recommonmark.parser.CommonMarkParser',
|
".md": "recommonmark.parser.CommonMarkParser",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ class AlbumId(SpotifyId.SpotifyId):
|
|||||||
matcher = AlbumId._PATTERN.search(uri)
|
matcher = AlbumId._PATTERN.search(uri)
|
||||||
if matcher is not None:
|
if matcher is not None:
|
||||||
album_id = matcher.group(1)
|
album_id = matcher.group(1)
|
||||||
return AlbumId(
|
return AlbumId(Utils.bytes_to_hex(AlbumId._BASE62.decode(album_id, 16)))
|
||||||
Utils.bytes_to_hex(AlbumId._BASE62.decode(album_id, 16)))
|
|
||||||
else:
|
else:
|
||||||
raise TypeError("Not a Spotify album ID: {}.f".format(uri))
|
raise TypeError("Not a Spotify album ID: {}.f".format(uri))
|
||||||
|
|
||||||
@@ -33,7 +32,8 @@ class AlbumId(SpotifyId.SpotifyId):
|
|||||||
|
|
||||||
def to_mercury_uri(self) -> str:
|
def to_mercury_uri(self) -> str:
|
||||||
return "spotify:album:{}".format(
|
return "spotify:album:{}".format(
|
||||||
AlbumId._BASE62.encode(Utils.hex_to_bytes(self._hexId)))
|
AlbumId._BASE62.encode(Utils.hex_to_bytes(self._hexId))
|
||||||
|
)
|
||||||
|
|
||||||
def hex_id(self) -> str:
|
def hex_id(self) -> str:
|
||||||
return self._hexId
|
return self._hexId
|
||||||
|
|||||||
@@ -17,15 +17,13 @@ class ArtistId(SpotifyId.SpotifyId):
|
|||||||
matcher = ArtistId._PATTERN.search(uri)
|
matcher = ArtistId._PATTERN.search(uri)
|
||||||
if matcher is not None:
|
if matcher is not None:
|
||||||
artist_id = matcher.group(1)
|
artist_id = matcher.group(1)
|
||||||
return ArtistId(
|
return ArtistId(Utils.bytes_to_hex(ArtistId._BASE62.decode(artist_id, 16)))
|
||||||
Utils.bytes_to_hex(ArtistId._BASE62.decode(artist_id, 16)))
|
|
||||||
else:
|
else:
|
||||||
raise TypeError("Not a Spotify artist ID: {}".format(uri))
|
raise TypeError("Not a Spotify artist ID: {}".format(uri))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_base62(base62: str) -> ArtistId:
|
def from_base62(base62: str) -> ArtistId:
|
||||||
return ArtistId(Utils.bytes_to_hex(ArtistId._BASE62.decode(base62,
|
return ArtistId(Utils.bytes_to_hex(ArtistId._BASE62.decode(base62, 16)))
|
||||||
16)))
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_hex(hex_str: str) -> ArtistId:
|
def from_hex(hex_str: str) -> ArtistId:
|
||||||
@@ -36,7 +34,8 @@ class ArtistId(SpotifyId.SpotifyId):
|
|||||||
|
|
||||||
def to_spotify_uri(self) -> str:
|
def to_spotify_uri(self) -> str:
|
||||||
return "spotify:artist:{}".format(
|
return "spotify:artist:{}".format(
|
||||||
ArtistId._BASE62.encode(Utils.hex_to_bytes(self._hexId)))
|
ArtistId._BASE62.encode(Utils.hex_to_bytes(self._hexId))
|
||||||
|
)
|
||||||
|
|
||||||
def hex_id(self) -> str:
|
def hex_id(self) -> str:
|
||||||
return self._hexId
|
return self._hexId
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ class ShowId(SpotifyId.SpotifyId):
|
|||||||
matcher = ShowId._PATTERN.search(uri)
|
matcher = ShowId._PATTERN.search(uri)
|
||||||
if matcher is not None:
|
if matcher is not None:
|
||||||
show_id = matcher.group(1)
|
show_id = matcher.group(1)
|
||||||
return ShowId(
|
return ShowId(Utils.bytes_to_hex(ShowId._BASE62.decode(show_id, 16)))
|
||||||
Utils.bytes_to_hex(ShowId._BASE62.decode(show_id, 16)))
|
|
||||||
else:
|
else:
|
||||||
raise TypeError("Not a Spotify show ID: {}".format(uri))
|
raise TypeError("Not a Spotify show ID: {}".format(uri))
|
||||||
|
|
||||||
@@ -35,7 +34,8 @@ class ShowId(SpotifyId.SpotifyId):
|
|||||||
|
|
||||||
def to_spotify_uri(self) -> str:
|
def to_spotify_uri(self) -> str:
|
||||||
return "spotify:show:{}".format(
|
return "spotify:show:{}".format(
|
||||||
ShowId._BASE62.encode(Utils.hex_to_bytes(self._hexId)))
|
ShowId._BASE62.encode(Utils.hex_to_bytes(self._hexId))
|
||||||
|
)
|
||||||
|
|
||||||
def hex_id(self) -> str:
|
def hex_id(self) -> str:
|
||||||
return self._hexId
|
return self._hexId
|
||||||
|
|||||||
@@ -17,15 +17,13 @@ class TrackId(PlayableId, SpotifyId):
|
|||||||
search = TrackId._PATTERN.search(uri)
|
search = TrackId._PATTERN.search(uri)
|
||||||
if search is not None:
|
if search is not None:
|
||||||
track_id = search.group(1)
|
track_id = search.group(1)
|
||||||
return TrackId(
|
return TrackId(Utils.bytes_to_hex(PlayableId.BASE62.decode(track_id, 16)))
|
||||||
Utils.bytes_to_hex(PlayableId.BASE62.decode(track_id, 16)))
|
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Not a Spotify track ID: {}".format(uri))
|
raise RuntimeError("Not a Spotify track ID: {}".format(uri))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_base62(base62: str) -> TrackId:
|
def from_base62(base62: str) -> TrackId:
|
||||||
return TrackId(Utils.bytes_to_hex(PlayableId.BASE62.decode(base62,
|
return TrackId(Utils.bytes_to_hex(PlayableId.BASE62.decode(base62, 16)))
|
||||||
16)))
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_hex(hex_str: str) -> TrackId:
|
def from_hex(hex_str: str) -> TrackId:
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ class Player(Closeable, PlayerSession.Listener, AudioSink.Listener):
|
|||||||
self._init_state()
|
self._init_state()
|
||||||
|
|
||||||
def _init_state(self):
|
def _init_state(self):
|
||||||
self._state = StateWrapper.StateWrapper(self._session, self,
|
self._state = StateWrapper.StateWrapper(self._session, self, self._conf)
|
||||||
self._conf)
|
|
||||||
|
|
||||||
class Anonymous(DeviceStateHandler.Listener):
|
class Anonymous(DeviceStateHandler.Listener):
|
||||||
_player: Player = None
|
_player: Player = None
|
||||||
@@ -46,10 +45,12 @@ class Player(Closeable, PlayerSession.Listener, AudioSink.Listener):
|
|||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def command(self, endpoint: DeviceStateHandler.Endpoint,
|
def command(
|
||||||
data: DeviceStateHandler.CommandBody) -> None:
|
self,
|
||||||
self._player._LOGGER.debug(
|
endpoint: DeviceStateHandler.Endpoint,
|
||||||
"Received command: {}".format(endpoint))
|
data: DeviceStateHandler.CommandBody,
|
||||||
|
) -> None:
|
||||||
|
self._player._LOGGER.debug("Received command: {}".format(endpoint))
|
||||||
|
|
||||||
self._deviceStateListener = Anonymous(self)
|
self._deviceStateListener = Anonymous(self)
|
||||||
self._state.add_listener(self._deviceStateListener)
|
self._state.add_listener(self._deviceStateListener)
|
||||||
|
|||||||
@@ -4,7 +4,12 @@ from librespot.dealer import DealerClient
|
|||||||
from librespot.player import Player, PlayerConfiguration
|
from librespot.player import Player, PlayerConfiguration
|
||||||
from librespot.player.state import DeviceStateHandler
|
from librespot.player.state import DeviceStateHandler
|
||||||
from librespot.proto import Connect
|
from librespot.proto import Connect
|
||||||
from librespot.proto.Player import ContextPlayerOptions, PlayerState, Restrictions, Suppressions
|
from librespot.proto.Player import (
|
||||||
|
ContextPlayerOptions,
|
||||||
|
PlayerState,
|
||||||
|
Restrictions,
|
||||||
|
Suppressions,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class StateWrapper(DeviceStateHandler.Listener, DealerClient.MessageListener):
|
class StateWrapper(DeviceStateHandler.Listener, DealerClient.MessageListener):
|
||||||
@@ -13,8 +18,7 @@ class StateWrapper(DeviceStateHandler.Listener, DealerClient.MessageListener):
|
|||||||
_player: Player = None
|
_player: Player = None
|
||||||
_device: DeviceStateHandler = None
|
_device: DeviceStateHandler = None
|
||||||
|
|
||||||
def __init__(self, session: Session, player: Player,
|
def __init__(self, session: Session, player: Player, conf: PlayerConfiguration):
|
||||||
conf: PlayerConfiguration):
|
|
||||||
self._session = session
|
self._session = session
|
||||||
self._player = player
|
self._player = player
|
||||||
self._device = DeviceStateHandler(session, self, conf)
|
self._device = DeviceStateHandler(session, self, conf)
|
||||||
@@ -22,27 +26,30 @@ class StateWrapper(DeviceStateHandler.Listener, DealerClient.MessageListener):
|
|||||||
|
|
||||||
self._device.add_listener(self)
|
self._device.add_listener(self)
|
||||||
self._session.dealer().add_message_listener(
|
self._session.dealer().add_message_listener(
|
||||||
self, "spotify:user:attributes:update", "hm://playlist/",
|
self,
|
||||||
"hm://collection/collection/" + self._session.username() + "/json")
|
"spotify:user:attributes:update",
|
||||||
|
"hm://playlist/",
|
||||||
|
"hm://collection/collection/" + self._session.username() + "/json",
|
||||||
|
)
|
||||||
|
|
||||||
def _init_state(self) -> PlayerState:
|
def _init_state(self) -> PlayerState:
|
||||||
return PlayerState(playback_speed=1.0,
|
return PlayerState(
|
||||||
suppressions=Suppressions(),
|
playback_speed=1.0,
|
||||||
context_restrictions=Restrictions(),
|
suppressions=Suppressions(),
|
||||||
options=ContextPlayerOptions(
|
context_restrictions=Restrictions(),
|
||||||
repeating_context=False,
|
options=ContextPlayerOptions(
|
||||||
shuffling_context=False,
|
repeating_context=False, shuffling_context=False, repeating_track=False
|
||||||
repeating_track=False),
|
),
|
||||||
position_as_of_timestamp=0,
|
position_as_of_timestamp=0,
|
||||||
position=0,
|
position=0,
|
||||||
is_playing=False)
|
is_playing=False,
|
||||||
|
)
|
||||||
|
|
||||||
def add_listener(self, listener: DeviceStateHandler.Listener):
|
def add_listener(self, listener: DeviceStateHandler.Listener):
|
||||||
self._device.add_listener(listener)
|
self._device.add_listener(listener)
|
||||||
|
|
||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
self._device.update_state(Connect.PutStateReason.NEW_DEVICE, 0,
|
self._device.update_state(Connect.PutStateReason.NEW_DEVICE, 0, self._state)
|
||||||
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
|
pass
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ from librespot.player import PlayerConfiguration
|
|||||||
|
|
||||||
|
|
||||||
class AudioSink:
|
class AudioSink:
|
||||||
def __init__(self, conf: PlayerConfiguration,
|
def __init__(self, conf: PlayerConfiguration, listener: AudioSink.Listener):
|
||||||
listener: AudioSink.Listener):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Listener:
|
class Listener:
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ class DeviceStateHandler:
|
|||||||
_deviceInfo: Connect.DeviceInfo = None
|
_deviceInfo: Connect.DeviceInfo = None
|
||||||
_listeners: list[DeviceStateHandler.Listener] = list()
|
_listeners: list[DeviceStateHandler.Listener] = list()
|
||||||
_putState: Connect.PutStateRequest = None
|
_putState: Connect.PutStateRequest = None
|
||||||
_putStateWorker: concurrent.futures.ThreadPoolExecutor = concurrent.futures.ThreadPoolExecutor(
|
_putStateWorker: concurrent.futures.ThreadPoolExecutor = (
|
||||||
|
concurrent.futures.ThreadPoolExecutor()
|
||||||
)
|
)
|
||||||
_connectionId: str = None
|
_connectionId: str = None
|
||||||
|
|
||||||
@@ -30,11 +31,11 @@ class DeviceStateHandler:
|
|||||||
def _update_connection_id(self, newer: str) -> None:
|
def _update_connection_id(self, newer: str) -> None:
|
||||||
newer = urllib.parse.unquote(newer, "UTF-8")
|
newer = urllib.parse.unquote(newer, "UTF-8")
|
||||||
|
|
||||||
if self._connectionId is None or \
|
if self._connectionId is None or self._connectionId != newer:
|
||||||
self._connectionId != newer:
|
|
||||||
self._connectionId = newer
|
self._connectionId = newer
|
||||||
self._LOGGER.debug("Updated Spotify-Connection-Id: {}".format(
|
self._LOGGER.debug(
|
||||||
self._connectionId))
|
"Updated Spotify-Connection-Id: {}".format(self._connectionId)
|
||||||
|
)
|
||||||
self._notify_ready()
|
self._notify_ready()
|
||||||
|
|
||||||
def add_listener(self, listener: DeviceStateHandler.Listener):
|
def add_listener(self, listener: DeviceStateHandler.Listener):
|
||||||
@@ -44,8 +45,12 @@ class DeviceStateHandler:
|
|||||||
for listener in self._listeners:
|
for listener in self._listeners:
|
||||||
listener.ready()
|
listener.ready()
|
||||||
|
|
||||||
def update_state(self, reason: Connect.PutStateReason, player_time: int,
|
def update_state(
|
||||||
state: Player.PlayerState):
|
self,
|
||||||
|
reason: Connect.PutStateReason,
|
||||||
|
player_time: int,
|
||||||
|
state: Player.PlayerState,
|
||||||
|
):
|
||||||
if self._connectionId is None:
|
if self._connectionId is None:
|
||||||
raise TypeError()
|
raise TypeError()
|
||||||
|
|
||||||
@@ -63,10 +68,13 @@ class DeviceStateHandler:
|
|||||||
|
|
||||||
def _put_connect_state(self, req: Connect.PutStateRequest):
|
def _put_connect_state(self, req: Connect.PutStateRequest):
|
||||||
self._session.api().put_connect_state(self._connectionId, req)
|
self._session.api().put_connect_state(self._connectionId, req)
|
||||||
self._LOGGER.info("Put state. ts: {}, connId: {}, reason: {}".format(
|
self._LOGGER.info(
|
||||||
req.client_side_timestamp,
|
"Put state. ts: {}, connId: {}, reason: {}".format(
|
||||||
Utils.truncate_middle(self._connectionId, 10),
|
req.client_side_timestamp,
|
||||||
req.put_state_reason))
|
Utils.truncate_middle(self._connectionId, 10),
|
||||||
|
req.put_state_reason,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
class Endpoint(enum.Enum):
|
class Endpoint(enum.Enum):
|
||||||
Play: str = "play"
|
Play: str = "play"
|
||||||
@@ -80,8 +88,11 @@ class DeviceStateHandler:
|
|||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def command(self, endpoint: DeviceStateHandler.Endpoint,
|
def command(
|
||||||
data: DeviceStateHandler.CommandBody) -> None:
|
self,
|
||||||
|
endpoint: DeviceStateHandler.Endpoint,
|
||||||
|
data: DeviceStateHandler.CommandBody,
|
||||||
|
) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def volume_changed(self) -> None:
|
def volume_changed(self) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user