librespot-python/librespot/audio/cdn/CdnFeedHelper.py

108 lines
3.9 KiB
Python
Raw Normal View History

2021-02-24 00:46:59 +01:00
from __future__ import annotations
2021-05-21 05:40:50 +02:00
2021-02-24 00:46:59 +01:00
import logging
import random
import time
import typing
2021-05-21 05:40:58 +02:00
from librespot.audio import HaltListener
from librespot.audio import NormalizationData
from librespot.audio import PlayableContentFeeder
2021-05-21 05:40:50 +02:00
from librespot.common import Utils
from librespot.core import Session
from librespot.proto import Metadata_pb2 as Metadata
from librespot.proto import StorageResolve_pb2 as StorageResolve
2021-05-21 05:40:50 +02:00
2021-02-24 00:46:59 +01:00
class CdnFeedHelper:
_LOGGER: logging = logging.getLogger(__name__)
@staticmethod
def get_url(resp: StorageResolve.StorageResolveResponse) -> str:
2021-02-24 00:46:59 +01:00
return random.choice(resp.cdnurl)
@staticmethod
2021-05-21 05:40:40 +02:00
def load_track(
session: Session,
track: Metadata.Track,
file: Metadata.AudioFile,
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, str],
2021-05-21 05:40:40 +02:00
preload: bool,
2021-05-26 12:53:59 +02:00
halt_listener: HaltListener.HaltListener,
2021-05-21 05:40:40 +02:00
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
2021-02-24 00:46:59 +01:00
if type(resp_or_url) is str:
url = resp_or_url
else:
url = CdnFeedHelper.get_url(resp_or_url)
start = int(time.time() * 1000)
key = session.audio_key().get_audio_key(track.gid, file.file_id)
audio_key_time = int(time.time() * 1000) - start
streamer = session.cdn().stream_file(file, key, url, halt_listener)
input_stream = streamer.stream()
2021-05-21 05:41:17 +02:00
normalization_data = NormalizationData.NormalizationData.read(
input_stream)
2021-05-21 05:40:40 +02:00
if input_stream.skip(0xA7) != 0xA7:
2021-02-24 00:46:59 +01:00
raise IOError("Couldn't skip 0xa7 bytes!")
return PlayableContentFeeder.PlayableContentFeeder.LoadedStream(
2021-05-21 05:40:40 +02:00
track,
streamer,
normalization_data,
2021-02-24 00:46:59 +01:00
PlayableContentFeeder.PlayableContentFeeder.Metrics(
2021-05-21 05:41:17 +02:00
file.file_id, preload, -1 if preload else audio_key_time),
2021-05-21 05:40:40 +02:00
)
2021-02-24 00:46:59 +01:00
@staticmethod
def load_episode_external(
session: Session, episode: Metadata.Episode,
2021-05-26 12:53:59 +02:00
halt_listener: HaltListener.HaltListener
2021-02-24 00:46:59 +01:00
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
resp = session.client().head(episode.external_url)
if resp.status_code != 200:
CdnFeedHelper._LOGGER.warning("Couldn't resolve redirect!")
url = resp.url
2021-05-21 05:41:17 +02:00
CdnFeedHelper._LOGGER.debug("Fetched external url for {}: {}".format(
2021-05-26 10:52:44 +02:00
Utils.bytes_to_hex(episode.gid), url))
2021-02-24 00:46:59 +01:00
2021-05-21 05:41:17 +02:00
streamer = session.cdn().stream_external_episode(
episode, url, halt_listener)
2021-02-24 00:46:59 +01:00
return PlayableContentFeeder.PlayableContentFeeder.LoadedStream(
2021-05-21 05:40:40 +02:00
episode,
streamer,
None,
2021-05-21 05:41:17 +02:00
PlayableContentFeeder.PlayableContentFeeder.Metrics(
None, False, -1),
2021-05-21 05:40:40 +02:00
)
2021-02-24 00:46:59 +01:00
@staticmethod
def load_episode(
2021-05-21 05:40:40 +02:00
session: Session,
episode: Metadata.Episode,
file: Metadata.AudioFile,
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, str],
2021-05-26 12:53:59 +02:00
halt_listener: HaltListener.HaltListener,
2021-02-24 00:46:59 +01:00
) -> PlayableContentFeeder.PlayableContentFeeder.LoadedStream:
if type(resp_or_url) is str:
url = resp_or_url
else:
url = CdnFeedHelper.get_url(resp_or_url)
start = int(time.time() * 1000)
key = session.audio_key().get_audio_key(episode.gid, file.file_id)
audio_key_time = int(time.time() * 1000) - start
streamer = session.cdn().stream_file(file, key, url, halt_listener)
input_stream = streamer.stream()
normalization_data = NormalizationData.NormalizationData.read(
input_stream)
2021-05-21 05:40:40 +02:00
if input_stream.skip(0xA7) != 0xA7:
2021-02-24 00:46:59 +01:00
raise IOError("Couldn't skip 0xa7 bytes!")
return PlayableContentFeeder.PlayableContentFeeder.LoadedStream(
2021-05-21 05:40:40 +02:00
episode,
streamer,
normalization_data,
2021-02-24 00:46:59 +01:00
PlayableContentFeeder.PlayableContentFeeder.Metrics(
2021-05-21 05:41:17 +02:00
file.file_id, False, audio_key_time),
2021-05-21 05:40:40 +02:00
)