Merge pull request #29 from kokarare1212/deepsource-transform-c875c54e
Format code with yapf
This commit is contained in:
commit
8f920a783b
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue