ddapi 0.10.0__tar.gz → 0.12.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.
- {ddapi-0.10.0 → ddapi-0.12.0}/PKG-INFO +16 -19
- ddapi-0.12.0/README.md +45 -0
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi/__init__.py +3 -3
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi/api.py +47 -16
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi/main.py +28 -20
- ddapi-0.12.0/ddapi/ddapi/scheme/__init__.py +4 -0
- ddapi-0.12.0/ddapi/ddapi/scheme/base.py +21 -0
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi/scheme/ddnet.py +4 -18
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi/scheme/ddstats_tw.py +4 -20
- ddapi-0.12.0/ddapi/ddapi/scheme/status_tw.py +131 -0
- ddapi-0.12.0/ddapi/ddapi/types.py +3 -0
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi.egg-info/PKG-INFO +16 -19
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi.egg-info/SOURCES.txt +2 -0
- {ddapi-0.10.0 → ddapi-0.12.0}/setup.cfg +3 -3
- {ddapi-0.10.0 → ddapi-0.12.0}/setup.py +2 -6
- ddapi-0.10.0/README.md +0 -45
- ddapi-0.10.0/ddapi/ddapi/scheme/__init__.py +0 -3
- ddapi-0.10.0/ddapi/ddapi/scheme/status_tw.py +0 -131
- {ddapi-0.10.0 → ddapi-0.12.0}/LICENSE +0 -0
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi.egg-info/dependency_links.txt +0 -0
- {ddapi-0.10.0 → ddapi-0.12.0}/ddapi/ddapi.egg-info/top_level.txt +0 -0
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ddapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: DDnet api
|
|
5
5
|
Home-page: https://github.com/ByFox213/ddapi
|
|
6
6
|
Author: ByFox
|
|
7
|
-
License:
|
|
7
|
+
License: MIT
|
|
8
8
|
Project-URL: Github, https://github.com/ByFox213/ddapi
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
9
|
Requires-Python: >=3.8
|
|
13
10
|
Description-Content-Type: text/markdown
|
|
14
11
|
License-File: LICENSE
|
|
15
12
|
Dynamic: author
|
|
16
|
-
Dynamic: classifier
|
|
17
13
|
Dynamic: description
|
|
18
14
|
Dynamic: description-content-type
|
|
19
15
|
Dynamic: home-page
|
|
16
|
+
Dynamic: license
|
|
20
17
|
Dynamic: license-file
|
|
21
18
|
Dynamic: project-url
|
|
22
19
|
Dynamic: requires-python
|
|
@@ -42,28 +39,28 @@ DDnet
|
|
|
42
39
|
|
|
43
40
|
```python
|
|
44
41
|
import asyncio
|
|
42
|
+
|
|
45
43
|
from ddapi import DDnetApi, DDPlayer
|
|
46
44
|
|
|
47
45
|
|
|
48
46
|
async def main():
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
user
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
assert isinstance(user, DDPlayer)
|
|
47
|
+
async with DDnetApi() as obj:
|
|
48
|
+
user: DDPlayer = await obj.player("Cor")
|
|
49
|
+
if user is not None:
|
|
50
|
+
text = f"{user.player}: {user.points.points}/{user.points.total}"
|
|
51
|
+
percent = round(user.points.total / user.points.points * 100)
|
|
52
|
+
print(f"{text}({percent}%)")
|
|
53
|
+
# Cor: 32950/32950(100%)
|
|
54
|
+
else:
|
|
55
|
+
print("Player not found")
|
|
59
56
|
|
|
60
57
|
|
|
61
58
|
asyncio.run(main())
|
|
62
59
|
```
|
|
63
60
|
|
|
64
61
|
Tested on Python
|
|
65
|
-
| 3.
|
|
66
|
-
|
|
67
|
-
|
|
|
62
|
+
| 3.10 | 3.11 | 3.12 |
|
|
63
|
+
|------|------|------|
|
|
64
|
+
| ✅ | ✅ | ✅ |
|
|
68
65
|
|
|
69
66
|
[other examples](https://github.com/ByFox213/ddapi/tree/main/example)
|
ddapi-0.12.0/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
ddapi is an api from the ddnet and qwik website
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install ddapi
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
or
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install git+https://github.com/ByFox213/ddapi
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage/Examples
|
|
16
|
+
|
|
17
|
+
DDnet
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import asyncio
|
|
21
|
+
|
|
22
|
+
from ddapi import DDnetApi, DDPlayer
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def main():
|
|
26
|
+
async with DDnetApi() as obj:
|
|
27
|
+
user: DDPlayer = await obj.player("Cor")
|
|
28
|
+
if user is not None:
|
|
29
|
+
text = f"{user.player}: {user.points.points}/{user.points.total}"
|
|
30
|
+
percent = round(user.points.total / user.points.points * 100)
|
|
31
|
+
print(f"{text}({percent}%)")
|
|
32
|
+
# Cor: 32950/32950(100%)
|
|
33
|
+
else:
|
|
34
|
+
print("Player not found")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
asyncio.run(main())
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Tested on Python
|
|
41
|
+
| 3.10 | 3.11 | 3.12 |
|
|
42
|
+
|------|------|------|
|
|
43
|
+
| ✅ | ✅ | ✅ |
|
|
44
|
+
|
|
45
|
+
[other examples](https://github.com/ByFox213/ddapi/tree/main/example)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""the module is made for the convenience of users to download and use"""
|
|
2
2
|
from .main import DDnetApi, DDstats, Status
|
|
3
|
-
from .scheme import *
|
|
3
|
+
from .scheme import * # noqa: F403
|
|
4
4
|
|
|
5
|
-
__version__ = "0.
|
|
6
|
-
__author__ =
|
|
5
|
+
__version__ = "0.12.0"
|
|
6
|
+
__author__ = "ByFox"
|
|
7
7
|
__LICENSE__ = "MIT"
|
|
@@ -1,43 +1,66 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
from abc import ABC
|
|
2
|
-
from typing import Optional,
|
|
3
|
+
from typing import Optional, Type, Any
|
|
3
4
|
|
|
4
5
|
import aiohttp
|
|
5
|
-
from aiohttp import ClientSession
|
|
6
|
-
from aiohttp.typedefs import DEFAULT_JSON_DECODER
|
|
6
|
+
from aiohttp import ClientSession
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
from ddapi.types import T
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import orjson
|
|
12
|
+
|
|
13
|
+
DEFAULT_JSON_DECODER = orjson.loads
|
|
14
|
+
except ImportError:
|
|
15
|
+
from aiohttp.typedefs import DEFAULT_JSON_DECODER
|
|
9
16
|
|
|
10
17
|
|
|
11
18
|
class API(ABC):
|
|
12
19
|
def __init__(
|
|
13
20
|
self,
|
|
14
21
|
session: ClientSession = None,
|
|
22
|
+
autoclose: bool = True,
|
|
15
23
|
json_loads: Any = DEFAULT_JSON_DECODER
|
|
16
24
|
):
|
|
17
25
|
self.__session = session
|
|
18
26
|
self.json_loads = json_loads
|
|
27
|
+
self.autoclose = autoclose
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return None
|
|
29
|
+
if self.__session is None:
|
|
30
|
+
self.__session = aiohttp.ClientSession()
|
|
23
31
|
|
|
24
|
-
async def
|
|
25
|
-
"""Send a GET request to the given URL and return the response as JSON."""
|
|
32
|
+
async def __aenter__(self):
|
|
26
33
|
if self.__session is None:
|
|
27
34
|
self.__session = aiohttp.ClientSession()
|
|
35
|
+
return self
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
async def __aexit__(self, _exc_type, _exc_val, _exc_tb):
|
|
38
|
+
if self.autoclose:
|
|
39
|
+
await self.close()
|
|
40
|
+
|
|
41
|
+
def __del__(self):
|
|
42
|
+
if self.__session is not None and not self.__session.closed:
|
|
43
|
+
loop = asyncio.get_event_loop()
|
|
44
|
+
if loop.is_running():
|
|
45
|
+
loop.create_task(self.close())
|
|
46
|
+
else:
|
|
47
|
+
loop.run_until_complete(self.close())
|
|
48
|
+
|
|
49
|
+
async def _get(self, url: str) -> Optional[dict]:
|
|
50
|
+
"""Send a GET request to the given URL and return the response as JSON."""
|
|
51
|
+
async with self.__session.get(url) as req:
|
|
52
|
+
return (
|
|
53
|
+
await req.json(loads=self.json_loads)
|
|
54
|
+
if req.status == 200
|
|
55
|
+
else None
|
|
56
|
+
)
|
|
34
57
|
|
|
35
58
|
async def _generate_model_instance(
|
|
36
59
|
self,
|
|
37
60
|
url: str,
|
|
38
|
-
model: Type[
|
|
61
|
+
model: Type[T],
|
|
39
62
|
k: Optional[str] = None
|
|
40
|
-
) -> Optional[
|
|
63
|
+
) -> Optional[T]:
|
|
41
64
|
"""Generate a model instance from the given URL and optional keyword arguments.
|
|
42
65
|
|
|
43
66
|
Args:
|
|
@@ -64,3 +87,11 @@ class API(ABC):
|
|
|
64
87
|
if self.__session is not None:
|
|
65
88
|
await self.__session.close()
|
|
66
89
|
self.__session = None
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def domain(self) -> str:
|
|
93
|
+
return "ddnet.org"
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def powered() -> None:
|
|
97
|
+
return None
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
1
2
|
from urllib.parse import quote
|
|
2
3
|
|
|
3
4
|
from .api import API
|
|
4
|
-
from .scheme import
|
|
5
|
+
from .scheme import DDPlayer, DDStatus, ReleasesMaps, Query, QueryMap, QueryMapper, \
|
|
6
|
+
Master, DMap, DProfile, SMap, Maps, Player, Info, BannedMaster, List, ListData, \
|
|
7
|
+
ListPl, ListPlData, MasterTw, ServerTwOne, Charts, ChartEnum, Stats
|
|
5
8
|
|
|
6
9
|
__all__ = (
|
|
7
10
|
"MasterEnum",
|
|
@@ -12,16 +15,16 @@ __all__ = (
|
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class MasterEnum(StrEnum):
|
|
15
|
-
master1 = "
|
|
16
|
-
master2 = "
|
|
17
|
-
master3 = "
|
|
18
|
-
master4 = "
|
|
18
|
+
master1 = "1"
|
|
19
|
+
master2 = "2"
|
|
20
|
+
master3 = "3"
|
|
21
|
+
master4 = "4"
|
|
19
22
|
|
|
20
23
|
|
|
21
24
|
class DDnetApi(API):
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
@property
|
|
26
|
+
def domain(self) -> str:
|
|
27
|
+
return "ddnet.org"
|
|
25
28
|
|
|
26
29
|
@staticmethod
|
|
27
30
|
def powered() -> str:
|
|
@@ -58,19 +61,19 @@ class DDnetApi(API):
|
|
|
58
61
|
return await self._generate_model_instance(
|
|
59
62
|
f"https://{self.domain}/maps/?query={quote(map_name)}",
|
|
60
63
|
QueryMap,
|
|
61
|
-
|
|
64
|
+
"maps",
|
|
62
65
|
)
|
|
63
66
|
|
|
64
67
|
async def query_mapper(self, player: str) -> QueryMapper:
|
|
65
68
|
return await self._generate_model_instance(
|
|
66
69
|
f"https://{self.domain}/maps/?qmapper={quote(player)}",
|
|
67
70
|
QueryMapper,
|
|
68
|
-
|
|
71
|
+
"players",
|
|
69
72
|
)
|
|
70
73
|
|
|
71
|
-
async def master(self,
|
|
74
|
+
async def master(self, number: MasterEnum = MasterEnum.master1) -> Master:
|
|
72
75
|
return await self._generate_model_instance(
|
|
73
|
-
f"https://{
|
|
76
|
+
f"https://master{number}.{self.domain}/ddnet/15/servers.json",
|
|
74
77
|
Master
|
|
75
78
|
)
|
|
76
79
|
|
|
@@ -82,9 +85,9 @@ class DDnetApi(API):
|
|
|
82
85
|
|
|
83
86
|
|
|
84
87
|
class DDstats(API):
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
@property
|
|
89
|
+
def domain(self) -> str:
|
|
90
|
+
return "ddstats.tw"
|
|
88
91
|
|
|
89
92
|
@staticmethod
|
|
90
93
|
def powered() -> str:
|
|
@@ -99,7 +102,7 @@ class DDstats(API):
|
|
|
99
102
|
|
|
100
103
|
async def map(self, map_name: str) -> SMap:
|
|
101
104
|
return await self._generate_model_instance(
|
|
102
|
-
f"https://
|
|
105
|
+
f"https://{self.domain}/map/json?map={quote(map_name)}",
|
|
103
106
|
SMap
|
|
104
107
|
)
|
|
105
108
|
|
|
@@ -119,9 +122,9 @@ class DDstats(API):
|
|
|
119
122
|
|
|
120
123
|
|
|
121
124
|
class Status(API):
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
@property
|
|
126
|
+
def domain(self) -> str:
|
|
127
|
+
return "status.tw"
|
|
125
128
|
|
|
126
129
|
@staticmethod
|
|
127
130
|
def powered() -> str:
|
|
@@ -193,7 +196,12 @@ class Status(API):
|
|
|
193
196
|
ServerTwOne,
|
|
194
197
|
)
|
|
195
198
|
|
|
196
|
-
async def server_charts(
|
|
199
|
+
async def server_charts(
|
|
200
|
+
self,
|
|
201
|
+
ip: str,
|
|
202
|
+
port: int | str,
|
|
203
|
+
chart: ChartEnum = ChartEnum.day
|
|
204
|
+
) -> Charts:
|
|
197
205
|
return await self._generate_model_instance(
|
|
198
206
|
f"https://api.{self.domain}/server/{quote(ip)}/{port}/chart/{chart}",
|
|
199
207
|
Charts,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
from ddapi import DData
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DDType(BaseModel):
|
|
9
|
+
Novice: Optional[DData] = None
|
|
10
|
+
Moderate: Optional[DData] = None
|
|
11
|
+
Brutal: Optional[DData] = None
|
|
12
|
+
Insane: Optional[DData] = None
|
|
13
|
+
Dummy: Optional[DData] = None
|
|
14
|
+
DDmaX_Easy: Optional[DData] = Field(default=None, validation_alias="DDmaX.Easy")
|
|
15
|
+
DDmaX_Next: Optional[DData] = Field(default=None, validation_alias="DDmaX.Next")
|
|
16
|
+
DDmaX_Nut: Optional[DData] = Field(default=None, validation_alias="DDmaX.Nut")
|
|
17
|
+
DDmaX_Pro: Optional[DData] = Field(default=None, validation_alias="DDmaX.Pro")
|
|
18
|
+
Oldschool: Optional[DData] = Field(default=None)
|
|
19
|
+
Race: Optional[DData] = None
|
|
20
|
+
Solo: Optional[DData] = None
|
|
21
|
+
total: Optional[DData] = None
|
|
@@ -5,7 +5,9 @@ from typing import Optional, Any
|
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
from .base import DDType
|
|
9
|
+
|
|
10
|
+
rm_list = ["DD-Persian", "/vDQMHSss8W", ""]
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class DPoints(BaseModel):
|
|
@@ -94,22 +96,6 @@ class DData(BaseModel):
|
|
|
94
96
|
maps: Optional[dict] = Field(default=None)
|
|
95
97
|
|
|
96
98
|
|
|
97
|
-
class DDType(BaseModel):
|
|
98
|
-
Novice: Optional[DData] = None
|
|
99
|
-
Moderate: Optional[DData] = None
|
|
100
|
-
Brutal: Optional[DData] = None
|
|
101
|
-
Insane: Optional[DData] = None
|
|
102
|
-
Dummy: Optional[DData] = None
|
|
103
|
-
DDmaX_Easy: Optional[DData] = Field(default=None, validation_alias='DDmaX.Easy')
|
|
104
|
-
DDmaX_Next: Optional[DData] = Field(default=None, validation_alias='DDmaX.Next')
|
|
105
|
-
DDmaX_Nut: Optional[DData] = Field(default=None, validation_alias='DDmaX.Nut')
|
|
106
|
-
DDmaX_Pro: Optional[DData] = Field(default=None, validation_alias='DDmaX.Pro')
|
|
107
|
-
Oldschool: Optional[DData] = Field(default=None)
|
|
108
|
-
Race: Optional[DData] = None
|
|
109
|
-
Solo: Optional[DData] = None
|
|
110
|
-
total: Optional[DData] = None
|
|
111
|
-
|
|
112
|
-
|
|
113
99
|
class Activity(BaseModel):
|
|
114
100
|
date: str
|
|
115
101
|
hours_played: int
|
|
@@ -220,7 +206,7 @@ class Master(BaseModel):
|
|
|
220
206
|
client.clan
|
|
221
207
|
for server in self.servers
|
|
222
208
|
for client in server.info.clients
|
|
223
|
-
if client !=
|
|
209
|
+
if client != ""
|
|
224
210
|
)
|
|
225
211
|
|
|
226
212
|
for i in remove_list:
|
|
@@ -4,7 +4,7 @@ from typing import Optional
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
from .base import DDType
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class PData(BaseModel):
|
|
@@ -12,22 +12,6 @@ class PData(BaseModel):
|
|
|
12
12
|
points: int
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
class PPoints(BaseModel):
|
|
16
|
-
Novice: Optional[PData] = None
|
|
17
|
-
Moderate: Optional[PData] = None
|
|
18
|
-
Brutal: Optional[PData] = None
|
|
19
|
-
Insane: Optional[PData] = None
|
|
20
|
-
Dummy: Optional[PData] = None
|
|
21
|
-
DDmaX_Easy: Optional[PData] = Field(default=None, validation_alias='DDmaX.Easy')
|
|
22
|
-
DDmaX_Next: Optional[PData] = Field(default=None, validation_alias='DDmaX.Next')
|
|
23
|
-
DDmaX_Nut: Optional[PData] = Field(default=None, validation_alias='DDmaX.Nut')
|
|
24
|
-
DDmaX_Pro: Optional[PData] = Field(default=None, validation_alias='DDmaX.Pro')
|
|
25
|
-
Oldschool: Optional[PData] = None
|
|
26
|
-
Race: Optional[PData] = None
|
|
27
|
-
Solo: Optional[PData] = None
|
|
28
|
-
total: Optional[PData] = None
|
|
29
|
-
|
|
30
|
-
|
|
31
15
|
class PointG(BaseModel):
|
|
32
16
|
date: str
|
|
33
17
|
points: int
|
|
@@ -117,9 +101,9 @@ class Points(BaseModel):
|
|
|
117
101
|
weekly_points: Optional[PData] = None
|
|
118
102
|
monthly_points: Optional[PData] = None
|
|
119
103
|
yearly_points: Optional[PData] = None
|
|
120
|
-
points:
|
|
121
|
-
rank_points:
|
|
122
|
-
team_points:
|
|
104
|
+
points: DDType
|
|
105
|
+
rank_points: DDType
|
|
106
|
+
team_points: DDType
|
|
123
107
|
|
|
124
108
|
|
|
125
109
|
class RecentActivity(BaseModel):
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Status.tw
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ChartEnum(StrEnum):
|
|
10
|
+
day = "day"
|
|
11
|
+
week = "week"
|
|
12
|
+
month = "month"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DataTw(BaseModel):
|
|
16
|
+
name: str
|
|
17
|
+
created_at: datetime = Field(serialization_alias="createdAt")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class VersionTw(BaseModel):
|
|
21
|
+
version: str
|
|
22
|
+
created_at: datetime = Field(serialization_alias="createdAt")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class CountryTw(BaseModel):
|
|
26
|
+
identifier: str
|
|
27
|
+
code: int
|
|
28
|
+
icon_url: str = Field(serialization_alias="iconUrl")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ClientTw(BaseModel):
|
|
32
|
+
name: str
|
|
33
|
+
country: CountryTw
|
|
34
|
+
score: int
|
|
35
|
+
is_player: bool = Field(serialization_alias="isPlayer")
|
|
36
|
+
is_afk: bool = Field(serialization_alias="isAfk")
|
|
37
|
+
team: int
|
|
38
|
+
created_at: datetime = Field(serialization_alias="createdAt")
|
|
39
|
+
clan: DataTw | None
|
|
40
|
+
server: "ServerTw" = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ServerTw(BaseModel):
|
|
44
|
+
ip: str
|
|
45
|
+
port: int
|
|
46
|
+
name: str
|
|
47
|
+
num_clients: int = Field(serialization_alias="numClients")
|
|
48
|
+
num_players: int = Field(serialization_alias="numPlayers")
|
|
49
|
+
max_clients: int = Field(serialization_alias="maxClients")
|
|
50
|
+
max_players: int = Field(serialization_alias="maxPlayers")
|
|
51
|
+
has_password: bool = Field(serialization_alias="hasPassword")
|
|
52
|
+
supports6: bool
|
|
53
|
+
supports7: bool
|
|
54
|
+
created_at: datetime = Field(serialization_alias="createdAt")
|
|
55
|
+
relevance_score: int = Field(serialization_alias="relevanceScore")
|
|
56
|
+
client_score_kind: str | None = Field(serialization_alias="clientScoreKind")
|
|
57
|
+
logo_url: str = Field(serialization_alias="logoUrl")
|
|
58
|
+
map: DataTw
|
|
59
|
+
website: Optional[str] = None
|
|
60
|
+
discord_invite: Optional[str] = Field(None, serialization_alias="discordInvite")
|
|
61
|
+
description: Optional[str] = None
|
|
62
|
+
game_type: DataTw = Field(serialization_alias="gameType")
|
|
63
|
+
version: VersionTw
|
|
64
|
+
clients: list[ClientTw]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ServerTwOne(BaseModel):
|
|
68
|
+
ip: str
|
|
69
|
+
port: int
|
|
70
|
+
online: ServerTw
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Chart(BaseModel):
|
|
74
|
+
avg_players: float = Field(serialization_alias="avgPlayers")
|
|
75
|
+
max_players: int = Field(serialization_alias="maxPlayers")
|
|
76
|
+
min_players: int = Field(serialization_alias="minPlayers")
|
|
77
|
+
timestamp: datetime
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Charts(BaseModel):
|
|
81
|
+
charts: list[Chart]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class MasterTw(BaseModel):
|
|
85
|
+
servers: list[ServerTw]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class Info(BaseModel):
|
|
89
|
+
app: str
|
|
90
|
+
version: str
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class BannedMasterData(BaseModel):
|
|
94
|
+
ip: str
|
|
95
|
+
is_active: bool = Field(serialization_alias="isActive")
|
|
96
|
+
reason: str | None
|
|
97
|
+
unban_date: datetime | None = Field(serialization_alias="unbanDate")
|
|
98
|
+
created_at: datetime = Field(serialization_alias="createdAt")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class BannedMaster(BaseModel):
|
|
102
|
+
servers: list[BannedMasterData]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class ListData(BaseModel):
|
|
106
|
+
name: str
|
|
107
|
+
created_at: datetime = Field(serialization_alias="createdAt")
|
|
108
|
+
servers: list[ServerTw]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class List(BaseModel):
|
|
112
|
+
data: list[ListData]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ListPlData(BaseModel):
|
|
116
|
+
name: str
|
|
117
|
+
created_at: datetime = Field(serialization_alias="createdAt")
|
|
118
|
+
players: list[ClientTw]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class ListPl(BaseModel):
|
|
122
|
+
data: list[ListPlData]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class Stats(BaseModel):
|
|
126
|
+
num_players: int = Field(serialization_alias="numPlayers")
|
|
127
|
+
num_clans: int = Field(serialization_alias="numClans")
|
|
128
|
+
num_servers: int = Field(serialization_alias="numServers")
|
|
129
|
+
num_maps: int = Field(serialization_alias="numMaps")
|
|
130
|
+
num_game_types: int = Field(serialization_alias="numGameTypes")
|
|
131
|
+
num_versions: int = Field(serialization_alias="numVersions")
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ddapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: DDnet api
|
|
5
5
|
Home-page: https://github.com/ByFox213/ddapi
|
|
6
6
|
Author: ByFox
|
|
7
|
-
License:
|
|
7
|
+
License: MIT
|
|
8
8
|
Project-URL: Github, https://github.com/ByFox213/ddapi
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
9
|
Requires-Python: >=3.8
|
|
13
10
|
Description-Content-Type: text/markdown
|
|
14
11
|
License-File: LICENSE
|
|
15
12
|
Dynamic: author
|
|
16
|
-
Dynamic: classifier
|
|
17
13
|
Dynamic: description
|
|
18
14
|
Dynamic: description-content-type
|
|
19
15
|
Dynamic: home-page
|
|
16
|
+
Dynamic: license
|
|
20
17
|
Dynamic: license-file
|
|
21
18
|
Dynamic: project-url
|
|
22
19
|
Dynamic: requires-python
|
|
@@ -42,28 +39,28 @@ DDnet
|
|
|
42
39
|
|
|
43
40
|
```python
|
|
44
41
|
import asyncio
|
|
42
|
+
|
|
45
43
|
from ddapi import DDnetApi, DDPlayer
|
|
46
44
|
|
|
47
45
|
|
|
48
46
|
async def main():
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
user
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
assert isinstance(user, DDPlayer)
|
|
47
|
+
async with DDnetApi() as obj:
|
|
48
|
+
user: DDPlayer = await obj.player("Cor")
|
|
49
|
+
if user is not None:
|
|
50
|
+
text = f"{user.player}: {user.points.points}/{user.points.total}"
|
|
51
|
+
percent = round(user.points.total / user.points.points * 100)
|
|
52
|
+
print(f"{text}({percent}%)")
|
|
53
|
+
# Cor: 32950/32950(100%)
|
|
54
|
+
else:
|
|
55
|
+
print("Player not found")
|
|
59
56
|
|
|
60
57
|
|
|
61
58
|
asyncio.run(main())
|
|
62
59
|
```
|
|
63
60
|
|
|
64
61
|
Tested on Python
|
|
65
|
-
| 3.
|
|
66
|
-
|
|
67
|
-
|
|
|
62
|
+
| 3.10 | 3.11 | 3.12 |
|
|
63
|
+
|------|------|------|
|
|
64
|
+
| ✅ | ✅ | ✅ |
|
|
68
65
|
|
|
69
66
|
[other examples](https://github.com/ByFox213/ddapi/tree/main/example)
|
|
@@ -5,11 +5,13 @@ setup.py
|
|
|
5
5
|
ddapi/ddapi/__init__.py
|
|
6
6
|
ddapi/ddapi/api.py
|
|
7
7
|
ddapi/ddapi/main.py
|
|
8
|
+
ddapi/ddapi/types.py
|
|
8
9
|
ddapi/ddapi.egg-info/PKG-INFO
|
|
9
10
|
ddapi/ddapi.egg-info/SOURCES.txt
|
|
10
11
|
ddapi/ddapi.egg-info/dependency_links.txt
|
|
11
12
|
ddapi/ddapi.egg-info/top_level.txt
|
|
12
13
|
ddapi/ddapi/scheme/__init__.py
|
|
14
|
+
ddapi/ddapi/scheme/base.py
|
|
13
15
|
ddapi/ddapi/scheme/ddnet.py
|
|
14
16
|
ddapi/ddapi/scheme/ddstats_tw.py
|
|
15
17
|
ddapi/ddapi/scheme/status_tw.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = ddapi
|
|
3
|
-
version = 0.
|
|
3
|
+
version = 0.12.0
|
|
4
4
|
author = ByFox
|
|
5
5
|
description = DDnet api
|
|
6
6
|
long_description = file: README.md
|
|
@@ -8,13 +8,13 @@ long_description_content_type = text/markdown
|
|
|
8
8
|
url = https://github.com/ByFox213/ddapi
|
|
9
9
|
project_urls =
|
|
10
10
|
github = https://github.com/ByFox213/ddapi
|
|
11
|
-
|
|
11
|
+
license_files = LICENSE
|
|
12
12
|
|
|
13
13
|
[options]
|
|
14
14
|
package_dir =
|
|
15
15
|
= ddapi
|
|
16
16
|
packages = find:
|
|
17
|
-
python_requires = >=3.
|
|
17
|
+
python_requires = >=3.9
|
|
18
18
|
|
|
19
19
|
[options.packages.find]
|
|
20
20
|
where = ddapi
|
|
@@ -5,20 +5,16 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
5
5
|
|
|
6
6
|
setuptools.setup(
|
|
7
7
|
name="ddapi",
|
|
8
|
-
version="0.
|
|
8
|
+
version="0.12.0",
|
|
9
9
|
author="ByFox",
|
|
10
10
|
description="DDnet api",
|
|
11
11
|
long_description=long_description,
|
|
12
12
|
long_description_content_type="text/markdown",
|
|
13
13
|
url="https://github.com/ByFox213/ddapi",
|
|
14
|
+
license="MIT",
|
|
14
15
|
project_urls={
|
|
15
16
|
"Github": "https://github.com/ByFox213/ddapi"
|
|
16
17
|
},
|
|
17
|
-
classifiers=[
|
|
18
|
-
"Programming Language :: Python :: 3",
|
|
19
|
-
"License :: OSI Approved :: MIT License",
|
|
20
|
-
"Operating System :: OS Independent",
|
|
21
|
-
],
|
|
22
18
|
package_dir={"": "ddapi"},
|
|
23
19
|
packages=setuptools.find_packages(where="ddapi"),
|
|
24
20
|
python_requires=">=3.8"
|
ddapi-0.10.0/README.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
ddapi is an api from the ddnet and qwik website
|
|
2
|
-
|
|
3
|
-
## Installation
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
pip install ddapi
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
or
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
pip install git+https://github.com/ByFox213/ddapi
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Usage/Examples
|
|
16
|
-
|
|
17
|
-
DDnet
|
|
18
|
-
|
|
19
|
-
```python
|
|
20
|
-
import asyncio
|
|
21
|
-
from ddapi import DDnetApi, DDPlayer
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
async def main():
|
|
25
|
-
obj = DDnetApi()
|
|
26
|
-
nickname = "Cor"
|
|
27
|
-
user: DDPlayer = await obj.player(nickname)
|
|
28
|
-
if user is None:
|
|
29
|
-
return "Player not found"
|
|
30
|
-
|
|
31
|
-
print(f"{user.player}: {user.points.points}")
|
|
32
|
-
# Cor: 31473
|
|
33
|
-
await obj.close() # Closing client Not necessary
|
|
34
|
-
assert isinstance(user, DDPlayer)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
asyncio.run(main())
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Tested on Python
|
|
41
|
-
| 3.9 | 3.10 | 3.11 | 3.12 |
|
|
42
|
-
|-----|------|------|------|
|
|
43
|
-
| ? | ? | ✅ | ✅ |
|
|
44
|
-
|
|
45
|
-
[other examples](https://github.com/ByFox213/ddapi/tree/main/example)
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
# Status.tw
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from enum import StrEnum
|
|
4
|
-
from typing import Optional
|
|
5
|
-
|
|
6
|
-
from pydantic import BaseModel
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class ChartEnum(StrEnum):
|
|
10
|
-
day = "day"
|
|
11
|
-
week = "week"
|
|
12
|
-
month = "month"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class DataTw(BaseModel):
|
|
16
|
-
name: str
|
|
17
|
-
createdAt: datetime
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class VersionTw(BaseModel):
|
|
21
|
-
version: str
|
|
22
|
-
createdAt: datetime
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class CountryTw(BaseModel):
|
|
26
|
-
identifier: str
|
|
27
|
-
code: int
|
|
28
|
-
iconUrl: str
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class ClientTw(BaseModel):
|
|
32
|
-
name: str
|
|
33
|
-
country: CountryTw
|
|
34
|
-
score: int
|
|
35
|
-
isPlayer: bool
|
|
36
|
-
isAfk: bool
|
|
37
|
-
team: int
|
|
38
|
-
createdAt: datetime
|
|
39
|
-
clan: DataTw | None
|
|
40
|
-
server: "ServerTw" = None
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class ServerTw(BaseModel):
|
|
44
|
-
ip: str
|
|
45
|
-
port: int
|
|
46
|
-
name: str
|
|
47
|
-
numClients: int
|
|
48
|
-
numPlayers: int
|
|
49
|
-
maxClients: int
|
|
50
|
-
maxPlayers: int
|
|
51
|
-
hasPassword: bool
|
|
52
|
-
supports6: bool
|
|
53
|
-
supports7: bool
|
|
54
|
-
createdAt: datetime
|
|
55
|
-
relevanceScore: int
|
|
56
|
-
clientScoreKind: str | None
|
|
57
|
-
logoUrl: str
|
|
58
|
-
map: DataTw
|
|
59
|
-
website: Optional[str] = None
|
|
60
|
-
discordInvite: Optional[str] = None
|
|
61
|
-
description: Optional[str] = None
|
|
62
|
-
gameType: DataTw
|
|
63
|
-
version: VersionTw
|
|
64
|
-
clients: list[ClientTw]
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class ServerTwOne(BaseModel):
|
|
68
|
-
ip: str
|
|
69
|
-
port: int
|
|
70
|
-
online: ServerTw
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class Chart(BaseModel):
|
|
74
|
-
avgPlayers: float
|
|
75
|
-
maxPlayers: int
|
|
76
|
-
minPlayers: int
|
|
77
|
-
timestamp: datetime
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
class Charts(BaseModel):
|
|
81
|
-
charts: list[Chart]
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
class MasterTw(BaseModel):
|
|
85
|
-
servers: list[ServerTw]
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
class Info(BaseModel):
|
|
89
|
-
app: str
|
|
90
|
-
version: str
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
class BannedMasterData(BaseModel):
|
|
94
|
-
ip: str
|
|
95
|
-
isActive: bool
|
|
96
|
-
reason: str | None
|
|
97
|
-
unbanDate: datetime | None
|
|
98
|
-
createdAt: datetime
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class BannedMaster(BaseModel):
|
|
102
|
-
servers: list[BannedMasterData]
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
class ListData(BaseModel):
|
|
106
|
-
name: str
|
|
107
|
-
createdAt: datetime
|
|
108
|
-
servers: list[ServerTw]
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
class List(BaseModel):
|
|
112
|
-
data: list[ListData]
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
class ListPlData(BaseModel):
|
|
116
|
-
name: str
|
|
117
|
-
createdAt: datetime
|
|
118
|
-
players: list[ClientTw]
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
class ListPl(BaseModel):
|
|
122
|
-
data: list[ListPlData]
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class Stats(BaseModel):
|
|
126
|
-
numPlayers: int
|
|
127
|
-
numClans: int
|
|
128
|
-
numServers: int
|
|
129
|
-
numMaps: int
|
|
130
|
-
numGameTypes: int
|
|
131
|
-
numVersions: int
|
|
File without changes
|
|
File without changes
|
|
File without changes
|