mirror of
https://github.com/Benexl/FastAnime.git
synced 2026-02-04 11:07:48 -08:00
feat: normalize anime titles
This commit is contained in:
@@ -9,6 +9,3 @@ anime_normalizer = {
|
||||
"Dungeon ni Deai o Motomeru no wa Machigatte Iru Darouka": "Dungeon ni Deai wo Motomeru no wa Machigatteiru Darou ka",
|
||||
'Hazurewaku no "Joutai Ijou Skill" de Saikyou ni Natta Ore ga Subete wo Juurin suru made': "Hazure Waku no [Joutai Ijou Skill] de Saikyou ni Natta Ore ga Subete wo Juurin Suru made",
|
||||
}
|
||||
|
||||
|
||||
anilist_sort_normalizer = {"search match": "SEARCH_MATCH"}
|
||||
|
||||
@@ -4,7 +4,6 @@ import click
|
||||
|
||||
from .. import __version__
|
||||
from ..libs.anime_provider import SERVERS_AVAILABLE, anime_sources
|
||||
from ..Utility.data import anilist_sort_normalizer
|
||||
from .commands import LazyGroup
|
||||
|
||||
commands = {
|
||||
@@ -116,9 +115,9 @@ signal.signal(signal.SIGINT, handle_exit)
|
||||
help="Auto select anime title?",
|
||||
)
|
||||
@click.option(
|
||||
"-S",
|
||||
"--sort-by",
|
||||
type=click.Choice(anilist_sort_normalizer.keys()), # pyright: ignore
|
||||
"--normalize-titles/--no-normalize-titles",
|
||||
type=bool,
|
||||
help="whether to normalize anime and episode titls given by providers",
|
||||
)
|
||||
@click.option("-d", "--downloads-dir", type=click.Path(), help="Downloads location")
|
||||
@click.option("--fzf", is_flag=True, help="Use fzf for the ui")
|
||||
@@ -165,7 +164,7 @@ def run_cli(
|
||||
quality,
|
||||
auto_next,
|
||||
auto_select,
|
||||
sort_by,
|
||||
normalize_titles,
|
||||
downloads_dir,
|
||||
fzf,
|
||||
default,
|
||||
@@ -232,6 +231,11 @@ def run_cli(
|
||||
ctx.obj.continue_from_history = continue_
|
||||
if ctx.get_parameter_source("skip") == click.core.ParameterSource.COMMANDLINE:
|
||||
ctx.obj.skip = skip
|
||||
if (
|
||||
ctx.get_parameter_source("normalize_titles")
|
||||
== click.core.ParameterSource.COMMANDLINE
|
||||
):
|
||||
ctx.obj.normalize_titles = normalize_titles
|
||||
|
||||
if quality:
|
||||
ctx.obj.quality = quality
|
||||
@@ -254,8 +258,6 @@ def run_cli(
|
||||
== click.core.ParameterSource.COMMANDLINE
|
||||
):
|
||||
ctx.obj.use_mpv_mod = use_mpv_mod
|
||||
if sort_by:
|
||||
ctx.obj.sort_by = sort_by
|
||||
if downloads_dir:
|
||||
ctx.obj.downloads_dir = downloads_dir
|
||||
if translation_type:
|
||||
|
||||
@@ -64,7 +64,7 @@ if TYPE_CHECKING:
|
||||
)
|
||||
@click.option(
|
||||
"--prompt/--no-prompt",
|
||||
help="Dont prompt for anything instead just do the best thing",
|
||||
help="Whether to prompt for anything instead just do the best thing",
|
||||
default=True,
|
||||
)
|
||||
@click.pass_obj
|
||||
@@ -99,6 +99,7 @@ def download(
|
||||
)
|
||||
|
||||
anime_provider = AnimeProvider(config.provider)
|
||||
anilist_anime_info = None
|
||||
|
||||
translation_type = config.translation_type
|
||||
download_dir = config.downloads_dir
|
||||
@@ -147,16 +148,18 @@ def download(
|
||||
}
|
||||
|
||||
if config.auto_select:
|
||||
search_result = max(
|
||||
selected_anime_title = max(
|
||||
search_results_.keys(), key=lambda title: fuzz.ratio(title, anime_title)
|
||||
)
|
||||
print("[cyan]Auto selecting:[/] ", search_result)
|
||||
print("[cyan]Auto selecting:[/] ", selected_anime_title)
|
||||
else:
|
||||
choices = list(search_results_.keys())
|
||||
if config.use_fzf:
|
||||
search_result = fzf.run(choices, "Please Select title: ", "FastAnime")
|
||||
selected_anime_title = fzf.run(
|
||||
choices, "Please Select title: ", "FastAnime"
|
||||
)
|
||||
else:
|
||||
search_result = fuzzy_inquirer(
|
||||
selected_anime_title = fuzzy_inquirer(
|
||||
choices,
|
||||
"Please Select title",
|
||||
)
|
||||
@@ -165,7 +168,7 @@ def download(
|
||||
with Progress() as progress:
|
||||
progress.add_task("Fetching Anime...", total=None)
|
||||
anime: Anime | None = anime_provider.get_anime(
|
||||
search_results_[search_result]["id"]
|
||||
search_results_[selected_anime_title]["id"]
|
||||
)
|
||||
if not anime:
|
||||
print("Sth went wring anime no found")
|
||||
@@ -215,6 +218,11 @@ def download(
|
||||
else:
|
||||
episodes_range = sorted(episodes, key=float)
|
||||
|
||||
if config.normalize_titles:
|
||||
from ...libs.common.mini_anilist import get_basic_anime_info_by_title
|
||||
|
||||
anilist_anime_info = get_basic_anime_info_by_title(anime["title"])
|
||||
|
||||
# lets download em
|
||||
for episode in episodes_range:
|
||||
try:
|
||||
@@ -279,13 +287,26 @@ def download(
|
||||
|
||||
subtitles = servers[server_name]["subtitles"]
|
||||
episode_title = servers[server_name]["episode_title"]
|
||||
print(f"[purple]Now Downloading:[/] {search_result} Episode {episode}")
|
||||
|
||||
if anilist_anime_info:
|
||||
selected_anime_title = (
|
||||
anilist_anime_info["title"][config.preferred_language]
|
||||
or anilist_anime_info["title"]["romaji"]
|
||||
or anilist_anime_info["title"]["english"]
|
||||
)
|
||||
import re
|
||||
|
||||
for episode_detail in anilist_anime_info["episodes"]:
|
||||
if re.match(f"Episode {episode}", episode_detail["title"]):
|
||||
episode_title = episode_detail["title"]
|
||||
break
|
||||
print(f"[purple]Now Downloading:[/] {episode_title}")
|
||||
subtitles = move_preferred_subtitle_lang_to_top(
|
||||
subtitles, config.sub_lang
|
||||
)
|
||||
downloader._download_file(
|
||||
link,
|
||||
search_result,
|
||||
selected_anime_title,
|
||||
episode_title,
|
||||
download_dir,
|
||||
silent,
|
||||
|
||||
@@ -42,6 +42,7 @@ def search(config: Config, anime_titles: str, episode_range: str):
|
||||
)
|
||||
|
||||
anime_provider = AnimeProvider(config.provider)
|
||||
anilist_anime_info = None
|
||||
|
||||
print(f"[green bold]Streaming:[/] {anime_titles}")
|
||||
for anime_title in anime_titles:
|
||||
@@ -123,6 +124,11 @@ def search(config: Config, anime_titles: str, episode_range: str):
|
||||
|
||||
episodes_range = iter(episodes_range)
|
||||
|
||||
if config.normalize_titles:
|
||||
from ...libs.common.mini_anilist import get_basic_anime_info_by_title
|
||||
|
||||
anilist_anime_info = get_basic_anime_info_by_title(anime["title"])
|
||||
|
||||
def stream_anime():
|
||||
clear()
|
||||
episode = None
|
||||
@@ -214,8 +220,23 @@ def search(config: Config, anime_titles: str, episode_range: str):
|
||||
stream_headers = servers[server]["headers"]
|
||||
subtitles = servers[server]["subtitles"]
|
||||
episode_title = servers[server]["episode_title"]
|
||||
print(f"[purple]Now Playing:[/] {search_result} Episode {episode}")
|
||||
|
||||
selected_anime_title = search_result
|
||||
if anilist_anime_info:
|
||||
selected_anime_title = (
|
||||
anilist_anime_info["title"][config.preferred_language]
|
||||
or anilist_anime_info["title"]["romaji"]
|
||||
or anilist_anime_info["title"]["english"]
|
||||
)
|
||||
import re
|
||||
|
||||
for episode_detail in anilist_anime_info["episodes"]:
|
||||
if re.match(f"Episode {episode}", episode_detail["title"]):
|
||||
episode_title = episode_detail["title"]
|
||||
break
|
||||
print(
|
||||
f"[purple]Now Playing:[/] {selected_anime_title} Episode {episode}"
|
||||
)
|
||||
subtitles = move_preferred_subtitle_lang_to_top(
|
||||
subtitles, config.sub_lang
|
||||
)
|
||||
|
||||
@@ -97,6 +97,7 @@ class Config(object):
|
||||
"rofi_theme_confirm": "",
|
||||
"ffmpegthumnailer_seek_time": "-1",
|
||||
"sub_lang": "eng",
|
||||
"normalize_titles": "true",
|
||||
}
|
||||
)
|
||||
self.configparser.add_section("stream")
|
||||
@@ -121,6 +122,7 @@ class Config(object):
|
||||
self.sort_by = self.get_sort_by()
|
||||
self.continue_from_history = self.get_continue_from_history()
|
||||
self.auto_next = self.get_auto_next()
|
||||
self.normalize_titles = self.get_normalize_titles()
|
||||
self.auto_select = self.get_auto_select()
|
||||
self.use_mpv_mod = self.get_use_mpv_mod()
|
||||
self.quality = self.get_quality()
|
||||
@@ -217,6 +219,9 @@ class Config(object):
|
||||
def get_rofi_theme_confirm(self):
|
||||
return self.configparser.get("general", "rofi_theme_confirm")
|
||||
|
||||
def get_normalize_titles(self):
|
||||
return self.configparser.getboolean("general", "normalize_titles")
|
||||
|
||||
# --- stream section ---
|
||||
def get_skip(self):
|
||||
return self.configparser.getboolean("stream", "skip")
|
||||
|
||||
@@ -120,12 +120,24 @@ def media_player_controls(
|
||||
subtitles = move_preferred_subtitle_lang_to_top(
|
||||
selected_server["subtitles"], config.sub_lang
|
||||
)
|
||||
episode_title = selected_server["episode_title"]
|
||||
if config.normalize_titles:
|
||||
import re
|
||||
|
||||
for episode_detail in fastanime_runtime_state.selected_anime_anilist[
|
||||
"streamingEpisodes"
|
||||
]:
|
||||
if re.match(
|
||||
f"Episode {current_episode_number}", episode_detail["title"]
|
||||
):
|
||||
episode_title = episode_detail["title"]
|
||||
break
|
||||
if config.sync_play:
|
||||
from ..utils.syncplay import SyncPlayer
|
||||
|
||||
stop_time, total_time = SyncPlayer(
|
||||
current_episode_stream_link,
|
||||
selected_server["episode_title"],
|
||||
episode_title,
|
||||
headers=selected_server["headers"],
|
||||
subtitles=subtitles,
|
||||
)
|
||||
@@ -137,7 +149,7 @@ def media_player_controls(
|
||||
config.anime_provider,
|
||||
fastanime_runtime_state,
|
||||
config,
|
||||
selected_server["episode_title"],
|
||||
episode_title,
|
||||
start_time,
|
||||
headers=selected_server["headers"],
|
||||
subtitles=subtitles,
|
||||
@@ -147,7 +159,7 @@ def media_player_controls(
|
||||
else:
|
||||
stop_time, total_time = run_mpv(
|
||||
current_episode_stream_link,
|
||||
selected_server["episode_title"],
|
||||
episode_title,
|
||||
start_time=start_time,
|
||||
custom_args=custom_args,
|
||||
headers=selected_server["headers"],
|
||||
@@ -514,12 +526,23 @@ def provider_anime_episode_servers_menu(
|
||||
subtitles = move_preferred_subtitle_lang_to_top(
|
||||
selected_server["subtitles"], config.sub_lang
|
||||
)
|
||||
episode_title = selected_server["episode_title"]
|
||||
if config.normalize_titles:
|
||||
import re
|
||||
|
||||
for episode_detail in fastanime_runtime_state.selected_anime_anilist[
|
||||
"streamingEpisodes"
|
||||
]:
|
||||
if re.match(f"Episode {current_episode_number}", episode_detail["title"]):
|
||||
episode_title = episode_detail["title"]
|
||||
break
|
||||
|
||||
if config.sync_play:
|
||||
from ..utils.syncplay import SyncPlayer
|
||||
|
||||
stop_time, total_time = SyncPlayer(
|
||||
current_stream_link,
|
||||
selected_server["episode_title"],
|
||||
episode_title,
|
||||
headers=selected_server["headers"],
|
||||
subtitles=subtitles,
|
||||
)
|
||||
@@ -533,7 +556,7 @@ def provider_anime_episode_servers_menu(
|
||||
anime_provider,
|
||||
fastanime_runtime_state,
|
||||
config,
|
||||
selected_server["episode_title"],
|
||||
episode_title,
|
||||
start_time,
|
||||
headers=selected_server["headers"],
|
||||
subtitles=subtitles,
|
||||
@@ -547,7 +570,7 @@ def provider_anime_episode_servers_menu(
|
||||
start_time = "0"
|
||||
stop_time, total_time = run_mpv(
|
||||
current_stream_link,
|
||||
selected_server["episode_title"],
|
||||
episode_title,
|
||||
start_time=start_time,
|
||||
custom_args=custom_args,
|
||||
headers=selected_server["headers"],
|
||||
@@ -1284,9 +1307,9 @@ def anilist_results_menu(
|
||||
choices = [*anime_data.keys(), "Back"]
|
||||
if config.use_fzf:
|
||||
if config.preview:
|
||||
from .utils import get_fzf_preview
|
||||
from .utils import get_fzf_anime_preview
|
||||
|
||||
preview = get_fzf_preview(search_results, anime_data.keys())
|
||||
preview = get_fzf_anime_preview(search_results, anime_data.keys())
|
||||
selected_anime_title = fzf.run(
|
||||
choices,
|
||||
prompt="Select Anime: ",
|
||||
|
||||
@@ -134,6 +134,18 @@ class MpvPlayer(object):
|
||||
)
|
||||
return
|
||||
self.current_media_title = selected_server["episode_title"]
|
||||
if config.normalize_titles:
|
||||
import re
|
||||
|
||||
for episode_detail in fastanime_runtime_state.selected_anime_anilist[
|
||||
"streamingEpisodes"
|
||||
]:
|
||||
if re.match(
|
||||
f"Episode {current_episode_number}", episode_detail["title"]
|
||||
):
|
||||
self.current_media_title = episode_detail["title"]
|
||||
break
|
||||
|
||||
links = selected_server["links"]
|
||||
|
||||
stream_link_ = filter_by_quality(quality, links)
|
||||
|
||||
@@ -147,6 +147,11 @@ query ($userId: Int, $status: MediaListStatus,$type:MediaType) {
|
||||
id
|
||||
}
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
averageScore
|
||||
episodes
|
||||
@@ -289,6 +294,11 @@ query($query:String,%s){
|
||||
progress
|
||||
}
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
averageScore
|
||||
episodes
|
||||
@@ -346,6 +356,11 @@ query($type:MediaType){
|
||||
id
|
||||
}
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
averageScore
|
||||
genres
|
||||
@@ -412,6 +427,15 @@ query($type:MediaType){
|
||||
progress
|
||||
}
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
favourites
|
||||
averageScore
|
||||
episodes
|
||||
@@ -472,6 +496,11 @@ query($type:MediaType){
|
||||
progress
|
||||
}
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
episodes
|
||||
favourites
|
||||
averageScore
|
||||
@@ -527,6 +556,11 @@ query($type:MediaType){
|
||||
|
||||
}
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
averageScore
|
||||
description
|
||||
@@ -591,6 +625,11 @@ query($type:MediaType){
|
||||
progress
|
||||
}
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
averageScore
|
||||
description
|
||||
@@ -659,6 +698,11 @@ query($type:MediaType){
|
||||
genres
|
||||
averageScore
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
tags {
|
||||
name
|
||||
@@ -753,6 +797,11 @@ query ($id: Int,$type:MediaType) {
|
||||
genres
|
||||
averageScore
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
tags {
|
||||
name
|
||||
@@ -827,6 +876,11 @@ query ($page: Int,$type:MediaType) {
|
||||
progress
|
||||
}
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
averageScore
|
||||
genres
|
||||
@@ -943,6 +997,11 @@ query($id:Int){
|
||||
countryOfOrigin
|
||||
averageScore
|
||||
popularity
|
||||
streamingEpisodes{
|
||||
title
|
||||
thumbnail
|
||||
}
|
||||
|
||||
favourites
|
||||
source
|
||||
hashtag
|
||||
|
||||
@@ -136,6 +136,11 @@ class AnilistMediaListProperties(TypedDict):
|
||||
hiddenFromStatusLists: bool
|
||||
|
||||
|
||||
class StreamingEpisode(TypedDict):
|
||||
title: str
|
||||
thumbnail: str
|
||||
|
||||
|
||||
class AnilistBaseMediaDataSchema(TypedDict):
|
||||
"""
|
||||
This a convenience class is used to type the received Anilist data to enhance dev experience
|
||||
@@ -159,6 +164,7 @@ class AnilistBaseMediaDataSchema(TypedDict):
|
||||
status: str
|
||||
nextAiringEpisode: AnilistMediaNextAiringEpisode
|
||||
season: str
|
||||
streamingEpisodes: list[StreamingEpisode]
|
||||
seasonYear: int
|
||||
duration: int
|
||||
synonyms: list[str]
|
||||
|
||||
223
fastanime/libs/common/mini_anilist.py
Normal file
223
fastanime/libs/common/mini_anilist.py
Normal file
@@ -0,0 +1,223 @@
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from requests import post
|
||||
from thefuzz import fuzz
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..anilist.types import AnilistDataSchema
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ANILIST_ENDPOINT = "https://graphql.anilist.co"
|
||||
"""
|
||||
query($query:String){
|
||||
Page(perPage:50){
|
||||
pageInfo{
|
||||
total
|
||||
currentPage
|
||||
hasNextPage
|
||||
}
|
||||
media(search:$query,type:ANIME){
|
||||
id
|
||||
idMal
|
||||
title{
|
||||
romaji
|
||||
english
|
||||
}
|
||||
episodes
|
||||
status
|
||||
nextAiringEpisode {
|
||||
timeUntilAiring
|
||||
airingAt
|
||||
episode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def search_foranime_with_anilist(anime_title: str):
|
||||
query = """
|
||||
query($query:String){
|
||||
Page(perPage:50){
|
||||
pageInfo{
|
||||
total
|
||||
currentPage
|
||||
hasNextPage
|
||||
}
|
||||
media(search:$query,type:ANIME){
|
||||
id
|
||||
idMal
|
||||
title{
|
||||
romaji
|
||||
english
|
||||
}
|
||||
episodes
|
||||
status
|
||||
nextAiringEpisode {
|
||||
timeUntilAiring
|
||||
airingAt
|
||||
episode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
response = post(
|
||||
ANILIST_ENDPOINT,
|
||||
json={"query": query, "variables": {"query": anime_title}},
|
||||
timeout=10,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
anilist_data: "AnilistDataSchema" = response.json()
|
||||
return {
|
||||
"pageInfo": anilist_data["data"]["Page"]["pageInfo"],
|
||||
"results": [
|
||||
{
|
||||
"id": anime_result["id"],
|
||||
"title": anime_result["title"]["romaji"]
|
||||
or anime_result["title"]["english"],
|
||||
"type": "anime",
|
||||
"availableEpisodes": list(
|
||||
range(
|
||||
1,
|
||||
(
|
||||
anime_result["episodes"]
|
||||
if not anime_result["status"] == "RELEASING"
|
||||
and anime_result["episodes"]
|
||||
else (
|
||||
anime_result["nextAiringEpisode"]["episode"] - 1
|
||||
if anime_result["nextAiringEpisode"]
|
||||
else 0
|
||||
)
|
||||
),
|
||||
)
|
||||
),
|
||||
}
|
||||
for anime_result in anilist_data["data"]["Page"]["media"]
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def get_mal_id_and_anilist_id(anime_title: str) -> "dict[str,int] | None":
|
||||
"""the abstraction over all none authenticated requests and that returns data of a similar type
|
||||
|
||||
Args:
|
||||
query: the anilist query
|
||||
variables: the anilist api variables
|
||||
|
||||
Returns:
|
||||
a boolean indicating success and none or an anilist object depending on success
|
||||
"""
|
||||
query = """
|
||||
query($query:String){
|
||||
Page(perPage:50){
|
||||
pageInfo{
|
||||
total
|
||||
currentPage
|
||||
hasNextPage
|
||||
}
|
||||
media(search:$query,type:ANIME){
|
||||
id
|
||||
idMal
|
||||
title{
|
||||
romaji
|
||||
english
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
try:
|
||||
variables = {"query": anime_title}
|
||||
response = post(
|
||||
ANILIST_ENDPOINT,
|
||||
json={"query": query, "variables": variables},
|
||||
timeout=10,
|
||||
)
|
||||
anilist_data: "AnilistDataSchema" = response.json()
|
||||
if response.status_code == 200:
|
||||
anime = max(
|
||||
anilist_data["data"]["Page"]["media"],
|
||||
key=lambda anime: max(
|
||||
(
|
||||
fuzz.ratio(anime, str(anime["title"]["romaji"])),
|
||||
fuzz.ratio(anime_title, str(anime["title"]["english"])),
|
||||
)
|
||||
),
|
||||
)
|
||||
return {"id_anilist": anime["id"], "id_mal": anime["idMal"]}
|
||||
except Exception as e:
|
||||
logger.error(f"Something unexpected occured {e}")
|
||||
|
||||
|
||||
def get_basic_anime_info_by_title(anime_title: str):
|
||||
"""the abstraction over all none authenticated requests and that returns data of a similar type
|
||||
|
||||
Args:
|
||||
query: the anilist query
|
||||
variables: the anilist api variables
|
||||
|
||||
Returns:
|
||||
a boolean indicating success and none or an anilist object depending on success
|
||||
"""
|
||||
query = """
|
||||
query($query:String){
|
||||
Page(perPage:50){
|
||||
pageInfo{
|
||||
total
|
||||
}
|
||||
media(search:$query,type:ANIME){
|
||||
id
|
||||
idMal
|
||||
title{
|
||||
romaji
|
||||
english
|
||||
}
|
||||
streamingEpisodes{
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
from ...Utility.data import anime_normalizer
|
||||
|
||||
# normalize the title
|
||||
anime_title = anime_normalizer.get(anime_title, anime_title)
|
||||
try:
|
||||
variables = {"query": anime_title}
|
||||
response = post(
|
||||
ANILIST_ENDPOINT,
|
||||
json={"query": query, "variables": variables},
|
||||
timeout=10,
|
||||
)
|
||||
anilist_data: "AnilistDataSchema" = response.json()
|
||||
if response.status_code == 200:
|
||||
anime = max(
|
||||
anilist_data["data"]["Page"]["media"],
|
||||
key=lambda anime: max(
|
||||
(
|
||||
fuzz.ratio(anime_title, str(anime["title"]["romaji"])),
|
||||
fuzz.ratio(anime_title, str(anime["title"]["english"])),
|
||||
)
|
||||
),
|
||||
)
|
||||
return {
|
||||
"idAilist": anime["id"],
|
||||
"idMal": anime["idMal"],
|
||||
"title": {
|
||||
"english": anime["title"]["english"],
|
||||
"romaji": anime["title"]["romaji"],
|
||||
},
|
||||
"episodes": [
|
||||
{"title": episode["title"]}
|
||||
for episode in anime["streamingEpisodes"]
|
||||
if episode
|
||||
],
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Something unexpected occured {e}")
|
||||
Reference in New Issue
Block a user