vprikol 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vprikol-0.1.0/PKG-INFO +16 -0
- vprikol-0.1.0/README.md +0 -0
- vprikol-0.1.0/pyproject.toml +17 -0
- vprikol-0.1.0/vprikol/__init__.py +3 -0
- vprikol-0.1.0/vprikol/api.py +32 -0
- vprikol-0.1.0/vprikol/main.py +161 -0
- vprikol-0.1.0/vprikol/model.py +206 -0
vprikol-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: vprikol
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary:
|
|
5
|
+
Author: evans
|
|
6
|
+
Author-email: szx@bk.ru
|
|
7
|
+
Requires-Python: >=3.10,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Requires-Dist: aiohttp (>=3.9.5,<4.0.0)
|
|
13
|
+
Requires-Dist: pydantic (>=2.7.4,<3.0.0)
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
|
vprikol-0.1.0/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "vprikol"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = ""
|
|
5
|
+
authors = ["evans <szx@bk.ru>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
packages = [{include = "vprikol"}]
|
|
8
|
+
|
|
9
|
+
[tool.poetry.dependencies]
|
|
10
|
+
python = "^3.10"
|
|
11
|
+
pydantic = "^2.7.4"
|
|
12
|
+
aiohttp = "^3.9.5"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
[build-system]
|
|
16
|
+
requires = ["poetry-core"]
|
|
17
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import Optional, Dict
|
|
2
|
+
|
|
3
|
+
import aiohttp
|
|
4
|
+
|
|
5
|
+
from .model import Response
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def get_json(url: str, params: Optional[Dict] = None, headers: Optional[Dict] = None) -> Response:
|
|
9
|
+
async with aiohttp.ClientSession(headers=headers) as session:
|
|
10
|
+
async with session.get(url, params=params) as response:
|
|
11
|
+
response_json = await response.json()
|
|
12
|
+
if response.ok:
|
|
13
|
+
return Response(data=response_json)
|
|
14
|
+
return Response(error=response_json, success=False)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def post_json(url: str, params: Optional[Dict] = None, headers: Optional[Dict] = None) -> Response:
|
|
18
|
+
async with aiohttp.ClientSession(headers=headers) as session:
|
|
19
|
+
async with session.post(url, params=params) as response:
|
|
20
|
+
response_json = await response.json()
|
|
21
|
+
if response.ok:
|
|
22
|
+
return Response(data=response_json)
|
|
23
|
+
return Response(error=response_json, success=False)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def get_bytes(url: str, params: Optional[Dict] = None, headers: Optional[Dict] = None) -> Response:
|
|
27
|
+
async with aiohttp.ClientSession(headers=headers) as session:
|
|
28
|
+
async with session.get(url, params=params) as response:
|
|
29
|
+
response_data = await response.read()
|
|
30
|
+
if response.status == 200:
|
|
31
|
+
return Response(data=response_data)
|
|
32
|
+
return Response(error=(await response.json()), success=False)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import time
|
|
3
|
+
from typing import List, Literal, Optional, Union, Dict
|
|
4
|
+
|
|
5
|
+
from pydantic import parse_obj_as, ValidationError
|
|
6
|
+
|
|
7
|
+
from .api import get_json, post_json, get_bytes
|
|
8
|
+
from .model import (IpAPIResponse, MembersAPIResponse, PlayerInfoAPIResponse, CreatedFindTaskAPIResponse,
|
|
9
|
+
ServerStatusAPIResponse, RatingAPIResponse, CheckRPUsernameAPIResponse, GenerateRPUsernameAPIResponse,
|
|
10
|
+
PlayerInfoNotFound, PlayerOnlineAPIResponse, GhettoZonesAPIResponse, PlayerEstateAPIResponse, PlayersAPIResponse)
|
|
11
|
+
|
|
12
|
+
Gender = Literal['male', 'female']
|
|
13
|
+
Nation = Literal['russian', 'american', 'german', 'french', 'italian', 'japanese', 'latinos', 'swedish', 'danish', 'romanian']
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class VprikolAPI:
|
|
17
|
+
def __init__(self, token: str, base_url: str = 'https://api.szx.su/'):
|
|
18
|
+
if not token.startswith('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.'):
|
|
19
|
+
raise Exception('Токен передан неправильно.')
|
|
20
|
+
self.headers = {'Authorization': f'Bearer {token}'}
|
|
21
|
+
self.base_url = base_url
|
|
22
|
+
|
|
23
|
+
async def get_ip_info(self, ip: str) -> IpAPIResponse:
|
|
24
|
+
result = await get_json(url=f'{self.base_url}ip', headers=self.headers, params={'ip': ip})
|
|
25
|
+
|
|
26
|
+
if not result.success:
|
|
27
|
+
raise Exception(result.error)
|
|
28
|
+
|
|
29
|
+
return IpAPIResponse(**result.data)
|
|
30
|
+
|
|
31
|
+
async def get_members(self, server_id: int, fraction_id: Union[int, List[int]]) -> Dict[str, MembersAPIResponse]:
|
|
32
|
+
result = await get_json(url=f'{self.base_url}members', headers=self.headers, params={'server_id': server_id, 'fraction_id': fraction_id})
|
|
33
|
+
|
|
34
|
+
if not result.success:
|
|
35
|
+
raise Exception(result.error)
|
|
36
|
+
|
|
37
|
+
response = {}
|
|
38
|
+
for fraction_id in result.data:
|
|
39
|
+
players = []
|
|
40
|
+
if not fraction_id.isdigit():
|
|
41
|
+
continue
|
|
42
|
+
for player in result.data[fraction_id]['players']:
|
|
43
|
+
players.append({'username': player, 'id': result.data[fraction_id]['players'][player]['id'],
|
|
44
|
+
'isOnline': result.data[fraction_id]['players'][player]['isOnline'],
|
|
45
|
+
'isLeader': result.data[fraction_id]['players'][player]['isLeader'],
|
|
46
|
+
'rank': result.data[fraction_id]['players'][player]['rank'],
|
|
47
|
+
'rankLabel': result.data[fraction_id]['players'][player]['rankLabel'],
|
|
48
|
+
'ingameId': result.data[fraction_id]['players'][player]['ingameId'],
|
|
49
|
+
'lvl': result.data[fraction_id]['players'][player]['lvl'],
|
|
50
|
+
'ping': result.data[fraction_id]['players'][player]['ping'],
|
|
51
|
+
'color': result.data[fraction_id]['players'][player]['color']
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
result.data[fraction_id]['players'] = players
|
|
55
|
+
response[fraction_id] = MembersAPIResponse(
|
|
56
|
+
**result.data[fraction_id]
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return response
|
|
60
|
+
|
|
61
|
+
async def get_player_information(self, server_id: int, nickname: str) -> Union[PlayerInfoAPIResponse, PlayerInfoNotFound]:
|
|
62
|
+
task = await post_json(url=f'{self.base_url}find/createTask', headers=self.headers, params={'server': server_id, 'nick': nickname})
|
|
63
|
+
|
|
64
|
+
if not task.success:
|
|
65
|
+
raise Exception(task.error)
|
|
66
|
+
|
|
67
|
+
task = CreatedFindTaskAPIResponse(**task.data)
|
|
68
|
+
while True:
|
|
69
|
+
result = await get_json(url=f'{self.base_url}find/getTaskResult', headers=self.headers, params={'request_id': task.request_id})
|
|
70
|
+
|
|
71
|
+
if not result.success and result.error.error_code and result.error.error_code == 425:
|
|
72
|
+
await asyncio.sleep(0.5)
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
if result.error and result.error.error_code == 422:
|
|
76
|
+
return PlayerInfoNotFound(**result.error.dict())
|
|
77
|
+
|
|
78
|
+
if result.error and result.error.error_code in [500, 502, 503]:
|
|
79
|
+
raise Exception(result.error.detail)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
return PlayerInfoAPIResponse(**result.data)
|
|
83
|
+
except ValidationError:
|
|
84
|
+
return PlayerInfoAPIResponse(**result.data)
|
|
85
|
+
|
|
86
|
+
async def get_server_status(self, server_id: Optional[int] = None) -> Union[List[ServerStatusAPIResponse], ServerStatusAPIResponse]:
|
|
87
|
+
params = {'server': server_id} if server_id else None
|
|
88
|
+
|
|
89
|
+
result = await get_json(url=f'{self.base_url}status', headers=self.headers, params=params)
|
|
90
|
+
|
|
91
|
+
if not result.success:
|
|
92
|
+
raise Exception(result.error)
|
|
93
|
+
|
|
94
|
+
if isinstance(result.data, list):
|
|
95
|
+
return parse_obj_as(List[ServerStatusAPIResponse], result.data)
|
|
96
|
+
|
|
97
|
+
return ServerStatusAPIResponse(**result.data)
|
|
98
|
+
|
|
99
|
+
async def get_rating(self, server_id: int, rating_type: Literal[1, 2, 3]) -> RatingAPIResponse:
|
|
100
|
+
result = await get_json(url=f'{self.base_url}rating', headers=self.headers, params={'type': rating_type, 'server': server_id})
|
|
101
|
+
|
|
102
|
+
if not result.success:
|
|
103
|
+
raise Exception(result.error)
|
|
104
|
+
|
|
105
|
+
return RatingAPIResponse(**result.data)
|
|
106
|
+
|
|
107
|
+
async def check_rp_nickname(self, nickname: str, ai: bool = False) -> CheckRPUsernameAPIResponse:
|
|
108
|
+
result = await get_json(url=f'{self.base_url}checkrp', headers=self.headers, params={'nick': nickname, 'ai': int(ai)})
|
|
109
|
+
|
|
110
|
+
if not result.success:
|
|
111
|
+
raise Exception(result.error)
|
|
112
|
+
|
|
113
|
+
return CheckRPUsernameAPIResponse(**result.data)
|
|
114
|
+
|
|
115
|
+
async def generate_rp_nickname(self, gender: Gender, nation: Nation) -> GenerateRPUsernameAPIResponse:
|
|
116
|
+
result = await get_json(url=f'{self.base_url}rpnick', headers=self.headers, params={'gender': gender, 'nation': nation})
|
|
117
|
+
|
|
118
|
+
if not result.success:
|
|
119
|
+
raise Exception(result.error)
|
|
120
|
+
|
|
121
|
+
return GenerateRPUsernameAPIResponse(**result.data)
|
|
122
|
+
|
|
123
|
+
async def get_player_online(self, nickname: str, server_id: int, count: int = 100, offset: int = 0, date: int = int(time.time())) -> PlayerOnlineAPIResponse:
|
|
124
|
+
result = await get_json(url=f'{self.base_url}online', headers=self.headers, params={'nickname': nickname, 'count': count, 'offset': offset, 'server_id': server_id, 'filter_by_date': date})
|
|
125
|
+
|
|
126
|
+
if not result.success:
|
|
127
|
+
raise Exception(result.error)
|
|
128
|
+
|
|
129
|
+
return PlayerOnlineAPIResponse(**result.data)
|
|
130
|
+
|
|
131
|
+
async def get_ghetto_map(self, server_id: int) -> bytes:
|
|
132
|
+
result = await get_bytes(url=f'{self.base_url}ghetto/map', headers=self.headers, params={'server_id': server_id})
|
|
133
|
+
|
|
134
|
+
if not result.success:
|
|
135
|
+
raise Exception(result.error)
|
|
136
|
+
|
|
137
|
+
return result.data
|
|
138
|
+
|
|
139
|
+
async def get_ghetto_zones(self, server_id: int) -> GhettoZonesAPIResponse:
|
|
140
|
+
result = await get_json(url=f'{self.base_url}ghetto/zones', headers=self.headers, params={'server_id': server_id})
|
|
141
|
+
|
|
142
|
+
if not result.success:
|
|
143
|
+
raise Exception(result.error)
|
|
144
|
+
|
|
145
|
+
return GhettoZonesAPIResponse(**result.data)
|
|
146
|
+
|
|
147
|
+
async def get_estate(self, nickname: str, server_id: int) -> PlayerEstateAPIResponse:
|
|
148
|
+
result = await get_json(url=f'{self.base_url}estate', headers=self.headers, params={'server_id': server_id, 'nickname': nickname})
|
|
149
|
+
|
|
150
|
+
if not result.success:
|
|
151
|
+
raise Exception(result.error)
|
|
152
|
+
|
|
153
|
+
return PlayerEstateAPIResponse(**result.data)
|
|
154
|
+
|
|
155
|
+
async def get_players(self, server_id: int, nicknames: Optional[List[Union[str, int]]] = None) -> PlayersAPIResponse:
|
|
156
|
+
result = await get_json(url=f'{self.base_url}players?nicknames={nicknames}', headers=self.headers, params={'server_id': server_id})
|
|
157
|
+
|
|
158
|
+
if not result.success:
|
|
159
|
+
raise Exception(result.error)
|
|
160
|
+
|
|
161
|
+
return PlayersAPIResponse(**result.data)
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
from typing import TypeVar, List, Optional, Dict, Generic, Union
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
DataT = TypeVar('DataT')
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FastAPIErrorDetail(BaseModel):
|
|
9
|
+
loc: List[str]
|
|
10
|
+
message: str = Field(alias='msg')
|
|
11
|
+
type: str
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FastApiErrorResponse(BaseModel):
|
|
15
|
+
detail: Union[list[FastAPIErrorDetail] , str]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class APIErrorResponse(BaseModel):
|
|
19
|
+
error_code: int
|
|
20
|
+
detail: str
|
|
21
|
+
queue_position: Optional[int] = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Response(BaseModel, Generic[DataT]):
|
|
25
|
+
data: Optional[DataT] = None
|
|
26
|
+
error: Optional[Union[FastApiErrorResponse, APIErrorResponse]] = None
|
|
27
|
+
success: bool = True
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MembersAPIPlayer(BaseModel):
|
|
31
|
+
username: str
|
|
32
|
+
id: Optional[int] = None
|
|
33
|
+
is_online: bool = Field(alias='isOnline')
|
|
34
|
+
is_leader: bool = Field(alias='isLeader')
|
|
35
|
+
rank: int
|
|
36
|
+
rank_label: Optional[str] = Field(None, alias='rankLabel')
|
|
37
|
+
ingame_id: Optional[int] = Field(None, alias='ingameId')
|
|
38
|
+
ping: Optional[int]
|
|
39
|
+
lvl: Optional[int]
|
|
40
|
+
color: Optional[int]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class MembersAPIRecord(BaseModel):
|
|
44
|
+
count: int
|
|
45
|
+
date: str
|
|
46
|
+
leader: str
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class MembersAPIResponse(BaseModel):
|
|
50
|
+
server_label: str = Field(alias='serverName')
|
|
51
|
+
fraction_label: str = Field(alias='fractionLabel')
|
|
52
|
+
players: List[MembersAPIPlayer]
|
|
53
|
+
record: MembersAPIRecord
|
|
54
|
+
total_players: int = Field(alias='totalPlayers')
|
|
55
|
+
total_online: int = Field(alias='totalOnline')
|
|
56
|
+
leader_nickname: Optional[str] = Field(None, alias='leaderNick')
|
|
57
|
+
is_leader_online: bool = Field(alias='isLeaderOnline')
|
|
58
|
+
online_updated_at: int = Field(alias='onlineUpdatedAt')
|
|
59
|
+
members_updated_at: int = Field(alias='membersUpdatedAt')
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ServerStatusAPIResponse(BaseModel):
|
|
63
|
+
server_number: int = Field(alias='number')
|
|
64
|
+
ip: str
|
|
65
|
+
port: int
|
|
66
|
+
online_players: int = Field(alias='onlinePlayers')
|
|
67
|
+
max_players: int = Field(alias='maxPlayers')
|
|
68
|
+
is_closed: bool = Field(alias='isClosed')
|
|
69
|
+
server_label: str = Field(alias='serverLabel')
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class CreatedFindTaskAPIResponse(BaseModel):
|
|
73
|
+
request_id: str
|
|
74
|
+
request_time: int
|
|
75
|
+
queue_position: int
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class PlayerInfoAPIResponse(BaseModel):
|
|
79
|
+
account_id: Optional[int] = Field(None, alias='accountId')
|
|
80
|
+
player_id: Optional[int] = Field(None, alias='playerId')
|
|
81
|
+
lvl: Optional[int] = None
|
|
82
|
+
cash: Optional[int] = None
|
|
83
|
+
bank: Optional[int] = None
|
|
84
|
+
individual_account: Optional[int] = Field(None, alias='individualAccount')
|
|
85
|
+
deposit: Optional[int] = None
|
|
86
|
+
total_money: Optional[int] = Field(None, alias='totalMoney')
|
|
87
|
+
is_online: bool = Field(False, alias='isOnline')
|
|
88
|
+
job_label: Optional[str] = Field(None, alias='jobLabel')
|
|
89
|
+
job_id: Optional[int] = Field(None, alias='jobId')
|
|
90
|
+
rank_number: Optional[int] = Field(None, alias='rankNumber')
|
|
91
|
+
rank_label: Optional[str] = Field(None, alias='rankLabel')
|
|
92
|
+
is_leader: bool = Field(False, alias='isLeader')
|
|
93
|
+
org_label: str = Field('', alias='orgLabel')
|
|
94
|
+
org_id: int = Field(0, alias='orgId')
|
|
95
|
+
vip_lvl: Optional[int] = Field(None, alias='vipLvl')
|
|
96
|
+
vip_label: Optional[str] = Field(None, alias='vipLabel')
|
|
97
|
+
phone_number: Optional[int] = Field(None, alias='phoneNumber')
|
|
98
|
+
updated_at: int = Field(0, alias='updatedAt')
|
|
99
|
+
player_nick: str = Field('', alias='playerNick')
|
|
100
|
+
player_server: int = Field(0, alias='playerServer')
|
|
101
|
+
server_name: str = Field('', alias='serverName')
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class PlayerInfoNotFound(APIErrorResponse):
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class RatingPlayerInfo(BaseModel):
|
|
109
|
+
number: int
|
|
110
|
+
name: str
|
|
111
|
+
is_online: bool = Field('isOnline')
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class RatingAPIResponse(BaseModel):
|
|
115
|
+
server: str
|
|
116
|
+
players: List[RatingPlayerInfo]
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class IpAPIResponse(BaseModel):
|
|
120
|
+
ip: str
|
|
121
|
+
country: str
|
|
122
|
+
city: str
|
|
123
|
+
timezone: str
|
|
124
|
+
isp: str
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class CheckRPUsernameName(BaseModel):
|
|
128
|
+
rp: bool
|
|
129
|
+
graph: Optional[str] = None
|
|
130
|
+
gpt_answer: Optional[str] = None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class CheckRPUsernameAPIResponse(BaseModel):
|
|
134
|
+
name: CheckRPUsernameName
|
|
135
|
+
surname: CheckRPUsernameName
|
|
136
|
+
nickname: str = Field(alias='nick')
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class GhettoZonesData(BaseModel):
|
|
140
|
+
grove: int = Field(alias='2569507584')
|
|
141
|
+
ballas: int = Field(alias='2580283596')
|
|
142
|
+
vagos: int = Field(alias='2568805329')
|
|
143
|
+
rifa: int = Field(alias='2583651942')
|
|
144
|
+
aztec: int = Field(alias='2581790464')
|
|
145
|
+
nw: int = Field(alias='2155378856')
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class GhettoZonesAPIResponse(BaseModel):
|
|
149
|
+
data: GhettoZonesData
|
|
150
|
+
server_name: str = Field(alias='serverName')
|
|
151
|
+
updated_at: int = Field(alias='updatedAt')
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class AuctionInfo(BaseModel):
|
|
155
|
+
active: bool
|
|
156
|
+
minimal_bet: int = Field("minimalBet")
|
|
157
|
+
time_end: int = Field(alias='timeEnd')
|
|
158
|
+
start_price: int = Field(alias='startPrice')
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class Coordinates(BaseModel):
|
|
162
|
+
x: float
|
|
163
|
+
y: float
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class EstateItem(BaseModel):
|
|
167
|
+
id: int
|
|
168
|
+
name: Optional[str]
|
|
169
|
+
owner: Optional[str]
|
|
170
|
+
auction: AuctionInfo
|
|
171
|
+
coordinates: Coordinates
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class PlayerEstateAPIResponse(BaseModel):
|
|
175
|
+
server_id: int = Field(alias='serverId')
|
|
176
|
+
server_label: str = Field(alias='serverLabel')
|
|
177
|
+
nickname: str = Field(alias='nickname')
|
|
178
|
+
houses: List[EstateItem]
|
|
179
|
+
businesses: List[EstateItem]
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class GenerateRPUsernameAPIResponse(BaseModel):
|
|
183
|
+
name: str
|
|
184
|
+
surname: str
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class OnlinePlayerInfo(BaseModel):
|
|
188
|
+
login_at: int
|
|
189
|
+
logout_at: int
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class PlayerOnlineAPIResponse(BaseModel):
|
|
193
|
+
sessions: List[OnlinePlayerInfo]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class PlayerData(BaseModel):
|
|
197
|
+
ingame_id: Optional[int] = Field(None, alias='ingameId')
|
|
198
|
+
lvl: Optional[int] = None
|
|
199
|
+
ping: Optional[int] = None
|
|
200
|
+
color: Optional[int] = None
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class PlayersAPIResponse(BaseModel):
|
|
204
|
+
server_name: str = Field(alias='serverName')
|
|
205
|
+
updated_at: int = Field(alias='updatedAt')
|
|
206
|
+
data: Dict[str, Optional[PlayerData]]
|