예제 #1
0
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)
예제 #2
0
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
예제 #3
0
 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.')
예제 #4
0
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
예제 #5
0
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
예제 #6
0
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))
예제 #7
0
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
예제 #8
0
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}'))
예제 #9
0
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()
예제 #10
0
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
예제 #11
0
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
예제 #12
0
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
예제 #13
0
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
예제 #14
0
 def send_notification(summary, body):
     outputs.error_info('Notification system is not setup properly')