ddapi 0.5.1__tar.gz → 0.6.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ddapi
3
- Version: 0.5.1
3
+ Version: 0.6.0
4
4
  Summary: DDnet api
5
5
  Home-page: https://github.com/ByFox213/ddapi
6
6
  Author: ByFox
@@ -1,7 +1,7 @@
1
1
  """the module is made for the convenience of users to download and use"""
2
- from .main import DDnetApi, DDstats, StatusAPI, utc_times, DDStatsDB
2
+ from .main import DDnetApi, DDstats, DDStatsDB
3
3
  from .dataclass import *
4
4
 
5
- __version__ = "0.5.1"
5
+ __version__ = "0.6.0"
6
6
  __author__ = 'ByFox'
7
7
  __LICENSE__ = "MIT"
@@ -6,6 +6,7 @@ from pydantic import BaseModel, Field
6
6
 
7
7
  rm_list = ["DD-Persian", "/vDQMHSss8W"]
8
8
 
9
+
9
10
  # DDStats
10
11
 
11
12
 
@@ -407,29 +408,26 @@ class Master(BaseModel):
407
408
  yield i.info.clients
408
409
 
409
410
  def get_clans(self, limit: int = 50, rm: list[str] = None) -> list[tuple[Any, int]]:
410
- if rm is None:
411
- rm = []
412
- rm.extend(rm_list)
411
+ remove_list = [] if rm is None else rm
412
+ remove_list.extend(["DD-Persian", ''])
413
413
  if not self.servers:
414
414
  return []
415
- dat = Counter(client.clan
416
- for server in self.servers
417
- for client in server.info.clients
418
- if server.info is not None
419
- and server.info.clients is not None
420
- and client != '')
421
- for i in rm:
415
+ dat: Counter[Any] = Counter(client.clan
416
+ for server in self.servers
417
+ for client in server.info.clients
418
+ if server.info is not None
419
+ and server.info.clients is not None
420
+ and client != '')
421
+ for i in remove_list:
422
422
  del dat[i]
423
423
  return sorted(dat.items(), key=lambda x: x[1], reverse=True)[:limit]
424
424
 
425
- def get_count_servers(self, limit: int = 10) -> list[tuple[int, list | Any, str | None, str | None]]:
426
- dat = []
427
- for i in self.servers:
428
- add = i.addresses
429
- if isinstance(i.addresses, list):
430
- add = i.addresses[0]
431
- dat.append((i.get_count_client(), add, i.info.game_type, i.info.name))
432
- return sorted(dat, key=lambda x: x[0], reverse=True)[:limit]
425
+ def get_count_servers(self, limit: int = 10) -> list:
426
+ return sorted((
427
+ (i.get_count_client(), i.addresses[0], i.info.game_type, i.info.name)
428
+ if isinstance(i.addresses, list)
429
+ else (i.get_count_client(), i.addresses, i.info.game_type, i.info.name)
430
+ for i in self.servers), key=lambda x: x[0], reverse=True)[:limit]
433
431
 
434
432
 
435
433
  class QueryData(BaseModel):
@@ -0,0 +1,84 @@
1
+ import asyncio
2
+ from abc import ABC
3
+ from json import JSONDecoder
4
+ from typing import Union, Any
5
+ from urllib.parse import quote
6
+
7
+ import aiohttp
8
+ from aiohttp import ClientSession, ClientConnectorError
9
+ from aiohttp.typedefs import DEFAULT_JSON_DECODER
10
+
11
+ from .dataclass import Player
12
+
13
+
14
+ class API(ABC):
15
+ def __init__(self,
16
+ session: ClientSession = None,
17
+ json_loads: JSONDecoder = DEFAULT_JSON_DECODER,
18
+ emojis: dict[str, str] = None):
19
+ self.emojis = emojis
20
+ if emojis is None:
21
+ self.emojis = {"fox": "🦊"}
22
+ self.session = session
23
+ self.json_loads = json_loads
24
+ self.url = "https://ddstats.qwik.space/player/json?player={0}"
25
+
26
+ @staticmethod
27
+ def powered() -> str:
28
+ """Return an empty string."""
29
+ return ''
30
+
31
+ async def _get_emoji(self, player_name: str) -> str:
32
+ """Return an emoji for the given player name."""
33
+ for name, emoji in self.emojis.items():
34
+ if name in player_name.lower():
35
+ return emoji
36
+ return ''
37
+
38
+ async def _send(self, url: str) -> Union[dict, None]:
39
+ """Send a GET request to the given URL and return the response as JSON."""
40
+ if self.session is None:
41
+ self.session = aiohttp.ClientSession()
42
+ try:
43
+ async with self.session.get(url) as req:
44
+ if req.status == 200:
45
+ return await req.json(loads=self.json_loads)
46
+ return
47
+ except ClientConnectorError:
48
+ return
49
+
50
+ async def _generate(
51
+ self,
52
+ url: str,
53
+ model,
54
+ k: str = None,
55
+ emoji: str = None
56
+ ) -> Union[Any, None]:
57
+ """Generate a model instance from the given URL and optional keyword arguments."""
58
+ dat = await self._send(url)
59
+ if dat is None:
60
+ return
61
+ if k is not None:
62
+ dat = {k: dat}
63
+ if emoji is not None:
64
+ dat["emoji"] = emoji
65
+ return model(**dat)
66
+
67
+ async def close(self) -> None:
68
+ """Close the aiohttp session."""
69
+ if self.session:
70
+ await self.session.close()
71
+ self.session = None
72
+
73
+ async def player(self, player_name: str) -> Player:
74
+ """Fetch player data from the API and return it as a dictionary."""
75
+ return await self._generate(
76
+ self.url.format(quote(player_name)),
77
+ Player,
78
+ emoji=await self._get_emoji(player_name)
79
+ )
80
+
81
+ async def players(self, player_names: list[str]) -> tuple[Player]:
82
+ """Fetch data for multiple players from the API and return it as a list of dictionaries."""
83
+ tasks = [self.player(player_name) for player_name in player_names]
84
+ return await asyncio.gather(*tasks)
@@ -0,0 +1,97 @@
1
+ import asyncio
2
+ from typing import Union
3
+ from urllib.parse import quote
4
+
5
+ from .dataclass import DDPlayer, Master, Query, DMap, DDStatsSql, DDStatus
6
+ from .deflt import API
7
+
8
+ __all__ = (
9
+ "DDnetApi",
10
+ "DDstats",
11
+ "DDStatsDB"
12
+ )
13
+
14
+
15
+ class DDStatsDB(API):
16
+ def __init__(self):
17
+ super().__init__()
18
+
19
+ @staticmethod
20
+ def powered() -> str:
21
+ return 'ddstats.org'
22
+
23
+ async def _rt(self, url: str):
24
+ return await self._generate(url, DDStatsSql)
25
+
26
+ async def next(self, dd: DDStatsSql):
27
+ return await self._rt(dd.next_url)
28
+
29
+ async def sql(self, sql: str):
30
+ return await self._rt(f"https://db.ddstats.org/ddnet-7b306cf?sql={quote(sql)}")
31
+
32
+ async def mapinfo(self):
33
+ return await self._rt("https://db.ddstats.org/ddnet-7b306cf/mapinfo.json")
34
+
35
+ async def teamrace(self):
36
+ return await self._rt("https://db.ddstats.org/ddnet-7b306cf/teamrace.json")
37
+
38
+ async def race(self):
39
+ return await self._rt("https://db.ddstats.org/ddnet-7b306cf/race.json")
40
+
41
+ async def maps(self):
42
+ return await self._rt("https://db.ddstats.org/ddnet-7b306cf/maps.json")
43
+
44
+
45
+ class DDnetApi(API):
46
+ def __init__(self):
47
+ super().__init__()
48
+ self.url = "https://ddnet.org/"
49
+
50
+ @staticmethod
51
+ def powered() -> str:
52
+ return 'ddnet.org'
53
+
54
+ async def player(self, player_name: str) -> DDPlayer:
55
+ """Fetch player data from the API and return it as a dictionary."""
56
+ return await self._generate(
57
+ f"{self.url}players/?json2={quote(player_name)}",
58
+ DDPlayer,
59
+ emoji=await self._get_emoji(player_name)
60
+ )
61
+
62
+ async def players(self, player_names: list[str]) -> tuple[DDPlayer]:
63
+ """Fetch data for multiple players from the API and return it as a list of dictionaries."""
64
+ tasks = [self.player(player_name) for player_name in player_names]
65
+ return await asyncio.gather(*tasks)
66
+
67
+ async def status(self) -> Union[DDStatus, None]:
68
+ return await self._generate(
69
+ f"{self.url}status/json/stats.json",
70
+ DDStatus
71
+ )
72
+
73
+ async def query(self, player: str) -> Union[Query, None]:
74
+ return await self._generate(
75
+ f"{self.url}players/?query={quote(player)}",
76
+ Query,
77
+ "data",
78
+ emoji=await self._get_emoji(player)
79
+ )
80
+
81
+ async def master(self) -> Union[Master, None]:
82
+ return await self._generate(
83
+ "https://master1.ddnet.org/ddnet/15/servers.json",
84
+ Master
85
+ )
86
+
87
+ async def map(self, map_name: str) -> Union[DMap, None]:
88
+ return await self._generate(
89
+ f"{self.url}maps/?json={quote(map_name)}",
90
+ DMap
91
+ )
92
+
93
+
94
+ class DDstats(API):
95
+ @staticmethod
96
+ def powered() -> str:
97
+ return 'ddstats.tw'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ddapi
3
- Version: 0.5.1
3
+ Version: 0.6.0
4
4
  Summary: DDnet api
5
5
  Home-page: https://github.com/ByFox213/ddapi
6
6
  Author: ByFox
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = ddapi
3
- version = 0.5.0
3
+ version = 0.6.0
4
4
  author = ByFox
5
5
  description = DDnet api
6
6
  long_description = file: README.md
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="ddapi",
8
- version="0.5.1",
8
+ version="0.6.0",
9
9
  author="ByFox",
10
10
  description="DDnet api",
11
11
  long_description=long_description,
@@ -1,63 +0,0 @@
1
- from abc import ABC
2
- from typing import Union, Any
3
-
4
- import aiohttp
5
- from aiohttp import ClientSession, ClientConnectorError
6
- from aiohttp.typedefs import DEFAULT_JSON_DECODER, JSONDecoder
7
-
8
-
9
- class API(ABC):
10
- def __init__(self,
11
- session: ClientSession = None,
12
- json_loads: JSONDecoder = DEFAULT_JSON_DECODER,
13
- emojis: dict[str, str] = None):
14
- self.emojis = emojis
15
- if emojis is None:
16
- self.emojis = {"fox": "🦊"}
17
- self.session = session
18
- self.json_loads = json_loads
19
- self.url = "https://ddstats.qwik.space/player/json?player={0}"
20
-
21
- def __del__(self):
22
- self.session = None
23
-
24
- @staticmethod
25
- def powered() -> str:
26
- return ''
27
-
28
- def _get_emoji(self, player_name: str) -> str:
29
- for name, emoji in self.emojis.items():
30
- if name in player_name.lower():
31
- return emoji
32
- return ''
33
-
34
- def closed(self):
35
- return self.session.closed is None or self.session.closed
36
-
37
- async def _send(self, url: str) -> Union[dict, None]:
38
- if self.session is None:
39
- self.session = aiohttp.ClientSession()
40
- try:
41
- async with self.session.get(url) as req:
42
- if req.status == 200:
43
- usr = await req.text()
44
- if usr == '{}' or usr is None:
45
- return
46
- del usr
47
- return await req.json(loads=self.json_loads)
48
- return
49
- except ClientConnectorError:
50
- return
51
-
52
- async def _generate(self, url: str, model, k: str = None, emoji: str = None) -> Any:
53
- dat = await self._send(url)
54
- if dat is None:
55
- return
56
- if k is not None:
57
- dat = {k: dat}
58
- if emoji is not None:
59
- dat["emoji"] = emoji
60
- return model(**dat)
61
-
62
- async def close(self) -> None:
63
- return await self.session.close()
@@ -1,79 +0,0 @@
1
- import re
2
- from datetime import datetime
3
- from typing import Union
4
- from urllib.parse import quote
5
-
6
- from .dataclass import DDPlayer, Master, Player, Query, DMap, DDStatsSql, DDStatus
7
- from .deflt import API
8
-
9
- REG_SERVER = r"^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$"
10
-
11
- __all__ = (
12
- "utc_times",
13
- "DDnetApi",
14
- "DDstats",
15
- "DDStatsDB"
16
- )
17
-
18
-
19
- def utc_times(timestamp: int | float) -> datetime:
20
- return datetime.utcfromtimestamp(timestamp)
21
-
22
-
23
- class DDStatsDB(API):
24
- @staticmethod
25
- def powered() -> str:
26
- return 'ddstats.org'
27
-
28
- async def _rt(self, url: str):
29
- return await self._generate(url, DDStatsSql)
30
-
31
- async def next(self, dd: DDStatsSql):
32
- return await self._rt(dd.next_url)
33
-
34
- async def sql(self, sql: str):
35
- return await self._rt(f"https://db.ddstats.org/ddnet-7b306cf?sql={quote(sql)}")
36
-
37
- async def mapinfo(self):
38
- return await self._rt("https://db.ddstats.org/ddnet-7b306cf/mapinfo.json")
39
-
40
- async def teamrace(self):
41
- return await self._rt("https://db.ddstats.org/ddnet-7b306cf/teamrace.json")
42
-
43
- async def race(self):
44
- return await self._rt("https://db.ddstats.org/ddnet-7b306cf/race.json")
45
-
46
- async def maps(self):
47
- return await self._rt("https://db.ddstats.org/ddnet-7b306cf/maps.json")
48
-
49
-
50
- class DDnetApi(API):
51
- @staticmethod
52
- def powered() -> str:
53
- return 'ddnet.org'
54
-
55
- async def player(self, player: str) -> Union[DDPlayer, None]:
56
- return await self._generate(f"https://ddnet.org/players/?json2={quote(player)}", DDPlayer,
57
- emoji=self._get_emoji(player))
58
-
59
- async def status(self) -> Union[DDStatus, None]:
60
- return await self._generate("https://ddnet.org/status/json/stats.json", DDStatus)
61
-
62
- async def query(self, player: str) -> Union[Query, None]:
63
- return await self._generate(f"https://ddnet.org/players/?query={quote(player)}", Query, "data",
64
- emoji=self._get_emoji(player))
65
-
66
- async def master(self) -> Union[Master, None]:
67
- return await self._generate("https://master1.ddnet.org/ddnet/15/servers.json", Master)
68
-
69
- async def map(self, map_name: str) -> Union[DMap, None]:
70
- return await self._generate(f"https://ddnet.org/maps/?json={quote(map_name)}", DMap)
71
-
72
-
73
- class DDstats(API):
74
- @staticmethod
75
- def powered() -> str:
76
- return 'ddstats.tw'
77
-
78
- async def player(self, nickname) -> Union[Player, None]:
79
- return await self._generate(f"https://ddstats.tw/player/json?player={quote(nickname)}", Player, emoji=self._get_emoji(nickname))
File without changes
File without changes