Skip to content

Commit ad5a254

Browse files
authored
Update v1.1.0
Add cache for ```load_lang()``` .
1 parent c5a2a3b commit ad5a254

File tree

5 files changed

+127
-34
lines changed

5 files changed

+127
-34
lines changed

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
author = 'pwnblog'
2323

2424
# The full version, including alpha/beta/rc tags
25-
release = '1.0.12'
25+
release = '1.1.0'
2626

2727

2828
# -- General configuration ---------------------------------------------------
@@ -53,4 +53,4 @@
5353
# Add any paths that contain custom static files (such as style sheets) here,
5454
# relative to this directory. They are copied after the builtin static files,
5555
# so a file named "default.css" will overwrite the builtin "default.css".
56-
html_static_path = ['_static']
56+
html_static_path = ['_static']

docs/tutorial.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ in genshin TextMap json file.
5050

5151
We automated this process, just pass the correct language value(default 'en') and call :py:func:`enkapy.client.Enka.load_lang`
5252

53+
*New in 1.1.0: Now load_lang has cache! check ``force_cache`` and ``force_update`` parameters!*
54+
5355
*Note: if you don't load language data, all name field in returned object will be empty string*
5456

5557
Player basic info

enkapy/client.py

Lines changed: 120 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import os.path
23

34
import aiohttp
45
from aiocache import cached
@@ -22,12 +23,12 @@ class Enka:
2223
_URL = "https://enka.network/u/{uid}/__data.json"
2324
# https://github.com/theBowja/GenshinData-1
2425
# https://raw.githubusercontent.com/GrownNed/Homework/master
25-
_REPO_BASE = 'https://gitlab.com/Dimbreath/gamedata/-/raw/main/'
26-
_LANG_URL = _REPO_BASE + '/TextMap/TextMap{lang}.json'
27-
_AVATAR_URL = _REPO_BASE + '/ExcelBinOutput/AvatarExcelConfigData.json'
28-
_TALENT_URL = _REPO_BASE + '/ExcelBinOutput/AvatarTalentExcelConfigData.json'
29-
_SKILL_DEPOT_URL = _REPO_BASE + '/ExcelBinOutput/AvatarSkillDepotExcelConfigData.json'
30-
_SKILL_URL = _REPO_BASE + '/ExcelBinOutput/AvatarSkillExcelConfigData.json'
26+
_REPO_BASE = 'https://gitlab.com/Dimbreath/gamedata/-/raw/main'
27+
_LANG_URL = _REPO_BASE + '/TextMap/TextMap{lang}.json?inline=false'
28+
_AVATAR_URL = _REPO_BASE + '/ExcelBinOutput/AvatarExcelConfigData.json?inline=false'
29+
_TALENT_URL = _REPO_BASE + '/ExcelBinOutput/AvatarTalentExcelConfigData.json?inline=false'
30+
_SKILL_DEPOT_URL = _REPO_BASE + '/ExcelBinOutput/AvatarSkillDepotExcelConfigData.json?inline=false'
31+
_SKILL_URL = _REPO_BASE + '/ExcelBinOutput/AvatarSkillExcelConfigData.json?inline=false'
3132
USER_AGENT = "Mozilla/5.0"
3233
timeout = 30
3334
"""Http connection timeout"""
@@ -45,32 +46,120 @@ class Enka:
4546
"""Internal skill data"""
4647
lang = 'en'
4748
"""Language for text hash resolve"""
49+
_cache = 'cache'
50+
"""Cache folder name"""
4851

49-
async def load_lang(self, lang='en'):
52+
def _cache_exists(self, name):
5053
"""
51-
Load language data from Dimbreath repo
54+
Check if cache file exists and return full cache file path
55+
:param name: cache name
56+
:return: full cache file path
57+
"""
58+
package_path = os.path.dirname(os.path.realpath(__file__))
59+
cache_path = os.path.join(package_path, self._cache)
60+
cache_file_path = os.path.join(cache_path, name)
61+
62+
if not os.path.exists(cache_path):
63+
try:
64+
os.mkdir(cache_path)
65+
except OSError:
66+
pass
67+
return ''
68+
if not os.path.isdir(cache_path):
69+
try:
70+
os.remove(cache_path)
71+
except OSError:
72+
pass
73+
return ''
74+
if os.path.exists(cache_file_path):
75+
return cache_file_path
76+
else:
77+
return ''
78+
79+
async def _process_cache(self, client: aiohttp.ClientSession, url, cache_file, force_cache=False,
80+
force_update=False):
81+
"""
82+
Process cache
83+
:param client: aiohttp client
84+
:param url: git url
85+
:param cache_file: cache file name
86+
:param force_cache: ignore git update, force using cache file
87+
:param force_update: force update from git repo
88+
:return: cache file path
89+
"""
90+
cache_file_path = self._cache_exists(cache_file)
91+
if cache_file_path and not force_update:
92+
stat = os.stat(cache_file_path)
93+
file_size = stat.st_size
94+
if not force_cache:
95+
resp = await client.head(url, proxy=self.proxy)
96+
cl = int(resp.headers['Content-Length'])
97+
if cl != file_size:
98+
resp = await client.get(url, proxy=self.proxy)
99+
with open(cache_file_path, 'wb') as f:
100+
f.write(await resp.read())
101+
else:
102+
package_path = os.path.dirname(os.path.realpath(__file__))
103+
cache_path = os.path.join(package_path, self._cache)
104+
cache_file_path = os.path.join(cache_path, cache_file)
105+
resp = await client.get(url, proxy=self.proxy)
106+
with open(cache_file_path, 'wb') as f:
107+
f.write(await resp.read())
108+
return cache_file_path
109+
110+
async def load_lang(self, lang='en', force_cache=False, force_update=False):
111+
"""
112+
Load language data from cache or Dimbreath repo
52113
:param lang: language you want to load, default 'en'
114+
:param force_cache: Do not check repo update if cache file exists
115+
:param force_update: force update from git repo
53116
"""
117+
54118
async with aiohttp.ClientSession(headers={"User-Agent": self.USER_AGENT}) as client:
55119
if lang not in self._lang_data:
56-
resp = await client.get(self._LANG_URL.format(lang=lang.upper()), proxy=self.proxy)
57-
self._lang_data[lang] = await resp.json(content_type=None)
120+
cache_file_path = await self._process_cache(client,
121+
self._LANG_URL.format(lang=lang.upper()),
122+
'lang.json',
123+
force_cache,
124+
force_update)
125+
with open(cache_file_path, 'rb') as f:
126+
self._lang_data[lang] = json.load(f)
58127
if not self._avatar_data:
59-
resp = await client.get(self._AVATAR_URL, proxy=self.proxy)
60-
for x in await resp.json(content_type=None):
61-
self._avatar_data[x['id']] = x
128+
cache_file_path = await self._process_cache(client,
129+
self._AVATAR_URL,
130+
'avatar.json',
131+
force_cache,
132+
force_update)
133+
with open(cache_file_path, 'rb') as f:
134+
for x in json.load(f):
135+
self._avatar_data[x['id']] = x
62136
if not self._skill_depot_data:
63-
resp = await client.get(self._SKILL_DEPOT_URL, proxy=self.proxy)
64-
for x in await resp.json(content_type=None):
65-
self._skill_depot_data[x['id']] = x
137+
cache_file_path = await self._process_cache(client,
138+
self._SKILL_DEPOT_URL,
139+
'skill_depot.json',
140+
force_cache,
141+
force_update)
142+
with open(cache_file_path, 'rb') as f:
143+
for x in json.load(f):
144+
self._skill_depot_data[x['id']] = x
66145
if not self._skill_data:
67-
resp = await client.get(self._SKILL_URL, proxy=self.proxy)
68-
for x in await resp.json(content_type=None):
69-
self._skill_data[x['id']] = x
146+
cache_file_path = await self._process_cache(client,
147+
self._SKILL_URL,
148+
'skill.json',
149+
force_cache,
150+
force_update)
151+
with open(cache_file_path, 'rb') as f:
152+
for x in json.load(f):
153+
self._skill_data[x['id']] = x
70154
if not self._talent_data:
71-
resp = await client.get(self._TALENT_URL, proxy=self.proxy)
72-
for x in await resp.json(content_type=None):
73-
self._talent_data[x['talentId']] = x
155+
cache_file_path = await self._process_cache(client,
156+
self._TALENT_URL,
157+
'talent.json',
158+
force_cache,
159+
force_update)
160+
with open(cache_file_path, 'rb') as f:
161+
for x in json.load(f):
162+
self._talent_data[x['talentId']] = x
74163

75164
async def resolve_text_hash(self, text_hash, lang='en'):
76165
"""
@@ -121,14 +210,15 @@ async def fetch_user(self, uid: int) -> EnkaData:
121210
for character in obj.characters:
122211
if character.skill_depot_id in self._skill_depot_data:
123212
depot = self._skill_depot_data[character.skill_depot_id]
124-
burst_id = depot['energySkill']
125-
if burst_id in self._skill_data:
126-
cs = CharacterSkill()
127-
cs.id = burst_id
128-
cs.type = CharacterSkillType.ElementalBurst
129-
cs.name_hash = self._skill_data[burst_id]['nameTextMapHash']
130-
cs.icon = self._skill_data[burst_id]['skillIcon']
131-
character.skills.append(cs)
213+
if 'energySkill' in depot:
214+
burst_id = depot['energySkill']
215+
if burst_id in self._skill_data:
216+
cs = CharacterSkill()
217+
cs.id = burst_id
218+
cs.type = CharacterSkillType.ElementalBurst
219+
cs.name_hash = self._skill_data[burst_id]['nameTextMapHash']
220+
cs.icon = self._skill_data[burst_id]['skillIcon']
221+
character.skills.append(cs)
132222
for skill_id in depot['skills']:
133223
if skill_id and skill_id in self._skill_data:
134224
skill_info = self._skill_data[skill_id]

enkapy/model/artifact.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def icon_url(self) -> str:
6363
"""
6464
:return: Artifact icon url from https://enka.shinshin.moe/ui/
6565
"""
66-
return f'https://enka.shinshin.moe/ui/{self.icon}.png'
66+
return f'https://enka.network/ui/{self.icon}.png'
6767

6868
@property
6969
def name(self):

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setuptools.setup(
44
name="enka.py",
5-
version="1.0.12",
5+
version="1.1.0",
66
author="pwnblog",
77
description="Library for fetching JSON data from site https://enka.network/",
88
long_description=open("README.md", "r", encoding="utf-8").read(),
@@ -15,6 +15,7 @@
1515
"License :: OSI Approved :: MIT License",
1616
"Operating System :: OS Independent",
1717
],
18+
zip_safe=False,
1819
install_requires=[
1920
"pydantic",
2021
"aiohttp",

0 commit comments

Comments
 (0)