diff --git a/rip/cli.py b/rip/cli.py index 9556a8d..65c57f4 100644 --- a/rip/cli.py +++ b/rip/cli.py @@ -356,6 +356,19 @@ def config(ctx, **kwargs): @click.argument("PATH") @click.pass_context def convert(ctx, **kwargs): + """Batch convert audio files. + + This is a tool that is included with the `rip` program that assists with + converting audio files. This is essentially a wrapper over ffmpeg + that is designed to be easy to use with sensible default options. + + Examples (assuming /my/music is filled with FLAC files): + + $ rip convert MP3 /my/music + + $ rip convert ALAC --sampling-rate 48000 /my/music + + """ from streamrip import converter import concurrent.futures from tqdm import tqdm @@ -425,7 +438,15 @@ def convert(ctx, **kwargs): ) @click.pass_context def repair(ctx, **kwargs): - core.repair() + """Retry failed downloads. + + If the failed downloads database is enabled in the config file (it is by default), + when an item is not available for download, it is logged in the database. + + When this command is called, it tries to download those items again. This is useful + for times when a temporary server error may miss a few tracks in an album. + """ + core.repair(max_items=kwargs.get("num_items")) def none_chosen(): diff --git a/rip/core.py b/rip/core.py index dd484dd..de7a882 100644 --- a/rip/core.py +++ b/rip/core.py @@ -230,16 +230,19 @@ class MusicDL(list): "max_artwork_height": int(artwork["max_height"]), } - def repair(self, max_items=float("inf")): - print(list(self.failed_db)) + def repair(self, max_items=None): + if max_items is None: + max_items = float("inf") + if self.failed_db.is_dummy: click.secho( - "Failed downloads database must be enabled to repair!", fg="red" + "Failed downloads database must be enabled in the config file " + "to repair!", + fg="red", ) - exit(1) + raise click.Abort for counter, (source, media_type, item_id) in enumerate(self.failed_db): - # print(f"handling item {source = } {media_type = } {item_id = }") if counter >= max_items: break @@ -293,13 +296,11 @@ class MusicDL(list): try: item.download(**arguments) except NonStreamable as e: - print("caught in core") e.print(item) self.failed_db.add((item.client.source, item.type, item.id)) continue except PartialFailure as e: for failed_item in e.failed_items: - print(f"adding {failed_item} to database") self.failed_db.add(failed_item) continue diff --git a/streamrip/exceptions.py b/streamrip/exceptions.py index 9a37234..ad8e1d6 100644 --- a/streamrip/exceptions.py +++ b/streamrip/exceptions.py @@ -32,11 +32,16 @@ class NonStreamable(Exception): super().__init__(self.message) def print(self, item): + print(self.print_msg(item)) + + def print_msg(self, item) -> str: + base_msg = click.style(f"Unable to stream {item!s}.", fg="yellow") if self.message: - click.secho(f"Unable to stream {item!s}. Message: ", nl=False, fg="yellow") - click.secho(self.message, fg="red") - else: - click.secho(f"Unable to stream {item!s}.", fg="yellow") + base_msg += click.style(" Message: ", fg="yellow") + click.style( + self.message, fg="red" + ) + + return base_msg class InvalidContainerError(Exception): diff --git a/streamrip/media.py b/streamrip/media.py index e68493b..d9fcb26 100644 --- a/streamrip/media.py +++ b/streamrip/media.py @@ -230,6 +230,7 @@ class Track(Media): :param progress_bar: turn on/off progress bar :type progress_bar: bool """ + # raise NonStreamable self._prepare_download( quality=quality, parent_folder=parent_folder, @@ -976,16 +977,16 @@ class Tracklist(list): for future in future_map.keys(): try: future.result() - except NonStreamable: - print("caught in media conc") + except NonStreamable as e: item = future_map[future] + e.print(item) failed_downloads.append( (item.client.source, item.type, item.id) ) except (KeyboardInterrupt, SystemExit): executor.shutdown() - tqdm.write("Aborted! May take some time to shutdown.") + click.echo("Aborted! May take some time to shutdown.") raise click.Abort else: diff --git a/tests/tests.py b/tests/tests.py index 51fe46a..279f099 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -44,7 +44,7 @@ def download_albums(): procs.append(subprocess.run([*rip_url, url])) for p in procs: - print(p) + click.echo(p) def check_album_dl_success(folder, correct):