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 parse_gogo_url(url): whole_name = url.split('/')[-1] match = re.match(r'(.+)-episode-([0-9]+)', whole_name) if match: anime_name = match.group(1) episode = match.group(2) else: outputs.error_info("URL couldn't be parsed.") raise SystemExit return anime_name, episode
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 get_direct_video_url(gogo_url): soup = utils.get_soup(gogo_url) php_l = soup.find('iframe')['src'] ajx_l = config.ajax_t.substitute(q=php_l.split('?')[1]) r = requests.get(ajx_l) try: link = json.loads(r.text)['source_bk'][0]['file'] except (IndexError, KeyError): outputs.error_info('Unexpected error while obtaining stream url') raise SystemExit ftype = link.split('.')[-1] return link, ftype
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 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 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 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 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 get_direct_video_url(gogo_url): soup = utils.get_soup(gogo_url) if not soup: outputs.error_info("The video doesn't exist.") raise SystemExit iframe = soup.find('iframe') if not iframe: outputs.error_info("The video doesn't exist.") raise SystemExit php_l = iframe['src'] ajx_l = ajax_t.substitute(q=php_l.split('?')[1]) r = requests.get(ajx_l) try: link = json.loads(r.text)['source_bk'][0]['file'] except (IndexError, KeyError, TypeError) as e: outputs.error_info('Unexpected error while obtaining stream url.') outputs.error_info(f'ERR: {e}') raise SystemExit _, ext = os.path.splitext(link) if ext == '.m3u8': link = utils.get_m3u8_stream(link) return link, ext
def send_notification(summary, body): outputs.error_info('Notification system is not setup properly')