osudroid-api-wrapper 0.0.2__tar.gz → 0.0.4__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.
Files changed (25) hide show
  1. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/LICENSE +3 -1
  2. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/PKG-INFO +6 -3
  3. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/pyproject.toml +1 -1
  4. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/base/beatmap.py +2 -0
  5. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/base/mods.py +8 -2
  6. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/replay.py +51 -32
  7. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/replay_data/replayobjectdata.py +8 -0
  8. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/structs/profile.py +3 -2
  9. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper.egg-info/PKG-INFO +6 -3
  10. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/setup.cfg +0 -0
  11. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/__init__.py +0 -0
  12. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/__init__.py +0 -0
  13. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/base/__init__.py +0 -0
  14. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/base/player.py +0 -0
  15. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/replay_data/cursordata.py +0 -0
  16. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/replay_data/cursoroccurrence.py +0 -0
  17. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/replay_data/cursoroccurrencegroup.py +0 -0
  18. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/replay_data/hitresult.py +0 -0
  19. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/replay_data/movementtype.py +0 -0
  20. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/classes/score.py +0 -0
  21. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper/structs/__init__.py +0 -0
  22. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper.egg-info/SOURCES.txt +0 -0
  23. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper.egg-info/dependency_links.txt +0 -0
  24. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper.egg-info/requires.txt +0 -0
  25. {osudroid_api_wrapper-0.0.2 → osudroid_api_wrapper-0.0.4}/src/osudroid_api_wrapper.egg-info/top_level.txt +0 -0
@@ -1,6 +1,8 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 unclem2, Rian8337, xjunko
3
+ Copyright (c) 2021 FireRedz
4
+ Copyright (c) 2021 Rian8337
5
+ Copyright (c) 2025 unclem2
4
6
 
5
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
8
  of this software and associated documentation files (the "Software"), to deal
@@ -1,11 +1,13 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: osudroid-api-wrapper
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Python api wrapper for osu!droid
5
5
  Author-email: unclem <mannringyt11@gmail.com>
6
6
  License: MIT License
7
7
 
8
- Copyright (c) 2025 unclem2, Rian8337, xjunko
8
+ Copyright (c) 2021 FireRedz
9
+ Copyright (c) 2021 Rian8337
10
+ Copyright (c) 2025 unclem2
9
11
 
10
12
  Permission is hereby granted, free of charge, to any person obtaining a copy
11
13
  of this software and associated documentation files (the "Software"), to deal
@@ -37,3 +39,4 @@ Requires-Dist: beautifulsoup4>=4.10.0
37
39
  Requires-Dist: javaobj-py3>=0.4.4
38
40
  Requires-Dist: stream_unzip>=0.0.99
39
41
  Requires-Dist: python-dotenv>=1.0.0
42
+ Dynamic: license-file
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "osudroid-api-wrapper"
7
- version = "0.0.2"
7
+ version = "0.0.4"
8
8
  authors = [
9
9
  { name="unclem", email="mannringyt11@gmail.com" }
10
10
  ]
@@ -60,6 +60,8 @@ class Beatmap:
60
60
  }
61
61
  response = requests.get(url, params=params)
62
62
  data = response.json()
63
+ if len(data) == 0:
64
+ return None
63
65
  data = data[0]
64
66
 
65
67
  elif md5 is not None:
@@ -13,7 +13,7 @@ class Mods:
13
13
  return cls([mod_abbreviations.get(mod, mod) for mod in mods.split(",")])
14
14
 
15
15
  @classmethod
16
- def from_droid_replay(cls, mods: str):
16
+ def from_droid_replay(cls, mods: list):
17
17
  mod_mapping = {
18
18
  "MOD_NOFAIL": "NF", "MOD_EASY": "EZ", "MOD_HIDDEN": "HD",
19
19
  "MOD_HARDROCK": "HR", "MOD_SUDDENDEATH": "SD", "MOD_DOUBLETIME": "DT",
@@ -22,7 +22,7 @@ class Mods:
22
22
  "MOD_AUTO": "AT", "MOD_PRECISE": "PR", "MOD_REALLYEASY": "REZ",
23
23
  "MOD_SMALLCIRCLES": "SC", "MOD_PERFECT": "PF", "MOD_SUDDENDEATH": "SU",
24
24
  }
25
- return cls([mod_mapping.get(mod, mod) for mod in mods.split(",")])
25
+ return cls([mod_mapping.get(mod, mod) for mod in mods])
26
26
 
27
27
  @classmethod
28
28
  def from_droid_api(cls, mods: dict):
@@ -31,3 +31,9 @@ class Mods:
31
31
  return instance
32
32
 
33
33
 
34
+ @property
35
+ def to_dict(self):
36
+ return {
37
+ "mods": self.mods,
38
+ "speed_multiplier": self.speed_multiplier
39
+ }
@@ -31,6 +31,7 @@ from stream_unzip import stream_unzip
31
31
  import javaobj
32
32
  import struct
33
33
  import io
34
+ from .base.mods import Mods
34
35
  from .replay_data.movementtype import MovementType
35
36
  from .replay_data.cursordata import CursorData
36
37
  from .replay_data.hitresult import HitResult
@@ -53,8 +54,10 @@ class Replay:
53
54
  self.hit0: int = 0
54
55
  self.score: int = 0
55
56
  self.combo: int = 0
57
+ self.rank: str = None
58
+ self.accuracy: float = 0.0
56
59
  self.username: str = None
57
- self.parsed_mods: list = []
60
+ self.parsed_mods: Mods = []
58
61
  self.converted_mods: list = []
59
62
  self.__buffer_offset: int = 0
60
63
  self.cursor_data: list = []
@@ -65,6 +68,43 @@ class Replay:
65
68
  while chunk := f.read(65536):
66
69
  yield chunk
67
70
 
71
+ def __calculate_rank(self):
72
+ total_hits = self.hit300 + self.hit100 + self.hit50 + self.hit0
73
+ have_h_mods = False
74
+ for mod in self.converted_mods:
75
+ if mod == "HD" or mod == "FL":
76
+ have_h_mods = True
77
+ break
78
+ hit300ratio = self.hit300 / total_hits
79
+
80
+ if hit300ratio == 1:
81
+ self.rank = "XH" if have_h_mods else "X"
82
+ return self
83
+ elif hit300ratio >= 0.9:
84
+ if self.hit50 / total_hits <= 0.01 and self.hit0 == 0:
85
+ self.rank = "SH" if have_h_mods else "S"
86
+ return self
87
+ self.rank = "A"
88
+ return self
89
+ elif hit300ratio >= 0.8:
90
+ if self.hit0 == 0:
91
+ self.rank = "A"
92
+ return self
93
+ self.rank = "B"
94
+ return self
95
+ elif hit300ratio >= 0.7:
96
+ if self.hit0 == 0:
97
+ self.rank = "B"
98
+ return self
99
+ self.rank = "C"
100
+ return self
101
+ elif hit300ratio >= 0.6:
102
+ self.rank = "C"
103
+ return self
104
+ else:
105
+ self.rank = "D"
106
+ return self
107
+
68
108
 
69
109
 
70
110
  def __read_byte(self, replay_data):
@@ -87,33 +127,6 @@ class Replay:
87
127
  self.__buffer_offset += 4
88
128
  return struct.unpack(">f", replay_data.read(4))[0]
89
129
 
90
- def __droid_replay_mods_to_std(self):
91
- mod_mapping = {
92
- "MOD_NOFAIL": "NF",
93
- "MOD_EASY": "EZ",
94
- "MOD_HIDDEN": "HD",
95
- "MOD_HARDROCK": "HR",
96
- "MOD_SUDDENDEATH": "SD",
97
- "MOD_DOUBLETIME": "DT",
98
- "MOD_RELAX": "RX",
99
- "MOD_HALFTIME": "HT",
100
- "MOD_NIGHTCORE": "NC",
101
- "MOD_FLASHLIGHT": "FL",
102
- "MOD_SCOREV2": "V2",
103
- "MOD_AUTOPILOT": "AP",
104
- "MOD_AUTO": "AT",
105
- "MOD_PRECISE": "PR",
106
- "MOD_REALLYEASY": "REZ",
107
- "MOD_SMALLCIRCLES": "SC",
108
- "MOD_PERFECT": "PF",
109
- "MOD_SUDDENDEATH": "SU",
110
- }
111
-
112
- for mod in self.parsed_mods:
113
- if mod in mod_mapping:
114
- self.converted_mods.append(mod_mapping[mod])
115
- return self.converted_mods
116
-
117
130
  def __parse_movement_data(self, replay_data):
118
131
  replay_data = io.BytesIO(replay_data)
119
132
  size = self.__read_int(replay_data)
@@ -192,7 +205,7 @@ class Replay:
192
205
 
193
206
  self.replay_obj = javaobj.v2.loads(data_buffer.getvalue())
194
207
 
195
- for fields in self.replay_obj[0].to_dict['field_data'].values():
208
+ for fields in self.replay_obj[0].__dict__['field_data'].values():
196
209
  for field, value in fields.items():
197
210
  if field.name == 'version':
198
211
  self.version = value
@@ -207,14 +220,16 @@ class Replay:
207
220
  self.hit0, self.score, self.combo) = struct.unpack(">Qiiiiiiii", io.BytesIO(self.replay_obj[4].data).read(40))
208
221
  self.username = self.replay_obj[5].value
209
222
 
210
- for field in self.replay_obj[6].to_dict['field_data'].values():
223
+ for field in self.replay_obj[6].__dict__['field_data'].values():
211
224
  for field, value in field.items():
212
225
  if field.name == "elements":
213
226
  for element in value:
214
227
  self.parsed_mods.append(element.value)
215
228
  break
216
229
 
217
- self.__droid_replay_mods_to_std()
230
+ self.converted_mods = Mods.from_droid_replay(self.parsed_mods).mods
231
+ self.accuracy = round(((300 * self.hit300 + 100 * self.hit100 + 50 * self.hit50) / (300 * (self.hit300 + self.hit100 + self.hit50 + self.hit0))) * 100, 2)
232
+ self.__calculate_rank()
218
233
 
219
234
  if self.version >= 4:
220
235
  modifiers = self.replay_obj[7].value.split("|")
@@ -248,10 +263,14 @@ class Replay:
248
263
  self.__parse_movement_data(replay_data.getvalue())
249
264
  print(self.__buffer_offset)
250
265
  self.__parse_hitresult_data(replay_data.getvalue())
266
+
267
+
268
+
269
+ return self
251
270
 
252
271
  def __str__(self):
253
272
  string = ""
254
- for key, value in self.to_dict.items():
273
+ for key, value in self.__dict__.items():
255
274
  if key == "replay_obj" or key == "replay_file" or key == "cursor_data":
256
275
  continue
257
276
 
@@ -34,5 +34,13 @@ class ReplayObjectData:
34
34
  self.tickset:List[bool] = tickset
35
35
  self.result:hitresult.HitResult = result
36
36
 
37
+ @property
38
+ def to_dict(self):
39
+ return {
40
+ "accuracy": self.accuracy,
41
+ "tickset": self.tickset,
42
+ "result": self.result
43
+ }
44
+
37
45
 
38
46
 
@@ -1,5 +1,5 @@
1
- from classes.score import Score
2
- from classes.base.player import Player
1
+ from ..classes.score import Score
2
+ from ..classes.base.player import Player
3
3
  from typing import List
4
4
  import bs4
5
5
  import requests
@@ -56,6 +56,7 @@ class Profile():
56
56
  resp = requests.get(url)
57
57
  soup = bs4.BeautifulSoup(resp.text, 'html.parser')
58
58
  profile.player = Player._parse_from_bsoup(soup)
59
+ profile.player.uid = uid
59
60
  profile.__get_recent_scores(soup)
60
61
  profile.__get_top_scores(soup)
61
62
  return profile
@@ -1,11 +1,13 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: osudroid-api-wrapper
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Python api wrapper for osu!droid
5
5
  Author-email: unclem <mannringyt11@gmail.com>
6
6
  License: MIT License
7
7
 
8
- Copyright (c) 2025 unclem2, Rian8337, xjunko
8
+ Copyright (c) 2021 FireRedz
9
+ Copyright (c) 2021 Rian8337
10
+ Copyright (c) 2025 unclem2
9
11
 
10
12
  Permission is hereby granted, free of charge, to any person obtaining a copy
11
13
  of this software and associated documentation files (the "Software"), to deal
@@ -37,3 +39,4 @@ Requires-Dist: beautifulsoup4>=4.10.0
37
39
  Requires-Dist: javaobj-py3>=0.4.4
38
40
  Requires-Dist: stream_unzip>=0.0.99
39
41
  Requires-Dist: python-dotenv>=1.0.0
42
+ Dynamic: license-file