Giter Club home page Giter Club logo

genshin.py's Introduction

genshin.py

Downloads PyPI package Last Commit Coverage Discord

Modern API wrapper for Genshin Impact & Honkai Impact 3rd built on asyncio and pydantic.


Documentation: https://thesadru.github.io/genshin.py

API Reference: https://thesadru.github.io/genshin.py/pdoc/genshin

Source Code: https://github.com/thesadru/genshin.py


The primary focus of genshin.py is convenience. The entire project is fully type-hinted and abstracts a large amount of the api to be easier to use.

Key features:

  • All data is in the form of Pydantic Models which means full autocompletion and linter support.
  • Requests are significantly faster thanks to proper usage of asyncio.
  • Chinese and Engrish names returned by the API are renamed to simpler English fields.
  • Supports the majority of the popular endpoints.
  • Cleanly integrates with frameworks like FastAPI out of the box.

Note: This library is a successor to genshinstats - an unofficial wrapper for the Genshin Impact api.

Requirements

  • Python 3.8+
  • aiohttp
  • Pydantic
pip install genshin

Example

A very simple example of how genshin.py would be used:

import asyncio
import genshin

async def main():
    cookies = {"ltuid": 119480035, "ltoken": "cnF7TiZqHAAvYqgCBoSPx5EjwezOh1ZHoqSHf7dT"}
    client = genshin.Client(cookies)

    data = await client.get_genshin_user(710785423)
    print(f"User has a total of {data.stats.characters} characters")

asyncio.run(main())

Contributing

Any kind of contribution is welcome. Please read CONTRIBUTING.md to see what you need to do to make a contribution.

genshin.py's People

Contributors

bachelorforever avatar effortlessfury avatar helixachaos avatar jokelbaf avatar kgirtxd avatar kt-yeh avatar luckytain avatar mchubby avatar mrwan200 avatar nattyan-tv avatar nitolar avatar omg-xtao avatar polygonalr avatar seriaati avatar sharp-eyes avatar thesadru avatar tnkv avatar yasridho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

genshin.py's Issues

Offerings contain mixed types of `dict` and `Offering` (Model)

One of the recent updates to class Offering(APIModel) has resulted in get_genshin_user()'s return value, GenshinUserStats.explorations[x].offerings, became a list that contains two mixed types: Offering (Model) and dict.

Specifically, the Tree of Dreams (or 梦之树 on CN server) is having a type of dict.

We see that offerings has changed from typing.Sequence[Offering] to typing.Sequence[typing.Any]:

offerings: typing.Sequence[typing.Any],

and is now mixing Offering and dict:

offerings = [*offerings, dict(name=values["type"], level=values["level"])]

This change was causing some issues to us downstream users - we are expecting to use the offering model consistently in the iterable.

Is this the expected behavior? If so, do you mind sharing why the change was made?

Is get_user with all_characters flag broken?

I ran the example code below and just got a list of the same character over and over.

import asyncio
import genshin

async def main():
    cookies = {"ltuid": 119480035, "ltoken": "cnF7TiZqHAAvYqgCBoSPx5EjwezOh1ZHoqSHf7dT"}
    client = genshin.GenshinClient(cookies)

    data = await client.get_user(710785423, all_characters=True)
    print(f"Characters: {', '.join(c.name for c in data.characters)}")

    await client.close()

asyncio.run(main())
Characters: Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou, Beidou

Validation Errors for Model Activities

File "/usr/local/lib/python3.8/dist-packages/genshin/client/components/chronicle/genshin.py", line 134, in get_genshin_activities
return models.Activities(**data)
File "/usr/local/lib/python3.8/dist-packages/genshin/models/model.py", line 48, in init
super().init(**data)
File "pydantic/main.py", line 341, in pydantic.main.BaseModel.init
raise validation_error
pydantic.error_wrappers.ValidationError: 1 validation error for Activities
chess -> total_score
field required (type=value_error.missing)

Model Activities need to be updated.I encoutered multiple errors since ver 2.8.
In this case , chess activity's total_score is missing.
Need more tests here.

Generic exception raised from `_get_db_char` is difficult to handle

We were seeing this exception being thrown a few times:

raise Exception(
f"Character names not loaded for {lang!r}. Please run `await genshin.utility.update_characters_enka()`."
)

Our hope is to be able to gracefully handle the specific exception, for instance:

try:
    # load character
except LanguageNotFound as lang_exc:
    # log and handle error (update from enka)
    log.error(f"language {lang_exc.lang} not found")

without having to catch the generic Exception (which could be any other error types).

It'll be really helpful to us if we have something similar to a LanguageNotFound to catch and handle.

And of course, thank you for maintaining this great project.

Genshin Characters Icon URL problem

Some characters give icon URL not found like "Yae Miko" : UI_AvatarIcon_YaeMiko

But I found that the file name is wrong, the correct file name is : UI_AvatarIcon_Yae

But it seems that this problem only occurs in the international server.
I checked through the log and it seems that the Chinese server also has this problem..

Can it be fixed by hardcoding?

pydantic.error_wrappers.ValidationError: 21 validation errors for Activities

I got this error when using get_full_genshin_user.However get_genshin_characters works without error.I try to fetch hoyolab api, it response as normal.This error seem appear at a part of user.Anyone know why ?

pydantic.error_wrappers.ValidationError: 21 validation errors for Activities
hyakunin_ikki_v25 -> records -> 0 -> battles -> 0 -> characters -> 1 -> __root__
  Character data incomplete (type=value_error)

Custom cache aioredis problem and Fixed

I tried custom cache with docs this:
https://github.com/thesadru/genshin.py/blob/master/docs/caching.md#custom-caches

But I got this
image

And I added await after self.redis but I got error this:
image

But I have fixed with using "msgpack" to pack JSON data

import msgpack

async def _check_cache(self, key, check, lang):
        """Check the cache for any entries"""
        key = ":".join(map(str, key + (lang or self.lang,)))

        data = await self.redis.get(key)

        if data is None:
            return None

        if check is None or check(data):
            return msgpack.unpackb(data)

        await self.redis.delete(key)

        return None

    async def _update_cache(self, data, key, check=None, lang=None) -> None:
        """Update the cache with a new entry"""
        key = ":".join(map(str, key + (lang or self.lang,)))

        if check is not None and not check(data):
            return

        await self.redis.set(key, msgpack.packb(data), ex=3600)

Result:
image

Missing params causes request to return -130 error code in Traveler's Diary

I found that getting some of the Traveler's Diary on the Chinese server throws an exception.

Exception:
genshin.errors.GenshinException: [-130] 未设置默认角色
未设置默认角色Default role not set(Translate)

I found that the reason for this exception is that the request params on the Chinese server have been changed.

The following code needs to be modified

params["uid"] = uid
params["region"] = utility.recognize_genshin_server(uid)

if self.region == types.Region.OVERSEAS:
   params["uid"] = uid
   params["region"] = utility.recognize_genshin_server(uid)
elif self.region == types.Region.CHINESE:
   params["bind_uid"] = uid
   params["bind_region"] = utility.recognize_genshin_server(uid)
else:
   raise TypeError(f"{self.region!r} is not a valid region.")

Please note that this exception only happens to a small number of users.

Allow raw data to be returned

This has been bugging me for a while but can you include the raw json data in the returned pydantic model? Sometimes the assumption that you used to parse the json isn't correct, and I would have to hack into the library to get the original json to parse it myself.

Here's an example: The real-time notes API returns 'transformer': {'obtained': True, 'recovery_time': {'Day': 0, 'Hour': 5, 'Minute': 0, 'Second': 0, 'reached': True}, 'wiki': ''}. Mihoyo only returns the biggest time unit. In this case it rounds down to 5 hours so even if its 5 hours and 12 minutes it still returns 5 hours. The remaining_transformer_recovery_time as it's currently implemented gives the wrong impression that it will recover at this exact time. Meanwhile if I have the original json, I can display something like "parametric transformer will recover in 5 hours...", "parametric transformer will recover in 21 minutes..."

This is just one example. I have come across a few cases where the raw json is greatly appreciated, like the fields that you haven't yet added (e.g. data["transformer"]["obtained"])

Code Redemption Broken

I'm getting this error when trying to redeem a code.
genshin.errors.GenshinException: [-502] fail to get RPC client

Seems that the CODE_URL has changed, and replacing it with https://sg-hk4e-api.hoyoverse.com/common/apicdkey/api/webExchangeCdkey fixes the issue.

[invalid]Cannot recognize servers with UID starting with 4

There are already players with UIDs starting with 4 on the Chinese genshin server.
The recognize_genshin_server function needs to be modified

def recognize_genshin_server(uid: int) -> str:
"""Recognize which server a Genshin UID is from."""
server = {
"1": "cn_gf01",
"2": "cn_gf01",
"5": "cn_qd01",
"6": "os_usa",
"7": "os_euro",
"8": "os_asia",
"9": "os_cht",
}.get(str(uid)[0])
if server:
return server
raise ValueError(f"UID {uid} isn't associated with any server")

Can't set authkey on GenshinClient due to size mismatch

Trying to create a new GenshinClient instance with an authkey fails with the error authkey must have precisely 1024 characters. Trying to set the authkey on an existing instance results in the same error. The auth key I'm providing is longer than 1024 characters. The base64 decoded auth key, however, is exactly 1024 characters long. Providing that instead of the base64 encoded one results in a different error: authkey is not a valid base64 encoded string

Support for IOS

It is more a question than a real issue.
I was just wondering if it is possible to get the url in any way in ios.

Thank you !

Issue since Genshin 3.0

Hi,

Since the last version this script cannot found the authkey from output_log.txt
After check with patch #59 the new error is:
genshin.errors.AuthkeyTimeout: [-101] Authkey has timed out.

I relaunch software and see wishes history but the result is the same.

in the file genshin/utility/logfile.py
replace lines

match = re.search(r"https://.+?authkey=([^&#]+)&game_biz=hk4e_", string, re.MULTILINE)
if match is not None:
    return urllib.parse.unquote(match.group(1))

by

list_authkey = re.findall(r"https://.+?authkey=([^&#]+)&game_biz=hk4e_", string)
if len(list_auth_key) > 0:
    return urllib.parse.unquote(list_authkey[-1])

works

best regards

Cannot get CharacterRanks data from client.get_spiral_abyss() if I don't browse the Hoyolab app first

How to reproduce:

  1. Finish any floor of abyss
  2. Wait and don't open Hoyolab app or website
  3. Use client.get_spiral_abyss() function
  4. The CharacterRanks is empty. Everything else works.
  5. After you browse Hoyolab app or website, the CharacterRanks will show normally when using client.get_spiral_abyss()

Example

    data = await client.get_spiral_abyss(826263929)
    print(data)
SpiralAbyss(unlocked=False, season=48, 
    start_time=datetime.datetime(2022, 6, 15, 20, 0, tzinfo=datetime.timezone.utc), 
    end_time=datetime.datetime(2022, 6, 30, 19, 59, 59, tzinfo=datetime.timezone.utc), 
    total_battles=6, total_wins='6', max_floor='10-3', total_stars=18, 
    ranks=CharacterRanks(most_played=[], most_kills=[], strongest_strike=[], most_damage_taken=[], most_bursts_used=[], most_skills_used=[]), 
    floors=[Floor(floor=9, unlocked=True, stars=9, max_stars=9, chambers=[
    Chamber(chamber=1, stars=3, max_stars=3, battles=[Battle(half=1, timestamp=datetime.date(2022, 6, 16), characters=[AbyssCharacter(id=10000046, name='Hu Tao', element='Pyro', rarity=5, 
    .....

until_resin_recovery is always zero

    @property
    def until_resin_recovery(self) -> float:
        """The remaining time until resin recovery in seconds"""
        remaining = self.resin_recovered_at - datetime.now().astimezone()
        return min(remaining.total_seconds(), 0)

I believe you wanted to do max(..., 0)

Set which region to fetch for Traveler's diary?

I'm not too familiar with the actual API endpoint myself, but it seems the current implementation defaults to 1 region only? (I'm guessing at the mercy of the default returned values from the API endpoint)

genshin.error.InvalidCookies

How to reproduce ?
Using CLI to login after that invoke python -m genshin accounts --cookies "ltoken=...; ltuid=..."

Current behavior
It's just display error which state:

genshin.errors.InvalidCookies: [-100] Cookies are not valid.

Retire the need for cached genshin character names

By fetching data dynamically from (for example) enka's database or ambr.top we could eliminate the need to have a pr every single genshin update.

Why not just use purely the API

  • character names are not provided for many endpoints
  • no endpoint provides all names, icons, and ids
    • wiki uses custom ids and icons
    • calculator does not have consistent icons

Requirements

  • pass the language to every model (scope fuckery or major rewrite)
  • Fix whatever the hell this error is
  • find a way to cache things effectively in-between runs
  • update the documentation
  • hope to god the enka repo or ambr can never get shut down

TypeError: 'MergedPaginator' object is not iterable

i want to try wish history but i got this error
TypeError: 'MergedPaginator' object is not iterable

this is my code

import asyncio
import genshin
cookies = {"ltuid": xxxxxxxx, "ltoken": "xxxxxxxxxxxxxx"}
client = genshin.Client(cookies)

async def main():
    for wish in client.wish_history():
        print(f"{wish.time} - {wish.name} ({wish.rarity}* {wish.type})")

asyncio.run(main())

if my coding is wrong I'm sorry, I'm just learning to use python

InternalDatabaseError when trying to get genshin characters (Nilou's id doesn't exist)

Obtaining this exception when trying to retrieve the genshin characters from the API. It's due to Nilou's ID not being in the internal database.

Traceback (most recent call last):
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\ext\tasks\__init__.py", line 239, in _loop
    await self.coro(*args, **kwargs)
  File "c:\Users\ElRey\Documents\Scripts\Python\ReyBot\discord_tools\tasks.py", line 10, in updateGenshinChars    
    chars = await client.get_genshin_characters(cfg.genshin_data["uuid"])
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\client\components\chronicle\genshin.py", line 78, in get_genshin_characters
    data = await self._request_genshin_record("character", uid, lang=lang, method="POST")
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\client\components\chronicle\genshin.py", line 51, in _request_genshin_record
    return await self.request_game_record(
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\client\components\chronicle\base.py", line 63, in request_game_record
    data = await self.request_hoyolab(url, lang=lang, region=region, **kwargs)
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\client\components\base.py", line 380, in request_hoyolab
    data = await self.request(url, method=method, params=params, data=data, headers=headers, **kwargs)
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\client\components\base.py", line 294, in request
    response = await self.cookie_manager.request(
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\client\manager.py", line 243, in request
    return await self._request(method, url, cookies=self.cookies, **kwargs)
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\client\ratelimit.py", line 24, in inner
    x = await func(*args, **kwargs)
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\client\manager.py", line 137, in _request
    errors.raise_for_retcode(data)
  File "C:\Users\ElRey\AppData\Local\Programs\Python\Python310\lib\site-packages\genshin\errors.py", line 224, in raise_for_retcode
    raise exctype(data, msg)
genshin.errors.InternalDatabaseError: [-1] character id:10000070 is not exists

Request: Implement login by UID

Can you implement the login by UID? I think its the same as login_by_password with geetest. You can see:

there are important payload and headers for sendCode endpoint:
Payload

{"game_biz":"hk4e_global","lang":"en-us","level":"YOUR_AR","region":"YOUR_SERVER","uid":"YOUR_UID"}

Headers

x-rpc-aigis: 4ffcb4090c444aa0bee4c64d4616a704;eyJnZWV0ZXN0X2NoYWxsZW5nZSI6IjEwY2Y2OWNlMzlhMzljZTZkZmI5ZTk0MDE2YjQxODYwIiwiZ2VldGVzdF92YWxpZGF0ZSI6ImE3MjdmOWU4ZGQzZWU3ZDJiMWFjNDg1NjczMDU4ZWJiIiwiZ2VldGVzdF9zZWNjb2RlIjoiYTcyN2Y5ZThkZDNlZTdkMmIxYWM0ODU2NzMwNThlYmJ8am9yZGFuIn0=
x-rpc-app_id: ap0u1hssh534

Or you want to analyze or reverse engineering it just go to the new event at https://act.hoyoverse.com/ys/event/e20220928review_data/index.html?mhy_presentation_style=fullscreen&mhy_auth_required=true&game_biz=hk4e_global&mhy_landscape=true
HoYo is now accepting the login by UID with the verification code.

Support Honkai Impact daily sign-in

Since honkai has its own daily sign-in rewards it'd be nice to support it in genshin.py.

The logic is the exact same, only the base url and act id differ.
The biggest problem is figuring out how to properly implement it without much repetition.

Currently, users can use:

class HonkaiClient(GenshinClient):
    ACT_ID = "e202110291205111"
    REWARD_URL = "https://api-os-takumi.mihoyo.com/event/mani/"
client = HonkaiClient(...)
client.claim_daily_reward()

Chinese API Root Path Change

api-takumi.mihoyo.com to api-takumi-record.mihoyo.com
see:
https://github.com/Azure99/GenshinPlayerQuery/commit/74aba0696e0e4501e95bf0302677817a3e214e66

Implement the Traveler's Diary

The Traveler's Diary has been available in the hoyolab app for a while now.
Chinese users had it for some time already, as proved by https://github.com/hyhAsma/Genshin_id_inquiry/commit/904441a399874295a9e0b16125cae3f7012bfe7d
Implementations of it already exist (for example Snap.Genshin) but there don't seem to be any for overseas players.

This has been addressed before in thesadru/genshinstats#18 but the endpoint has been falsely identified as the endpoint for transaction logs.

This task would've ordinarily been very simple however this data is only visible from the app. This requires reverse-engineering the app itself which has been done for the Chinese Miyoushe app but not for the Overseas Hoyolab one. I will be attempting to somehow intercept requests but I do not have any experience with reverse-engineering apps so I would gladly appreciate any help.

PS: Chinese users may already use this feature thanks to 1600940.

diary_log repeats the same list

diary_log calls request_ledger with the param page when the API only accepts current_page.
As the param is wrong, the first page will always be returned.

genshin.errors.GenshinException: [10104] Upon attempting to get the notes for another user.

As the title suggests, attempting to use client.get_notes({uidOfSomeoneElse}) on another user that has a publicly open battle chronicle returns this exception. Is this because Hoyolab doesn't allow you to get notes for other users? If that's the case, the description "Tried to use a beta feature in an invalid context." doesn't sound correct (unless this is a beta feature that's actually being worked on, in that case go you!).

Hoyolab check in?

Does Hoyoverse remove the Hoyolab check in API? I still use genshinstats but when I use Hoyolab check in it throw an error genshinstats.errors.GenshinStatsException: Internal database error, see original message, did they remove it now?

All endpoints require cookies

authkey = g.utility.extract_authkey(authKey)
client = g.Client()
client.set_authkey(authkey)
return await client.wish_history(banner_id)

RuntimeError: Tried to make a request before setting cookies

New characters without defined names return the wrong image url

Try to get the data with get_partial_user, the image url of Yun Jin will be like https://upload-os-bbs.mihoyo.com/game_record/genshin/character_icon/UI_AvatarIcon_Yun Jin.png, but the raw date is UI_AvatarIcon_Yunjin.png.

If you change the default language parameter when querying, , this problem will happen for all new characters because of the different language names.

I think the image url should be generated from the raw data instead of the character.name.

genshin.errors.InvalidCookies: [-1071] Cookies are not valid.

I got this error from using the redeem_code function. 
The weird thing is, when I use other functions such as claim_daily_reward and genshin_accounts, it doesn't raise any errors.

Client = genshin.Client(
    cookies={
          "ltuid": 1234,
          "ltoken": "xxxxx"
    },
    authkey="xxxx",
)

x = await Client.redeem_code(code="GENSHINGIFT", uid=await Client._get_uid(game=Game.GENSHIN)
print(x)

I am not sure if I redeemed the claimed code, but I'm not really sure what the problem with this code is.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.