2021-10-24 10:35:06 +02:00
|
|
|
import os
|
2021-10-24 19:45:52 +02:00
|
|
|
from typing import Optional, Tuple
|
2021-10-23 17:36:37 +02:00
|
|
|
|
2021-10-25 07:36:17 +02:00
|
|
|
from librespot.audio.decoders import VorbisOnlyAudioQuality
|
2021-10-23 17:36:37 +02:00
|
|
|
from librespot.metadata import EpisodeId
|
|
|
|
from tqdm import tqdm
|
|
|
|
|
2021-10-27 09:25:27 +02:00
|
|
|
from const import (CHUNK_SIZE, ERROR, ID, ITEMS, NAME, ROOT_PODCAST_PATH, SHOW,
|
|
|
|
SKIP_EXISTING_FILES)
|
2021-10-30 11:43:07 +02:00
|
|
|
from utils import create_download_directory, fix_filename
|
2021-10-23 17:36:37 +02:00
|
|
|
from zspotify import ZSpotify
|
|
|
|
|
|
|
|
EPISODE_INFO_URL = 'https://api.spotify.com/v1/episodes'
|
|
|
|
SHOWS_URL = 'https://api.spotify.com/v1/shows'
|
|
|
|
|
|
|
|
|
2021-10-25 07:36:17 +02:00
|
|
|
def get_episode_info(episode_id_str) -> Tuple[Optional[str], Optional[str]]:
|
|
|
|
info = ZSpotify.invoke_url(f'{EPISODE_INFO_URL}/{episode_id_str}')
|
2021-10-23 17:36:37 +02:00
|
|
|
if ERROR in info:
|
|
|
|
return None, None
|
2021-10-30 11:43:07 +02:00
|
|
|
return fix_filename(info[SHOW][NAME]), fix_filename(info[NAME])
|
2021-10-23 17:36:37 +02:00
|
|
|
|
|
|
|
|
2021-10-25 07:36:17 +02:00
|
|
|
def get_show_episodes(show_id_str) -> list:
|
2021-10-23 17:36:37 +02:00
|
|
|
episodes = []
|
2021-10-24 06:20:41 +02:00
|
|
|
offset = 0
|
|
|
|
limit = 50
|
|
|
|
|
|
|
|
while True:
|
2021-10-31 02:20:25 +02:00
|
|
|
resp = ZSpotify.invoke_url_with_params(
|
|
|
|
f'{SHOWS_URL}/{show_id_str}/episodes', limit=limit, offset=offset)
|
2021-10-24 06:20:41 +02:00
|
|
|
offset += limit
|
|
|
|
for episode in resp[ITEMS]:
|
|
|
|
episodes.append(episode[ID])
|
|
|
|
if len(resp[ITEMS]) < limit:
|
|
|
|
break
|
2021-10-23 17:36:37 +02:00
|
|
|
|
|
|
|
return episodes
|
|
|
|
|
|
|
|
|
2021-10-31 02:20:25 +02:00
|
|
|
def download_podcast_experimental(url, filename):
|
|
|
|
import functools
|
|
|
|
import pathlib
|
|
|
|
import shutil
|
|
|
|
import requests
|
|
|
|
from tqdm.auto import tqdm
|
|
|
|
|
|
|
|
r = requests.get(url, stream=True, allow_redirects=True)
|
|
|
|
if r.status_code != 200:
|
|
|
|
r.raise_for_status() # Will only raise for 4xx codes, so...
|
|
|
|
raise RuntimeError(
|
|
|
|
f"Request to {url} returned status code {r.status_code}")
|
|
|
|
file_size = int(r.headers.get('Content-Length', 0))
|
|
|
|
|
|
|
|
path = pathlib.Path(filename).expanduser().resolve()
|
|
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
|
|
desc = "(Unknown total file size)" if file_size == 0 else ""
|
|
|
|
r.raw.read = functools.partial(
|
|
|
|
r.raw.read, decode_content=True) # Decompress if needed
|
|
|
|
with tqdm.wrapattr(r.raw, "read", total=file_size, desc=desc) as r_raw:
|
|
|
|
with path.open("wb") as f:
|
|
|
|
shutil.copyfileobj(r_raw, f)
|
|
|
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
2021-10-23 17:36:37 +02:00
|
|
|
def download_episode(episode_id) -> None:
|
|
|
|
podcast_name, episode_name = get_episode_info(episode_id)
|
|
|
|
|
|
|
|
extra_paths = podcast_name + '/'
|
|
|
|
|
2021-10-25 07:36:17 +02:00
|
|
|
if podcast_name is None:
|
2021-10-23 17:36:37 +02:00
|
|
|
print('### SKIPPING: (EPISODE NOT FOUND) ###')
|
|
|
|
else:
|
|
|
|
filename = podcast_name + ' - ' + episode_name
|
|
|
|
|
2021-10-26 20:30:19 +02:00
|
|
|
download_directory = os.path.join(
|
|
|
|
os.path.dirname(__file__),
|
|
|
|
ZSpotify.get_config(ROOT_PODCAST_PATH),
|
|
|
|
extra_paths,
|
|
|
|
)
|
2021-10-27 09:25:27 +02:00
|
|
|
download_directory = os.path.realpath(download_directory)
|
2021-10-24 10:35:06 +02:00
|
|
|
create_download_directory(download_directory)
|
2021-10-23 17:36:37 +02:00
|
|
|
|
2021-10-31 02:20:25 +02:00
|
|
|
filepath = os.path.join(download_directory, f"{filename}.mp3")
|
|
|
|
|
|
|
|
download_url = ZSpotify.invoke_url(
|
|
|
|
'https://api-partner.spotify.com/pathfinder/v1/query?operationName=getEpisode&variables={"uri":"spotify:episode:3u0krXMhLcdGZUZkDVmMSt"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"224ba0fd89fcfdfb3a15fa2d82a6112d3f4e2ac88fba5c6713de04d1b72cf482"}}')["data"]["episode"]["audio"]["items"][-1]["url"]
|
|
|
|
|
|
|
|
download_podcast_experimental(download_url, filepath)
|
2021-10-23 17:36:37 +02:00
|
|
|
|
|
|
|
# convert_audio_format(ROOT_PODCAST_PATH +
|
2021-10-26 20:30:19 +02:00
|
|
|
# extra_paths + filename + '.ogg')
|