diff --git a/bandcamp_dl/__main__.py b/bandcamp_dl/__main__.py index 1c6b8da..f74fa03 100755 --- a/bandcamp_dl/__main__.py +++ b/bandcamp_dl/__main__.py @@ -62,10 +62,12 @@ def main(): action='store_true', default=conf.no_confirm) parser.add_argument('--embed-genres', help='Embed album/track genres', action='store_true', default=conf.embed_genres) - parser.add_argument('--truncate-album', metavar='LENGTH', type=int, default=0, + parser.add_argument('--truncate-album', metavar='LENGTH', type=int, default=conf.truncate_album, help='Truncate album title to a maximum length. 0 for no limit.') - parser.add_argument('--truncate-track', metavar='LENGTH', type=int, default=0, + parser.add_argument('--truncate-track', metavar='LENGTH', type=int, default=conf.truncate_track, help='Truncate track title to a maximum length. 0 for no limit.') + parser.add_argument('--limit-req-per-minute', type=int, default=conf.limit_req_per_minute, + help='Limit the number of requests sent per minute. 0 for no limit.') arguments = parser.parse_args() @@ -92,7 +94,7 @@ def main(): ('ok_chars', config.OK_CHARS), ('space_char', config.SPACE_CHAR)]: if not getattr(arguments, arg): setattr(arguments, arg, val) - bandcamp = Bandcamp() + bandcamp = Bandcamp(limit_req_per_minute=arguments.limit_req_per_minute) if arguments.artist and arguments.album: urls = Bandcamp.generate_album_url(arguments.artist, arguments.album, "album") diff --git a/bandcamp_dl/bandcamp.py b/bandcamp_dl/bandcamp.py index ac20bbe..600c596 100644 --- a/bandcamp_dl/bandcamp.py +++ b/bandcamp_dl/bandcamp.py @@ -6,6 +6,7 @@ import bs4 import requests from requests.adapters import HTTPAdapter +from requests_ratelimiter import LimiterAdapter from urllib3.util import create_urllib3_context from urllib.parse import urlparse, urlunparse, urljoin @@ -51,17 +52,24 @@ def proxy_manager_for(self, *args, **kwargs): ctx.set_ciphers(DEFAULT_CIPHERS) class Bandcamp: - def __init__(self): + def __init__(self, limit_req_per_minute: int = 0): self.headers = {'User-Agent': f'bandcamp-dl/{__version__} ' f'(https://github.com/evolution0/bandcamp-dl)'} self.soup = None self.tracks = None self.logger = logging.getLogger("bandcamp-dl").getChild("Main") - # Mount the adapter with the custom SSL context to the session self.session = requests.Session() - self.adapter = SSLAdapter(ssl_context=ctx) - self.session.mount('https://', self.adapter) + # Mount the adapter with the custom SSL context to the session + self.ssl_adapter = SSLAdapter(ssl_context=ctx) + self.session.mount('https://', self.ssl_adapter) + + if 0 < limit_req_per_minute: + # Mount the rate-limiting adapter to the session + self.rate_adapter = LimiterAdapter(per_minute=limit_req_per_minute) + self.session.mount('https://', self.rate_adapter) + else: + self.rate_adapter = None def parse(self, url: str, art: bool = True, lyrics: bool = False, genres: bool = False, debugging: bool = False, cover_quality: int = 0) -> dict or None: diff --git a/bandcamp_dl/bandcampdownloader.py b/bandcamp_dl/bandcampdownloader.py index b628908..762ba27 100644 --- a/bandcamp_dl/bandcampdownloader.py +++ b/bandcamp_dl/bandcampdownloader.py @@ -6,6 +6,7 @@ from mutagen import mp3 from mutagen import id3 import requests +from requests_ratelimiter import LimiterAdapter import slugify from bandcamp_dl import __version__ @@ -26,7 +27,15 @@ def __init__(self, config, urls=None): """ self.headers = {'User-Agent': f'bandcamp-dl/{__version__} ' f'(https://github.com/evolution0/bandcamp-dl)'} + self.session = requests.Session() + if 0 < config.limit_req_per_minute: + # Mount the rate-limiting adapter to the session + self.rate_adapter = LimiterAdapter(per_minute=config.limit_req_per_minute) + self.session.mount('https://', self.rate_adapter) + else: + self.rate_adapter = None + self.logger = logging.getLogger("bandcamp-dl").getChild("Downloader") if type(urls) is str: diff --git a/bandcamp_dl/config.py b/bandcamp_dl/config.py index 1dc5506..231123d 100644 --- a/bandcamp_dl/config.py +++ b/bandcamp_dl/config.py @@ -44,7 +44,8 @@ class Config(dict): "cover_quality": 0, "untitled_path_from_slug": False, "truncate_album": 0, - "truncate_track": 0} + "truncate_track": 0, + "limit_req_per_minute": 0} def __init__(self, dict_=None): if dict_ is None: diff --git a/pyproject.toml b/pyproject.toml index 9c19e20..8569283 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,8 @@ dependencies = [ "requests >= 2.32.3", "unicode-slugify >= 0.1.5", "urllib3 >= 2.2.2", - "toml ; python_version < '3.11'" + "toml ; python_version < '3.11'", + "requests-ratelimiter >= 0.7.0", ] license = {text = "Unlicense"} @@ -37,4 +38,4 @@ bandcamp-dl = "bandcamp_dl.__main__:main" [project.urls] Documentation = "https://github.com/evolution0/bandcamp-dl/blob/master/README.rst" Source = "https://github.com/evolution0/bandcamp-dl" -Tracker = "https://github.com/evolution0/bandcamp-dl/issues" \ No newline at end of file +Tracker = "https://github.com/evolution0/bandcamp-dl/issues"