This commit is contained in:
ScuroNeko 2023-11-12 04:48:15 +03:00
parent 79094621bc
commit 9e0923c25d
39 changed files with 1184 additions and 83 deletions

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# Genshin Impact DB
---
### !! Supports 4.2 !!

38
main.py
View File

@ -1,12 +1,30 @@
from json import loads
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from fastapi.responses import JSONResponse
from pydantic import ValidationError
from src.errors import Response, NOT_FOUND
from src.routes.achievements import achievements
from src.routes.adventureranks import adventure_ranks
from src.routes.elements import elements
from src.routes.animals import animals
from src.routes.artifacts import artifacts
from src.routes.characters import characters
from src.routes.crafts import crafts
from src.routes.domains import domains
from src.routes.elements import elements
from src.routes.enemies import enemies
from src.routes.foods import foods
from src.routes.geographies import geographies
from src.routes.glider import gliders
from src.routes.materials import materials
from src.routes.namecards import namecards
from src.routes.outfits import outfits
from src.routes.talentmaterialtypes import talent_material_types
from src.routes.tcg import tcg
from src.routes.weaponmaterialtypes import weapon_material_types
from src.routes.weapons import weapons
app = FastAPI(title='Genshin Impact DB')
@ -19,10 +37,20 @@ async def not_found(r, e):
)
app.include_router(achievements)
app.include_router(adventure_ranks)
app.include_router(characters)
app.include_router(elements)
@app.exception_handler(ValidationError)
async def validation_error(_, e: ValidationError):
return JSONResponse(
status_code=412,
content=Response(error=True, response=loads(e.json())).model_dump()
)
routers = [achievements, adventure_ranks, animals, artifacts, characters, crafts, domains, elements, enemies, foods,
geographies, materials, namecards, outfits, talent_material_types, weapon_material_types, weapons, gliders,
tcg]
for router in routers:
app.include_router(router)
def custom_openapi():

View File

@ -1,5 +1,3 @@
from typing import Any, Optional
from pydantic import BaseModel
@ -15,3 +13,4 @@ class Response[T](BaseModel):
# Constants
NOT_FOUND = ErrorData(error_code=1, error_text='Not Found')
VALIDATION_ERROR = ErrorData(error_code=2, error_text='Validation Error')

View File

@ -4,7 +4,7 @@ from fastapi import APIRouter
from src.errors import Response
from src.types.achievements import AchievementGroups, Achievement
from src.utils import parse_query_langs, load_index, load_file, parse_result_lang
from src.utils import parse_query_langs, load_index, load_category, parse_result_lang
achievements = APIRouter(prefix='/achievements', tags=['Achievements'])
@ -33,7 +33,7 @@ async def get_achievement_group(name: str, query_languages: str = 'eng', result_
break
else:
raise HTTPException(404)
return Response[Achievement](response=load_file(result_lang, 'achievements', filename))
return Response[Achievement](response=load_category(result_lang, 'achievements', filename))
@achievements.get('/groups')
@ -60,4 +60,4 @@ async def get_achievement_group(name: str, query_languages: str = 'eng', result_
break
else:
raise HTTPException(404)
return Response[AchievementGroups](response=load_file(result_lang, 'achievementgroups', filename))
return Response[AchievementGroups](response=load_category(result_lang, 'achievementgroups', filename))

View File

@ -2,7 +2,7 @@ from fastapi import APIRouter, HTTPException
from src.errors import Response
from src.types.adventureranks import AdventureRank
from src.utils import parse_query_langs, load_index, parse_result_lang, load_file
from src.utils import parse_query_langs, load_index, parse_result_lang, load_category
adventure_ranks = APIRouter(prefix='/adventure_ranks', tags=['Adventure Ranks'])
@ -31,4 +31,4 @@ async def query_character(query: str, query_languages: str = 'eng', result_langu
break
else:
raise HTTPException(404)
return Response[AdventureRank](response=load_file(result_lang, 'adventureranks', filename))
return Response[AdventureRank](response=load_category(result_lang, 'adventureranks', filename))

26
src/routes/animals.py Normal file
View File

@ -0,0 +1,26 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.animals import Animal
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
animals = APIRouter(prefix='/animals', tags=['Animals'])
@animals.get('/')
async def get_animals(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'animals')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@animals.get('/{query}')
async def get_animal(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Animal]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'animals', query_langs)
print(filename)
return Response[Animal](response=load_category(result_lang, 'animals', filename))

25
src/routes/artifacts.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.artifacts import Artifact
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
artifacts = APIRouter(prefix='/artifacts', tags=['Artifacts'])
@artifacts.get('/')
async def get_artifacts(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'artifacts')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@artifacts.get('/{query}')
async def get_artifact(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Artifact]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'artifacts', query_langs)
return Response[Artifact](response=load_category(result_lang, 'artifacts', filename))

View File

@ -1,14 +1,14 @@
from fastapi import APIRouter, HTTPException
from src.errors import Response
from src.types.characters import Character
from src.utils import load_index, parse_query_langs, parse_result_lang, load_file
from src.types.characters import Character, Constellations, Talents
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, load_file, get_file_name
characters = APIRouter(prefix='/characters', tags=['Characters'])
@characters.get('/')
async def query_characters(query_field: str = 'names', query_languages: str = 'eng') -> Response:
async def get_characters(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
response = []
for query_lang in query_langs:
@ -17,18 +17,46 @@ async def query_characters(query_field: str = 'names', query_languages: str = 'e
return Response(error=False, response=response)
@characters.get('/{query}')
async def query_character(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Character]:
@characters.get('/{name}')
async def get_character(
name: str, query_languages: str = 'eng', result_language: str = 'ru',
images: bool = False, stats: bool = False, url: bool = False
) -> Response[Character]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(name, 'characters', query_langs)
filename = ''
for lang in query_langs:
index: dict[str, str] = load_index(lang, 'characters')['names']
for key, value in index.items():
if key.lower().startswith(query):
filename = value
break
else:
raise HTTPException(404)
return Response[Character](response=load_file(result_lang, 'characters', filename))
response = load_category(result_lang, 'characters', filename)
if images:
images_file = load_file('image', 'characters')
response.update({'images': images_file[filename]})
if stats:
stats_file = load_file('stats', 'characters')
response.update({'stats': stats_file[filename]})
if url:
url_file = load_file('url', 'characters')
if filename in url_file:
response.update({'url': url_file[filename]})
version_file = load_file('version', 'characters')
response.update({'version': version_file[filename]})
return Response[Character](response=response)
@characters.get('/{name}/constellations')
async def get_constellations(
name: str, query_languages: str = 'eng', result_language: str = 'ru',
) -> Response[Constellations]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(name, 'characters', query_langs)
return Response[Constellations](response=load_category(result_lang, 'constellations', filename))
@characters.get('/{name}/talents')
async def get_talents(name: str, query_languages: str = 'eng', result_language: str = 'ru',) -> Response[Talents]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(name, 'characters', query_langs)
return Response[Talents](response=load_category(result_lang, 'talents', filename))

25
src/routes/crafts.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.crafts import Craft
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
crafts = APIRouter(prefix='/crafts', tags=['Crafts'])
@crafts.get('/')
async def get_crafts(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'crafts')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@crafts.get('/{query}')
async def get_craft(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Craft]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'crafts', query_langs)
return Response[Craft](response=load_category(result_lang, 'crafts', filename))

25
src/routes/domains.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.domains import Domain
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
domains = APIRouter(prefix='/domains', tags=['Domains'])
@domains.get('/')
async def get_domains(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'domains')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@domains.get('/{query}', response_model_exclude_none=True)
async def get_domain(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Domain]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'domains', query_langs)
return Response[Domain](response=load_category(result_lang, 'domains', filename))

View File

@ -1,19 +1,12 @@
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from fastapi import APIRouter
from src.constants import LANGUAGES
from src.errors import Response
from src.types.characters import Character
from src.types.elements import Element
from src.utils import load_index, parse_query_langs, parse_result_lang, load_file
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
elements = APIRouter(prefix='/elements', tags=['Elements'])
class QueryCharacters(BaseModel):
res: dict[str, list[str]]
@elements.get('/')
async def query_elements(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
@ -28,14 +21,5 @@ async def query_elements(query_field: str = 'names', query_languages: str = 'eng
async def query_element(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Element]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = ''
for lang in query_langs:
index: dict[str, str] = load_index(lang, 'elements')['names']
for key, value in index.items():
if key.lower().startswith(query):
filename = value
break
else:
raise HTTPException(404)
return Response[Element](response=load_file(result_lang, 'elements', filename))
filename = get_file_name(query, 'elements', query_langs)
return Response[Element](response=load_category(result_lang, 'elements', filename))

25
src/routes/enemies.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.enemies import Enemy
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
enemies = APIRouter(prefix='/enemies', tags=['Enemies'])
@enemies.get('/')
async def get_enemies(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'enemies')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@enemies.get('/{query}', response_model_exclude_none=True)
async def get_enemy(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Enemy]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'enemies', query_langs)
return Response[Enemy](response=load_category(result_lang, 'enemies', filename))

25
src/routes/foods.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.foods import Food
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
foods = APIRouter(prefix='/foods', tags=['Foods'])
@foods.get('/')
async def get_foods(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'foods')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@foods.get('/{query}', response_model_exclude_none=True)
async def get_food(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Food]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'foods', query_langs)
return Response[Food](response=load_category(result_lang, 'foods', filename))

25
src/routes/geographies.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.geographies import Geography
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
geographies = APIRouter(prefix='/geographies', tags=['Geographies'])
@geographies.get('/')
async def get_geographies(query_field: str = 'names', query_languages: str = 'eng') -> Response:
query_langs = parse_query_langs(query_languages)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'geographies')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@geographies.get('/{query}', response_model_exclude_none=True)
async def get_geography(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Geography]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'geographies', query_langs)
return Response[Geography](response=load_category(result_lang, 'geographies', filename))

25
src/routes/glider.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.gliders import Glider
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
gliders = APIRouter(prefix='/gliders', tags=['Gliders'])
@gliders.get('/')
async def get_gliders(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'windgliders')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@gliders.get('/{query}', response_model_exclude_none=True)
async def get_glider(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Glider]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'windgliders', query_langs)
return Response[Glider](response=load_category(result_lang, 'windgliders', filename))

25
src/routes/materials.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.materials import Material
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
materials = APIRouter(prefix='/materials', tags=['Materials'])
@materials.get('/')
async def get_materials(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'materials')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@materials.get('/{query}', response_model_exclude_none=True)
async def get_material(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Material]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'materials', query_langs)
return Response[Material](response=load_category(result_lang, 'materials', filename))

25
src/routes/namecards.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.namecards import NameCard
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
namecards = APIRouter(prefix='/namecards', tags=['Namecards'])
@namecards.get('/')
async def get_namecards(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'namecards')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@namecards.get('/{query}', response_model_exclude_none=True)
async def get_namecard(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[NameCard]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'namecards', query_langs)
return Response[NameCard](response=load_category(result_lang, 'namecards', filename))

25
src/routes/outfits.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.outfits import Outfit
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
outfits = APIRouter(prefix='/outfits', tags=['Outfits'])
@outfits.get('/')
async def get_outfits(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'outfits')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@outfits.get('/{query}', response_model_exclude_none=True)
async def get_outfit(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Outfit]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'outfits', query_langs)
return Response[Outfit](response=load_category(result_lang, 'outfits', filename))

View File

@ -0,0 +1,27 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.talentmaterialtypes import TalentMaterialType
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
talent_material_types = APIRouter(prefix='/talent_material_type', tags=['Talent Material'])
@talent_material_types.get('/')
async def get_talent_material_types(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'talentmaterialtypes')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@talent_material_types.get('/{query}', response_model_exclude_none=True)
async def get_talent_material_type(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[TalentMaterialType]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'talentmaterialtypes', query_langs)
return Response[TalentMaterialType](response=load_category(result_lang, 'talentmaterialtypes', filename))

202
src/routes/tcg.py Normal file
View File

@ -0,0 +1,202 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.tcg import ActionCard, CardBack, CardBox, CharacterCard, DetailedRule, EnemyCard, Keyword, LevelReward, \
StatusEffect, Summon
from src.utils import get_file_name, parse_result_lang, parse_query_langs, load_category, load_index
tcg = APIRouter(prefix='/tcg', tags=['TCG'])
@tcg.get('/action_cards')
async def get_action_cards(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgactioncards')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/action_cards/{query}', response_model_exclude_none=True)
async def get_action_card(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[ActionCard]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgactioncards', query_langs)
return Response[ActionCard](response=load_category(result_lang, 'tcgactioncards', filename))
@tcg.get('/card_backs')
async def get_card_backs(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgcardbacks')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/card_back/{query}', response_model_exclude_none=True)
async def get_card_back(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[CardBack]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgcardbacks', query_langs)
return Response[CardBack](response=load_category(result_lang, 'tcgcardbacks', filename))
@tcg.get('/card_boxes')
async def get_card_boxes(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgcardboxes')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/card_boxes/{query}', response_model_exclude_none=True)
async def get_card_box(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[CardBox]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgcardboxes', query_langs)
return Response[CardBox](response=load_category(result_lang, 'tcgcardboxes', filename))
@tcg.get('/character_cards')
async def get_character_cards(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgcharactercards')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/character_cards/{query}', response_model_exclude_none=True)
async def get_character_card(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[CharacterCard]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgcharactercards', query_langs)
return Response[CharacterCard](response=load_category(result_lang, 'tcgcharactercards', filename))
@tcg.get('/enemy_cards')
async def get_enemy_cards(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgenemycards')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/enemy_cards/{query}', response_model_exclude_none=True)
async def get_enemy_card(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[EnemyCard]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgenemycards', query_langs)
return Response[EnemyCard](response=load_category(result_lang, 'tcgenemycards', filename))
@tcg.get('/detailed_rules')
async def get_detailed_rules(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgdetailedrules')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/detailed_rules/{query}', response_model_exclude_none=True)
async def get_detailed_rule(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[DetailedRule]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgdetailedrules', query_langs)
return Response[DetailedRule](response=load_category(result_lang, 'tcgdetailedrules', filename))
@tcg.get('/keywords')
async def get_keywords(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgkeywords')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/keywords/{query}', response_model_exclude_none=True)
async def get_keyword(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[Keyword]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgkeywords', query_langs)
return Response[Keyword](response=load_category(result_lang, 'tcgkeywords', filename))
@tcg.get('/level_rewards')
async def get_level_rewards(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcglevelrewards')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/level_rewards/{query}', response_model_exclude_none=True)
async def get_level_reward(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[LevelReward]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcglevelrewards', query_langs)
return Response[LevelReward](response=load_category(result_lang, 'tcglevelrewards', filename))
@tcg.get('/status_effects')
async def get_status_effects(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgstatuseffects')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/status_effects/{query}', response_model_exclude_none=True)
async def get_status_effect(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[StatusEffect]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgstatuseffects', query_langs)
return Response[StatusEffect](response=load_category(result_lang, 'tcgstatuseffects', filename))
@tcg.get('/summons')
async def get_summons(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'tcgsummons')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@tcg.get('/summons/{query}', response_model_exclude_none=True)
async def get_summon(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[Summon]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'tcgsummons', query_langs)
return Response[Summon](response=load_category(result_lang, 'tcgsummons', filename))

View File

@ -0,0 +1,27 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.weaponmaterialtypes import WeaponMaterialType
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
weapon_material_types = APIRouter(prefix='/weapon_material_type', tags=['Weapon Material'])
@weapon_material_types.get('/')
async def get_weapon_material_types(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'weaponmaterialtypes')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@weapon_material_types.get('/{query}', response_model_exclude_none=True)
async def get_weapon_material_type(
query: str, query_languages: str = 'eng', result_language: str = 'ru'
) -> Response[WeaponMaterialType]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'weaponmaterialtypes', query_langs)
return Response[WeaponMaterialType](response=load_category(result_lang, 'weaponmaterialtypes', filename))

25
src/routes/weapons.py Normal file
View File

@ -0,0 +1,25 @@
from fastapi import APIRouter
from src.errors import Response
from src.types.weapons import Weapon
from src.utils import load_index, parse_query_langs, parse_result_lang, load_category, get_file_name
weapons = APIRouter(prefix='/weapons', tags=['Weapons'])
@weapons.get('/')
async def get_weapons(query_field: str = 'names', result_language: str = 'eng') -> Response:
query_langs = parse_query_langs(result_language)
response: list[dict[str, list[str]]] = []
for query_lang in query_langs:
chars = load_index(query_lang, 'weapons')
response.append({query_lang: list(chars[query_field].keys())})
return Response[list[dict[str, list[str]]]](error=False, response=response)
@weapons.get('/{query}', response_model_exclude_none=True)
async def get_weapon(query: str, query_languages: str = 'eng', result_language: str = 'ru') -> Response[Weapon]:
query_langs = parse_query_langs(query_languages)
result_lang = parse_result_lang(result_language)
filename = get_file_name(query, 'weapons', query_langs)
return Response[Weapon](response=load_category(result_lang, 'weapons', filename))

9
src/types/animals.py Normal file
View File

@ -0,0 +1,9 @@
from pydantic import BaseModel
class Animal(BaseModel):
name: str
description: str
category: str
counttype: str
sortorder: int

22
src/types/artifacts.py Normal file
View File

@ -0,0 +1,22 @@
from typing import List
from pydantic import BaseModel, Field
class Piece(BaseModel):
name: str
relictype: str
description: str
story: str
class Artifact(BaseModel):
name: str
rarity: List[str]
field_2pc: str = Field(..., alias='2pc')
field_4pc: str = Field(..., alias='4pc')
flower: Piece
plume: Piece
sands: Piece
goblet: Piece
circlet: Piece

View File

@ -1,5 +1,6 @@
from pydantic import BaseModel
from typing import List
from typing import List, Optional
from pydantic import BaseModel, Field
class Cv(BaseModel):
@ -9,43 +10,66 @@ class Cv(BaseModel):
korean: str
class Ascend1Item(BaseModel):
name: str
count: int
class Ascend2Item(BaseModel):
name: str
count: int
class Ascend3Item(BaseModel):
name: str
count: int
class Ascend4Item(BaseModel):
name: str
count: int
class Ascend5Item(BaseModel):
name: str
count: int
class Ascend6Item(BaseModel):
class AscendItem(BaseModel):
name: str
count: int
class Costs(BaseModel):
ascend1: List[Ascend1Item]
ascend2: List[Ascend2Item]
ascend3: List[Ascend3Item]
ascend4: List[Ascend4Item]
ascend5: List[Ascend5Item]
ascend6: List[Ascend6Item]
ascend1: List[AscendItem]
ascend2: List[AscendItem]
ascend3: List[AscendItem]
ascend4: List[AscendItem]
ascend5: List[AscendItem]
ascend6: List[AscendItem]
class Images(BaseModel):
card: str
portrait: str
icon: str
sideicon: str
cover1: str
cover2: str
hoyolab_avatar: str = Field(..., alias='hoyolab-avatar')
nameicon: str
nameiconcard: str
namegachasplash: str
namegachaslice: str
namesideicon: str
class Base(BaseModel):
hp: float
attack: float
defense: float
critrate: float
critdmg: float
class Curve(BaseModel):
hp: str
attack: str
defense: str
class PromotionItem(BaseModel):
maxlevel: int
hp: float
attack: float
defense: float
specialized: float
class Stats(BaseModel):
base: Base
curve: Curve
specialized: str
promotion: List[PromotionItem]
class URL(BaseModel):
fandom: str
class Character(BaseModel):
@ -66,4 +90,69 @@ class Character(BaseModel):
birthday: str
constellation: str
cv: Cv
costs: Costs
costs: Costs
images: Optional[Images] = None
stats: Optional[Stats] = None
url: Optional[URL] = None
version: str
# Constellations
class Constellation(BaseModel):
name: str
effect: str
class Constellations(BaseModel):
name: str
c1: Constellation
c2: Constellation
c3: Constellation
c4: Constellation
c5: Constellation
c6: Constellation
# Talents
class Attributes(BaseModel):
labels: List[str]
class Combat(BaseModel):
name: str
info: str
description: Optional[str] = None
attributes: Attributes
class Passive(BaseModel):
name: str
info: str
class LvlItem(BaseModel):
name: str
count: int
class TalentCosts(BaseModel):
lvl2: List[LvlItem]
lvl3: List[LvlItem]
lvl4: List[LvlItem]
lvl5: List[LvlItem]
lvl6: List[LvlItem]
lvl7: List[LvlItem]
lvl8: List[LvlItem]
lvl9: List[LvlItem]
lvl10: List[LvlItem]
class Talents(BaseModel):
name: str
combat1: Combat
combat2: Combat
combat3: Combat
passive1: Passive
passive2: Passive
passive3: Passive
costs: TalentCosts

18
src/types/crafts.py Normal file
View File

@ -0,0 +1,18 @@
from typing import List, Optional
from pydantic import BaseModel
class RecipeItem(BaseModel):
name: str
count: int
class Craft(BaseModel):
name: str
filter: str
sortorder: int
unlockrank: int
resultcount: int
moracost: Optional[int] = 0
recipe: List[RecipeItem]

23
src/types/domains.py Normal file
View File

@ -0,0 +1,23 @@
from typing import List, Optional
from pydantic import BaseModel
class RewardpreviewItem(BaseModel):
name: str
count: Optional[int] = None
rarity: Optional[str] = None
class Domain(BaseModel):
name: str
region: str
domainentrance: str
domaintype: str
description: str
recommendedlevel: int
recommendedelements: List[str]
unlockrank: int
rewardpreview: List[RewardpreviewItem]
disorder: List[str]
monsterlist: List[str]

18
src/types/enemies.py Normal file
View File

@ -0,0 +1,18 @@
from typing import List, Optional
from pydantic import BaseModel
class RewardpreviewItem(BaseModel):
name: str
count: Optional[float] = None
rarity: Optional[str] = None
class Enemy(BaseModel):
name: str
specialname: str
enemytype: str
category: str
description: str
rewardpreview: List[RewardpreviewItem]

29
src/types/foods.py Normal file
View File

@ -0,0 +1,29 @@
from typing import List, Optional
from pydantic import BaseModel
class Quality(BaseModel):
effect: str
description: str
class Ingredient(BaseModel):
name: str
count: int
class Food(BaseModel):
name: str
rarity: str
foodtype: str
foodfilter: str
foodcategory: str
effect: str
description: str
basedish: Optional[str] = None
character: Optional[str] = None
suspicious: Optional[Quality] = None
normal: Optional[Quality] = None
delicious: Optional[Quality] = None
ingredients: List[Ingredient]

10
src/types/geographies.py Normal file
View File

@ -0,0 +1,10 @@
from pydantic import BaseModel
class Geography(BaseModel):
name: str
area: str
description: str
region: str
showonlyunlocked: bool = False
sortorder: int

12
src/types/gliders.py Normal file
View File

@ -0,0 +1,12 @@
from typing import List
from pydantic import BaseModel
class Glider(BaseModel):
name: str
description: str
rarity: str
story: str
sortorder: int
source: List[str]

13
src/types/materials.py Normal file
View File

@ -0,0 +1,13 @@
from typing import List
from pydantic import BaseModel
class Material(BaseModel):
name: str
description: str
sortorder: int
rarity: str
category: str
materialtype: str
source: List[str]

10
src/types/namecards.py Normal file
View File

@ -0,0 +1,10 @@
from typing import List
from pydantic import BaseModel
class NameCard(BaseModel):
name: str
description: str
sortorder: int
source: List[str]

11
src/types/outfits.py Normal file
View File

@ -0,0 +1,11 @@
from typing import List, Optional
from pydantic import BaseModel
class Outfit(BaseModel):
name: str
description: str
isdefault: bool
character: str
source: Optional[List[str]] = None

View File

@ -0,0 +1,14 @@
from typing import List
from pydantic import BaseModel, Field
class TalentMaterialType(BaseModel):
name: str
field_2starname: str = Field(..., alias='2starname')
field_3starname: str = Field(..., alias='3starname')
field_4starname: str = Field(..., alias='4starname')
day: List[str]
location: str
region: str
domainofmastery: str

152
src/types/tcg.py Normal file
View File

@ -0,0 +1,152 @@
from typing import List, Optional
from pydantic import BaseModel
class Playcost(BaseModel):
costtype: str
count: int
# Action Cards
class ActionCard(BaseModel):
id: int
name: str
cardtype: str
cardtypetext: str
tags: List[str]
tagstext: List[str]
description: str
descriptionraw: str
descriptionreplaced: str
storytitle: str
storytext: str
source: str = None
playcost: List[Playcost]
# Card backs
class CardBack(BaseModel):
id: int
name: str
description: str
descriptionraw: str
source: str
rarity: int
class CardBox(BaseModel):
id: int
name: str
description: str
descriptionraw: str
source: str
rarity: int
# Character cards
class Skill(BaseModel):
id: int
name: str
descriptionraw: str
basedamage: Optional[int] = None
baseelement: Optional[str] = None
descriptionreplaced: str
description: str
typetag: str
type: str
playcost: List[Playcost]
class CharacterCard(BaseModel):
id: int
name: str
hp: int
maxenergy: int
tags: List[str]
tagstext: List[str]
storytitle: str
storytext: str
source: str
skills: List[Skill]
# Enemy card
class EnemyCard(BaseModel):
id: int
name: str
hp: int
maxenergy: int
tags: List[str]
tagstext: List[str]
skills: List[Skill]
# Detailed rules
class Rule(BaseModel):
title: str
titleraw: str
content: str
contentraw: str
filename_image: Optional[str] = None
class DetailedRule(BaseModel):
id: int
name: str
rules: List[Rule]
# Keywords
class Keyword(BaseModel):
id: int
name: str
nameraw: str
description: str
descriptionraw: str
# Level rewards
class Reward(BaseModel):
id: int
name: str
count: int
class LevelReward(BaseModel):
id: int
name: str
exp: int = None
icontype: str
unlockdescription: str
unlockdescriptionraw: str
rewards: List[Reward]
# Status effects
class StatusEffect(BaseModel):
id: int
name: str
statustypetext: str
cardtype: str
cardtypetext: str
tags: List[str]
description: str
descriptionraw: str
descriptionreplaced: str
# Summons
class Summon(BaseModel):
id: int
name: str
cardtypetext: str
tags: List
tagstext: List
description: str
descriptionraw: str
descriptionreplaced: str
countingtype: str
tokentype: str
hinttype: str

View File

@ -0,0 +1,15 @@
from typing import List
from pydantic import BaseModel, Field
class WeaponMaterialType(BaseModel):
name: str
field_2starname: str = Field(..., alias='2starname')
field_3starname: str = Field(..., alias='3starname')
field_4starname: str = Field(..., alias='4starname')
field_5starname: str = Field(..., alias='5starname')
day: List[str]
location: str
region: str
domainofforgery: str

37
src/types/weapons.py Normal file
View File

@ -0,0 +1,37 @@
from typing import List
from pydantic import BaseModel
class AscendItem(BaseModel):
name: str
count: int
class Costs(BaseModel):
ascend1: List[AscendItem]
ascend2: List[AscendItem]
ascend3: List[AscendItem]
ascend4: List[AscendItem]
ascend5: List[AscendItem]
ascend6: List[AscendItem]
class Weapon(BaseModel):
name: str
description: str
weapontype: str
rarity: str
story: str
baseatk: int
substat: str
subvalue: str
effectname: str
effect: str
r1: List[str]
r2: List[str]
r3: List[str]
r4: List[str]
r5: List[str]
weaponmaterialtype: str
costs: Costs

View File

@ -1,6 +1,8 @@
from json import load
from os.path import join
from fastapi import HTTPException
from src.constants import LANGUAGES, DEFAULT_RESULT, DEFAULT_QUERY, DATA_FOLDER
@ -9,11 +11,27 @@ def load_index(language: str, category: str):
return load(f)
def load_file(lang: str, category: str, name: str) -> dict:
def load_category(lang: str, category: str, name: str) -> dict:
with open(join(DATA_FOLDER, lang, category, f'{name}.json'), 'r', encoding='utf-8') as f:
return load(f)
def load_file(folder: str, name: str) -> dict:
with open(join(DATA_FOLDER, folder, f'{name}.json'), 'r', encoding='utf-8') as f:
return load(f)
def get_file_name(query, category, langs) -> str:
for lang in langs:
index: dict[str, str] = load_index(lang, category)['names']
for key, value in index.items():
for k in key.lower().split(' '):
if k.startswith(query.lower()):
return value
else:
raise HTTPException(404)
def parse_query_langs(langs: str) -> list[str]:
languages = langs.replace(' ', '').split(',')
query = []