def watch(anime_name, new, update_all, _list, quality, log_level, remove, download_dir, provider): """ With watch you can keep track of any anime you watch. Available Commands after selection of an anime:\n set : set episodes_done, provider and title. Ex: set episodes_done=3\n remove : remove selected anime from watch list\n update : Update the episodes of the currrent anime\n watch : Watch selected anime\n download : Download episodes of selected anime """ util.setup_logger(log_level) util.print_info(__version__) watcher = _watch.Watcher() if new: if anime_name: query = anime_name else: query = click.prompt('Enter a anime name or url', type=str) url = util.search(query, provider) watcher.new(url) sys.exit(0) if remove: anime = watcher.get(anime_name) if anime and click.confirm("Remove '{}'".format(anime.title), abort=True): watcher.remove(anime) else: logging.error("Couldn't find '{}'. " "Use a better search term.".format(anime_name)) sys.exit(1) sys.exit(0) if update_all: animes = watcher.anime_list() for anime in animes: watcher.update_anime(anime) if _list: list_animes(watcher, quality, download_dir) sys.exit(0) if anime_name: anime = watcher.get(anime_name) if not anime: logging.error("Couldn't find '{}'." "Use a better search term.".format(anime_name)) sys.exit(1) anime.quality = quality logging.info('Found {}'.format(anime.title)) watch_anime(watcher, anime)
def command(test_query): """Test all sites to see which ones are working and which ones aren't. Test naruto as a default.""" util.print_info(__version__) logger = logging.getLogger("anime_downloader") logger.setLevel(logging.ERROR) threads = [] for site in sitenames: t = SiteThread(site, daemon=True) t.start() threads.append(t) for thread in threads: if os.name == 'nt': p, f = 'Works: ', "Doesn't work: " # Emojis doesn't work in cmd else: p, f = '✅ ', '❌ ' thread.join(timeout=10) if not thread.is_alive(): if not thread.exception: # echo(click.style('Works ', fg='green') + site) echo(click.style(p, fg='green') + thread.site) else: logging.debug('Error occurred during testing') logging.debug(thread.exception) echo(click.style(f, fg='red') + thread.site) else: logging.debug('timeout during testing') echo(click.style(f, fg='red') + thread.site)
def dl(ctx, anime_url, episode_range, url, player, skip_download, quality, force_download, log_level, download_dir): """ Download the anime using the url or search for it. """ util.setup_logger(log_level) util.print_info(__version__) cls = get_anime_class(anime_url) if not cls: anime_url = util.search_and_get_url(anime_url) cls = get_anime_class(anime_url) try: anime = cls(anime_url, quality=quality) except NotFoundError as e: echo(e.args[0]) return if episode_range is None: episode_range = '1:' + str(len(anime) + 1) logging.info('Found anime: {}'.format(anime.title)) anime = util.split_anime(anime, episode_range) util.process_anime(anime, player=player, force_download=force_download, download_dir=download_dir, url=url, skip_download=skip_download)
def dl(ctx, anime_url, episode_range, url, player, skip_download, quality, force_download, log_level, download_dir, file_format, provider, external_downloader): """ Download the anime using the url or search for it. """ util.setup_logger(log_level) util.print_info(__version__) cls = get_anime_class(anime_url) if not cls: anime_url = util.search(anime_url, provider) cls = get_anime_class(anime_url) try: anime = cls(anime_url, quality=quality) except Exception as e: echo(click.style(str(e), fg='red')) return # TODO: Refractor this somewhere else. (util?) if episode_range is None: episode_range = '1:' if episode_range.endswith(':'): episode_range += str(len(anime) + 1) if episode_range.startswith(':'): episode_range = '1' + episode_range logging.info('Found anime: {}'.format(anime.title)) anime = util.split_anime(anime, episode_range) if url or player: skip_download = True if download_dir and not skip_download: logging.info('Downloading to {}'.format(os.path.abspath(download_dir))) for episode in anime: if url: util.print_episodeurl(episode) if player: util.play_episode(episode, player=player) if not skip_download: if external_downloader: logging.info('Downloading episode {} of {}'.format( episode.ep_no, anime.title)) util.external_download(external_downloader, episode, file_format, path=download_dir) continue episode.download(force=force_download, path=download_dir, format=file_format) print()
def command(ctx, anime_url, episode_range, url, player, skip_download, quality, force_download, download_dir, file_format, provider, external_downloader, chunk_size, disable_ssl, fallback_qualities, choice): """ Download the anime using the url or search for it. """ util.print_info(__version__) # TODO: Replace by factory cls = get_anime_class(anime_url) disable_ssl = cls and cls.__name__ == 'Masterani' or disable_ssl session.get_session().verify = not disable_ssl if not cls: anime_url = util.search(anime_url, provider, choice) cls = get_anime_class(anime_url) anime = cls(anime_url, quality=quality, fallback_qualities=fallback_qualities) logger.info('Found anime: {}'.format(anime.title)) animes = util.parse_ep_str(anime, episode_range) # TODO: # Two types of plugins: # - Aime plugin: Pass the whole anime # - Ep plugin: Pass each episode if url or player: skip_download = True if download_dir and not skip_download: logger.info('Downloading to {}'.format(os.path.abspath(download_dir))) for episode in animes: if url: util.print_episodeurl(episode) if player: util.play_episode(episode, player=player) if not skip_download: if external_downloader: logging.info('Downloading episode {} of {}'.format( episode.ep_no, anime.title)) util.external_download(external_downloader, episode, file_format, path=download_dir) continue if chunk_size is not None: chunk_size *= 1e6 chunk_size = int(chunk_size) with requests_cache.disabled(): episode.download(force=force_download, path=download_dir, format=file_format, range_size=chunk_size) print()
def dl(ctx, anime_url, episode_range, url, player, skip_download, quality, force_download, log_level, download_dir, file_format, provider): """ Download the anime using the url or search for it. """ util.setup_logger(log_level) util.print_info(__version__) cls = get_anime_class(anime_url) if not cls: anime_url = util.search(anime_url, provider) cls = get_anime_class(anime_url) try: anime = cls(anime_url, quality=quality) except Exception as e: echo(click.style(str(e), fg='red')) return if episode_range is None: episode_range = '1:' + str(len(anime) + 1) logging.info('Found anime: {}'.format(anime.title)) anime = util.split_anime(anime, episode_range) if url or player: skip_download = True if download_dir and not skip_download: logging.info('Downloading to {}'.format(os.path.abspath(download_dir))) for episode in anime: if url: util.print_episodeurl(episode) if player: util.play_episode(episode, player=player) if not skip_download: episode.download(force=force_download, path=download_dir, format=file_format) print()
def command(ctx, anime_url, episode_range, url, player, skip_download, quality, force_download, download_dir, file_format, provider, external_downloader, chunk_size, disable_ssl, fallback_qualities, choice, skip_fillers, speed_limit): """ Download the anime using the url or search for it. """ query = anime_url[:] util.print_info(__version__) # TODO: Replace by factory cls = get_anime_class(anime_url) disable_ssl = cls and cls.__name__ == 'Masterani' or disable_ssl session.get_session().verify = not disable_ssl if not cls: anime_url, _ = util.search(anime_url, provider, choice) cls = get_anime_class(anime_url) anime = cls(anime_url, quality=quality, fallback_qualities=fallback_qualities) logger.info('Found anime: {}'.format(anime.title)) animes = util.parse_ep_str(anime, episode_range) if not animes: # Issue #508. raise exceptions.NotFoundError('No episodes found within index.') # TODO: # Two types of plugins: # - Aime plugin: Pass the whole anime # - Ep plugin: Pass each episode if url or player: skip_download = True if download_dir and not skip_download: logger.info('Downloading to {}'.format(os.path.abspath(download_dir))) if skip_fillers: fillers = util.get_filler_episodes(query) if speed_limit: logger.info("Speed is being limited to {}".format(speed_limit)) for episode in animes: if skip_fillers and fillers: if episode.ep_no in fillers: logger.info("Skipping episode {} because it is a filler.".format(episode.ep_no)) continue if url: util.print_episodeurl(episode) if player: util.play_episode(episode, player=player, title=f'{anime.title} - Episode {episode.ep_no}') if not skip_download: if external_downloader: logging.info('Downloading episode {} of {}'.format( episode.ep_no, anime.title) ) util.external_download(external_downloader, episode, file_format, speed_limit, path=download_dir) continue if chunk_size is not None: chunk_size *= 1e6 chunk_size = int(chunk_size) with requests_cache.disabled(): episode.download(force=force_download, path=download_dir, format=file_format, range_size=chunk_size) print()
def command(ctx, anime_url, episode_range, player, force_download, provider, skip_fillers, ratio, url, choice, download_metadata): """ dl with fallback providers\n Will use another provider even if the chosen one fails.\n """ # Borrows some config from the original dl command. # This can all be flags, but ezdl is made to be easy. fallback_qualities = Config['dl']['fallback_qualities'] download_dir = Config['dl']['download_dir'] quality = Config['dl']['quality'] url = Config['dl']['url'] if not url else url skip_download = Config['dl']['skip_download'] chunk_size = Config['dl']['chunk_size'] speed_limit = Config['dl']['speed_limit'] external_downloader = Config['dl']['external_downloader'] file_format = Config['ezdl']['file_format'] fallback_providers = Config['ezdl']['fallback_providers'] query = anime_url[:] util.print_info(__version__) fallback_providers.insert(0, provider) # Eliminates duplicates while keeping order providers = sorted(set(fallback_providers), key=fallback_providers.index) info = animeinfo.search_anilist(query, choice) logger.info('Selected "{}" '.format(info.title)) episode_count = info.episodes - 1 # Interprets the episode range for use in a for loop. # 1:3 -> for _episode in range(1, 4): episode_range = util.parse_episode_range(episode_count, episode_range) episode_range_split = episode_range.split(':') # Issue #508. if episode_range_split[0] > episode_range_split[-1]: raise exceptions.NotFoundError('No episodes found within index.') # Stores the choices for each provider, to prevent re-prompting search. # As the current setup runs episode wise without this a 12 episode series would give 12+ prompts. choice_dict = {} # Doesn't work on nyaa since it only returns one episode. for episode_range in range(int(episode_range_split[0]), int(episode_range_split[-1]) + 1): # Exits if all providers are skipped. if [choice_dict[i] for i in choice_dict] == [0] * len(providers): logger.info('All providers skipped, exiting') exit() for provider in providers: if not get_anime_class(provider): logger.info('"{}" is an invalid provider'.format(provider)) continue logger.debug('Current provider: {}'.format(provider)) # TODO: Replace by factory cls = get_anime_class(anime_url) # To make the downloads use the correct name if URL:s are used. real_provider = cls.sitename if cls else provider # This will allow for animeinfo metadata in filename and one filename for multiple providers. rep_dict = { 'animeinfo_anime_title': util.slugify(info.title), 'provider': util.slugify(real_provider), 'anime_title': '{anime_title}', 'ep_no': '{ep_no}' } fixed_file_format = file_format.format(**rep_dict) # Keeping this as I don't know the impact of removing it. # It's False by default in normal dl. disable_ssl = False session.get_session().verify = not disable_ssl # This is just to make choices in providers presistent between searches. choice_provider = choice_dict.get(provider) if not cls: _anime_url, choice_provider = util.search(anime_url, provider, val=choice_provider, season_info=info, ratio=ratio) choice_dict[provider] = choice_provider if choice_provider == 0 or not _anime_url: logger.info('Skipped') continue cls = get_anime_class(_anime_url) try: anime = cls(_anime_url, quality=quality, fallback_qualities=fallback_qualities) # I have yet to investigate all errors this can output # No sources found gives error which exits the script except: continue logger.debug('Found anime: {}'.format(anime.title)) try: animes = util.parse_ep_str(anime, str(episode_range)) except RuntimeError: logger.error( 'No episode found with index {}'.format(episode_range)) continue except: logger.error('Unknown provider error') continue # TODO: # Two types of plugins: # - Aime plugin: Pass the whole anime # - Ep plugin: Pass each episode if url or player: skip_download = True if download_dir and not skip_download: logger.info('Downloading to {}'.format( os.path.abspath(download_dir))) if skip_fillers: fillers = util.get_filler_episodes(query) for episode in animes: if skip_fillers and fillers: if episode.ep_no in fillers: logger.info( "Skipping episode {} because it is a filler.". format(episode.ep_no)) continue if download_metadata: util.download_metadata(fixed_file_format, info.metadata, episode) if url: util.print_episodeurl(episode) if player: util.play_episode( episode, player=player, title=f'{anime.title} - Episode {episode.ep_no}') if not skip_download: if external_downloader: logging.info('Downloading episode {} of {}'.format( episode.ep_no, anime.title)) util.external_download(external_downloader, episode, fixed_file_format, path=download_dir, speed_limit=speed_limit) continue if chunk_size is not None: chunk_size = int(chunk_size) chunk_size *= 1e6 with requests_cache.disabled(): episode.download(force=force_download, path=download_dir, format=fixed_file_format, range_size=chunk_size) print() # If it's all successfull proceeds to next ep instead of looping. break
def command(anime_name, new, update_all, _list, quality, remove, download_dir, mal_import, provider): """ With watch you can keep track of any anime you watch. Available Commands after selection of an anime:\n set : set episodes_done, provider and title. Ex: set episodes_done=3\n remove : remove selected anime from watch list\n update : Update the episodes of the currrent anime\n watch : Watch selected anime\n download : Download episodes of selected anime back : Returns back to the list """ util.print_info(__version__) watcher = _watch.Watcher() if not os.path.exists(watcher.WATCH_FILE): with open(watcher.WATCH_FILE, "w") as f: f.write("[]") if new: if anime_name: query = anime_name else: query = click.prompt('Enter a anime name or url', type=str) url, _ = util.search(query, provider) watcher.new(url) sys.exit(0) with open(watcher.WATCH_FILE, "r") as f: contents = f.read() # print(contents) if "[]" in contents: logger.error( "Add something to the watch list using `anime watch --new`") sys.exit(1) if remove: anime = watcher.get(anime_name) if anime and click.confirm("Remove '{}'".format(anime.title), abort=True): watcher.remove(anime) else: logging.error("Couldn't find '{}'. " "Use a better search term.".format(anime_name)) sys.exit(1) sys.exit(0) if update_all: animes = watcher.anime_list() for anime in animes: watcher.update_anime(anime) if mal_import: # Hack, but needed to prompt the user. Uses the anime name as # parameter. PATH = anime_name if PATH: query = PATH else: query = click.prompt('Enter the file path for the MAL .xml file', type=str) if query.endswith('.xml'): watcher._import_from_MAL(query) sys.exit(0) else: logging.error( "Either the file selected was not an .xml or no file was selected." ) sys.exit(1) # Defaults the command to anime watch -l all. # It's a bit of a hack to use sys.argv, but doesn't break # if new commands are added (provided you used a bunch of and statements) _list = 'all' if sys.argv[-1] == 'watch' else _list if _list: filt = _list list_animes(watcher, quality, download_dir, None, _filter=filt) sys.exit(0) if anime_name: anime = watcher.get(anime_name) if not anime: logger.error("Couldn't find '{}'." "Use a better search term.".format(anime_name)) sys.exit(1) anime.quality = quality logger.info('Found {}'.format(anime.title)) watch_anime(watcher, anime, quality, download_dir)
def command(anime_name, new, update_all, _list, quality, remove, download_dir, provider): """ With watch you can keep track of any anime you watch. Available Commands after selection of an anime:\n set : set episodes_done, provider and title. Ex: set episodes_done=3\n remove : remove selected anime from watch list\n update : Update the episodes of the currrent anime\n watch : Watch selected anime\n download : Download episodes of selected anime """ util.print_info(__version__) echo( 'Watch is deprecated in favour of adl: https://github.com/RaitaroH/adl .' ) echo( 'You can use dl command to stream anime if you do not want anime tracking.' ) echo('watch command may come back in the future.') watcher = _watch.Watcher() if new: if anime_name: query = anime_name else: query = click.prompt('Enter a anime name or url', type=str) url = util.search(query, provider) watcher.new(url) sys.exit(0) if remove: anime = watcher.get(anime_name) if anime and click.confirm("Remove '{}'".format(anime.title), abort=True): watcher.remove(anime) else: logging.error("Couldn't find '{}'. " "Use a better search term.".format(anime_name)) sys.exit(1) sys.exit(0) if update_all: animes = watcher.anime_list() for anime in animes: watcher.update_anime(anime) if _list: list_animes(watcher, quality, download_dir) sys.exit(0) if anime_name: anime = watcher.get(anime_name) if not anime: logger.error("Couldn't find '{}'." "Use a better search term.".format(anime_name)) sys.exit(1) anime.quality = quality logger.info('Found {}'.format(anime.title)) watch_anime(watcher, anime)
def command(ctx, anime_url, episode_range, url, player, skip_download, quality, force_download, download_dir, file_format, provider, external_downloader, chunk_size, disable_ssl, fallback_qualities, choice, skip_fillers, speed_limit, sub, dub): """ Download the anime using the url or search for it. """ """if episode_range: regexed_range = re.compile("^:?(\d+)?:?(\d+)?$").search(episode_range) # Prevent such cases as: :5: and :1:1 if not regexed_range or (len(regexed_range.groups()) >= episode_range.count(":") and episode_range.count(":") != 1): raise click.UsageError( "Invalid value for '--episode' / '-e': {} is not a valid range".format(episode_range)) """ if sub and dub: raise click.UsageError( "--dub/-d and --sub/-s flags cannot be used together") query = anime_url[:] util.print_info(__version__) # TODO: Replace by factory cls = get_anime_class(anime_url) disable_ssl = cls and cls.__name__ == 'Masterani' or disable_ssl session.get_session().verify = not disable_ssl if not cls: anime_url, _ = util.search(anime_url, provider, choice) cls = get_anime_class(anime_url) subbed = None if sub or dub: subbed = subbed is not None anime = cls(anime_url, quality=quality, fallback_qualities=fallback_qualities, subbed=subbed) logger.info('Found anime: {}'.format(anime.title)) animes = util.parse_ep_str(anime, episode_range) if not animes: # Issue #508. raise exceptions.NotFoundError('No episodes found within index.') # TODO: # Two types of plugins: # - Aime plugin: Pass the whole anime # - Ep plugin: Pass each episode if url or player: skip_download = True if download_dir and not skip_download: logger.info('Downloading to {}'.format(os.path.abspath(download_dir))) if skip_fillers: fillers = util.get_filler_episodes(query) if speed_limit: logger.info("Speed is being limited to {}".format(speed_limit)) for episode in animes: if skip_fillers and fillers: if episode.ep_no in fillers: logger.info( "Skipping episode {} because it is a filler.".format( episode.ep_no)) continue if url: util.print_episodeurl(episode) if player: util.play_episode(episode, player=player, title=f'{anime.title} - Episode {episode.ep_no}') if not skip_download: if external_downloader: logging.info('Downloading episode {} of {}'.format( episode.ep_no, anime.title)) util.external_download(external_downloader, episode, file_format, speed_limit, path=download_dir) continue if chunk_size is not None: chunk_size *= 1e6 chunk_size = int(chunk_size) with requests_cache.disabled(): episode.download(force=force_download, path=download_dir, format=file_format, range_size=chunk_size) print()
def dl(ctx, anime_url, episode_range, url, player, skip_download, quality, force_download, log_level, download_dir, file_format, provider, external_downloader, chunk_size, disable_ssl, fallback_qualities): """ Download the anime using the url or search for it. """ util.setup_logger(log_level) util.print_info(__version__) cls = get_anime_class(anime_url) disable_ssl = cls and cls.__name__ == 'Masterani' or disable_ssl session.get_session().verify = not disable_ssl if not cls: anime_url = util.search(anime_url, provider) cls = get_anime_class(anime_url) try: anime = cls(anime_url, quality=quality, fallback_qualities=fallback_qualities) except Exception as e: if log_level != 'DEBUG': echo(click.style(str(e), fg='red')) else: raise return logging.info('Found anime: {}'.format(anime.title)) anime = util.parse_ep_str(anime, episode_range) if url or player: skip_download = True if download_dir and not skip_download: logging.info('Downloading to {}'.format(os.path.abspath(download_dir))) for episode in anime: if url: util.print_episodeurl(episode) if player: util.play_episode(episode, player=player) if not skip_download: if external_downloader: logging.info('Downloading episode {} of {}'.format( episode.ep_no, anime.title)) util.external_download(external_downloader, episode, file_format, path=download_dir) continue if chunk_size is not None: chunk_size *= 1e6 chunk_size = int(chunk_size) episode.download(force=force_download, path=download_dir, format=file_format, range_size=chunk_size) print()
def command(anime, prompt_found, providers, exclude, verify, v_tries, no_fuzzy, print_results, timeout): """Test all sites to see which ones are working and which ones aren't. Test naruto as a default. Return results for each provider.""" util.print_info(__version__) logger = logging.getLogger("anime_downloader") logger.setLevel(logging.ERROR) if providers: providers = [p.strip() for p in providers.split(",")] for p in providers: if not p in sitenames: raise click.BadParameter( f"{p}. Choose from {', '.join(sitenames)}") else: providers = sitenames if exclude: exclude = [e.strip() for e in exclude.split(",")] for e in exclude: if not e in sitenames: raise click.BadParameter( f"{e}. Choose from {', '.join(sitenames)}") else: if e in providers: providers.remove(e) if os.name == 'nt': p, f = '', '' # Emojis don't work in cmd else: p, f = '✅ ', '❌ ' if verify: timeout = timeout + (3 * (v_tries - 1)) threads = [] matches = [] for provider in providers: t = SiteThread(provider, anime, verify, v_tries, daemon=True) t.start() threads.append(t) for i, thread in enumerate(threads): try: click.echo(f"[{i+1} of {len(threads)}] Searching ", nl=False) click.secho(f"{thread.provider}", nl=False, fg="cyan") click.echo(f"... (CTRL-C to stop) : ", nl=False) thread.join(timeout=timeout) if not thread.is_alive(): if not thread.exception: if thread.search_result: if not no_fuzzy: ratio = fuzz.token_set_ratio( anime.lower(), thread.search_result.lower()) else: ratio = 100 if ratio > 50: matches.append( [thread.provider, thread.search_result, ratio]) click.secho(p + "Works, anime found.", fg="green") if prompt_found: if print_results: click.echo( f"\n- - -{thread.provider}- - -\n\n{thread.search_result}" ) confirm = click.confirm( f"Found anime in {thread.provider}. Keep seaching?", default=True) if not confirm: break else: click.secho(p + "Works, anime not found.", fg="yellow") else: click.secho(p + "Works, anime not found.", fg="yellow") else: logging.debug('Error occurred during testing.') logging.debug(thread.exception) if thread.search_result: click.secho( f + "Not working: anime found, extraction failed.", fg="red") else: click.secho(f + "Not working.", fg="red") else: logging.debug('Timeout during testing.') click.secho( f + "Not working: Timeout. Use -t to specify longer waiting period.", fg="red") except KeyboardInterrupt: skip = click.confirm( f"\nSkip {thread.provider} and continue searching? (Press enter for Yes)", default=True) if not skip: break if print_results: click.echo("\n" + util.format_matches(matches)) else: click.echo("\n" + "Test finished.")
def command(anime_name, new, update_all, _list, quality, remove, download_dir, provider): """ With watch you can keep track of any anime you watch. Available Commands after selection of an anime:\n set : set episodes_done, provider and title. Ex: set episodes_done=3\n remove : remove selected anime from watch list\n update : Update the episodes of the currrent anime\n watch : Watch selected anime\n download : Download episodes of selected anime back : Returns back to the list """ util.print_info(__version__) watcher = _watch.Watcher() if new: if anime_name: query = anime_name else: query = click.prompt('Enter a anime name or url', type=str) url = util.search(query, provider) watcher.new(url) sys.exit(0) if remove: anime = watcher.get(anime_name) if anime and click.confirm("Remove '{}'".format(anime.title), abort=True): watcher.remove(anime) else: logging.error("Couldn't find '{}'. " "Use a better search term.".format(anime_name)) sys.exit(1) sys.exit(0) if update_all: animes = watcher.anime_list() for anime in animes: watcher.update_anime(anime) # Defaults the command to anime watch -l all. # It's a bit of a hack to use sys.argv, but doesn't break # if new commands are added (provided you used a bunch of and statements) _list = 'all' if sys.argv[-1] == 'watch' else _list if _list: filt = _list list_animes(watcher, quality, download_dir, None, _filter=filt) sys.exit(0) if anime_name: anime = watcher.get(anime_name) if not anime: logger.error("Couldn't find '{}'." "Use a better search term.".format(anime_name)) sys.exit(1) anime.quality = quality logger.info('Found {}'.format(anime.title)) watch_anime(watcher, anime, quality, download_dir)