def search_results(s): all_res = s.find('ul', {'class': 'items'}) for list_item in all_res.find_all('li'): an = list_item.p.a['href'].split('/')[-1] utils.write_cache(an, append=True) outputs.normal_info(an, end=' \t') outputs.normal_info(list_item.p.a.text)
def download_file(url, filepath, replace=False): if os.path.exists(filepath) and not replace: outputs.warning_info('File already downloaded, skipping.') return part_file = f'{filepath}.part' c = pycurl.Curl() c.setopt(pycurl.URL, url) c.setopt(pycurl.NOPROGRESS, 0) curl_header = [f'{k}: {v}' for k, v in config.down_headers.items()] if os.path.exists(part_file) and not replace: outputs.normal_info('Previously Downloaded part found.') wmode = 'ab' curl_header.append( config.resume_t.substitute(size=os.path.getsize(part_file))) else: wmode = 'wb' c.setopt(pycurl.HTTPHEADER, curl_header) try: with open(part_file, wmode) as writer: c.setopt(pycurl.WRITEDATA, writer) c.perform() c.close() except (KeyboardInterrupt, pycurl.error) as e: c.close() outputs.error_info(f"Download Failed {e}") raise SystemExit os.rename(part_file, filepath)
def download_m3u8(url, filepath, replace=False): if os.path.exists(filepath) and not replace: outputs.warning_info('File already downloaded, skipping.') return part_file = f'{filepath}.part' media = m3u8.load(url) total = len(media.segments) with open(part_file, 'wb') as writer: c = pycurl.Curl() curl_header = [f'{k}: {v}' for k, v in config.down_headers.items()] c.setopt(pycurl.HTTPHEADER, curl_header) c.setopt(pycurl.WRITEDATA, writer) try: for i, f in enumerate(media.segments): uri = f.absolute_uri c.setopt(pycurl.URL, uri) c.perform() outputs.normal_info('\rDownloaded :', f'{(i+1)*100//total}% ({i+1} of {total})', end="") c.close() except (KeyboardInterrupt, pycurl.error) as e: c.close() raise SystemExit(f"Download Failed {e}") outputs.normal_info() os.rename(part_file, filepath)
def search_results(s): all_res = s.find("ul", {"class": "items"}) for list_item in all_res.find_all("li"): an = list_item.p.a["href"].split("/")[-1] utils.write_cache(an, append=True) outputs.normal_info(an, end=" \t") outputs.normal_info(list_item.p.a.text)
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 anime_info(args): name, _ = read_args(args, episodes=False) soup = utils.get_soup(anime_source_module.get_anime_url(name)) info = soup.find("div", {"class": "anime_info_body"}) h = html2text.HTML2Text() h.ignore_links = True for t in info.find_all("p", {"class": "type"}): outputs.normal_info(h.handle(t.decode_contents()), end="")
def anime_info(args): name = read_args(args, episodes=False) soup = utils.get_soup(gogoanime.get_anime_url(name)) info = soup.find('div', {'class': 'anime_info_body'}) h = html2text.HTML2Text() h.ignore_links = True for t in info.find_all('p', {'class': 'type'}): outputs.normal_info(h.handle(t.decode_contents()), end="")
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 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 onecmd(self, ind): if ind == 'EOF': outputs.normal_info() return try: return super().onecmd(ind) except (SystemExit, KeyboardInterrupt): outputs.normal_info() except (ConnectionError, ConnectTimeout): outputs.error_info('Slow or no Internet connection. Try again.')
def do_history(self, inp): """show the history of the commands. """ try: import readline for j in range(1, readline.get_current_history_length() + 1): h = readline.get_history_item(j) if re.match(inp, h): outputs.normal_info(f'{j:3d}: {h}') except ImportError: pass
def anime_log(args): outputs.bold_info('Watched\t\tAnime Name') 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).items() for k, v in logs: outputs.normal_info(f'{v}\t\t{k}')
def default(self, inp): try: if 'import' in inp: return self.import_mod(inp) if '=' in inp: exec(inp, {}, shell_commands) else: retval = eval(inp, {}, shell_commands) outputs.success_tag('RET:', end=' ') outputs.normal_info(retval) except Exception as e: outputs.error_tag('ERR:', end=' ') outputs.normal_info(e) traceback.print_exc(chain=False)
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 do_history(self, inp): """show the history of the commands. """ if not self.in_cmdloop: for j, h in enumerate(open(config.historyfile), start=1): h = h.strip() if re.match(inp, h): outputs.normal_info(f'{j:3d}: {h}') return try: import readline for j in range(1, readline.get_current_history_length() + 1): h = readline.get_history_item(j) if re.match(inp, h): outputs.normal_info(f'{j:3d}: {h}') except ImportError: pass
def list_local_episodes(args): in_dict = utils.get_local_episodes(*args) out_dict = dict() for anime, eps in in_dict.items(): new_eps = utils.compress_range(utils.extract_range(eps)) if new_eps != "": out_dict[anime] = new_eps empties = set(in_dict).difference(set(out_dict)) if len(out_dict) == 0: outputs.warning_info("No local entries found.") else: outputs.bold_info("Episodes\tAnime Name") for k, v in out_dict.items(): outputs.normal_info(f"{v}\t\t{k}") if len(empties) > 0: outputs.warning_info("Directories without Episodes:") outputs.warning_info(", ".join(empties))
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 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 display_anime_eps_list(animes_dict): tracklist = read_log(logfile=config.ongoingfile) log = read_log() clear_cache() for name, ep in animes_dict: outputs.normal_info(f"{name} : ep-{ep}" if ep else name, end=" ") write_cache(name, append=True) if name in tracklist: watched = extract_range(Log(tracklist[name]).eps) if not ep: outputs.warning_tag("TRACKED", end="") elif int(ep) in watched: outputs.warning_tag("WATCHED", end="") else: outputs.success_tag("NEW", end="") elif name in log: outputs.success_tag("LOGGED", end="") outputs.normal_info()
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 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
def verify_anime_exists(anime_name, verbose=False): if utils.read_log(anime_name) is not None: if verbose: outputs.normal_info(anime_name, 'LOG', reverse=True) return True elif anime_name in utils.read_cache(complete=True): if verbose: outputs.normal_info(anime_name, 'CACHE', reverse=True) return True elif utils.get_anime_path(anime_name, check=True)[0]: if verbose: outputs.normal_info(anime_name, 'LOCAL', reverse=True) return True elif utils.get_soup(get_anime_url(anime_name)) is not None: if verbose: outputs.normal_info(anime_name, 'SITE', reverse=True) return True else: return False
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 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 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 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 do_help(self, topic): if len(topic) == 0: import __init__ outputs.normal_info(__init__.__doc__) super().do_help(topic)
def list_saved_anime(): anime_list = utils.read_log(logfile=config.watchlaterfile) for anime, log in anime_list.items(): outputs.normal_info(utils.Log(log).show())
def list_tracked(): anime_list = utils.read_log(logfile=config.ongoingfile) for anime, log in anime_list.items(): outputs.normal_info(utils.Log(log).show())