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 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 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 save_anime(args): """Put the anime into watch later list.""" anime_name, eps = read_args(args) watched = utils.read_log(anime_name) if watched: watched_eps = utils.extract_range(utils.Log(watched).eps) else: watched_eps = [] save_eps = set(eps).difference(set(watched_eps)) if not save_eps: outputs.warning_info('Already watched the provided episodes.') return utils.write_log(anime_name, utils.compress_range(save_eps), append=True, logfile=config.watchlaterfile)
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 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 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 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 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 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))