示例#1
0
 def test_check_sources_random(self):
     iterations = 0
     animes = get_animes()
     while iterations <= MAX_SOURCE_TEST_ITERATION:
         iterations += 1
         random_anime = random.choice(animes)
         current_sources = get_sources(random_anime)
         if current_sources:
             source = random.choice(current_sources)
             url = urljoin(TWIST_CDN_URL, source.source)
             try:
                 client = get_auth_client()
                 r = client.get(
                     url,
                     headers={
                         **dict(client.headers),
                         "referer": TWIST_URL,
                         "range": "bytes=0-10",
                     },
                 )
                 r.raise_for_status()
             except httpx.HTTPError as e:
                 print(
                     f"Error on iteration n°{iterations} for {random_anime.full_title()}\n\tepisode={source.number}"
                     f"{e}\n")
                 continue
             print(
                 f"Found source for {random_anime.full_title()}\n\tepisode={source.number}\n\turl={r.url}"
             )
             break
     assert iterations <= 100
示例#2
0
 def test_get_animes(self):
     animes = get_animes()
     assert len(animes) > 1000
     naruto_anime = list(filter(lambda a: a.slug.slug == "naruto",
                                animes))[0]
     assert naruto_anime.title == "Naruto"
     assert naruto_anime.id == 451
示例#3
0
def filter_animes(
    search: str,
    animes: Optional[List[Anime]] = None,
    threshold: int = FUZZY_SEARCH_THRESHOLD,
    limit: int = FUZZY_SEARCH_MAX_RESULTS,
):
    if animes is None:
        animes = get_animes()
    animes_by_title = dict(
        sorted(((anime.title, anime) for anime in animes), key=lambda x: x[0])
    )
    animes_by_alt_title = dict(
        sorted(
            ((anime.alt_title, anime) for anime in animes if anime.alt_title),
            key=lambda x: x[0],
        )
    )
    selected_animes_with_score_by_id = {}
    for anime in animes_by_title.values():
        score = fuzz.token_set_ratio(search.lower(), anime.title.lower())
        if score > threshold:
            selected_animes_with_score_by_id[anime.id] = (score, anime)
    for anime in animes_by_alt_title.values():
        score = fuzz.token_set_ratio(search.lower(), anime.alt_title.lower())
        if score > threshold:
            selected_animes_with_score_by_id[anime.id] = (score, anime)
    return list(
        x[1]
        for x in sorted(
            selected_animes_with_score_by_id.values(),
            key=lambda x: x[0],
            reverse=True,
        )
    )[:limit]
示例#4
0
 def get_choices(context: Dict[str, str]) -> List[Dict[str, Union[str, Anime]]]:
     animes = get_animes()
     if context.get("filter"):
         animes = filter_animes(context["filter"], animes=animes)
     return [
         {"name": anime.full_title(), "value": anime}
         for anime in sorted((a for a in animes), key=lambda a: a.title)
     ]
示例#5
0
def display_anime_details(slug: str = typer.Argument(
    None, help=ANIME_SLUG_HELP, callback=select_anime_slug), ):
    """
    Give more details on a specific anime like the number of episodes from a given anime slug
    """
    animes = get_animes()
    animes_by_slug = {anime.slug.slug: anime for anime in animes}
    try:
        anime = animes_by_slug[slug]
    except KeyError:
        raise typer.BadParameter(invalid_slug_message(slug=slug,
                                                      animes=animes))
    typer.echo(anime_details_message(get_anime_details(anime)))
示例#6
0
def display_animes(search: Optional[str] = typer.Option(
    None, help="Filter results with fuzzy search")):
    """
    Search and display information about available animes and optionally use --search to fuzzy search

    Among the information given, the slug is what is used in other commands
    """
    animes = get_animes()
    if search:
        animes = filter_animes(search, animes)

    for anime in animes:
        typer.echo(anime_message(anime))
示例#7
0
def download(
    slug: str = typer.Argument(None,
                               help=ANIME_SLUG_HELP,
                               callback=select_anime_slug),
    directory: str = typer.Option(
        CWD_DIR, "--d", help="Directory where files will be uploaded"),
    nfrom: int = typer.Option(
        None,
        "--nfrom",
        help="Select episodes greater or equal to the given number"),
    nto: int = typer.Option(
        None,
        "--nto",
        help="Select episodes lesser or equal to the given number"),
    dfrom: datetime.datetime = typer.Option(
        None, "--dfrom", help="Select episodes uploaded after the given date"),
    dto: datetime.datetime = typer.Option(
        None, "--dto", help="Select episodes uploaded before the given date"),
):
    """
    Download a list of episodes from a given anime slug

    The output directory can be specified
    """
    directory = Path(directory)
    animes = get_animes()
    animes_by_slug = {anime.slug.slug: anime for anime in animes}
    try:
        anime = animes_by_slug[slug]
    except KeyError:
        raise typer.BadParameter(invalid_slug_message(slug=slug,
                                                      animes=animes))
    sources = get_sources(anime)
    filtered_source_ids = set(source.id for source in sources)
    if nfrom:
        if type(nfrom) is int:
            filtered_source_ids -= set(source.id for source in sources
                                       if source.number < nfrom)
    if dfrom:
        filtered_source_ids -= set(source.id for source in sources
                                   if source.created_at < dfrom)
    if nto:
        filtered_source_ids -= set(source.id for source in sources
                                   if source.number > nto)

    if dto:
        filtered_source_ids -= set(source.id for source in sources
                                   if source.created_at > dto)

    sources = list(
        sorted(
            (source for source in sources if source.id in filtered_source_ids),
            key=lambda s: s.number,
        ))
    if not sources:
        typer.secho("No sources to download ! ", bold=True)
        raise typer.Exit(code=1)
    typer.echo(download_starting_message(sources=sources, directory=directory))
    for source in sources:
        typer.echo(
            f"{anime.title} - S{anime.season:02d} - E{source.number:02d}")
        title_slug = slugify(anime.title)
        current_dir = directory / title_slug
        if not current_dir.exists():
            current_dir.mkdir(parents=True, exist_ok=True)
        ext = source.source.rsplit(".", 1)[-1]
        filepath = (
            current_dir /
            f"{title_slug}-S{anime.season:02d}-E{source.number:03d}.{ext}")
        download_source(source, filepath)