def anime_log(args): log_args = dict() if len(args) == 0: pass elif args[0].isnumeric(): log_args["number"] = int(args[0]) else: log_args["pattern"] = re.compile(args[0]) if len(args) == 2: log_args["number"] = int(args[1]) logs = utils.read_log(**log_args) ongoing = utils.read_log(logfile=config.ongoingfile) if len(logs) == 0: if len(args) == 0: outputs.warning_info("No log entries found.") else: outputs.prompt_val("Log entries not found for arguments", args[0], "error") return outputs.bold_info("Watched\t\tAnime Name") for k, log in logs.items(): outputs.normal_info(utils.Log(log).show(), end=" ") if k in ongoing: outputs.warning_tag("TRACKED", end="") outputs.normal_info()
def set_geometry(value): if re.match(r'^([0-9]+-?)+$', value): config.geometry = value config.compile_ext_player_command() else: outputs.prompt_val('Incorrect Argument', value, 'error') outputs.prompt_val('External Player command', " ".join(config.ext_player_command))
def play_local_anime(args): name, episodes = read_args(args) for e in episodes: path = utils.get_episode_path(name, e, check=True) if not path: outputs.prompt_val("File not found locally", f"{name}:ep-{e}", "error") continue stream_from_url(path, name, e, local=True)
def set_quality(quality): if quality.isnumeric(): config.video_quality = int(quality) elif quality.isalnum(): if re.match(r"[0-9]+p", quality): config.video_quality = int(quality[:-1]) else: outputs.prompt_val("Invalid quality format", quality, "error") else: outputs.normal_info(f"Current quality: {quality}")
def set_quality(quality): if quality.isnumeric(): config.QUALITY_PREFERENCE = int(quality) elif quality.isalnum(): if re.match(r'[0-9]+p', quality): config.QUALITY_PREFERENCE = int(quality[:-1]) else: outputs.prompt_val('Invalid quality format', quality, 'error') else: outputs.normal_info(f'Current quality: {quality}')
def toggle_fullscreen(value): if value.lower() in ['on', 'yes']: config.fullscreen = True config.compile_ext_player_command() elif value.lower() in ['off', 'no']: config.fullscreen = False config.compile_ext_player_command() else: outputs.prompt_val('Incorrect Argument', value, 'error') outputs.prompt_val('External Player command', " ".join(config.ext_player_command))
def set_geometry(value): if re.match(r"^([0-9]+-?)+$", value): player_module.geometry = value player_module.compile_command( flags=config.ext_player_flags, fullscreen=config.ext_player_fullscreen ) else: outputs.prompt_val("Incorrect Argument", value, "error") outputs.prompt_val("External Player command", " ".join(player_module.player_command))
def continue_play(args): name, episodes = read_args(args) watched = utils.read_log().get(name) outputs.prompt_val('Watched', watched, 'success') if not watched: last = 0 else: last = int(watched.split('-')[-1]) play_anime( [name, utils.compress_range(filter(lambda e: e > last, episodes))])
def list_episodes(args): name = read_args(args, episodes=False) available_rng = gogoanime.get_episodes_range(gogoanime.get_anime_url(name)) if len(args) == 2: _, episodes = read_args(args) eps = set(episodes) avl_eps = set(utils.extract_range(available_rng)) res = eps.intersection(avl_eps) available_rng = utils.compress_range(res) outputs.prompt_val(f'Available episodes', available_rng) outputs.prompt_val(f'Watched episodes', utils.read_log(name), 'success') utils.write_cache(name)
def list_episodes(args): name, _ = read_args(args, episodes=False) available_rng = anime_source_module.get_episodes_range(anime_source_module.get_anime_url(name)) if len(args) == 2: _, episodes = read_args(args) eps = set(episodes) avl_eps = set(utils.extract_range(available_rng)) res = eps.intersection(avl_eps) available_rng = utils.compress_range(res) outputs.prompt_val("Available episodes", available_rng) log = utils.Log(utils.read_log(name)) outputs.prompt_val("Watched episodes", log.eps, "success", end=' ') outputs.normal_info(log.last_updated_fmt) utils.write_cache(name)
def read_cache(num=1, complete=False): if not os.path.exists(config.cachefile): return list() if complete else None else: with open(config.cachefile, 'r') as r: lines = r.readlines() if complete: return list(map(lambda l: l.strip(), lines)) else: try: return lines[num - 1].strip() except IndexError: outputs.error_info("The choice number is too large.") outputs.prompt_val("Total items in cache", len(lines), 'error') raise SystemExit
def track_anime(args): """Put an anime into the track list""" anime_name = read_args(args, episodes=False) watched_episodes = utils.read_log(anime_name) if watched_episodes is None: outputs.warning_info( 'Log entry not found. Setting only new episodes for tracking.') _, episodes = read_args(args) episodes = utils.compress_range(episodes) else: outputs.prompt_val(f'Watched', watched_episodes, 'success') episodes = watched_episodes utils.write_log(anime_name, episodes, append=False, logfile=config.ongoingfile)
def track_anime(args): """Put an anime into the track list""" anime_name, episodes = read_args(args, episodes=False) log = utils.read_log(anime_name) if log is None: outputs.warning_info( "Log entry not found.") if not episodes: _, episodes = read_args(args) episodes = utils.compress_range(episodes) else: episodes = utils.Log(log).eps outputs.prompt_val("Watched", episodes, "success") utils.write_log(anime_name, episodes, append=False, logfile=config.ongoingfile)
def toggle_fullscreen(value): if value.lower() in ["on", "yes", "true"]: config.ext_player_fullscreen = True anime_source_module.compile_command( flags=config.ext_player_flags, fullscreen=True ) elif value.lower() in ["off", "no", "false"]: config.ext_player_fullscreen = False anime_source_module.compile_command( flags=config.ext_player_flags, fullscreen=False ) else: outputs.prompt_val("Incorrect Argument", value, "error") outputs.prompt_val("External Player command", " ".join(config.ext_player_command))
def download_from_url(url, anime_name=None, episode=None): if not anime_name or not episode: anime_name, episode = anime_source_module.parse_url(url) os.makedirs(os.path.join(config.anime_dir, f"./{anime_name}"), exist_ok=True) outputs.prompt_val("Downloading", url) durl, ext = anime_source_module.get_direct_video_url(url) if not durl: outputs.error_info("Url for the file not found") raise SystemExit if ext == ".m3u8": utils.download_m3u8( durl, utils.get_episode_path(anime_name, episode, make=True)) else: utils.download_file( durl, utils.get_episode_path(anime_name, episode, ext=ext, make=True))
def check_anime(args): name, episodes = read_args(args) unavail_eps = [] for e in episodes: url = anime_source_module.get_episode_url(name, e) outputs.normal_info("Testing:", url) durl, ext = anime_source_module.get_direct_video_url(url) if not durl: raise SystemExit("Url for the file not found") if not os.path.exists( os.path.join(config.anime_dir, f"./{name}/ep{e:02d}.{ext}")): unavail_eps.append(e) if len(unavail_eps) == 0: outputs.success_info( "All episodes in given range are locally available") else: outputs.prompt_val("Missing episodes", utils.compress_range(unavail_eps), "warning")
def get_updates(anime_name=''): """Check and display the updates on the tracked anime list.""" updates = anime_updates(anime_name) if len(updates) == 0: outputs.normal_info("No new episodes released.") return if anime_name == '': outputs.prompt_val(f'anime(s) has new episodes.', len(updates), 'success', sep=" ", reverse=True) outputs.normal_info('-' * 50) for anime, episodes in updates.items(): outputs.normal_info(anime, end='\n\t') outputs.success_tag(len(episodes), end=' ') outputs.prompt_val('new episodes', utils.compress_range(episodes), 'success')
def check_anime(args): name, episodes = read_args(args) unavail_eps = [] for e in episodes: url = gogoanime.get_episode_url(name, e) outputs.normal_info('Testing:', url) durl, ext = gogoanime.get_direct_video_url(url) if not durl: raise SystemExit('Url for the file not found') if not os.path.exists( os.path.join(config.anime_dir, f'./{name}/ep{e:02d}.{ext}')): unavail_eps.append(e) if len(unavail_eps) == 0: outputs.success_info( 'All episodes in given range are locally available') else: outputs.prompt_val('Missing episodes', utils.compress_range(unavail_eps), 'warning')
def extract_range(range_str): if range_str is None or range_str.strip() == '': return iter() ranges = range_str.split(',') try: for r in ranges: if '-' in r: rng = r.split('-') if len(rng) > 2: outputs.prompt_val('Incorrect formatting', r, 'error') raise SystemExit yield from range(int(rng[0]), int(rng[1]) + 1) else: yield int(r) except ValueError as e: outputs.error_info(f'Incorrect formatting: use integers for episodes') outputs.error_tag(e) raise SystemExit
def continue_play(args, play_func=play_anime): name, _ = read_args(args, episodes=False) log = utils.Log(utils.read_log().get(name)) watch_later = utils.read_log(name, logfile=config.watchlaterfile) if watch_later: episodes = utils.extract_range(utils.Log(watch_later).eps) else: _, episodes = read_args(args) outputs.prompt_val("Watched", log._eps, "success", end='\t') outputs.normal_info(log.last_updated_fmt) if not log.eps: last = 0 else: last = int(re.split('-|,', log.eps)[-1]) to_play = utils.compress_range(filter(lambda e: e > last, episodes)) if to_play.strip(): play_func([name, to_play]) else: unsave_anime(name)
def get_updates(anime_name=""): """Check and display the updates on the tracked anime list.""" updates = anime_updates(anime_name) if len(updates) == 0: outputs.normal_info("No new episodes released.") return if anime_name == "": outputs.prompt_val( "anime(s) has new episodes.", len(updates), "success", sep=" ", reverse=True, ) outputs.normal_info("-" * 50) for anime, episodes in updates.items(): outputs.normal_info(anime, end="\n\t") outputs.success_tag(len(episodes), end=" ") outputs.prompt_val("new episodes", utils.compress_range(episodes), "success")
def download_from_url(gogo_url, anime_name=None, episode=None): if not anime_name or not episode: anime_name, episode = gogoanime.parse_gogo_url(gogo_url) os.makedirs(os.path.join(config.anime_dir, f'./{anime_name}'), exist_ok=True) outputs.prompt_val('Downloading', gogo_url) durl, ext = gogoanime.get_direct_video_url(gogo_url) if not durl: outputs.error_info('Url for the file not found') raise SystemExit if ext == 'm3u8': m3u8_url = utils.get_m3u8_stream(durl) utils.download_m3u8( m3u8_url, os.path.join(config.anime_dir, f'./{anime_name}/ep{episode:02d}.{ext}')) else: utils.download_file( durl, os.path.join(config.anime_dir, f'./{anime_name}/ep{episode:02d}.{ext}'))
def stream_from_url(url, anime_name=None, episode=None, *, local=False): if not anime_name or not episode: anime_name, episode = anime_source_module.parse_url(url) if local: durl = url _, ext = os.path.splitext(durl) else: outputs.normal_info("Getting Streaming Link:", url) durl, ext = anime_source_module.get_direct_video_url(url) if not durl: outputs.error_info("Url for the file not found") raise SystemExit outputs.prompt_val("Stream link", durl, "success") try: if config.ext_player_confirm: choice = input(f"Open {config.ext_player} Player? <Y/n>") if choice == "" or choice.lower() == "y": pass else: raise SystemExit else: for i in range(11): outputs.normal_info( f"\rOpening External Player in: {1-i/10:1.1f} sec.", end="") time.sleep(0.1) outputs.normal_info() retval = player_module.play_media( durl, title=f"ANIME:{anime_name}:ep-{episode}{ext}") if retval: utils.write_log(anime_name, episode) utils.update_tracklist(anime_name, episode) utils.write_cache(anime_name) utils.update_watchlater(anime_name, episode) return except KeyboardInterrupt: outputs.warning_info("\nInturrupted, Exiting...") raise SystemExit outputs.normal_info()
def stream_from_url(url, anime_name=None, episode=None): if not anime_name or not episode: anime_name, episode = gogoanime.parse_gogo_url(url) outputs.normal_info('Getting Streaming Link:', url) durl, ext = gogoanime.get_direct_video_url(url) if not durl: outputs.error_info('Url for the file not found') raise SystemExit if ext == 'm3u8': durl = utils.get_m3u8_stream(durl) outputs.prompt_val(f'Stream link', durl, 'success') try: for i in range(11): outputs.normal_info( f'\rOpening External Player in: {1-i/10:1.1f} sec.', end='') time.sleep(0.1) except KeyboardInterrupt: outputs.warning_info('\nInturrupted, Exiting...') raise SystemExit outputs.normal_info() while True: t1 = time.time() ret_val = subprocess.call(" ".join(config.ext_player_command + [durl]), shell=True) if ret_val == 2: # mpv error code outputs.error_info('Couldn\'t open the stream.') if input("retry?<Y/n>") == '': continue else: raise SystemExit if (time.time() - t1) > ( 5 * 60 ): # 5 minutes watchtime at least, otherwise consider it unwatched. # TODO: use direct communication with mpv to know if episode was watched. utils.write_log(anime_name, episode) utils.update_tracklist(anime_name, episode) utils.write_cache(anime_name) return
def read_args(args, episodes=True, verbose=True): if len(args) == 0: name = utils.read_cache() elif len(args) == 1 and args[0].isnumeric(): name = utils.read_cache(int(args[0])) if verbose: outputs.prompt_val("Name", name) elif "/" in args[0]: name = args[0].strip("/").split("/")[-1] else: name = anime_source_module.process_anime_name(args[0].strip('"')) if not anime_source_module.verify_anime_exists(name): outputs.prompt_val("Anime with the name doesn't exist", args[0], "error") raise SystemExit if not name: outputs.error_info("Numbers choice invalid, or invalid context.") raise SystemExit if len(args) <= 1: if episodes: if verbose: outputs.warning_info("Episodes range not given defaulting to all") available_rng = anime_source_module.get_episodes_range( anime_source_module.get_anime_url(name)) if verbose: outputs.prompt_val("Available episodes", available_rng) eps = utils.extract_range(available_rng) else: eps = None elif len(args) == 2: eps = utils.extract_range(args[1]) else: outputs.error_info("Too many arguments.\n") outputs.normal_info(__doc__) raise SystemExit return name, eps
def read_args(args, episodes=True, verbose=True): if len(args) == 0: name = utils.read_cache() elif args[0].isnumeric(): name = utils.read_cache(int(args[0])) if verbose: outputs.prompt_val('Name', name) elif '/' in args[0]: name = args[0].strip('/').split('/')[-1] else: name = gogoanime.process_anime_name(args[0]) if not gogoanime.verify_anime_exists(name): outputs.prompt_val(f'Anime with the name doesn\'t exist', args[0], 'error') raise SystemExit if not name: outputs.error_info('Numbers choice invalid, or invalid context.') raise SystemExit if not episodes: return name if len(args) <= 1: if verbose: outputs.warning_info('Episodes range not given defaulting to all') available_rng = gogoanime.get_episodes_range( gogoanime.get_anime_url(name)) if verbose: outputs.prompt_val('Available episodes', available_rng) episodes = utils.extract_range(available_rng) elif len(args) == 2: episodes = utils.extract_range(args[1]) else: outputs.error_info('Too many arguments.\n') outputs.normal_info(__doc__) raise SystemExit return name, episodes