From d154b2be201954aaaad3e3fc636b67b83d7806b9 Mon Sep 17 00:00:00 2001 From: Ritiek Malhotra Date: Mon, 23 Mar 2020 18:29:23 +0530 Subject: [PATCH] Download while simultaneously encoding --- spotdl/__init__.py | 2 + spotdl/download.py | 66 ++++++++++++++++++++++++++++++++ spotdl/encode/encoders/ffmpeg.py | 4 +- spotdl/helpers.py | 20 ++++++++++ 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 spotdl/download.py create mode 100644 spotdl/helpers.py diff --git a/spotdl/__init__.py b/spotdl/__init__.py index 64c7d51..ddf7530 100644 --- a/spotdl/__init__.py +++ b/spotdl/__init__.py @@ -1 +1,3 @@ __version__ = "1.2.6" + +from spotdl.download import Track diff --git a/spotdl/download.py b/spotdl/download.py new file mode 100644 index 0000000..b647cc9 --- /dev/null +++ b/spotdl/download.py @@ -0,0 +1,66 @@ +import tqdm + +import subprocess +import urllib.request + +from spotdl.encode.encoders import EncoderFFmpeg + +CHUNK_SIZE= 16 * 1024 +HEADERS = [('Range', 'bytes=0-'),] + +class Track: + def __init__(self, metadata): + self.metadata = metadata + self.network_headers = HEADERS + self._chunksize = CHUNK_SIZE + + def _make_request(self, url): + request = urllib.request.Request(url) + for header in self.network_headers: + request.add_header(*header) + return urllib.request.urlopen(request) + + def _calculate_total_chunks(self, filesize): + return (filesize // self._chunksize) + 1 + + def download_while_re_encoding(self, path, encoder=EncoderFFmpeg(), show_progress=True): + stream = self.metadata["streams"].getbest() + total_chunks = self._calculate_total_chunks(stream["filesize"]) + response = self._make_request(stream["download_url"]) + process = encoder.re_encode_from_stdin( + stream["encoding"], + path + ) + for _ in tqdm.trange(total_chunks): + chunk = response.read(self._chunksize) + process.stdin.write(chunk) + + process.stdin.close() + process.wait() + + def download(self, path, show_progress=True): + stream = self.metadata["streams"].getbest() + total_chunks = self._calculate_total_chunks(stream["filesize"]) + response = self._make_request(stream["download_url"]) + with open(path, "wb") as fout: + for _ in tqdm.trange(total_chunks): + chunk = response.read(self._chunksize) + fout.write(chunk) + + def re_encode(self, input_path, target_path, encoder=EncoderFFmpeg(), show_progress=True): + stream = self.metadata["streams"].getbest() + total_chunks = self._calculate_total_chunks(stream["filesize"]) + process = encoder.re_encode_from_stdin( + stream["encoding"], + target_path + ) + with open(input_path, "rb") as fin: + for _ in tqdm.trange(total_chunks): + chunk = fin.read(self._chunksize) + process.stdin.write(chunk) + + process.stdin.close() + process.wait() + + def apply_metadata(path): + pass diff --git a/spotdl/encode/encoders/ffmpeg.py b/spotdl/encode/encoders/ffmpeg.py index b9f0273..afbefb0 100644 --- a/spotdl/encode/encoders/ffmpeg.py +++ b/spotdl/encode/encoders/ffmpeg.py @@ -13,7 +13,7 @@ RULES = { "m4a": "-acodec copy", "flac": "-codec:a flac -ar 48000", }, - "webm": { + "opus": { "mp3": "-codec:a libmp3lame -ar 48000", "m4a": "-cutoff 20000 -codec:a aac -ar 48000", "flac": "-codec:a flac -ar 48000", @@ -99,6 +99,6 @@ class EncoderFFmpeg(EncoderBase): output_file, input_encoding=input_encoding, ) - process = subprocess.Popen(encode_command) + process = subprocess.Popen(encode_command, stdin=subprocess.PIPE) return process diff --git a/spotdl/helpers.py b/spotdl/helpers.py new file mode 100644 index 0000000..fc6c2d0 --- /dev/null +++ b/spotdl/helpers.py @@ -0,0 +1,20 @@ +import subprocess +import threading + + +def download(url, path=".", progress_bar=True, ): + command = ("ffmpeg", "-y", "-i", "-", "output.wav") + + content = pytube.YouTube("https://www.youtube.com/watch?v=SE0nYFJ0ZvQ") + stream = content.streams[0] + response = urllib.request.urlopen(stream.url) + + process = subprocess.Popen(command, stdin=subprocess.PIPE) + + while True: + chunk = response.read(16 * 1024) + if not chunk: + break + process.stdin.write(chunk) + + process.stdin.close()