Merge pull request #29 from kokarare1212/deepsource-transform-c875c54e

Format code with yapf
This commit is contained in:
こうから 2021-05-21 12:52:22 +09:00 committed by GitHub
commit 8f920a783b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 431 additions and 117 deletions

View File

@ -1,10 +1,11 @@
from librespot.audio.HaltListener import HaltListener
from librespot.standard.InputStream import InputStream
import math import math
import threading import threading
import time import time
import typing import typing
from librespot.audio.HaltListener import HaltListener
from librespot.standard.InputStream import InputStream
class AbsChunkedInputStream(InputStream, HaltListener): class AbsChunkedInputStream(InputStream, HaltListener):
preload_ahead: typing.Final[int] = 3 preload_ahead: typing.Final[int] = 3
@ -63,8 +64,7 @@ class AbsChunkedInputStream(InputStream, HaltListener):
raise IOError("Stream is closed!") raise IOError("Stream is closed!")
self._pos = where self._pos = where
self.check_availability(int(self._pos / (128 * 1024)), self.check_availability(int(self._pos / (128 * 1024)), False, False)
False, False)
def skip(self, n: int) -> int: def skip(self, n: int) -> int:
if n < 0: if n < 0:
@ -111,8 +111,8 @@ class AbsChunkedInputStream(InputStream, HaltListener):
for i in range(chunk + 1, for i in range(chunk + 1,
min(self.chunks() - 1, chunk + self.preload_ahead) + 1): min(self.chunks() - 1, chunk + self.preload_ahead) + 1):
if self.requested_chunks( if (self.requested_chunks()[i]
)[i] and self.retries[i] < self.preload_chunk_retries: and self.retries[i] < self.preload_chunk_retries):
self.request_chunk_from_stream(i) self.request_chunk_from_stream(i)
self.requested_chunks()[chunk] = True self.requested_chunks()[chunk] = True

View File

@ -1,13 +1,18 @@
from __future__ import annotations from __future__ import annotations
from librespot.audio import NormalizationData, PlayableContentFeeder, HaltListener
from librespot.common import Utils
from librespot.core import Session
from librespot.proto import Metadata, StorageResolve
import logging import logging
import random import random
import time import time
import typing import typing
from librespot.audio import HaltListener
from librespot.audio import NormalizationData
from librespot.audio import PlayableContentFeeder
from librespot.common import Utils
from librespot.core import Session
from librespot.proto import Metadata
from librespot.proto import StorageResolve
class CdnFeedHelper: class CdnFeedHelper:
_LOGGER: logging = logging.getLogger(__name__) _LOGGER: logging = logging.getLogger(__name__)
@ -17,10 +22,14 @@ class CdnFeedHelper:
return random.choice(resp.cdnurl) return random.choice(resp.cdnurl)
@staticmethod @staticmethod
def load_track(session: Session, track: Metadata.Track, file: Metadata.AudioFile, def load_track(
session: Session,
track: Metadata.Track,
file: Metadata.AudioFile,
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, str], resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, str],
preload: bool, halt_listener: HaltListener)\ preload: bool,
-> PlayableContentFeeder.PlayableContentFeeder.LoadedStream: halt_listener: HaltListener,
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
if type(resp_or_url) is str: if type(resp_or_url) is str:
url = resp_or_url url = resp_or_url
else: else:
@ -31,13 +40,17 @@ class CdnFeedHelper:
streamer = session.cdn().stream_file(file, key, url, halt_listener) streamer = session.cdn().stream_file(file, key, url, halt_listener)
input_stream = streamer.stream() input_stream = streamer.stream()
normalization_data = NormalizationData.NormalizationData.read(input_stream) normalization_data = NormalizationData.NormalizationData.read(
if input_stream.skip(0xa7) != 0xa7: input_stream)
if input_stream.skip(0xA7) != 0xA7:
raise IOError("Couldn't skip 0xa7 bytes!") raise IOError("Couldn't skip 0xa7 bytes!")
return PlayableContentFeeder.PlayableContentFeeder.LoadedStream( return PlayableContentFeeder.PlayableContentFeeder.LoadedStream(
track, streamer, normalization_data, track,
streamer,
normalization_data,
PlayableContentFeeder.PlayableContentFeeder.Metrics( PlayableContentFeeder.PlayableContentFeeder.Metrics(
file.file_id, preload, -1 if preload else audio_key_time)) file.file_id, preload, -1 if preload else audio_key_time),
)
@staticmethod @staticmethod
def load_episode_external( def load_episode_external(
@ -56,15 +69,20 @@ class CdnFeedHelper:
streamer = session.cdn().stream_external_episode( streamer = session.cdn().stream_external_episode(
episode, url, halt_listener) episode, url, halt_listener)
return PlayableContentFeeder.PlayableContentFeeder.LoadedStream( return PlayableContentFeeder.PlayableContentFeeder.LoadedStream(
episode, streamer, None, episode,
streamer,
None,
PlayableContentFeeder.PlayableContentFeeder.Metrics( PlayableContentFeeder.PlayableContentFeeder.Metrics(
None, False, -1)) None, False, -1),
)
@staticmethod @staticmethod
def load_episode( def load_episode(
session: Session, episode: Metadata.Episode, file: Metadata.AudioFile, session: Session,
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, episode: Metadata.Episode,
str], halt_listener: HaltListener file: Metadata.AudioFile,
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, str],
halt_listener: HaltListener,
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream: ) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
if type(resp_or_url) is str: if type(resp_or_url) is str:
url = resp_or_url url = resp_or_url
@ -77,9 +95,12 @@ class CdnFeedHelper:
streamer = session.cdn().stream_file(file, key, url, halt_listener) streamer = session.cdn().stream_file(file, key, url, halt_listener)
input_stream = streamer.stream() input_stream = streamer.stream()
normalization_data = NormalizationData.read(input_stream) normalization_data = NormalizationData.read(input_stream)
if input_stream.skip(0xa7) != 0xa7: if input_stream.skip(0xA7) != 0xA7:
raise IOError("Couldn't skip 0xa7 bytes!") raise IOError("Couldn't skip 0xa7 bytes!")
return PlayableContentFeeder.PlayableContentFeeder.LoadedStream( return PlayableContentFeeder.PlayableContentFeeder.LoadedStream(
episode, streamer, normalization_data, episode,
streamer,
normalization_data,
PlayableContentFeeder.PlayableContentFeeder.Metrics( PlayableContentFeeder.PlayableContentFeeder.Metrics(
file.file_id, False, audio_key_time)) file.file_id, False, audio_key_time),
)

View File

@ -1,26 +1,9 @@
from __future__ import annotations from __future__ import annotations
from Crypto.Hash import HMAC, SHA1
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from librespot.audio import AudioKeyManager, PlayableContentFeeder
from librespot.audio.cdn import CdnManager
from librespot.audio.storage import ChannelManager
from librespot.cache import CacheManager
from librespot.common.Utils import Utils
from librespot.core import ApResolver, EventService, SearchManager, TokenProvider
from librespot.crypto import CipherPair, DiffieHellman, Packet
from librespot.dealer import ApiClient, DealerClient
from librespot.mercury import MercuryClient, SubListener
from librespot.proto import Authentication, Connect, Keyexchange
from librespot.proto.ExplicitContentPubsub import UserAttributesUpdate
from librespot.standard import BytesInputStream, Closeable, Proxy
from librespot.Version import Version
import base64 import base64
import defusedxml.ElementTree
import json import json
import logging import logging
import os import os
import requests
import sched import sched
import socket import socket
import struct import struct
@ -28,32 +11,299 @@ import threading
import time import time
import typing import typing
import defusedxml.ElementTree
import requests
from Crypto.Hash import HMAC
from Crypto.Hash import SHA1
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from librespot.audio import AudioKeyManager
from librespot.audio import PlayableContentFeeder
from librespot.audio.cdn import CdnManager
from librespot.audio.storage import ChannelManager
from librespot.cache import CacheManager
from librespot.common.Utils import Utils
from librespot.core import ApResolver
from librespot.core import EventService
from librespot.core import SearchManager
from librespot.core import TokenProvider
from librespot.crypto import CipherPair
from librespot.crypto import DiffieHellman
from librespot.crypto import Packet
from librespot.dealer import ApiClient
from librespot.dealer import DealerClient
from librespot.mercury import MercuryClient
from librespot.mercury import SubListener
from librespot.proto import Authentication
from librespot.proto import Connect
from librespot.proto import Keyexchange
from librespot.proto.ExplicitContentPubsub import UserAttributesUpdate
from librespot.standard import BytesInputStream
from librespot.standard import Closeable
from librespot.standard import Proxy
from librespot.Version import Version
class Session(Closeable, SubListener, DealerClient.MessageListener): class Session(Closeable, SubListener, DealerClient.MessageListener):
_LOGGER: logging = logging.getLogger(__name__) _LOGGER: logging = logging.getLogger(__name__)
_serverKey: bytes = bytes([ _serverKey: bytes = bytes([
0xac, 0xe0, 0x46, 0x0b, 0xff, 0xc2, 0x30, 0xaf, 0xf4, 0x6b, 0xfe, 0xc3, 0xAC,
0xbf, 0xbf, 0x86, 0x3d, 0xa1, 0x91, 0xc6, 0xcc, 0x33, 0x6c, 0x93, 0xa1, 0xE0,
0x4f, 0xb3, 0xb0, 0x16, 0x12, 0xac, 0xac, 0x6a, 0xf1, 0x80, 0xe7, 0xf6, 0x46,
0x14, 0xd9, 0x42, 0x9d, 0xbe, 0x2e, 0x34, 0x66, 0x43, 0xe3, 0x62, 0xd2, 0x0B,
0x32, 0x7a, 0x1a, 0x0d, 0x92, 0x3b, 0xae, 0xdd, 0x14, 0x02, 0xb1, 0x81, 0xFF,
0x55, 0x05, 0x61, 0x04, 0xd5, 0x2c, 0x96, 0xa4, 0x4c, 0x1e, 0xcc, 0x02, 0xC2,
0x4a, 0xd4, 0xb2, 0x0c, 0x00, 0x1f, 0x17, 0xed, 0xc2, 0x2f, 0xc4, 0x35, 0x30,
0x21, 0xc8, 0xf0, 0xcb, 0xae, 0xd2, 0xad, 0xd7, 0x2b, 0x0f, 0x9d, 0xb3, 0xAF,
0xc5, 0x32, 0x1a, 0x2a, 0xfe, 0x59, 0xf3, 0x5a, 0x0d, 0xac, 0x68, 0xf1, 0xF4,
0xfa, 0x62, 0x1e, 0xfb, 0x2c, 0x8d, 0x0c, 0xb7, 0x39, 0x2d, 0x92, 0x47, 0x6B,
0xe3, 0xd7, 0x35, 0x1a, 0x6d, 0xbd, 0x24, 0xc2, 0xae, 0x25, 0x5b, 0x88, 0xFE,
0xff, 0xab, 0x73, 0x29, 0x8a, 0x0b, 0xcc, 0xcd, 0x0c, 0x58, 0x67, 0x31, 0xC3,
0x89, 0xe8, 0xbd, 0x34, 0x80, 0x78, 0x4a, 0x5f, 0xc9, 0x6b, 0x89, 0x9d, 0xBF,
0x95, 0x6b, 0xfc, 0x86, 0xd7, 0x4f, 0x33, 0xa6, 0x78, 0x17, 0x96, 0xc9, 0xBF,
0xc3, 0x2d, 0x0d, 0x32, 0xa5, 0xab, 0xcd, 0x05, 0x27, 0xe2, 0xf7, 0x10, 0x86,
0xa3, 0x96, 0x13, 0xc4, 0x2f, 0x99, 0xc0, 0x27, 0xbf, 0xed, 0x04, 0x9c, 0x3D,
0x3c, 0x27, 0x58, 0x04, 0xb6, 0xb2, 0x19, 0xf9, 0xc1, 0x2f, 0x02, 0xe9, 0xA1,
0x48, 0x63, 0xec, 0xa1, 0xb6, 0x42, 0xa0, 0x9d, 0x48, 0x25, 0xf8, 0xb3, 0x91,
0x9d, 0xd0, 0xe8, 0x6a, 0xf9, 0x48, 0x4d, 0xa1, 0xc2, 0xba, 0x86, 0x30, 0xC6,
0x42, 0xea, 0x9d, 0xb3, 0x08, 0x6c, 0x19, 0x0e, 0x48, 0xb3, 0x9d, 0x66, 0xCC,
0xeb, 0x00, 0x06, 0xa2, 0x5a, 0xee, 0xa1, 0x1b, 0x13, 0x87, 0x3c, 0xd7, 0x33,
0x19, 0xe6, 0x55, 0xbd 0x6C,
0x93,
0xA1,
0x4F,
0xB3,
0xB0,
0x16,
0x12,
0xAC,
0xAC,
0x6A,
0xF1,
0x80,
0xE7,
0xF6,
0x14,
0xD9,
0x42,
0x9D,
0xBE,
0x2E,
0x34,
0x66,
0x43,
0xE3,
0x62,
0xD2,
0x32,
0x7A,
0x1A,
0x0D,
0x92,
0x3B,
0xAE,
0xDD,
0x14,
0x02,
0xB1,
0x81,
0x55,
0x05,
0x61,
0x04,
0xD5,
0x2C,
0x96,
0xA4,
0x4C,
0x1E,
0xCC,
0x02,
0x4A,
0xD4,
0xB2,
0x0C,
0x00,
0x1F,
0x17,
0xED,
0xC2,
0x2F,
0xC4,
0x35,
0x21,
0xC8,
0xF0,
0xCB,
0xAE,
0xD2,
0xAD,
0xD7,
0x2B,
0x0F,
0x9D,
0xB3,
0xC5,
0x32,
0x1A,
0x2A,
0xFE,
0x59,
0xF3,
0x5A,
0x0D,
0xAC,
0x68,
0xF1,
0xFA,
0x62,
0x1E,
0xFB,
0x2C,
0x8D,
0x0C,
0xB7,
0x39,
0x2D,
0x92,
0x47,
0xE3,
0xD7,
0x35,
0x1A,
0x6D,
0xBD,
0x24,
0xC2,
0xAE,
0x25,
0x5B,
0x88,
0xFF,
0xAB,
0x73,
0x29,
0x8A,
0x0B,
0xCC,
0xCD,
0x0C,
0x58,
0x67,
0x31,
0x89,
0xE8,
0xBD,
0x34,
0x80,
0x78,
0x4A,
0x5F,
0xC9,
0x6B,
0x89,
0x9D,
0x95,
0x6B,
0xFC,
0x86,
0xD7,
0x4F,
0x33,
0xA6,
0x78,
0x17,
0x96,
0xC9,
0xC3,
0x2D,
0x0D,
0x32,
0xA5,
0xAB,
0xCD,
0x05,
0x27,
0xE2,
0xF7,
0x10,
0xA3,
0x96,
0x13,
0xC4,
0x2F,
0x99,
0xC0,
0x27,
0xBF,
0xED,
0x04,
0x9C,
0x3C,
0x27,
0x58,
0x04,
0xB6,
0xB2,
0x19,
0xF9,
0xC1,
0x2F,
0x02,
0xE9,
0x48,
0x63,
0xEC,
0xA1,
0xB6,
0x42,
0xA0,
0x9D,
0x48,
0x25,
0xF8,
0xB3,
0x9D,
0xD0,
0xE8,
0x6A,
0xF9,
0x48,
0x4D,
0xA1,
0xC2,
0xBA,
0x86,
0x30,
0x42,
0xEA,
0x9D,
0xB3,
0x08,
0x6C,
0x19,
0x0E,
0x48,
0xB3,
0x9D,
0x66,
0xEB,
0x00,
0x06,
0xA2,
0x5A,
0xEE,
0xA1,
0x1B,
0x13,
0x87,
0x3C,
0xD7,
0x19,
0xE6,
0x55,
0xBD,
]) ])
_keys: DiffieHellman = None _keys: DiffieHellman = None
_inner: Session.Inner = None _inner: Session.Inner = None
@ -101,14 +351,16 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
if conf.proxyAuth and conf.proxyType is not Proxy.Type.DIRECT: if conf.proxyAuth and conf.proxyType is not Proxy.Type.DIRECT:
if conf.proxyAuth: if conf.proxyAuth:
proxy_setting = [ proxy_setting = [
conf.proxyUsername, conf.proxyPassword, conf.proxyAddress, conf.proxyUsername,
conf.proxyPort conf.proxyPassword,
conf.proxyAddress,
conf.proxyPort,
] ]
else: else:
proxy_setting = [conf.proxyAddress, conf.proxyPort] proxy_setting = [conf.proxyAddress, conf.proxyPort]
client.proxies = { client.proxies = {
"http": "{}:{}@{}:{}".format(*proxy_setting), "http": "{}:{}@{}:{}".format(*proxy_setting),
"https": "{}:{}@{}:{}".format(*proxy_setting) "https": "{}:{}@{}:{}".format(*proxy_setting),
} }
return client return client
@ -119,7 +371,7 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
if (lo & 0x80) == 0: if (lo & 0x80) == 0:
return lo return lo
hi = buffer[1] hi = buffer[1]
return lo & 0x7f | hi << 7 return lo & 0x7F | hi << 7
def client(self) -> requests.Session: def client(self) -> requests.Session:
return self._client return self._client
@ -140,7 +392,8 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
diffie_hellman=Keyexchange.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]),
)
client_hello_bytes = client_hello.SerializeToString() client_hello_bytes = client_hello.SerializeToString()
length = 2 + 4 + len(client_hello_bytes) length = 2 + 4 + len(client_hello_bytes)
@ -178,8 +431,10 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
diffie_hellman.gs) diffie_hellman.gs)
# noinspection PyTypeChecker # noinspection PyTypeChecker
if not pkcs1_v1_5.verify( if not pkcs1_v1_5.verify(
sha1, ap_response_message.challenge.login_crypto_challenge. sha1,
diffie_hellman.gs_signature): ap_response_message.challenge.login_crypto_challenge.
diffie_hellman.gs_signature,
):
raise RuntimeError("Failed signature check!") raise RuntimeError("Failed signature check!")
# Solve challenge # Solve challenge
@ -203,7 +458,8 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
diffie_hellman=Keyexchange.LoginCryptoDiffieHellmanResponse( diffie_hellman=Keyexchange.LoginCryptoDiffieHellmanResponse(
hmac=challenge)), hmac=challenge)),
pow_response=Keyexchange.PoWResponseUnion(), pow_response=Keyexchange.PoWResponseUnion(),
crypto_response=Keyexchange.CryptoResponseUnion()) crypto_response=Keyexchange.CryptoResponseUnion(),
)
client_response_plaintext_bytes = client_response_plaintext.SerializeToString( client_response_plaintext_bytes = client_response_plaintext.SerializeToString(
) )
@ -216,8 +472,10 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
self._conn.set_timeout(1) self._conn.set_timeout(1)
scrap = self._conn.read(4) scrap = self._conn.read(4)
if 4 == len(scrap): if 4 == len(scrap):
length = (scrap[0] << 24) | (scrap[1] << 16) | ( length = ((scrap[0] << 24)
scrap[2] << 8) | (scrap[3] & 0xff) | (scrap[1] << 16)
| (scrap[2] << 8)
| (scrap[3] & 0xFF))
payload = self._conn.read(length - 4) payload = self._conn.read(length - 4)
failed = Keyexchange.APResponseMessage() failed = Keyexchange.APResponseMessage()
failed.ParseFromString(payload) failed.ParseFromString(payload)
@ -245,7 +503,8 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
self._channelManager = ChannelManager(self) self._channelManager = ChannelManager(self)
self._api = ApiClient.ApiClient(self) self._api = ApiClient.ApiClient(self)
self._cdnManager = CdnManager(self) self._cdnManager = CdnManager(self)
self._contentFeeder = PlayableContentFeeder.PlayableContentFeeder(self) self._contentFeeder = PlayableContentFeeder.PlayableContentFeeder(
self)
self._cacheManager = CacheManager(self) self._cacheManager = CacheManager(self)
self._dealer = DealerClient(self) self._dealer = DealerClient(self)
self._search = SearchManager.SearchManager(self) self._search = SearchManager.SearchManager(self)
@ -276,8 +535,10 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
os=Authentication.Os.OS_UNKNOWN, os=Authentication.Os.OS_UNKNOWN,
cpu_family=Authentication.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,
version_string=Version.version_string()) ),
version_string=Version.version_string(),
)
self._send_unchecked(Packet.Type.login, self._send_unchecked(Packet.Type.login,
client_response_encrypted.SerializeToString()) client_response_encrypted.SerializeToString())
@ -317,8 +578,10 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
{ {
"username": self._apWelcome.canonical_username, "username": self._apWelcome.canonical_username,
"credentials": base64.b64encode(reusable).decode(), "credentials": base64.b64encode(reusable).decode(),
"type": reusable_type "type": reusable_type,
}, f) },
f,
)
elif packet.is_cmd(Packet.Type.auth_failure): elif packet.is_cmd(Packet.Type.auth_failure):
ap_login_failed = Keyexchange.APLoginFailed() ap_login_failed = Keyexchange.APLoginFailed()
@ -535,7 +798,10 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
Authentication.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), True) auth_data=self._apWelcome.reusable_auth_credentials,
),
True,
)
self._LOGGER.info("Re-authenticated as {}!".format( self._LOGGER.info("Re-authenticated as {}!".format(
self._apWelcome.canonical_username)) self._apWelcome.canonical_username))
@ -575,8 +841,8 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
self._userAttributes)) self._userAttributes))
def get_user_attribute(self, key: str, fallback: str = None) -> str: def get_user_attribute(self, key: str, fallback: str = None) -> str:
return self._userAttributes.get(key) if self._userAttributes.get( return (self._userAttributes.get(key)
key) is not None else fallback if self._userAttributes.get(key) is not None else fallback)
def event(self, resp: MercuryClient.Response) -> None: def event(self, resp: MercuryClient.Response) -> None:
if resp.uri == "spotify:user:attributes:update": if resp.uri == "spotify:user:attributes:update":
@ -611,18 +877,20 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
conf = None conf = None
preferred_locale: str = None preferred_locale: str = None
def __init__(self, def __init__(
self,
device_type: Connect.DeviceType, device_type: Connect.DeviceType,
device_name: str, device_name: str,
preferred_locale: str, preferred_locale: str,
conf: Session.Configuration, conf: Session.Configuration,
device_id: str = None): device_id: str = None,
):
self.preferred_locale = preferred_locale self.preferred_locale = preferred_locale
self.conf = conf self.conf = conf
self.device_type = device_type self.device_type = device_type
self.device_name = device_name self.device_name = device_name
self.device_id = device_id if device_id is not None else Utils.random_hex_string( self.device_id = (device_id if device_id is not None else
40) Utils.random_hex_string(40))
class AbsBuilder: class AbsBuilder:
conf = None conf = None
@ -682,7 +950,8 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
typ=Authentication.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"]),
)
except KeyError: except KeyError:
pass pass
@ -692,7 +961,8 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
self.login_credentials = Authentication.LoginCredentials( self.login_credentials = Authentication.LoginCredentials(
username=username, username=username,
typ=Authentication.AuthenticationType.AUTHENTICATION_USER_PASS, typ=Authentication.AuthenticationType.AUTHENTICATION_USER_PASS,
auth_data=password.encode()) auth_data=password.encode(),
)
return self return self
def create(self) -> Session: def create(self) -> Session:
@ -700,10 +970,15 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
raise RuntimeError("You must select an authentication method.") raise RuntimeError("You must select an authentication method.")
session = Session( session = Session(
Session.Inner(self.device_type, self.device_name, Session.Inner(
self.preferred_locale, self.conf, self.device_type,
self.device_id), self.device_name,
ApResolver.get_random_accesspoint()) self.preferred_locale,
self.conf,
self.device_id,
),
ApResolver.get_random_accesspoint(),
)
session._connect() session._connect()
session._authenticate(self.login_credentials) session._authenticate(self.login_credentials)
return session return session
@ -730,12 +1005,22 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
# Fetching # Fetching
retry_on_chunk_error: bool retry_on_chunk_error: bool
def __init__(self, proxy_enabled: bool, proxy_type: Proxy.Type, def __init__(
proxy_address: str, proxy_port: int, proxy_auth: bool, self,
proxy_username: str, proxy_password: str, proxy_enabled: bool,
cache_enabled: bool, cache_dir: str, proxy_type: Proxy.Type,
do_cache_clean_up: bool, store_credentials: bool, proxy_address: str,
stored_credentials_file: str, retry_on_chunk_error: bool): proxy_port: int,
proxy_auth: bool,
proxy_username: str,
proxy_password: str,
cache_enabled: bool,
cache_dir: str,
do_cache_clean_up: bool,
store_credentials: bool,
stored_credentials_file: str,
retry_on_chunk_error: bool,
):
self.proxyEnabled = proxy_enabled self.proxyEnabled = proxy_enabled
self.proxyType = proxy_type self.proxyType = proxy_type
self.proxyAddress = proxy_address self.proxyAddress = proxy_address
@ -844,11 +1129,20 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
def build(self) -> Session.Configuration: def build(self) -> Session.Configuration:
return Session.Configuration( return Session.Configuration(
self.proxyEnabled, self.proxyType, self.proxyAddress, self.proxyEnabled,
self.proxyPort, self.proxyAuth, self.proxyUsername, self.proxyType,
self.proxyPassword, self.cache_enabled, self.cache_dir, self.proxyAddress,
self.do_cache_clean_up, self.store_credentials, self.proxyPort,
self.stored_credentials_file, self.retry_on_chunk_error) self.proxyAuth,
self.proxyUsername,
self.proxyPassword,
self.cache_enabled,
self.cache_dir,
self.do_cache_clean_up,
self.store_credentials,
self.stored_credentials_file,
self.retry_on_chunk_error,
)
class SpotifyAuthenticationException(Exception): class SpotifyAuthenticationException(Exception):
def __init__(self, login_failed: Keyexchange.APLoginFailed): def __init__(self, login_failed: Keyexchange.APLoginFailed):
@ -1021,18 +1315,17 @@ class Session(Closeable, SubListener, DealerClient.MessageListener):
self.session._LOGGER.debug("Received 0x10: {}".format( self.session._LOGGER.debug("Received 0x10: {}".format(
Utils.bytes_to_hex(packet.payload))) Utils.bytes_to_hex(packet.payload)))
continue continue
if cmd == Packet.Type.mercury_sub or \ if (cmd == Packet.Type.mercury_sub
cmd == Packet.Type.mercury_unsub or \ or cmd == Packet.Type.mercury_unsub
cmd == Packet.Type.mercury_event or \ or cmd == Packet.Type.mercury_event
cmd == Packet.Type.mercury_req: or cmd == Packet.Type.mercury_req):
self.session.mercury().dispatch(packet) self.session.mercury().dispatch(packet)
continue continue
if cmd == Packet.Type.aes_key or \ if cmd == Packet.Type.aes_key or cmd == Packet.Type.aes_key_error:
cmd == Packet.Type.aes_key_error:
self.session.audio_key().dispatch(packet) self.session.audio_key().dispatch(packet)
continue continue
if cmd == Packet.Type.channel_error or \ if (cmd == Packet.Type.channel_error
cmd == Packet.Type.stream_chunk_res: or cmd == Packet.Type.stream_chunk_res):
self.session.channel().dispatch(packet) self.session.channel().dispatch(packet)
continue continue
if cmd == Packet.Type.product_info: if cmd == Packet.Type.product_info: