completed the basic ui and anilist module

This commit is contained in:
Benedict Xavier Wanyonyi
2024-05-15 20:33:20 +03:00
commit ffe5db9e33
44 changed files with 3775 additions and 0 deletions

0
app/libs/__init__.py Normal file
View File

View File

@@ -0,0 +1 @@
from .anilist import AniList

134
app/libs/anilist/anilist.py Normal file
View File

@@ -0,0 +1,134 @@
from .queries_graphql import (
most_favourite_query,
most_recently_updated_query,
most_popular_query,
trending_query,
most_scored_query,
recommended_query,
search_query,
anime_characters_query,
anime_relations_query,
airing_schedule_query,
upcoming_anime_query
)
import requests
# from kivy.network.urlrequest import UrlRequestRequests
class AniList:
@classmethod
def get_data(cls,query:str,variables:dict = {})->tuple[bool,dict]:
url = "https://graphql.anilist.co"
# req=UrlRequestRequests(url, cls.got_data,)
try:
response = requests.post(url,json={"query":query,"variables":variables},timeout=5)
return (True,response.json())
except requests.exceptions.Timeout:
return (False,{"Error":"Timeout Exceeded for connection there might be a problem with your internet or anilist is down."})
except requests.exceptions.ConnectionError:
return (False,{"Error":"There might be a problem with your internet or anilist is down."})
except Exception as e:
return (False,{"Error":f"{e}"})
@classmethod
def got_data(cls):
pass
@classmethod
def search(cls,
query:str|None=None,
sort:list[str]|None=None,
genre_in:list[str]|None=None,
genre_not_in:list[str]|None=None,
popularity_greater:int|None=None,
popularity_lesser:int|None=None,
averageScore_greater:int|None=None,
averageScore_lesser:int|None=None,
tag_in:list[str]|None=None,
tag_not_in:list[str]|None=None,
status_in:list[str]|None=None,
status_not_in:list[str]|None=None,
endDate_greater:int|None=None,
endDate_lesser:int|None=None,
start_greater:int|None=None,
start_lesser:int|None=None,
page:int|None=None
)->tuple[bool,dict]:
variables = {}
for key, val in list(locals().items())[1:]:
if val is not None and key not in ["variables"]:
variables[key] = val
search_results = cls.get_data(search_query,variables=variables)
return search_results
@classmethod
def get_trending(cls)->tuple[bool,dict]:
trending = cls.get_data(trending_query)
return trending
@classmethod
def get_most_favourite(cls)->tuple[bool,dict]:
most_favourite = cls.get_data(most_favourite_query)
return most_favourite
@classmethod
def get_most_scored(cls)->tuple[bool,dict]:
most_scored = cls.get_data(most_scored_query)
return most_scored
@classmethod
def get_most_recently_updated(cls)->tuple[bool,dict]:
most_recently_updated = cls.get_data(most_recently_updated_query)
return most_recently_updated
@classmethod
def get_most_popular(cls)->tuple[bool,dict]:
most_popular = cls.get_data(most_popular_query)
return most_popular
# FIXME:dont know why its not giving useful data
@classmethod
def get_recommended_anime_for(cls,id:int)->tuple[bool,dict]:
recommended_anime = cls.get_data(recommended_query)
return recommended_anime
@classmethod
def get_charcters_of(cls,id:int)->tuple[bool,dict]:
variables = {"id":id}
characters = cls.get_data(anime_characters_query,variables)
return characters
@classmethod
def get_related_anime_for(cls,id:int)->tuple[bool,dict]:
variables = {"id":id}
related_anime = cls.get_data(anime_relations_query,variables)
return related_anime
@classmethod
def get_airing_schedule_for(cls,id:int)->tuple[bool,dict]:
variables = {"id":id}
airing_schedule = cls.get_data(airing_schedule_query,variables)
return airing_schedule
@classmethod
def get_upcoming_anime(cls,page:int)->tuple[bool,dict]:
variables = {"page":page}
upcoming_anime = cls.get_data(upcoming_anime_query,variables)
return upcoming_anime
if __name__ == "__main__":
import json
# data = AniList.get_most_popular()
# data = AniList.get_most_favourite()
# data = AniList.get_most_recently_updated()
# data = AniList.get_trending()
# data = AniList.get_most_scored()
# term = input("enter term: ")
data = AniList.search(query="Ninja")
# data = AniList.get_recommended_anime_for(21)
# data = AniList.get_related_anime_for(21)
# data = AniList.get_airing_schedule_for(21)
# data = AniList.get_upcoming_anime(1)
print(json.dumps(data,indent=4))
pass

View File

@@ -0,0 +1,576 @@
optional_variables = "\
$page:Int,\
$sort:[MediaSort],\
$genre_in:[String],\
$genre_not_in:[String],\
$tag_in:[String],\
$tag_not_in:[String],\
$status_in:[MediaStatus],\
$status_not_in:[MediaStatus],\
$popularity_greater:Int,\
$popularity_lesser:Int,\
$averageScore_greater:Int,\
$averageScore_lesser:Int,\
$startDate_greater:FuzzyDateInt,\
$startDate_lesser:FuzzyDateInt,\
$endDate_greater:FuzzyDateInt,\
$endDate_lesser:FuzzyDateInt\
"
# FuzzyDateInt = (yyyymmdd)
# MediaStatus = (FINISHED,RELEASING,NOT_YET_RELEASED,CANCELLED,HIATUS)
search_query = """
query($query:String,%s){
Page(perPage:15,page:$page){
pageInfo{
total
currentPage
}
media(
search:$query,
genre_in:$genre_in,
genre_not_in:$genre_not_in,
tag_in:$tag_in,
tag_not_in:$tag_not_in,
status_in:$status_in,
status_not_in:$status_not_in,
popularity_greater:$popularity_greater,
popularity_lesser:$popularity_lesser,
averageScore_greater:$averageScore_greater,
averageScore_lesser:$averageScore_lesser,
startDate_greater:$startDate_greater,
startDate_lesser:$startDate_lesser,
endDate_greater:$endDate_greater,
endDate_lesser:$endDate_lesser,
sort:$sort,
type:ANIME
)
{
id
title{
romaji
english
}
coverImage{
medium
}
trailer {
site
id
}
popularity
favourites
averageScore
episodes
genres
studios{
nodes{
name
favourites
}
}
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
description
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
""" % optional_variables
trending_query = """
query{
Page(perPage:15){
media(sort:TRENDING_DESC,type:ANIME){
id
title{
romaji
english
}
coverImage{
medium
}
trailer {
site
id
}
popularity
favourites
averageScore
genres
episodes
description
studios {
nodes {
name
favourites
}
}
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
"""
# mosts
most_favourite_query = """
query{
Page(perPage:15){
media(sort:FAVOURITES_DESC,type:ANIME){
id
title{
romaji
english
}
coverImage{
medium
}
trailer {
site
id
}
popularity
favourites
averageScore
episodes
description
genres
studios {
nodes {
name
favourites
}
}
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
"""
most_scored_query = """
query{
Page(perPage:15){
media(sort:SCORE_DESC,type:ANIME){
id
title{
romaji
english
}
coverImage{
medium
}
trailer {
site
id
}
popularity
episodes
favourites
averageScore
description
genres
studios {
nodes {
name
favourites
}
}
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
"""
most_popular_query = """
query{
Page(perPage:15){
media(sort:POPULARITY_DESC,type:ANIME){
id
title{
romaji
english
}
coverImage{
medium
}
trailer {
site
id
}
popularity
favourites
averageScore
description
episodes
genres
studios {
nodes {
name
favourites
}
}
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
"""
most_recently_updated_query = """
query{
Page(perPage:15){
media(sort:UPDATED_AT_DESC,type:ANIME){
id
title{
romaji
english
}
coverImage{
medium
}
trailer {
site
id
}
popularity
favourites
averageScore
description
genres
episodes
studios {
nodes {
name
favourites
}
}
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
"""
recommended_query = """
query {
Page(perPage:15) {
media( type: ANIME) {
recommendations(sort:RATING_DESC){
nodes{
media{
id
title{
english
romaji
native
}
coverImage{
medium
}
description
episodes
trailer{
site
id
}
genres
averageScore
popularity
favourites
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
}
}
}
"""
anime_characters_query = """
query($id:Int){
Page {
media(id:$id, type: ANIME) {
characters {
nodes {
name {
first
middle
last
full
native
}
image {
medium
}
description
gender
dateOfBirth {
year
month
day
}
age
bloodType
favourites
}
}
}
}
}
"""
anime_relations_query = """
query ($id: Int) {
Page(perPage: 20) {
media(id: $id, sort: POPULARITY_DESC, type: ANIME) {
relations {
nodes {
id
title {
english
romaji
native
}
coverImage {
medium
}
description
episodes
trailer {
site
id
}
genres
averageScore
popularity
favourites
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
}
}
"""
airing_schedule_query = """
query ($id: Int) {
Page {
media(id: $id, sort: POPULARITY_DESC, type: ANIME) {
airingSchedule(notYetAired:true){
nodes{
airingAt
timeUntilAiring
episode
}
}
}
}
}
"""
upcoming_anime_query = """
query ($page: Int) {
Page(page: $page) {
pageInfo {
total
perPage
currentPage
hasNextPage
}
media(type: ANIME, status: NOT_YET_RELEASED,sort:POPULARITY_DESC) {
id
title {
romaji
english
}
coverImage {
medium
}
trailer {
site
id
}
popularity
favourites
averageScore
genres
episodes
description
studios {
nodes {
name
favourites
}
}
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}
}
"""
# print(search_query)

View File

@@ -0,0 +1,71 @@
query($query:String){
Page(perPage:15,page:$page){
pageInfo{
total
currentPage
}
media(
search:$query,
genre_in:$genre_in,
genre_not_in:$genre_not_in,
tag_in:$tag_in,
tag_not_in:$tag_not_in,
status_in:$status_in,
status_not_in:$status_not_in,
popularity_greater:$popularity_greater,
popularity_lesser:$popularity_lesser,
averageScore_greater:$averageScore_greater,
averageScore_lesser:$averageScore_lesser,
startDate_greater:$startDate_greater,
startDate_lesser:$startDate_lesser,
endDate_greater:$endDate_greater,
endDate_lesser:$endDate_lesser,
sort:$sort,
type:ANIME
)
{
id
title{
romaji
english
}
coverImage{
medium
}
trailer {
site
id
}
popularity
favourites
averageScore
episodes
genres
studios{
nodes{
name
favourites
}
}
tags {
name
}
startDate {
year
month
day
}
endDate {
year
month
day
}
status
nextAiringEpisode {
timeUntilAiring
airingAt
episode
}
}
}

View File

@@ -0,0 +1 @@
3.12

View File

@@ -0,0 +1 @@
from .animdl_api import AnimdlApi

View File

@@ -0,0 +1,82 @@
from subprocess import run, PIPE
from difflib import SequenceMatcher
import time
import json
import re
class AnimdlApi:
@classmethod
def run_command(cls,cmds:list):
return run(["C:\\Users\\bxavi\\.pyenv\\pyenv-win\\versions\\3.10.11\\python.exe","-m", "animdl", *cmds],capture_output=True,stdin=PIPE,text=True)
@classmethod
def get_anime_match(cls,anime_item,title):
return SequenceMatcher(None,title,anime_item[0]).ratio()
@classmethod
def get_anime_url_by_title(cls,title:str):
result = cls.run_command(["search",title])
possible_animes = cls.output_parser(result)
if possible_animes:
anime_url = max(possible_animes.items(),key=lambda anime_item:cls.get_anime_match(anime_item,title))
return anime_url # {"title","anime url"}
return None
@classmethod
def get_stream_urls_by_anime_url(cls,anime_url:str):
if anime_url:
try:
result = cls.run_command(["grab",anime_url])
return [json.loads(episode.strip()) for episode in result.stdout.strip().split("\n")]
except:
return None
return None
@classmethod
def get_stream_urls_by_anime_title(cls,title:str):
anime = cls.get_anime_url_by_title(title)
if anime:
return anime[0],cls.get_stream_urls_by_anime_url(anime[1])
return None
@classmethod
def contains_only_spaces(cls,input_string):
return all(char.isspace() for char in input_string)
@classmethod
def output_parser(cls,result_of_cmd:str):
data = result_of_cmd.stderr.split("\n")[3:]
parsed_data = {}
pass_next = False
for i,data_item in enumerate(data[:]):
if pass_next:
pass_next = False
continue
if not data_item or cls.contains_only_spaces(data_item):
continue
item = data_item.split(" / ")
numbering = r"^\d*\.\s*"
try:
if item[1] == "" or cls.contains_only_spaces(item[1]):
pass_next = True
parsed_data.update({f"{re.sub(numbering,'',item[0])}":f"{data[i+1]}"})
else:
parsed_data.update({f"{re.sub(numbering,'',item[0])}":f"{item[1]}"})
except:
pass
return parsed_data
if __name__ == "__main__":
# for anime_title,url in AnimdlApi.get_anime_url_by_title("jujutsu").items():
# t = AnimdlApi.get_stream_urls_by_anime_url("https://allanime.to/anime/LYKSutL2PaAjYyXWz")
start = time.time()
t = AnimdlApi.get_stream_urls_by_anime_title("KONOSUBA -God's Blessing on This Wonderful World! 3")
delta = time.time() - start
print(t)
print(f"Took: {delta} secs")