diff --git a/build/lib/labylib/Cape.py b/build/lib/labylib/Cape.py index fcac83d..a96f5ec 100644 --- a/build/lib/labylib/Cape.py +++ b/build/lib/labylib/Cape.py @@ -2,15 +2,11 @@ import requests import hashlib import time -class RequestError(Exception): pass - class Texture: endpoint = "https://www.labymod.net/page/php/cape.php" - def __init__(self,cookie,img): - self.validate(cookie,img) - + def __init__(self,cookie): self.body = b"" # Initialize request body self.cookies = dict(PHPSESSID = cookie) self.boundary = self.boundary() @@ -33,13 +29,9 @@ class Texture: } self.appendBinaryFormData(b"cosmetic",b"cape") - self.appendBinaryFormData(b"file",self.bOpen(img)) # ----------------------------------- - def validate(self,cookie,file): - return True - # Generate boundary header from MD5-hash of current time def boundary(self): seed = str(time.time()) @@ -83,7 +75,9 @@ class Texture: # ----------------------------------- - def update(self): + def update(self,img): + self.appendBinaryFormData(b"file",self.bOpen(img)) + self.closeBinaryFormData() # Add final boundary header request = requests.post(Texture.endpoint, @@ -93,6 +87,157 @@ class Texture: ) # Raise exception if request fails - # Use [3:5] to clean up junk chars from reponse body - if(str(request.text)[3:5] != "OK"): - raise RequestError(str(request.text)) \ No newline at end of file + request.raise_for_status() + +class Template: + + endpoint = "https://www.labymod.net/page/php/setCapeTpl.php" + templates = { + "labymod": "10_LABYMOD.png", + "minecon2011": "30_MINECON2011.png", + "minecon2012": "30_MINECON2012.png", + "minecon2013": "30_MINECON2013.png", + "minecon2015": "30_MINECON2015.png", + "minecon2016": "30_MINECON2016.png", + "minecon2019": "30_MINECON2019.png", + "prismarine": "30_PRISMARINE.png", + "christmas2010": "40_CHRISTMAS2010.png", + "cobalt": "40_COBALT.png", + "julianclark": "40_JULIANCLARK.png", + "mapmaker": "40_MAPMAKER.png", + "mojira": "40_MOJIRA.png", + "mrmessiah": "40_MRMESSIAH.png", + "newyear": "40_NEWYEAR.png", + "scrolls": "40_SCROLLS.png", + "translator": "40_TRANSLATOR.png", + "turtle": "40_TURTLE.png", + "winner": "40_WINNER.png" + } + + def __init__(self,cookie): + self.cookies = dict(PHPSESSID = cookie) + + self.headers = { + "accept": "*/*", + "accept-encoding": "gzip, deflate, br", + "accept-language": "en-US,en;q=0.9,sv;q=0.8", + "cache-control": "no-cache", + "dnt": "1", + "user-agent": "Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0", + "origin": "https://www.labymod.net", + "pragma": "no-cache", + "referer": "https://www.labymod.net/dashboard", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "x-requested-with": "XMLHttpRequest", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" + } + + self.body = "" + + # Payload + self.addEncodedFormData("cosmetic","cape") + + # ----------------------------------- + + # Add URLEncoded form data (x-www-form-urlencoded) + def addEncodedFormData(self,key,value): + body = "&" + + # Remove '&' delimiter for first item + if(self.body == ""): + body = "" + + body += f"{key}={value}" + + self.body += body + + # ----------------------------------- + + def update(self,value): + value = value.lower() + + if(value not in Template.templates): + raise ValueError(f"'{value}' is not a valid template.") + + texture = Template.templates[value] + + self.addEncodedFormData("cape",texture) + + request = requests.post(Template.endpoint, + headers = self.headers, + cookies = self.cookies, + data = self.body + ) + + # Raise exception if request fails + request.raise_for_status() + +class Visibility: + + endpoint = "https://www.labymod.net/api/change" + + def __init__(self,cookie): + self.cookies = dict(PHPSESSID = cookie) + + self.headers = { + "accept": "*/*", + "accept-encoding": "gzip, deflate, br", + "accept-language": "en-US,en;q=0.9,sv;q=0.8", + "cache-control": "no-cache", + "dnt": "1", + "user-agent": "Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0", + "origin": "https://www.labymod.net", + "pragma": "no-cache", + "referer": "https://www.labymod.net/dashboard", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "x-requested-with": "XMLHttpRequest", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" + } + + self.body = "" + + # Payload + self.addEncodedFormData("type","switch") + self.addEncodedFormData("item",459595) + self.addEncodedFormData("site","control") + + # ----------------------------------- + + # Add URLEncoded form data (x-www-form-urlencoded) + def addEncodedFormData(self,key,value): + body = "&" + + # Remove '&' delimiter for first item + if(self.body == ""): + body = "" + + body += f"{key}={value}" + + self.body += body + + # ----------------------------------- + + def update(self,value): + # Interpret strings + if(type(value) != int): + if(value == "show"): + value = 1 + elif(value == "hide"): + value = 0 + else: + raise ValueError(f"'{value}' is not a valid visibility state.") + + self.addEncodedFormData("value",value) + + request = requests.post(Visibility.endpoint, + headers = self.headers, + cookies = self.cookies, + data = self.body + ) + + # Raise exception if request fails + request.raise_for_status() \ No newline at end of file diff --git a/build/lib/labylib/Hat.py b/build/lib/labylib/Hat.py new file mode 100644 index 0000000..13df56d --- /dev/null +++ b/build/lib/labylib/Hat.py @@ -0,0 +1,126 @@ +import requests + +class Texture: + + endpoint = "https://www.labymod.net/api/change" + + def __init__(self,cookie): + self.cookies = dict(PHPSESSID = cookie) + + self.headers = { + "accept": "*/*", + "accept-encoding": "gzip, deflate, br", + "accept-language": "en-US,en;q=0.9,sv;q=0.8", + "cache-control": "no-cache", + "dnt": "1", + "user-agent": "Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0", + "origin": "https://www.labymod.net", + "pragma": "no-cache", + "referer": "https://www.labymod.net/dashboard", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "x-requested-with": "XMLHttpRequest", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" + } + + self.body = "" + + # Payload + self.addEncodedFormData("type","country") + self.addEncodedFormData("item",459594) + self.addEncodedFormData("site","control") + + # ----------------------------------- + + # Add URLEncoded form data (x-www-form-urlencoded) + def addEncodedFormData(self,key,value): + body = "&" + + # Remove '&' delimiter for first item + if(self.body == ""): + body = "" + + body += f"{key}={value}" + + self.body += body + + # ----------------------------------- + + def update(self,value): + self.addEncodedFormData("value",value) + + request = requests.post(Texture.endpoint, + headers = self.headers, + cookies = self.cookies, + data = self.body + ) + + # Raise exception if request fails + request.raise_for_status() + +class Visibility: + + endpoint = "https://www.labymod.net/api/change" + + def __init__(self,cookie): + self.cookies = dict(PHPSESSID = cookie) + + self.headers = { + "accept": "*/*", + "accept-encoding": "gzip, deflate, br", + "accept-language": "en-US,en;q=0.9,sv;q=0.8", + "cache-control": "no-cache", + "dnt": "1", + "user-agent": "Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0", + "origin": "https://www.labymod.net", + "pragma": "no-cache", + "referer": "https://www.labymod.net/dashboard", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "x-requested-with": "XMLHttpRequest", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" + } + + self.body = "" + + # Payload + self.addEncodedFormData("type","switch") + self.addEncodedFormData("item",459594) + self.addEncodedFormData("site","control") + + # ----------------------------------- + + # Add URLEncoded form data (x-www-form-urlencoded) + def addEncodedFormData(self,key,value): + body = "&" + + # Remove '&' delimiter for first item + if(self.body == ""): + body = "" + + body += f"{key}={value}" + + self.body += body + + # ----------------------------------- + + def update(self,value): + # Interpret strings + if(type(value) != int): + if(value == "show"): + value = 1 + else: + value = 0 + + self.addEncodedFormData("value",value) + + request = requests.post(Visibility.endpoint, + headers = self.headers, + cookies = self.cookies, + data = self.body + ) + + # Raise exception if request fails + request.raise_for_status() \ No newline at end of file diff --git a/dist/labylib-0.1.0.tar.gz b/dist/labylib-0.1.0.tar.gz deleted file mode 100644 index 904d2d5..0000000 Binary files a/dist/labylib-0.1.0.tar.gz and /dev/null differ diff --git a/dist/labylib-0.1.0-py3-none-any.whl b/dist/labylib-0.2.0-py3-none-any.whl similarity index 62% rename from dist/labylib-0.1.0-py3-none-any.whl rename to dist/labylib-0.2.0-py3-none-any.whl index 8cfb6c5..5fa5077 100644 Binary files a/dist/labylib-0.1.0-py3-none-any.whl and b/dist/labylib-0.2.0-py3-none-any.whl differ diff --git a/dist/labylib-0.2.0.tar.gz b/dist/labylib-0.2.0.tar.gz new file mode 100644 index 0000000..9ac490c Binary files /dev/null and b/dist/labylib-0.2.0.tar.gz differ diff --git a/labylib.egg-info/PKG-INFO b/labylib.egg-info/PKG-INFO index 39effd8..1e002ad 100644 --- a/labylib.egg-info/PKG-INFO +++ b/labylib.egg-info/PKG-INFO @@ -1,7 +1,7 @@ Metadata-Version: 2.1 Name: labylib -Version: 0.1.0 -Summary: Python API to modify LabyMod cosmetics +Version: 0.2.0 +Summary: API to modify LabyMod cosmetics Home-page: https://github.com/VictorWesterlund/labylib Author: VicW Author-email: victor.vesterlund@gmail.com @@ -23,64 +23,77 @@ Description: ![Labylib](https://storage.googleapis.com/public.victorwesterlund.c ## Installation 1. Download and install [Python 3](https://www.python.org/downloads/) for your architecture. - 2. Clone this repo to your machine, or [download a zip](/VictorWesterlund/labylib/archive/master.zip) + 2. Install the latest version of labylib with [`pip3`](https://pypi.org/project/labylib/) ```bash - $ git clone https://github.com/VictorWesterlund/labylib/ - $ gh repo clone VictorWesterlund/labylib + $ python3 -m pip install labylib + ``` + *..or if that doesn't work* + ```python + $ pip3 install labylib ``` ## Quickstart - **1. Import a cosmetics module from `labylib/`.** - - [A list of all modules and classes can be found here](https://github.com/VictorWesterlund/labylib/wiki/Module-reference-sheet) - ```python - from labylib import Cape + 1. Import a labylib Module from the [list of available modules](https://github.com/VictorWesterlund/labylib/wiki/labylib-Modules). + ```python3 + from labylib import ``` - **2. Initialize a module class.** - - All labylib classes take a `PHPSESSID` as their first argument. - - _Example with `Cape` where a file-path is expected as a second argument:_ - ```python - texture = Cape.Texture("","") # labylib = Cape.Texture("772nnas663jkc8ahbb2","/home/VicW/coolCape-2.png") + 2. Each Module comes with a set of classes available to each cosmetic. Pick a class for your Module. (`Visibility`,`Texture` etc.) + 3. Initialize the class by passing it a `PHPSESSID`
+ [**Here's what it is and where to find it**](https://github.com/VictorWesterlund/labylib/wiki/Find-your-PHPSESSID) + ```python3 + # Example + cape_vis = Cape.Visibility(PHPSESSID) + ``` + 4. Call `update()` with a value expected by the class. Just like Modules, the value expected depends on the class. + ```python3 + # Example + cape_vis.update("show") ``` - **3. Submit a cosmetic update** - ```python - texture.update() - ``` - Python's [Built-in-exceptions](https://docs.python.org/3/library/exceptions.html#exception-hierarchy) are rasied as needed for missing texture files (`FileNotFoundError`) etc. If a request was sucuessfully sent to the Labymod endpoint, but it returned something falsey (not `OK`). A custom-defined `RequestError` exception will be raised; containing the response received from the endpoint. - ```python - try: - texture.update() - except RequestError as error: - print("Caugh RequestError exception:" + error) - # "Caugh RequestError exception: Session expired." + # Advanced Usage + ## Request headers, cookies and body + Each class instance can be modified before `update()` is called to make changes to the request headers, cookies etc. You can even add additional encoded form data to the request body if necessary. + + labylib uses [`Requests`](https://requests.readthedocs.io/en/master/) under the hood and request parameters like headers and cookies can be modified in accordance with `Request`'s conventions. + ```python3 + # This will send add a "foo=bar" cookie and header with the request + cape_vis.cookies["foo"] = "bar" + cape_vis.headers["foo"] = "bar" + + cape_vis.update("show") ``` - ## Advanced usage - ### HTTP POST Headers - Request headers and cookies can be accessed and modified pre-submission by applying standard list modifications on the followin objects: `self.headers` and `self.cookies` - ```python - texture = Cape.Texture("","") + ### To append form data to the request body of an instance: - texture.headers["Origin"] = "https://example.com/" - texture.cookies["Foo"] = "Bar" - - labylib.update() + **For `x-www-form-urlencoded` requests:** Append form data with the `addEncodedFormData(key,value)` method: + ```python3 + # This will add "foo=bar" to the URL encoded payload + cape_vis.addEncodedFormData("foo","bar") + cape_vis.update("show") ``` - ### HTTP POST Body - Binary form-data can be appended by calling `self.appendBinaryFormData(name,payload)`. - ```python - texture = Cape.Texture("","") - texture.appendBinaryFormData(b"foo",b"bar") - texture.appendBinaryFormData(b"file","/home/VicW/home/VicW/coolCape-2.png") # Note that 'payload' is a String in this case (as opposed to Binary) + **For `multipart/form-data` requests:** Append binary form data with the `addBinaryFormData(key,payload)` method: + ```python3 + # This will create a new payload boundary containing "foo=bar" + cape_texture.addBinaryFormData(b"foor",b"bar") + cape_texture.update("show") ``` - Special form-data types ('names'): - |name|Description - |--|--| - |`'file'`| Submit cosmetic texture file as BLOB by passing `payload` a binary-encoded PNG.
_`self.bOpen()` can be used to 'open()' a file as binary string._ + You can also append `image/png` files by passing "file" as the `key` argument. You can either pass binary data directly as a BLOB to `payload` or use `bOpen()` to load an image from disk: + ```python3 + # This will create a new payload boundary with a "Content-Type: image/png" header and BLOB body + cape_texture.addBinaryFormData(b"file",cape_vis.bOpen("~/someImage.png")) + cape_texture.update("~/myAwesomeTexture.png") + ``` + + ## Contribute + + If you find any bugs with- or would like to suggest features to labylib, please submit them under [Issues](https://github.com/VictorWesterlund/labylib/issues) + + Pull requests to labylib are highly encouraged! + + ## License + + [GNU General Public License v3.0](https://github.com/VictorWesterlund/labylib/blob/master/LICENSE) Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 diff --git a/labylib.egg-info/SOURCES.txt b/labylib.egg-info/SOURCES.txt index 5f90f3a..127b85e 100644 --- a/labylib.egg-info/SOURCES.txt +++ b/labylib.egg-info/SOURCES.txt @@ -1,6 +1,7 @@ README.md setup.py labylib/Cape.py +labylib/Hat.py labylib/__init__.py labylib.egg-info/PKG-INFO labylib.egg-info/SOURCES.txt diff --git a/setup.py b/setup.py index 27e7eac..513789b 100644 --- a/setup.py +++ b/setup.py @@ -5,10 +5,10 @@ with open("README.md","r") as fh: setuptools.setup( name="labylib", - version="0.1.0", + version="0.2.0", author="VicW", author_email="victor.vesterlund@gmail.com", - description="Python API to modify LabyMod cosmetics", + description="API to modify LabyMod cosmetics", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/VictorWesterlund/labylib",