mirror of
https://github.com/nathom/streamrip.git
synced 2025-05-25 04:24:49 -04:00
Remove mutagen dependency for converter, bug fixes
This commit is contained in:
parent
89ddd0d3a6
commit
39f54db075
6 changed files with 32 additions and 27 deletions
|
@ -152,7 +152,7 @@ class QobuzClient(ClientInterface):
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
# for multithreading
|
# for multithreading
|
||||||
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
|
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
|
||||||
self.session.mount('https://', adapter)
|
self.session.mount("https://", adapter)
|
||||||
self.session.headers.update(
|
self.session.headers.update(
|
||||||
{
|
{
|
||||||
"User-Agent": AGENT,
|
"User-Agent": AGENT,
|
||||||
|
@ -377,6 +377,11 @@ class DeezerClient(ClientInterface):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
|
# for multithreading
|
||||||
|
adapter = requests.adapters.HTTPAdapter(pool_connections=300, pool_maxsize=300)
|
||||||
|
self.session.mount("https://", adapter)
|
||||||
|
|
||||||
|
# no login required
|
||||||
self.logged_in = True
|
self.logged_in = True
|
||||||
|
|
||||||
def search(self, query: str, media_type: str = "album", limit: int = 200) -> dict:
|
def search(self, query: str, media_type: str = "album", limit: int = 200) -> dict:
|
||||||
|
@ -392,9 +397,6 @@ class DeezerClient(ClientInterface):
|
||||||
# TODO: more robust url sanitize
|
# TODO: more robust url sanitize
|
||||||
query = query.replace(" ", "+")
|
query = query.replace(" ", "+")
|
||||||
|
|
||||||
if media_type.endswith("s"):
|
|
||||||
media_type = media_type[:-1]
|
|
||||||
|
|
||||||
# TODO: use limit parameter
|
# TODO: use limit parameter
|
||||||
response = self.session.get(f"{DEEZER_BASE}/search/{media_type}?q={query}")
|
response = self.session.get(f"{DEEZER_BASE}/search/{media_type}?q={query}")
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
@ -453,7 +455,7 @@ class TidalClient(ClientInterface):
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
# for multithreading
|
# for multithreading
|
||||||
adapter = requests.adapters.HTTPAdapter(pool_connections=200, pool_maxsize=200)
|
adapter = requests.adapters.HTTPAdapter(pool_connections=200, pool_maxsize=200)
|
||||||
self.session.mount('https://', adapter)
|
self.session.mount("https://", adapter)
|
||||||
|
|
||||||
def login(
|
def login(
|
||||||
self,
|
self,
|
||||||
|
@ -675,7 +677,7 @@ class TidalClient(ClientInterface):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def _update_authorization(self):
|
def _update_authorization(self):
|
||||||
self.session.headers.update({'authorization': f"Bearer {self.access_token}"})
|
self.session.headers.update({"authorization": f"Bearer {self.access_token}"})
|
||||||
|
|
||||||
|
|
||||||
class SoundCloudClient(ClientInterface):
|
class SoundCloudClient(ClientInterface):
|
||||||
|
|
|
@ -86,7 +86,7 @@ class Config:
|
||||||
"path_format": {"folder": FOLDER_FORMAT, "track": TRACK_FORMAT},
|
"path_format": {"folder": FOLDER_FORMAT, "track": TRACK_FORMAT},
|
||||||
"check_for_updates": True,
|
"check_for_updates": True,
|
||||||
"lastfm": {"source": "qobuz"},
|
"lastfm": {"source": "qobuz"},
|
||||||
"concurrent_downloads": {"enabled": True, "max_connections": None}
|
"concurrent_downloads": {"enabled": True, "max_connections": None},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, path: str = None):
|
def __init__(self, path: str = None):
|
||||||
|
|
|
@ -5,13 +5,12 @@ import subprocess
|
||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from mutagen.flac import FLAC as FLAC_META
|
|
||||||
from mutagen.mp4 import MP4 as M4A_META
|
|
||||||
|
|
||||||
from .exceptions import ConversionError
|
from .exceptions import ConversionError
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SAMPLING_RATES = (44100, 48000, 88200, 96000, 176400, 192000)
|
||||||
|
|
||||||
|
|
||||||
class Converter:
|
class Converter:
|
||||||
"""Base class for audio codecs."""
|
"""Base class for audio codecs."""
|
||||||
|
@ -112,13 +111,10 @@ class Converter:
|
||||||
|
|
||||||
if self.lossless:
|
if self.lossless:
|
||||||
if isinstance(self.sampling_rate, int):
|
if isinstance(self.sampling_rate, int):
|
||||||
meta_objects = {
|
sampling_rates = "|".join(
|
||||||
"flac": FLAC_META,
|
str(rate) for rate in SAMPLING_RATES if rate <= self.sampling_rate
|
||||||
"alac": M4A_META,
|
)
|
||||||
}
|
command.extend(['-af', f"aformat=sample_rates={sampling_rates}"])
|
||||||
audio = meta_objects[self.container](self.filename)
|
|
||||||
old_sr = audio.info.sample_rate
|
|
||||||
command.extend(["-ar", str(min(old_sr, self.sampling_rate))])
|
|
||||||
|
|
||||||
elif self.sampling_rate is not None:
|
elif self.sampling_rate is not None:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
|
@ -135,6 +131,7 @@ class Converter:
|
||||||
elif self.bit_depth is not None:
|
elif self.bit_depth is not None:
|
||||||
raise TypeError(f"Bit depth must be int, not {type(self.bit_depth)}")
|
raise TypeError(f"Bit depth must be int, not {type(self.bit_depth)}")
|
||||||
|
|
||||||
|
# automatically overwrite
|
||||||
command.extend(["-y", self.tempfile])
|
command.extend(["-y", self.tempfile])
|
||||||
|
|
||||||
return command
|
return command
|
||||||
|
|
|
@ -167,7 +167,9 @@ class MusicDL(list):
|
||||||
],
|
],
|
||||||
"stay_temp": self.config.session["conversion"]["enabled"],
|
"stay_temp": self.config.session["conversion"]["enabled"],
|
||||||
"conversion": self.config.session["conversion"],
|
"conversion": self.config.session["conversion"],
|
||||||
"concurrent_downloads": self.config.session['concurrent_downloads']['enabled'],
|
"concurrent_downloads": self.config.session["concurrent_downloads"][
|
||||||
|
"enabled"
|
||||||
|
],
|
||||||
}
|
}
|
||||||
logger.debug("Arguments from config: %s", arguments)
|
logger.debug("Arguments from config: %s", arguments)
|
||||||
for item in self:
|
for item in self:
|
||||||
|
|
|
@ -609,8 +609,9 @@ class Tracklist(list):
|
||||||
if kwargs.get("concurrent_downloads", True):
|
if kwargs.get("concurrent_downloads", True):
|
||||||
processes = []
|
processes = []
|
||||||
for item in self:
|
for item in self:
|
||||||
proc = threading.Thread(target=target, args=(item,), kwargs=kwargs)
|
proc = threading.Thread(
|
||||||
proc.daemon = True
|
target=target, args=(item,), kwargs=kwargs, daemon=True
|
||||||
|
)
|
||||||
proc.start()
|
proc.start()
|
||||||
processes.append(proc)
|
processes.append(proc)
|
||||||
|
|
||||||
|
@ -844,7 +845,11 @@ class Album(Tracklist):
|
||||||
embed_cover_size in self.cover_urls
|
embed_cover_size in self.cover_urls
|
||||||
), f"Invalid cover size. Must be in {self.cover_urls.keys()}"
|
), f"Invalid cover size. Must be in {self.cover_urls.keys()}"
|
||||||
|
|
||||||
tqdm_download(self.cover_urls[embed_cover_size], cover_path)
|
embed_cover_url = self.cover_urls[embed_cover_size]
|
||||||
|
if embed_cover_url is not None:
|
||||||
|
tqdm_download(embed_cover_url, cover_path)
|
||||||
|
else: # sometimes happens with Deezer
|
||||||
|
tqdm_download(self.cover_urls["small"], cover_path)
|
||||||
|
|
||||||
if kwargs.get("keep_hires_cover", True):
|
if kwargs.get("keep_hires_cover", True):
|
||||||
tqdm_download(
|
tqdm_download(
|
||||||
|
@ -880,17 +885,15 @@ class Album(Tracklist):
|
||||||
disc_folder = os.path.join(self.folder, f"Disc {track.meta.discnumber}")
|
disc_folder = os.path.join(self.folder, f"Disc {track.meta.discnumber}")
|
||||||
kwargs["parent_folder"] = disc_folder
|
kwargs["parent_folder"] = disc_folder
|
||||||
else:
|
else:
|
||||||
kwargs['parent_folder'] = self.folder
|
kwargs["parent_folder"] = self.folder
|
||||||
|
|
||||||
track.download(
|
track.download(quality=quality, database=database, **kwargs)
|
||||||
quality=quality, database=database, **kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
# deezer tracks come tagged
|
# deezer tracks come tagged
|
||||||
if kwargs.get("tag_tracks", True) and self.client.source != "deezer":
|
if kwargs.get("tag_tracks", True) and self.client.source != "deezer":
|
||||||
track.tag(cover=self.cover_obj, embed_cover=kwargs.get("embed_cover", True))
|
track.tag(cover=self.cover_obj, embed_cover=kwargs.get("embed_cover", True))
|
||||||
|
|
||||||
if safe_get(kwargs, 'conversion', 'enabled', default=False):
|
if safe_get(kwargs, "conversion", "enabled", default=False):
|
||||||
track.convert(**kwargs["conversion"])
|
track.convert(**kwargs["conversion"])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -19,7 +19,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
|
adapter = requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)
|
||||||
session.mount('https://', adapter)
|
session.mount("https://", adapter)
|
||||||
|
|
||||||
|
|
||||||
def safe_get(d: dict, *keys: Hashable, default=None):
|
def safe_get(d: dict, *keys: Hashable, default=None):
|
||||||
|
@ -117,6 +117,7 @@ def tqdm_download(url: str, filepath: str, params: dict = None):
|
||||||
total = int(r.headers.get("content-length", 0))
|
total = int(r.headers.get("content-length", 0))
|
||||||
logger.debug(f"File size = {total}")
|
logger.debug(f"File size = {total}")
|
||||||
if total < 1000 and not url.endswith("jpg") and not url.endswith("png"):
|
if total < 1000 and not url.endswith("jpg") and not url.endswith("png"):
|
||||||
|
print(url)
|
||||||
raise NonStreamable(url)
|
raise NonStreamable(url)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue