importing the compiled pb2 modules with alias
This commit is contained in:
parent
81cbd5a588
commit
3fcf78eb23
|
@ -11,7 +11,7 @@ from zeroconf import Zeroconf
|
||||||
from librespot.common import Utils
|
from librespot.common import Utils
|
||||||
from librespot.core import Session
|
from librespot.core import Session
|
||||||
from librespot.crypto import DiffieHellman
|
from librespot.crypto import DiffieHellman
|
||||||
from librespot.proto import Connect_pb2
|
from librespot.proto import Connect_pb2 as Connect
|
||||||
from librespot.standard import Closeable
|
from librespot.standard import Closeable
|
||||||
from librespot.standard import Runnable
|
from librespot.standard import Runnable
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class ZeroconfServer(Closeable):
|
||||||
)
|
)
|
||||||
|
|
||||||
class Inner:
|
class Inner:
|
||||||
device_type: Connect_pb2.DeviceType = None
|
device_type: Connect.DeviceType = None
|
||||||
device_name: str = None
|
device_name: str = None
|
||||||
device_id: str = None
|
device_id: str = None
|
||||||
preferred_locale: str = None
|
preferred_locale: str = None
|
||||||
|
@ -69,7 +69,7 @@ class ZeroconfServer(Closeable):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device_type: Connect_pb2.DeviceType,
|
device_type: Connect.DeviceType,
|
||||||
device_name: str,
|
device_name: str,
|
||||||
preferred_locale: str,
|
preferred_locale: str,
|
||||||
conf: Session.Configuration,
|
conf: Session.Configuration,
|
||||||
|
|
|
@ -12,8 +12,8 @@ from librespot.common.Utils import Utils
|
||||||
from librespot.core import Session
|
from librespot.core import Session
|
||||||
from librespot.metadata import PlayableId
|
from librespot.metadata import PlayableId
|
||||||
from librespot.metadata import TrackId
|
from librespot.metadata import TrackId
|
||||||
from librespot.proto import Metadata_pb2
|
from librespot.proto import Metadata_pb2 as Metadata
|
||||||
from librespot.proto import StorageResolve_pb2
|
from librespot.proto import StorageResolve_pb2 as StorageResolve
|
||||||
|
|
||||||
|
|
||||||
class PlayableContentFeeder:
|
class PlayableContentFeeder:
|
||||||
|
@ -26,7 +26,7 @@ class PlayableContentFeeder:
|
||||||
def __init__(self, session: Session):
|
def __init__(self, session: Session):
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|
||||||
def pick_alternative_if_necessary(self, track: Metadata_pb2.Track):
|
def pick_alternative_if_necessary(self, track: Metadata.Track):
|
||||||
if len(track.file) > 0:
|
if len(track.file) > 0:
|
||||||
return track
|
return track
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ class PlayableContentFeeder:
|
||||||
|
|
||||||
def resolve_storage_interactive(
|
def resolve_storage_interactive(
|
||||||
self, file_id: bytes,
|
self, file_id: bytes,
|
||||||
preload: bool) -> StorageResolve_pb2.StorageResolveResponse:
|
preload: bool) -> StorageResolve.StorageResolveResponse:
|
||||||
resp = self.session.api().send(
|
resp = self.session.api().send(
|
||||||
"GET",
|
"GET",
|
||||||
(self.STORAGE_RESOLVE_INTERACTIVE_PREFETCH
|
(self.STORAGE_RESOLVE_INTERACTIVE_PREFETCH
|
||||||
|
@ -65,13 +65,13 @@ class PlayableContentFeeder:
|
||||||
if body is None:
|
if body is None:
|
||||||
RuntimeError("Response body is empty!")
|
RuntimeError("Response body is empty!")
|
||||||
|
|
||||||
storage_resolve_response = StorageResolve_pb2.StorageResolveResponse()
|
storage_resolve_response = StorageResolve.StorageResolveResponse()
|
||||||
storage_resolve_response.ParseFromString(body)
|
storage_resolve_response.ParseFromString(body)
|
||||||
return storage_resolve_response
|
return storage_resolve_response
|
||||||
|
|
||||||
def load_track(
|
def load_track(
|
||||||
self,
|
self,
|
||||||
track_id_or_track: typing.Union[TrackId, Metadata_pb2.Track],
|
track_id_or_track: typing.Union[TrackId, Metadata.Track],
|
||||||
audio_quality_picker: AudioQualityPicker,
|
audio_quality_picker: AudioQualityPicker,
|
||||||
preload: bool,
|
preload: bool,
|
||||||
halt_listener: HaltListener,
|
halt_listener: HaltListener,
|
||||||
|
@ -94,9 +94,9 @@ class PlayableContentFeeder:
|
||||||
|
|
||||||
def load_stream(
|
def load_stream(
|
||||||
self,
|
self,
|
||||||
file: Metadata_pb2.AudioFile,
|
file: Metadata.AudioFile,
|
||||||
track: Metadata_pb2.Track,
|
track: Metadata.Track,
|
||||||
episode: Metadata_pb2.Episode,
|
episode: Metadata.Episode,
|
||||||
preload: bool,
|
preload: bool,
|
||||||
halt_lister: HaltListener,
|
halt_lister: HaltListener,
|
||||||
):
|
):
|
||||||
|
@ -104,41 +104,41 @@ class PlayableContentFeeder:
|
||||||
raise RuntimeError()
|
raise RuntimeError()
|
||||||
|
|
||||||
resp = self.resolve_storage_interactive(file.file_id, preload)
|
resp = self.resolve_storage_interactive(file.file_id, preload)
|
||||||
if resp.result == StorageResolve_pb2.StorageResolveResponse.Result.CDN:
|
if resp.result == StorageResolve.StorageResolveResponse.Result.CDN:
|
||||||
if track is not None:
|
if track is not None:
|
||||||
return CdnFeedHelper.load_track(self.session, track, file,
|
return CdnFeedHelper.load_track(self.session, track, file,
|
||||||
resp, preload, halt_lister)
|
resp, preload, halt_lister)
|
||||||
return CdnFeedHelper.load_episode(self.session, episode, file,
|
return CdnFeedHelper.load_episode(self.session, episode, file,
|
||||||
resp, preload, halt_lister)
|
resp, preload, halt_lister)
|
||||||
elif resp.result == StorageResolve_pb2.StorageResolveResponse.Result.STORAGE:
|
elif resp.result == StorageResolve.StorageResolveResponse.Result.STORAGE:
|
||||||
if track is None:
|
if track is None:
|
||||||
# return StorageFeedHelper
|
# return StorageFeedHelper
|
||||||
pass
|
pass
|
||||||
elif resp.result == StorageResolve_pb2.StorageResolveResponse.Result.RESTRICTED:
|
elif resp.result == StorageResolve.StorageResolveResponse.Result.RESTRICTED:
|
||||||
raise RuntimeError("Content is restricted!")
|
raise RuntimeError("Content is restricted!")
|
||||||
elif resp.result == StorageResolve_pb2.StorageResolveResponse.Response.UNRECOGNIZED:
|
elif resp.result == StorageResolve.StorageResolveResponse.Response.UNRECOGNIZED:
|
||||||
raise RuntimeError("Content is unrecognized!")
|
raise RuntimeError("Content is unrecognized!")
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unknown result: {}".format(resp.result))
|
raise RuntimeError("Unknown result: {}".format(resp.result))
|
||||||
|
|
||||||
class LoadedStream:
|
class LoadedStream:
|
||||||
episode: Metadata_pb2.Episode
|
episode: Metadata.Episode
|
||||||
track: Metadata_pb2.Track
|
track: Metadata.Track
|
||||||
input_stream: GeneralAudioStream
|
input_stream: GeneralAudioStream
|
||||||
normalization_data: NormalizationData
|
normalization_data: NormalizationData
|
||||||
metrics: PlayableContentFeeder.Metrics
|
metrics: PlayableContentFeeder.Metrics
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
track_or_episode: typing.Union[Metadata_pb2.Track, Metadata_pb2.Episode],
|
track_or_episode: typing.Union[Metadata.Track, Metadata.Episode],
|
||||||
input_stream: GeneralAudioStream,
|
input_stream: GeneralAudioStream,
|
||||||
normalization_data: NormalizationData,
|
normalization_data: NormalizationData,
|
||||||
metrics: PlayableContentFeeder.Metrics,
|
metrics: PlayableContentFeeder.Metrics,
|
||||||
):
|
):
|
||||||
if type(track_or_episode) is Metadata_pb2.Track:
|
if type(track_or_episode) is Metadata.Track:
|
||||||
self.track = track_or_episode
|
self.track = track_or_episode
|
||||||
self.episode = None
|
self.episode = None
|
||||||
elif type(track_or_episode) is Metadata_pb2.Episode:
|
elif type(track_or_episode) is Metadata.Episode:
|
||||||
self.track = None
|
self.track = None
|
||||||
self.episode = track_or_episode
|
self.episode = track_or_episode
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from librespot.common.Utils import Utils
|
from librespot.common.Utils import Utils
|
||||||
from librespot.proto import Metadata_pb2
|
from librespot.proto import Metadata_pb2 as Metadata
|
||||||
|
|
||||||
|
|
||||||
class StreamId:
|
class StreamId:
|
||||||
|
@ -7,8 +7,8 @@ class StreamId:
|
||||||
episode_gid: bytes = None
|
episode_gid: bytes = None
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
file: Metadata_pb2.AudioFile = None,
|
file: Metadata.AudioFile = None,
|
||||||
episode: Metadata_pb2.Episode = None):
|
episode: Metadata.Episode = None):
|
||||||
if file is None and episode is None:
|
if file is None and episode is None:
|
||||||
return
|
return
|
||||||
if file is not None:
|
if file is not None:
|
||||||
|
|
|
@ -10,23 +10,23 @@ from librespot.audio import NormalizationData
|
||||||
from librespot.audio import PlayableContentFeeder
|
from librespot.audio import PlayableContentFeeder
|
||||||
from librespot.common import Utils
|
from librespot.common import Utils
|
||||||
from librespot.core import Session
|
from librespot.core import Session
|
||||||
from librespot.proto import Metadata_pb2
|
from librespot.proto import Metadata_pb2 as Metadata
|
||||||
from librespot.proto import StorageResolve_pb2
|
from librespot.proto import StorageResolve_pb2 as StorageResolve
|
||||||
|
|
||||||
|
|
||||||
class CdnFeedHelper:
|
class CdnFeedHelper:
|
||||||
_LOGGER: logging = logging.getLogger(__name__)
|
_LOGGER: logging = logging.getLogger(__name__)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_url(resp: StorageResolve_pb2.StorageResolveResponse) -> str:
|
def get_url(resp: StorageResolve.StorageResolveResponse) -> str:
|
||||||
return random.choice(resp.cdnurl)
|
return random.choice(resp.cdnurl)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_track(
|
def load_track(
|
||||||
session: Session,
|
session: Session,
|
||||||
track: Metadata_pb2.Track,
|
track: Metadata.Track,
|
||||||
file: Metadata_pb2.AudioFile,
|
file: Metadata.AudioFile,
|
||||||
resp_or_url: typing.Union[StorageResolve_pb2.StorageResolveResponse, str],
|
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, str],
|
||||||
preload: bool,
|
preload: bool,
|
||||||
halt_listener: HaltListener,
|
halt_listener: HaltListener,
|
||||||
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
|
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
|
||||||
|
@ -54,7 +54,7 @@ class CdnFeedHelper:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_episode_external(
|
def load_episode_external(
|
||||||
session: Session, episode: Metadata_pb2.Episode,
|
session: Session, episode: Metadata.Episode,
|
||||||
halt_listener: HaltListener
|
halt_listener: HaltListener
|
||||||
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
|
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
|
||||||
resp = session.client().head(episode.external_url)
|
resp = session.client().head(episode.external_url)
|
||||||
|
@ -79,9 +79,9 @@ class CdnFeedHelper:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_episode(
|
def load_episode(
|
||||||
session: Session,
|
session: Session,
|
||||||
episode: Metadata_pb2.Episode,
|
episode: Metadata.Episode,
|
||||||
file: Metadata_pb2.AudioFile,
|
file: Metadata.AudioFile,
|
||||||
resp_or_url: typing.Union[StorageResolve_pb2.StorageResolveResponse, str],
|
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, str],
|
||||||
halt_listener: HaltListener,
|
halt_listener: HaltListener,
|
||||||
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
|
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
|
||||||
if type(resp_or_url) is str:
|
if type(resp_or_url) is str:
|
||||||
|
|
|
@ -17,14 +17,14 @@ from librespot.audio.decrypt import NoopAudioDecrypt
|
||||||
from librespot.audio.format import SuperAudioFormat
|
from librespot.audio.format import SuperAudioFormat
|
||||||
from librespot.audio.storage import ChannelManager
|
from librespot.audio.storage import ChannelManager
|
||||||
from librespot.common import Utils
|
from librespot.common import Utils
|
||||||
from librespot.proto import StorageResolve_pb2
|
from librespot.proto import StorageResolve_pb2 as StorageResolve
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from librespot.audio.decrypt.AudioDecrypt import AudioDecrypt
|
from librespot.audio.decrypt.AudioDecrypt import AudioDecrypt
|
||||||
from librespot.audio.HaltListener import HaltListener
|
from librespot.audio.HaltListener import HaltListener
|
||||||
from librespot.cache.CacheManager import CacheManager
|
from librespot.cache.CacheManager import CacheManager
|
||||||
from librespot.core.Session import Session
|
from librespot.core.Session import Session
|
||||||
from librespot.proto import Metadata_pb2
|
from librespot.proto import Metadata_pb2 as Metadata
|
||||||
|
|
||||||
|
|
||||||
class CdnManager:
|
class CdnManager:
|
||||||
|
@ -50,7 +50,7 @@ class CdnManager:
|
||||||
|
|
||||||
return body
|
return body
|
||||||
|
|
||||||
def stream_external_episode(self, episode: Metadata_pb2.Episode,
|
def stream_external_episode(self, episode: Metadata.Episode,
|
||||||
external_url: str,
|
external_url: str,
|
||||||
halt_listener: HaltListener):
|
halt_listener: HaltListener):
|
||||||
return CdnManager.Streamer(
|
return CdnManager.Streamer(
|
||||||
|
@ -65,7 +65,7 @@ class CdnManager:
|
||||||
|
|
||||||
def stream_file(
|
def stream_file(
|
||||||
self,
|
self,
|
||||||
file: Metadata_pb2.AudioFile,
|
file: Metadata.AudioFile,
|
||||||
key: bytes,
|
key: bytes,
|
||||||
url: str,
|
url: str,
|
||||||
halt_listener: HaltListener,
|
halt_listener: HaltListener,
|
||||||
|
@ -96,9 +96,9 @@ class CdnManager:
|
||||||
if body is None:
|
if body is None:
|
||||||
raise IOError("Response body is empty!")
|
raise IOError("Response body is empty!")
|
||||||
|
|
||||||
proto = StorageResolve_pb2.StorageResolveResponse()
|
proto = StorageResolve.StorageResolveResponse()
|
||||||
proto.ParseFromString(body)
|
proto.ParseFromString(body)
|
||||||
if proto.result == StorageResolve_pb2.StorageResolveResponse.Result.CDN:
|
if proto.result == StorageResolve.StorageResolveResponse.Result.CDN:
|
||||||
url = random.choice(proto.cdnurl)
|
url = random.choice(proto.cdnurl)
|
||||||
self._LOGGER.debug("Fetched CDN url for {}: {}".format(
|
self._LOGGER.debug("Fetched CDN url for {}: {}".format(
|
||||||
Utils.bytes_to_hex(file_id), url))
|
Utils.bytes_to_hex(file_id), url))
|
||||||
|
|
|
@ -3,10 +3,10 @@ from __future__ import annotations
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from librespot.proto import Metadata_pb2
|
from librespot.proto import Metadata_pb2 as Metadata
|
||||||
|
|
||||||
|
|
||||||
class AudioQualityPicker:
|
class AudioQualityPicker:
|
||||||
def get_file(self,
|
def get_file(self,
|
||||||
files: typing.List[Metadata_pb2.AudioFile]) -> Metadata_pb2.AudioFile:
|
files: typing.List[Metadata.AudioFile]) -> Metadata.AudioFile:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from librespot.proto import Metadata_pb2
|
from librespot.proto import Metadata_pb2 as Metadata
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,19 +8,19 @@ class SuperAudioFormat(enum.Enum):
|
||||||
AAC = 0x02
|
AAC = 0x02
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get(audio_format: Metadata_pb2.AudioFile.Format):
|
def get(audio_format: Metadata.AudioFile.Format):
|
||||||
if audio_format == Metadata_pb2.AudioFile.Format.OGG_VORBIS_96 or \
|
if audio_format == Metadata.AudioFile.Format.OGG_VORBIS_96 or \
|
||||||
audio_format == Metadata_pb2.AudioFile.Format.OGG_VORBIS_160 or \
|
audio_format == Metadata.AudioFile.Format.OGG_VORBIS_160 or \
|
||||||
audio_format == Metadata_pb2.AudioFile.Format.OGG_VORBIS_320:
|
audio_format == Metadata.AudioFile.Format.OGG_VORBIS_320:
|
||||||
return SuperAudioFormat.VORBIS
|
return SuperAudioFormat.VORBIS
|
||||||
if audio_format == Metadata_pb2.AudioFile.Format.MP3_256 or \
|
if audio_format == Metadata.AudioFile.Format.MP3_256 or \
|
||||||
audio_format == Metadata_pb2.AudioFile.Format.MP3_320 or \
|
audio_format == Metadata.AudioFile.Format.MP3_320 or \
|
||||||
audio_format == Metadata_pb2.AudioFile.Format.MP3_160 or \
|
audio_format == Metadata.AudioFile.Format.MP3_160 or \
|
||||||
audio_format == Metadata_pb2.AudioFile.Format.MP3_96 or \
|
audio_format == Metadata.AudioFile.Format.MP3_96 or \
|
||||||
audio_format == Metadata_pb2.AudioFile.Format.MP3_160_ENC:
|
audio_format == Metadata.AudioFile.Format.MP3_160_ENC:
|
||||||
return SuperAudioFormat.MP3
|
return SuperAudioFormat.MP3
|
||||||
if audio_format == Metadata_pb2.AudioFile.Format.AAC_24 or \
|
if audio_format == Metadata.AudioFile.Format.AAC_24 or \
|
||||||
audio_format == Metadata_pb2.AudioFile.Format.AAC_48 or \
|
audio_format == Metadata.AudioFile.Format.AAC_48 or \
|
||||||
audio_format == Metadata_pb2.AudioFile.Format.AAC_24_NORM:
|
audio_format == Metadata.AudioFile.Format.AAC_24_NORM:
|
||||||
return SuperAudioFormat.AAC
|
return SuperAudioFormat.AAC
|
||||||
raise RuntimeError("Unknown audio format: {}".format(audio_format))
|
raise RuntimeError("Unknown audio format: {}".format(audio_format))
|
||||||
|
|
|
@ -35,9 +35,9 @@ from librespot.dealer import ApiClient
|
||||||
from librespot.dealer import DealerClient
|
from librespot.dealer import DealerClient
|
||||||
from librespot.mercury import MercuryClient
|
from librespot.mercury import MercuryClient
|
||||||
from librespot.mercury import SubListener
|
from librespot.mercury import SubListener
|
||||||
from librespot.proto import Authentication_pb2
|
from librespot.proto import Authentication_pb2 as Authentication
|
||||||
from librespot.proto import Connect_pb2
|
from librespot.proto import Connect_pb2 as Connect
|
||||||
from librespot.proto import Keyexchange_pb2
|
from librespot.proto import Keyexchange_pb2 as Keyexchange
|
||||||
from librespot.proto.ExplicitContentPubsub_pb2 import UserAttributesUpdate
|
from librespot.proto.ExplicitContentPubsub_pb2 import UserAttributesUpdate
|
||||||
from librespot.standard import BytesInputStream
|
from librespot.standard import BytesInputStream
|
||||||
from librespot.standard import Closeable
|
from librespot.standard import Closeable
|
||||||
|
@ -319,7 +319,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
_conn: Session.ConnectionHolder = None
|
_conn: Session.ConnectionHolder = None
|
||||||
_cipherPair: CipherPair = None
|
_cipherPair: CipherPair = None
|
||||||
_receiver: Session.Receiver = None
|
_receiver: Session.Receiver = None
|
||||||
_apWelcome: Authentication_pb2.APWelcome = None
|
_apWelcome: Authentication.APWelcome = None
|
||||||
_mercuryClient: MercuryClient = None
|
_mercuryClient: MercuryClient = None
|
||||||
_audioKeyManager: AudioKeyManager = None
|
_audioKeyManager: AudioKeyManager = None
|
||||||
_channelManager: ChannelManager = None
|
_channelManager: ChannelManager = None
|
||||||
|
@ -380,13 +380,13 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
|
|
||||||
nonce = os.urandom(0x10)
|
nonce = os.urandom(0x10)
|
||||||
|
|
||||||
client_hello = Keyexchange_pb2.ClientHello(
|
client_hello = Keyexchange.ClientHello(
|
||||||
build_info=Version.standard_build_info(),
|
build_info=Version.standard_build_info(),
|
||||||
cryptosuites_supported=[
|
cryptosuites_supported=[
|
||||||
Keyexchange_pb2.Cryptosuite.CRYPTO_SUITE_SHANNON
|
Keyexchange.Cryptosuite.CRYPTO_SUITE_SHANNON
|
||||||
],
|
],
|
||||||
login_crypto_hello=Keyexchange_pb2.LoginCryptoHelloUnion(
|
login_crypto_hello=Keyexchange.LoginCryptoHelloUnion(
|
||||||
diffie_hellman=Keyexchange_pb2.LoginCryptoDiffieHellmanHello(
|
diffie_hellman=Keyexchange.LoginCryptoDiffieHellmanHello(
|
||||||
gc=self._keys.public_key_array(), server_keys_known=1), ),
|
gc=self._keys.public_key_array(), server_keys_known=1), ),
|
||||||
client_nonce=nonce,
|
client_nonce=nonce,
|
||||||
padding=bytes([0x1E]),
|
padding=bytes([0x1E]),
|
||||||
|
@ -412,7 +412,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
buffer = self._conn.read(length - 4)
|
buffer = self._conn.read(length - 4)
|
||||||
acc.write(buffer)
|
acc.write(buffer)
|
||||||
|
|
||||||
ap_response_message = Keyexchange_pb2.APResponseMessage()
|
ap_response_message = Keyexchange.APResponseMessage()
|
||||||
ap_response_message.ParseFromString(buffer)
|
ap_response_message.ParseFromString(buffer)
|
||||||
shared_key = Utils.to_byte_array(
|
shared_key = Utils.to_byte_array(
|
||||||
self._keys.compute_shared_key(
|
self._keys.compute_shared_key(
|
||||||
|
@ -450,12 +450,12 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
mac.update(acc.array())
|
mac.update(acc.array())
|
||||||
|
|
||||||
challenge = mac.digest()
|
challenge = mac.digest()
|
||||||
client_response_plaintext = Keyexchange_pb2.ClientResponsePlaintext(
|
client_response_plaintext = Keyexchange.ClientResponsePlaintext(
|
||||||
login_crypto_response=Keyexchange_pb2.LoginCryptoResponseUnion(
|
login_crypto_response=Keyexchange.LoginCryptoResponseUnion(
|
||||||
diffie_hellman=Keyexchange_pb2.LoginCryptoDiffieHellmanResponse(
|
diffie_hellman=Keyexchange.LoginCryptoDiffieHellmanResponse(
|
||||||
hmac=challenge)),
|
hmac=challenge)),
|
||||||
pow_response=Keyexchange_pb2.PoWResponseUnion(),
|
pow_response=Keyexchange.PoWResponseUnion(),
|
||||||
crypto_response=Keyexchange_pb2.CryptoResponseUnion(),
|
crypto_response=Keyexchange.CryptoResponseUnion(),
|
||||||
)
|
)
|
||||||
|
|
||||||
client_response_plaintext_bytes = client_response_plaintext.SerializeToString(
|
client_response_plaintext_bytes = client_response_plaintext.SerializeToString(
|
||||||
|
@ -474,7 +474,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
| (scrap[2] << 8)
|
| (scrap[2] << 8)
|
||||||
| (scrap[3] & 0xFF))
|
| (scrap[3] & 0xFF))
|
||||||
payload = self._conn.read(length - 4)
|
payload = self._conn.read(length - 4)
|
||||||
failed = Keyexchange_pb2.APResponseMessage()
|
failed = Keyexchange.APResponseMessage()
|
||||||
failed.ParseFromString(payload)
|
failed.ParseFromString(payload)
|
||||||
raise RuntimeError(failed)
|
raise RuntimeError(failed)
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
|
@ -490,7 +490,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
self._LOGGER.info("Connection successfully!")
|
self._LOGGER.info("Connection successfully!")
|
||||||
|
|
||||||
def _authenticate(self,
|
def _authenticate(self,
|
||||||
credentials: Authentication_pb2.LoginCredentials) -> None:
|
credentials: Authentication.LoginCredentials) -> None:
|
||||||
self._authenticate_partial(credentials, False)
|
self._authenticate_partial(credentials, False)
|
||||||
|
|
||||||
with self._authLock:
|
with self._authLock:
|
||||||
|
@ -521,16 +521,16 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
self, "hm://connect-state/v1/connect/logout")
|
self, "hm://connect-state/v1/connect/logout")
|
||||||
|
|
||||||
def _authenticate_partial(self,
|
def _authenticate_partial(self,
|
||||||
credentials: Authentication_pb2.LoginCredentials,
|
credentials: Authentication.LoginCredentials,
|
||||||
remove_lock: bool) -> None:
|
remove_lock: bool) -> None:
|
||||||
if self._cipherPair is None:
|
if self._cipherPair is None:
|
||||||
raise RuntimeError("Connection not established!")
|
raise RuntimeError("Connection not established!")
|
||||||
|
|
||||||
client_response_encrypted = Authentication_pb2.ClientResponseEncrypted(
|
client_response_encrypted = Authentication.ClientResponseEncrypted(
|
||||||
login_credentials=credentials,
|
login_credentials=credentials,
|
||||||
system_info=Authentication_pb2.SystemInfo(
|
system_info=Authentication.SystemInfo(
|
||||||
os=Authentication_pb2.Os.OS_UNKNOWN,
|
os=Authentication.Os.OS_UNKNOWN,
|
||||||
cpu_family=Authentication_pb2.CpuFamily.CPU_UNKNOWN,
|
cpu_family=Authentication.CpuFamily.CPU_UNKNOWN,
|
||||||
system_information_string=Version.system_info_string(),
|
system_information_string=Version.system_info_string(),
|
||||||
device_id=self._inner.device_id,
|
device_id=self._inner.device_id,
|
||||||
),
|
),
|
||||||
|
@ -542,7 +542,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
|
|
||||||
packet = self._cipherPair.receive_encoded(self._conn)
|
packet = self._cipherPair.receive_encoded(self._conn)
|
||||||
if packet.is_cmd(Packet.Type.ap_welcome):
|
if packet.is_cmd(Packet.Type.ap_welcome):
|
||||||
self._apWelcome = Authentication_pb2.APWelcome()
|
self._apWelcome = Authentication.APWelcome()
|
||||||
self._apWelcome.ParseFromString(packet.payload)
|
self._apWelcome.ParseFromString(packet.payload)
|
||||||
|
|
||||||
self._receiver = Session.Receiver(self)
|
self._receiver = Session.Receiver(self)
|
||||||
|
@ -564,7 +564,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
|
|
||||||
if self._inner.conf.store_credentials:
|
if self._inner.conf.store_credentials:
|
||||||
reusable = self._apWelcome.reusable_auth_credentials
|
reusable = self._apWelcome.reusable_auth_credentials
|
||||||
reusable_type = Authentication_pb2.AuthenticationType.Name(
|
reusable_type = Authentication.AuthenticationType.Name(
|
||||||
self._apWelcome.reusable_auth_credentials_type)
|
self._apWelcome.reusable_auth_credentials_type)
|
||||||
|
|
||||||
if self._inner.conf.stored_credentials_file is None:
|
if self._inner.conf.stored_credentials_file is None:
|
||||||
|
@ -581,7 +581,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
)
|
)
|
||||||
|
|
||||||
elif packet.is_cmd(Packet.Type.auth_failure):
|
elif packet.is_cmd(Packet.Type.auth_failure):
|
||||||
ap_login_failed = Keyexchange_pb2.APLoginFailed()
|
ap_login_failed = Keyexchange.APLoginFailed()
|
||||||
ap_login_failed.ParseFromString(packet.payload)
|
ap_login_failed.ParseFromString(packet.payload)
|
||||||
raise Session.SpotifyAuthenticationException(ap_login_failed)
|
raise Session.SpotifyAuthenticationException(ap_login_failed)
|
||||||
else:
|
else:
|
||||||
|
@ -745,7 +745,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
def username(self) -> str:
|
def username(self) -> str:
|
||||||
return self.ap_welcome().canonical_username
|
return self.ap_welcome().canonical_username
|
||||||
|
|
||||||
def ap_welcome(self) -> Authentication_pb2.APWelcome:
|
def ap_welcome(self) -> Authentication.APWelcome:
|
||||||
self._wait_auth_lock()
|
self._wait_auth_lock()
|
||||||
if self._apWelcome is None:
|
if self._apWelcome is None:
|
||||||
raise RuntimeError("Session isn't authenticated!")
|
raise RuntimeError("Session isn't authenticated!")
|
||||||
|
@ -770,7 +770,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
def preferred_locale(self) -> str:
|
def preferred_locale(self) -> str:
|
||||||
return self._inner.preferred_locale
|
return self._inner.preferred_locale
|
||||||
|
|
||||||
def device_type(self) -> Connect_pb2.DeviceType:
|
def device_type(self) -> Connect.DeviceType:
|
||||||
return self._inner.device_type
|
return self._inner.device_type
|
||||||
|
|
||||||
def device_name(self) -> str:
|
def device_name(self) -> str:
|
||||||
|
@ -792,7 +792,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
ApResolver.get_random_accesspoint(), self._inner.conf)
|
ApResolver.get_random_accesspoint(), self._inner.conf)
|
||||||
self._connect()
|
self._connect()
|
||||||
self._authenticate_partial(
|
self._authenticate_partial(
|
||||||
Authentication_pb2.LoginCredentials(
|
Authentication.LoginCredentials(
|
||||||
typ=self._apWelcome.reusable_auth_credentials_type,
|
typ=self._apWelcome.reusable_auth_credentials_type,
|
||||||
username=self._apWelcome.canonical_username,
|
username=self._apWelcome.canonical_username,
|
||||||
auth_data=self._apWelcome.reusable_auth_credentials,
|
auth_data=self._apWelcome.reusable_auth_credentials,
|
||||||
|
@ -868,7 +868,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Inner:
|
class Inner:
|
||||||
device_type: Connect_pb2.DeviceType = None
|
device_type: Connect.DeviceType = None
|
||||||
device_name: str = None
|
device_name: str = None
|
||||||
device_id: str = None
|
device_id: str = None
|
||||||
conf = None
|
conf = None
|
||||||
|
@ -876,7 +876,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device_type: Connect_pb2.DeviceType,
|
device_type: Connect.DeviceType,
|
||||||
device_name: str,
|
device_name: str,
|
||||||
preferred_locale: str,
|
preferred_locale: str,
|
||||||
conf: Session.Configuration,
|
conf: Session.Configuration,
|
||||||
|
@ -893,7 +893,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
conf = None
|
conf = None
|
||||||
device_id = None
|
device_id = None
|
||||||
device_name = "librespot-python"
|
device_name = "librespot-python"
|
||||||
device_type = Connect_pb2.DeviceType.COMPUTER
|
device_type = Connect.DeviceType.COMPUTER
|
||||||
preferred_locale = "en"
|
preferred_locale = "en"
|
||||||
|
|
||||||
def __init__(self, conf: Session.Configuration = None):
|
def __init__(self, conf: Session.Configuration = None):
|
||||||
|
@ -921,12 +921,12 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_device_type(
|
def set_device_type(
|
||||||
self, device_type: Connect_pb2.DeviceType) -> Session.AbsBuilder:
|
self, device_type: Connect.DeviceType) -> Session.AbsBuilder:
|
||||||
self.device_type = device_type
|
self.device_type = device_type
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class Builder(AbsBuilder):
|
class Builder(AbsBuilder):
|
||||||
login_credentials: Authentication_pb2.LoginCredentials = None
|
login_credentials: Authentication.LoginCredentials = None
|
||||||
|
|
||||||
def stored(self):
|
def stored(self):
|
||||||
pass
|
pass
|
||||||
|
@ -943,8 +943,8 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self.login_credentials = Authentication_pb2.LoginCredentials(
|
self.login_credentials = Authentication.LoginCredentials(
|
||||||
typ=Authentication_pb2.AuthenticationType.Value(
|
typ=Authentication.AuthenticationType.Value(
|
||||||
obj["type"]),
|
obj["type"]),
|
||||||
username=obj["username"],
|
username=obj["username"],
|
||||||
auth_data=base64.b64decode(obj["credentials"]),
|
auth_data=base64.b64decode(obj["credentials"]),
|
||||||
|
@ -955,9 +955,9 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def user_pass(self, username: str, password: str) -> Session.Builder:
|
def user_pass(self, username: str, password: str) -> Session.Builder:
|
||||||
self.login_credentials = Authentication_pb2.LoginCredentials(
|
self.login_credentials = Authentication.LoginCredentials(
|
||||||
username=username,
|
username=username,
|
||||||
typ=Authentication_pb2.AuthenticationType.AUTHENTICATION_USER_PASS,
|
typ=Authentication.AuthenticationType.AUTHENTICATION_USER_PASS,
|
||||||
auth_data=password.encode(),
|
auth_data=password.encode(),
|
||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
|
@ -1142,9 +1142,9 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
|
||||||
)
|
)
|
||||||
|
|
||||||
class SpotifyAuthenticationException(Exception):
|
class SpotifyAuthenticationException(Exception):
|
||||||
def __init__(self, login_failed: Keyexchange_pb2.APLoginFailed):
|
def __init__(self, login_failed: Keyexchange.APLoginFailed):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
Keyexchange_pb2.ErrorCode.Name(login_failed.error_code))
|
Keyexchange.ErrorCode.Name(login_failed.error_code))
|
||||||
|
|
||||||
class Accumulator:
|
class Accumulator:
|
||||||
buffer: bytes = bytes()
|
buffer: bytes = bytes()
|
||||||
|
|
|
@ -9,8 +9,8 @@ from librespot.metadata import ArtistId
|
||||||
from librespot.metadata import EpisodeId
|
from librespot.metadata import EpisodeId
|
||||||
from librespot.metadata import ShowId
|
from librespot.metadata import ShowId
|
||||||
from librespot.metadata import TrackId
|
from librespot.metadata import TrackId
|
||||||
from librespot.proto import Connect_pb2
|
from librespot.proto import Connect_pb2 as Connect
|
||||||
from librespot.proto import Metadata_pb2
|
from librespot.proto import Metadata_pb2 as Metadata
|
||||||
from librespot.standard import Closeable
|
from librespot.standard import Closeable
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class ApiClient(Closeable):
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def put_connect_state(self, connection_id: str,
|
def put_connect_state(self, connection_id: str,
|
||||||
proto: Connect_pb2.PutStateRequest) -> None:
|
proto: Connect.PutStateRequest) -> None:
|
||||||
resp = self.send(
|
resp = self.send(
|
||||||
"PUT",
|
"PUT",
|
||||||
"/connect-state/v1/devices/{}".format(self._session.device_id()),
|
"/connect-state/v1/devices/{}".format(self._session.device_id()),
|
||||||
|
@ -72,7 +72,7 @@ class ApiClient(Closeable):
|
||||||
self._LOGGER.warning("PUT state returned {}. headers: {}".format(
|
self._LOGGER.warning("PUT state returned {}. headers: {}".format(
|
||||||
resp.status_code, resp.headers))
|
resp.status_code, resp.headers))
|
||||||
|
|
||||||
def get_metadata_4_track(self, track: TrackId) -> Metadata_pb2.Track:
|
def get_metadata_4_track(self, track: TrackId) -> Metadata.Track:
|
||||||
resp = self.send("GET", "/metadata/4/track/{}".format(track.hex_id()),
|
resp = self.send("GET", "/metadata/4/track/{}".format(track.hex_id()),
|
||||||
None, None)
|
None, None)
|
||||||
ApiClient.StatusCodeException.check_status(resp)
|
ApiClient.StatusCodeException.check_status(resp)
|
||||||
|
@ -80,11 +80,11 @@ class ApiClient(Closeable):
|
||||||
body = resp.content
|
body = resp.content
|
||||||
if body is None:
|
if body is None:
|
||||||
raise RuntimeError()
|
raise RuntimeError()
|
||||||
proto = Metadata_pb2.Track()
|
proto = Metadata.Track()
|
||||||
proto.ParseFromString(body)
|
proto.ParseFromString(body)
|
||||||
return proto
|
return proto
|
||||||
|
|
||||||
def get_metadata_4_episode(self, episode: EpisodeId) -> Metadata_pb2.Episode:
|
def get_metadata_4_episode(self, episode: EpisodeId) -> Metadata.Episode:
|
||||||
resp = self.send("GET",
|
resp = self.send("GET",
|
||||||
"/metadata/4/episode/{}".format(episode.hex_id()),
|
"/metadata/4/episode/{}".format(episode.hex_id()),
|
||||||
None, None)
|
None, None)
|
||||||
|
@ -93,11 +93,11 @@ class ApiClient(Closeable):
|
||||||
body = resp.content
|
body = resp.content
|
||||||
if body is None:
|
if body is None:
|
||||||
raise IOError()
|
raise IOError()
|
||||||
proto = Metadata_pb2.Episode()
|
proto = Metadata.Episode()
|
||||||
proto.ParseFromString(body)
|
proto.ParseFromString(body)
|
||||||
return proto
|
return proto
|
||||||
|
|
||||||
def get_metadata_4_album(self, album: AlbumId) -> Metadata_pb2.Album:
|
def get_metadata_4_album(self, album: AlbumId) -> Metadata.Album:
|
||||||
resp = self.send("GET", "/metadata/4/album/{}".format(album.hex_id()),
|
resp = self.send("GET", "/metadata/4/album/{}".format(album.hex_id()),
|
||||||
None, None)
|
None, None)
|
||||||
ApiClient.StatusCodeException.check_status(resp)
|
ApiClient.StatusCodeException.check_status(resp)
|
||||||
|
@ -105,11 +105,11 @@ class ApiClient(Closeable):
|
||||||
body = resp.content
|
body = resp.content
|
||||||
if body is None:
|
if body is None:
|
||||||
raise IOError()
|
raise IOError()
|
||||||
proto = Metadata_pb2.Album()
|
proto = Metadata.Album()
|
||||||
proto.ParseFromString(body)
|
proto.ParseFromString(body)
|
||||||
return proto
|
return proto
|
||||||
|
|
||||||
def get_metadata_4_artist(self, artist: ArtistId) -> Metadata_pb2.Artist:
|
def get_metadata_4_artist(self, artist: ArtistId) -> Metadata.Artist:
|
||||||
resp = self.send("GET",
|
resp = self.send("GET",
|
||||||
"/metadata/4/artist/{}".format(artist.hex_id()), None,
|
"/metadata/4/artist/{}".format(artist.hex_id()), None,
|
||||||
None)
|
None)
|
||||||
|
@ -118,11 +118,11 @@ class ApiClient(Closeable):
|
||||||
body = resp.content
|
body = resp.content
|
||||||
if body is None:
|
if body is None:
|
||||||
raise IOError()
|
raise IOError()
|
||||||
proto = Metadata_pb2.Artist()
|
proto = Metadata.Artist()
|
||||||
proto.ParseFromString(body)
|
proto.ParseFromString(body)
|
||||||
return proto
|
return proto
|
||||||
|
|
||||||
def get_metadata_4_show(self, show: ShowId) -> Metadata_pb2.Show:
|
def get_metadata_4_show(self, show: ShowId) -> Metadata.Show:
|
||||||
resp = self.send("GET", "/metadata/4/show/{}".format(show.hex_id()),
|
resp = self.send("GET", "/metadata/4/show/{}".format(show.hex_id()),
|
||||||
None, None)
|
None, None)
|
||||||
ApiClient.StatusCodeException.check_status(resp)
|
ApiClient.StatusCodeException.check_status(resp)
|
||||||
|
@ -130,7 +130,7 @@ class ApiClient(Closeable):
|
||||||
body = resp.content
|
body = resp.content
|
||||||
if body is None:
|
if body is None:
|
||||||
raise IOError()
|
raise IOError()
|
||||||
proto = Metadata_pb2.Show()
|
proto = Metadata.Show()
|
||||||
proto.ParseFromString(body)
|
proto.ParseFromString(body)
|
||||||
return proto
|
return proto
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ from librespot.crypto import Packet
|
||||||
from librespot.mercury import JsonMercuryRequest
|
from librespot.mercury import JsonMercuryRequest
|
||||||
from librespot.mercury import RawMercuryRequest
|
from librespot.mercury import RawMercuryRequest
|
||||||
from librespot.mercury import SubListener
|
from librespot.mercury import SubListener
|
||||||
from librespot.proto import Mercury_pb2
|
from librespot.proto import Mercury_pb2 as Mercury
|
||||||
from librespot.proto import Pubsub_pb2
|
from librespot.proto import Pubsub_pb2 as Pubsub
|
||||||
from librespot.standard import BytesInputStream
|
from librespot.standard import BytesInputStream
|
||||||
from librespot.standard import BytesOutputStream
|
from librespot.standard import BytesOutputStream
|
||||||
from librespot.standard import Closeable
|
from librespot.standard import Closeable
|
||||||
|
@ -42,7 +42,7 @@ class MercuryClient(PacketsReceiver.PacketsReceiver, Closeable):
|
||||||
|
|
||||||
if len(response.payload) > 0:
|
if len(response.payload) > 0:
|
||||||
for payload in response.payload:
|
for payload in response.payload:
|
||||||
sub = Pubsub_pb2.Subscription()
|
sub = Pubsub.Subscription()
|
||||||
sub.ParseFromString(payload)
|
sub.ParseFromString(payload)
|
||||||
self._subscriptions.append(
|
self._subscriptions.append(
|
||||||
MercuryClient.InternalSubListener(sub.uri, listener, True))
|
MercuryClient.InternalSubListener(sub.uri, listener, True))
|
||||||
|
@ -150,7 +150,7 @@ class MercuryClient(PacketsReceiver.PacketsReceiver, Closeable):
|
||||||
|
|
||||||
self._partials.pop(seq)
|
self._partials.pop(seq)
|
||||||
|
|
||||||
header = Mercury_pb2.Header()
|
header = Mercury.Header()
|
||||||
header.ParseFromString(partial[0])
|
header.ParseFromString(partial[0])
|
||||||
|
|
||||||
resp = MercuryClient.Response(header, partial)
|
resp = MercuryClient.Response(header, partial)
|
||||||
|
@ -257,7 +257,7 @@ class MercuryClient(PacketsReceiver.PacketsReceiver, Closeable):
|
||||||
payload: typing.List[bytes]
|
payload: typing.List[bytes]
|
||||||
status_code: int
|
status_code: int
|
||||||
|
|
||||||
def __init__(self, header: Mercury_pb2.Header,
|
def __init__(self, header: Mercury.Header,
|
||||||
payload: typing.List[bytes]):
|
payload: typing.List[bytes]):
|
||||||
self.uri = header.uri
|
self.uri = header.uri
|
||||||
self.status_code = header.status_code
|
self.status_code = header.status_code
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from librespot.proto import Mercury_pb2
|
from librespot.proto import Mercury_pb2 as Mercury
|
||||||
|
|
||||||
|
|
||||||
class RawMercuryRequest:
|
class RawMercuryRequest:
|
||||||
header: Mercury_pb2.Header
|
header: Mercury.Header
|
||||||
payload: typing.List[bytes]
|
payload: typing.List[bytes]
|
||||||
|
|
||||||
def __init__(self, header: Mercury_pb2.Header, payload: typing.List[bytes]):
|
def __init__(self, header: Mercury.Header, payload: typing.List[bytes]):
|
||||||
self.header = header
|
self.header = header
|
||||||
self.payload = payload
|
self.payload = payload
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class RawMercuryRequest:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_user_field(self,
|
def add_user_field(self,
|
||||||
field: Mercury_pb2.UserField = None,
|
field: Mercury.UserField = None,
|
||||||
key: str = None,
|
key: str = None,
|
||||||
value: str = None):
|
value: str = None):
|
||||||
if field is None and (key is None or value is None):
|
if field is None and (key is None or value is None):
|
||||||
|
@ -74,7 +74,7 @@ class RawMercuryRequest:
|
||||||
self.header_dict["user_fields"].append(field)
|
self.header_dict["user_fields"].append(field)
|
||||||
if key is not None and value is not None:
|
if key is not None and value is not None:
|
||||||
self.header_dict["user_fields"].append(
|
self.header_dict["user_fields"].append(
|
||||||
Mercury_pb2.UserField(key=key, value=value.encode()))
|
Mercury.UserField(key=key, value=value.encode()))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_payload_part(self, part: bytes):
|
def add_payload_part(self, part: bytes):
|
||||||
|
@ -85,5 +85,5 @@ class RawMercuryRequest:
|
||||||
return self.add_payload_part(msg)
|
return self.add_payload_part(msg)
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
return RawMercuryRequest(Mercury_pb2.Header(**self.header_dict),
|
return RawMercuryRequest(Mercury.Header(**self.header_dict),
|
||||||
self.payload)
|
self.payload)
|
||||||
|
|
|
@ -7,7 +7,7 @@ from librespot.dealer import DealerClient
|
||||||
from librespot.player import Player
|
from librespot.player import Player
|
||||||
from librespot.player import PlayerConfiguration
|
from librespot.player import PlayerConfiguration
|
||||||
from librespot.player.state import DeviceStateHandler
|
from librespot.player.state import DeviceStateHandler
|
||||||
from librespot.proto import Connect_pb2
|
from librespot.proto import Connect_pb2 as Connect
|
||||||
from librespot.proto.Player_pb2 import ContextPlayerOptions
|
from librespot.proto.Player_pb2 import ContextPlayerOptions
|
||||||
from librespot.proto.Player_pb2 import PlayerState
|
from librespot.proto.Player_pb2 import PlayerState
|
||||||
from librespot.proto.Player_pb2 import Restrictions
|
from librespot.proto.Player_pb2 import Restrictions
|
||||||
|
@ -52,7 +52,7 @@ class StateWrapper(DeviceStateHandler.Listener, DealerClient.MessageListener):
|
||||||
self._device.add_listener(listener)
|
self._device.add_listener(listener)
|
||||||
|
|
||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
self._device.update_state(Connect_pb2.PutStateReason.NEW_DEVICE, 0,
|
self._device.update_state(Connect.PutStateReason.NEW_DEVICE, 0,
|
||||||
self._state)
|
self._state)
|
||||||
|
|
||||||
def on_message(self, uri: str, headers: typing.Dict[str, str],
|
def on_message(self, uri: str, headers: typing.Dict[str, str],
|
||||||
|
|
|
@ -6,7 +6,7 @@ import typing
|
||||||
from librespot.audio.decoders.AudioQuality import AudioQuality
|
from librespot.audio.decoders.AudioQuality import AudioQuality
|
||||||
from librespot.audio.format.AudioQualityPicker import AudioQualityPicker
|
from librespot.audio.format.AudioQualityPicker import AudioQualityPicker
|
||||||
from librespot.audio.format.SuperAudioFormat import SuperAudioFormat
|
from librespot.audio.format.SuperAudioFormat import SuperAudioFormat
|
||||||
from librespot.proto import Metadata_pb2
|
from librespot.proto import Metadata_pb2 as Metadata
|
||||||
|
|
||||||
|
|
||||||
class VorbisOnlyAudioQuality(AudioQualityPicker):
|
class VorbisOnlyAudioQuality(AudioQualityPicker):
|
||||||
|
@ -17,7 +17,7 @@ class VorbisOnlyAudioQuality(AudioQualityPicker):
|
||||||
self.preferred = preferred
|
self.preferred = preferred
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_vorbis_file(files: typing.List[Metadata_pb2.AudioFile]):
|
def get_vorbis_file(files: typing.List[Metadata.AudioFile]):
|
||||||
for file in files:
|
for file in files:
|
||||||
if (hasattr(file, "format") and SuperAudioFormat.get(file.format)
|
if (hasattr(file, "format") and SuperAudioFormat.get(file.format)
|
||||||
== SuperAudioFormat.VORBIS):
|
== SuperAudioFormat.VORBIS):
|
||||||
|
@ -25,13 +25,13 @@ class VorbisOnlyAudioQuality(AudioQualityPicker):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_file(self, files: typing.List[Metadata_pb2.AudioFile]):
|
def get_file(self, files: typing.List[Metadata.AudioFile]):
|
||||||
matches: typing.List[Metadata_pb2.AudioFile] = self.preferred.get_matches(
|
matches: typing.List[Metadata.AudioFile] = self.preferred.get_matches(
|
||||||
files)
|
files)
|
||||||
vorbis: Metadata_pb2.AudioFile = VorbisOnlyAudioQuality.get_vorbis_file(
|
vorbis: Metadata.AudioFile = VorbisOnlyAudioQuality.get_vorbis_file(
|
||||||
matches)
|
matches)
|
||||||
if vorbis is None:
|
if vorbis is None:
|
||||||
vorbis: Metadata_pb2.AudioFile = VorbisOnlyAudioQuality.get_vorbis_file(
|
vorbis: Metadata.AudioFile = VorbisOnlyAudioQuality.get_vorbis_file(
|
||||||
files)
|
files)
|
||||||
if vorbis is not None:
|
if vorbis is not None:
|
||||||
self._LOGGER.warning(
|
self._LOGGER.warning(
|
||||||
|
|
|
@ -11,16 +11,16 @@ import urllib.parse
|
||||||
from librespot.common import Utils
|
from librespot.common import Utils
|
||||||
from librespot.core import Session
|
from librespot.core import Session
|
||||||
from librespot.player import PlayerConfiguration
|
from librespot.player import PlayerConfiguration
|
||||||
from librespot.proto import Connect_pb2
|
from librespot.proto import Connect_pb2 as Connect
|
||||||
from librespot.proto import Player_pb2
|
from librespot.proto import Player_pb2 as Player
|
||||||
|
|
||||||
|
|
||||||
class DeviceStateHandler:
|
class DeviceStateHandler:
|
||||||
_LOGGER: logging = logging.getLogger(__name__)
|
_LOGGER: logging = logging.getLogger(__name__)
|
||||||
_session: Session = None
|
_session: Session = None
|
||||||
_deviceInfo: Connect_pb2.DeviceInfo = None
|
_deviceInfo: Connect.DeviceInfo = None
|
||||||
_listeners: typing.List[DeviceStateHandler.Listener] = []
|
_listeners: typing.List[DeviceStateHandler.Listener] = []
|
||||||
_putState: Connect_pb2.PutStateRequest = None
|
_putState: Connect.PutStateRequest = None
|
||||||
_putStateWorker: concurrent.futures.ThreadPoolExecutor = (
|
_putStateWorker: concurrent.futures.ThreadPoolExecutor = (
|
||||||
concurrent.futures.ThreadPoolExecutor())
|
concurrent.futures.ThreadPoolExecutor())
|
||||||
_connectionId: str = None
|
_connectionId: str = None
|
||||||
|
@ -28,7 +28,7 @@ class DeviceStateHandler:
|
||||||
def __init__(self, session: Session, player, conf: PlayerConfiguration):
|
def __init__(self, session: Session, player, conf: PlayerConfiguration):
|
||||||
self._session = session
|
self._session = session
|
||||||
self._deviceInfo = None
|
self._deviceInfo = None
|
||||||
self._putState = Connect_pb2.PutStateRequest()
|
self._putState = Connect.PutStateRequest()
|
||||||
|
|
||||||
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")
|
||||||
|
@ -48,9 +48,9 @@ class DeviceStateHandler:
|
||||||
|
|
||||||
def update_state(
|
def update_state(
|
||||||
self,
|
self,
|
||||||
reason: Connect_pb2.PutStateReason,
|
reason: Connect.PutStateReason,
|
||||||
player_time: int,
|
player_time: int,
|
||||||
state: Player_pb2.PlayerState,
|
state: Player.PlayerState,
|
||||||
):
|
):
|
||||||
if self._connectionId is None:
|
if self._connectionId is None:
|
||||||
raise TypeError()
|
raise TypeError()
|
||||||
|
@ -67,7 +67,7 @@ class DeviceStateHandler:
|
||||||
|
|
||||||
self._putStateWorker.submit(self._put_connect_state, self._putState)
|
self._putStateWorker.submit(self._put_connect_state, self._putState)
|
||||||
|
|
||||||
def _put_connect_state(self, req: Connect_pb2.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("Put state. ts: {}, connId: {}, reason: {}".format(
|
||||||
req.client_side_timestamp,
|
req.client_side_timestamp,
|
||||||
|
|
Loading…
Reference in New Issue