Skip to content

Commit

Permalink
New class for Skin & Cape
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucino772 committed Nov 12, 2021
1 parent 03f6ae9 commit 5645a93
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 48 deletions.
151 changes: 104 additions & 47 deletions mojang/account/structures/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,83 +14,140 @@ class NameChange(NamedTuple):
allowed (bool): Wether the user can change name
created_at (dt.datetime): When was the user created
"""

allowed: bool
created_at: dt.datetime

class _SkinCapeBase(NamedTuple):
source: str
variant: str = None

class _Resource:
def __init__(self, source: str, load: bool = True) -> None:
self.__source = source
self.__data = bytes()
self.__extension = None

if load:
self.load()

@property
def source(self):
return self.__source

@property
def data(self):
return self.__data

@property
def extension(self):
return self.__extension

@classmethod
def _filename_from_url(cls, url: str):
url_path = urlparse(url).path
match = re.match(r'^([\w,\s-]+)\.([A-Za-z]{3})$', path.basename(url_path))
match = re.match(
r"^([\w,\s-]+)\.([A-Za-z]{3})$", path.basename(url_path)
)
if match:
return match.groups()

@classmethod
def _filename_from_headers(cls, headers: dict):
# Check content-disposition
if 'content-disposition' in headers.keys():
cdisp = headers['content-disposition']
file_names = re.findall('filename=(.+)', cdisp)
if "content-disposition" in headers.keys():
cdisp = headers["content-disposition"]
file_names = re.findall("filename=(.+)", cdisp)
if len(file_names) > 0:
return file_names[0][0], file_names[0][1][1:]

# Check content-type
if 'content-type' in headers.keys():
ctype = headers['content-type']
if (not 'text' in ctype) and (not 'html' in ctype):
return ctype.split('/')
if "content-type" in headers.keys():
ctype = headers["content-type"]
if (not "text" in ctype) and (not "html" in ctype):
return ctype.split("/")

@classmethod
def _download_bytes(cls, url: str):
response = requests.get(url)
if response.ok:
filename = cls._filename_from_headers(response.headers) or cls._filename_from_url(url) or ['download', None]
filename = (
cls._filename_from_headers(response.headers)
or cls._filename_from_url(url)
or ["download", None]
)
return filename, response.content

@property
def data(self):
if not hasattr(self, '_data'):
_data = b''
_extension = None

if validators.url(self.source):
response = self._download_bytes(self.source)
if response:
_extension = response[0][1]
_data = response[1]
elif path.exists(self.source):
basename = path.basename(self.source)
_extension = path.splitext(basename)[1][1:]

with open(self.source, 'rb') as fp:
_data = fp.read()

if _extension != 'png':
pass # TODO: Raise Exception

object.__setattr__(self, '_data', _data)

return self._data

def save(self, dest: str):
if not dest.endswith('.png'):
dest += '.png'

with open(dest, 'wb') as fp:
fp.write(self.data)

class Skin(_SkinCapeBase):
def load(self):
if validators.url(self.source):
response = self._download_bytes(self.source)
if response:
self.__extension = response[0][1]
self.__data = response[1]
elif path.exists(self.source):
basename = path.basename(self.source)
self.__extension = path.splitext(basename)[1][1:]

with open(self.source, "rb") as fp:
self.__data = fp.read()
else:
pass # TODO: Raise Exception

def save(self, dest: str, add_extension: bool = True):
if (
len(path.splitext(dest)[1]) == 0
and self.__extension != None
and add_extension == True
):
dest += self.__extension

with open(dest, "wb") as fp:
fp.write(self.__data)

return dest


class Skin(_Resource):
"""
Attributes:
source (str): The source where the skin is located
variant (str): The variant of skin (default to 'classic')
"""

class Cape(_SkinCapeBase):
def __init__(self, source: str, variant: str, load: bool = True) -> None:
super().__init__(source, load=load)
self.__variant = variant

@property
def variant(self):
return self.__variant

def __hash__(self) -> int:
return hash((self.source, self.variant, self.data))

def __eq__(self, o: object) -> bool:
if isinstance(o, Skin):
return hash(self) == hash(o)

return False

def __repr__(self) -> str:
return f"Skin(source='{self.source}', variant='{self.variant}')"

__str__ = __repr__

class Cape(_Resource):
"""
Attributes:
source (str): The source where the cape is located
"""
def __hash__(self) -> int:
return hash((self.source, self.data))

def __eq__(self, o: object) -> bool:
if isinstance(o, Cape):
return hash(self) == hash(o)

return False

def __repr__(self) -> str:
return f"Cape(source='{self.source}'')"

__str__ = __repr__
2 changes: 1 addition & 1 deletion tests/test_mojang.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_unexistent_names(self):

def test_existent_profile(self):
self.assertEqual(mojang.user('069a79f444e94726a5befca90e38aaf5'), UserProfile('Notch', '069a79f444e94726a5befca90e38aaf5', False, False, NameInfoList([NameInfo('Notch', None)]), Skin('http://textures.minecraft.net/texture/292009a4925b58f02c77dadc3ecef07ea4c7472f64e0fdc32ce5522489362680', 'classic'), None))
self.assertEqual(mojang.user('853c80ef3c3749fdaa49938b674adae6'), UserProfile('jeb_', '853c80ef3c3749fdaa49938b674adae6', False, False, NameInfoList([NameInfo('jeb_', None)]), Skin('http://textures.minecraft.net/texture/7fd9ba42a7c81eeea22f1524271ae85a8e045ce0af5a6ae16c6406ae917e68b5', 'classic'), Cape('http://textures.minecraft.net/texture/9e507afc56359978a3eb3e32367042b853cddd0995d17d0da995662913fb00f7', None)))
self.assertEqual(mojang.user('853c80ef3c3749fdaa49938b674adae6'), UserProfile('jeb_', '853c80ef3c3749fdaa49938b674adae6', False, False, NameInfoList([NameInfo('jeb_', None)]), Skin('http://textures.minecraft.net/texture/7fd9ba42a7c81eeea22f1524271ae85a8e045ce0af5a6ae16c6406ae917e68b5', 'classic'), Cape('http://textures.minecraft.net/texture/9e507afc56359978a3eb3e32367042b853cddd0995d17d0da995662913fb00f7')))

def test_unexistent_profile(self):
self.assertEqual(mojang.user('069a79f444e94726a5befca90e38aaf6'), None)

0 comments on commit 5645a93

Please sign in to comment.