From fb9cc79c2cd2c51c8a2f2e8f2f2669ff20a84d4d Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Thu, 12 Nov 2020 02:51:08 +0100 Subject: [PATCH 1/4] Added Labylib demo program 'animated-textures' (Work in progress) Created the first demo program for Labylib. 'animated-textures' does as of this commit, not have labylib core attached. Referenced in 'animated-textures.py' is a TODO where the labylib initiator hook should be called or created. --- .gitignore | 1 + animate.py | 160 +++++++++++++++++++++++++++++++++++++++++++ animated-textures.py | 151 ++++++++++++++++++++++++++++++++++++++++ labylib/__init__.py | 0 4 files changed, 312 insertions(+) create mode 100644 .gitignore create mode 100644 animate.py create mode 100644 animated-textures.py create mode 100644 labylib/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3a3232 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +animated-textures/* \ No newline at end of file diff --git a/animate.py b/animate.py new file mode 100644 index 0000000..860d356 --- /dev/null +++ b/animate.py @@ -0,0 +1,160 @@ +import re +import json +import importlib +from pathlib import Path + +# from labylib import Cape + +# Don't forget to reflect in .gitignore if you change this +name = "animated-textures" + +class Config: + + textures = f"./{name}/" # Cosmetic textures path + f = f"./{name}/config.json" # JSON Config file + default = '{"PHPSESSID": "","cosmetics": {"cape": {"interval": "15","randomOrder": "False"}}}' # Default config + pattern = "^[-,a-zA-Z0-9]{1,128}$" # PHPSESSID pattern + + def __init__(self): + self.config = None + self.exists = True # Config file already exists + self.load() + + # Example: getCosmetic("cape") + def getCosmetic(self,key): + return self.config["cosmetics"][key] + + # Example: setCosmetic("cape","interval",30) + def setCosmetic(self,cosmetic,key,value): + self.config["cosmetics"][cosmetic][key] = value + self.save() + + def setPHPSESSID(self,phpsessid): + self.config["PHPSESSID"] = phpsessid + self.save() + + # ----------------------------------------------------- + + # (Over)write config file + def save(self): + f = open(Config.f,"w") + f.write(json.dumps(self.config)) + f.close() + + # Create config file from default template + def create(self): + self.exists = False + + Path(Config.textures).mkdir(parents=True,exist_ok=True) + + f = open(Config.f,"w") + f.write(Config.default) + f.close() + + # Load the config file from disk into memory + def load(self): + # Create config file if absent + if(Path(Config.f).is_file() == False): + self.create() + + f = open(Config.f,"r") + self.config = json.load(f) + f.close() + + return True + +class Main: + + def __init__(self): + self.config = Config() + self.init() + + # Guided step-by-step setup + def wizard(self): + # +-----------+ + # | Labylib | + # +-----------+ + def box(string): + charset = ["+","-","|"] # Corner,borderX,borderY + string = f" {string} " # Text padding + + box = charset[0] + # Repeat 'borderX' char for string length + for x in string: + box += charset[1] + box += charset[0] + + # Stitch it all together + string = f"{charset[2]}{string}{charset[2]}" + string = f"{box}\n{string}\n{box}" + + return string + + msgDone = "Done! Closing Wizard" + + print(box("Labylib Setup Wizard")) + print("Make sure you read the README before you begin\n") + + self.config.setPHPSESSID(input("Paste your PHPSESSID here:\n")) + + advanced = input("\nDo you wish to modify the default cosmetic settings? 'y/n'[n]: ") + if(advanced != "y"): + print(box(msgDone)) + self.start() + return + + wizard = self.config.config["cosmetics"] + + # Iterate over all cosmetics in config + for cosmetic in wizard: + print(box("Cosmetic > " + cosmetic.capitalize())) + + # Iterate over every cosmetic setting + for key, default in wizard[cosmetic].items(): + value = input(f"Set value for '{key}'[{default}]: ") + # Ignore input if empty or data type doesn't match default + if(len(value) < 1): + print(f"Input error: Expected data type '{type(default)}'. Falling back to default") + value = default + + self.config.setCosmetic(cosmetic,key,value) + + print(box(msgDone)) + self.start() + + #for cosmetic in wizard: + + def start(self): + phpsessid = self.config.config["PHPSESSID"] + start = input(f"\nStart Labylib for PHPSESSID '{phpsessid}'? 'y/n/config'[y]: ") + + if(start == "n"): + return + + if(start == "config"): + self.wizard() + return + + # TODO: Attach labylib hook here + + def init(self): + print("Labylib 0.0.1\n") + + if(self.config.exists and len(self.config.config["PHPSESSID"]) > 1): + self.start() + return + + for cosmetic in self.config.config["cosmetics"]: + Path(Config.textures + cosmetic).mkdir(parents=True,exist_ok=True) + + # Prompt if user wants to use guided setup + print("-- Labylib Animated Textures --\nSince this is your first time here, would you like to walk through the setup process?\n") + wizard = input("Start guided setup? 'y/n':[y] ") + if(wizard == "n"): + print(f"A config file '{Config.f}' has been created for you. Run this command again when you're ready") + return + + self.wizard() + +# Start Labylib +labylib = Main() \ No newline at end of file diff --git a/animated-textures.py b/animated-textures.py new file mode 100644 index 0000000..92e64a9 --- /dev/null +++ b/animated-textures.py @@ -0,0 +1,151 @@ +import re +import json +import importlib +from pathlib import Path + +# from labylib import Cape + +class Config: + + f = ".animate-config.json" + pattern = "^[-,a-zA-Z0-9]{1,128}$" # PHPSESSID pattern + + template = '{\n\t"PHPSESSID": "",\n\t"cosmetics": {\n\t\t"cape": {\n\t\t\t"interval": 15,\n\t\t\t"random": false\n\t\t}\n\t}\n}' + + def __init__(self): + self.config = None + self.exists = True # Config file already exists + self.load() + + # Example: getCosmetic("cape") + def getCosmetic(self,key): + return self.config["cosmetics"][key] + + # Example: setCosmetic("cape","interval",30) + def setCosmetic(self,cosmetic,key,value): + self.config["cosmetics"][cosmetic][key] = value + self.save() + + def setPHPSESSID(self,phpsessid): + self.config["PHPSESSID"] = phpsessid + self.save() + + # ----------------------------------------------------- + + # (Over)write config file + def save(self): + f = open(Config.f,"w") + f.write(json.dumps(self.config)) + f.close() + + # Create config file from template + def create(self): + self.exists = False + + f = open(Config.f,"w") + f.write(Config.template) + f.close() + + # Load the config file from disk into memory + def load(self): + # Create config file if absent + if(Path(Config.f).is_file() == False): + self.create() + + f = open(Config.f,"r") + self.config = json.load(f) + f.close() + return True + +class Main: + + def __init__(self): + self.config = Config() + self.init() + + # Guided step-by-step setup + def wizard(self): + # +-----------+ + # | Labylib | + # +-----------+ + def box(string): + charset = ["+","-","|"] # Corner,borderX,borderY + string = f" {string} " # Text padding + + box = charset[0] + # Repeat 'borderX' char for string length + for x in string: + box += charset[1] + box += charset[0] + + # Stitch it all together + string = f"{charset[2]}{string}{charset[2]}" + string = f"{box}\n{string}\n{box}" + + return string + + msgDone = "Done! Closing Wizard" + + print(box("Labylib Setup Wizard")) + print("Make sure you read the README before you begin\n") + + self.config.setPHPSESSID(input("Paste your PHPSESSID here:\n")) + + advanced = input("\nDo you wish to modify the default cosmetic settings? 'y/n'[n]: ") + if(advanced != "y"): + print(box(msgDone)) + self.start() + return + + wizard = self.config.config["cosmetics"] + + # Iterate over all cosmetics in config + for cosmetic in wizard: + print(box("Cosmetic > " + cosmetic.capitalize())) + + # Iterate over every cosmetic setting + for key, default in wizard[cosmetic].items(): + value = input(f"Set value for '{key}'[{default}]: ") + # Ignore input if empty or data type doesn't match default + if(len(value) < 1): + print(f"Input error: Expected data type '{type(default)}'. Falling back to default") + value = default + + self.config.setCosmetic(cosmetic,key,value) + + print(box(msgDone)) + self.start() + + #for cosmetic in wizard: + + def start(self): + phpsessid = self.config.config["PHPSESSID"] + start = input(f"\nStart Labylib for PHPSESSID '{phpsessid}'? 'y/n/config'[y]: ") + + if(start == "n"): + return + + if(start == "config"): + self.wizard() + return + + print("Labylib is running.. (type 'stop' to close Labylib)") + + def init(self): + print("Labylib 0.0.1") + + if(self.config.exists and len(self.config.config["PHPSESSID"]) > 1): + self.start() + return + + # Prompt if user wants to use guided setup + print("-- Welcome to Labylib --\nSince this is your first time here, would you like to walk through the setup process?\n") + wizard = input("Start guided setup? 'y/n':[y] ") + if(wizard == "n"): + print(f"A config file '{Config.f}' has been created for you. Run this command again when you're ready") + return + + self.wizard() + +# Start Labylib +labylib = Main() \ No newline at end of file diff --git a/labylib/__init__.py b/labylib/__init__.py new file mode 100644 index 0000000..e69de29 From c7194c6039495fa0936fd2c751183c5884f100de Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Thu, 12 Nov 2020 02:54:32 +0100 Subject: [PATCH 2/4] Corrected filename Oopsie commit! Filename 'animate.py' is now corrected to 'animated-textures.py' --- animate.py | 160 ------------------------------------------- animated-textures.py | 25 ++++--- 2 files changed, 17 insertions(+), 168 deletions(-) delete mode 100644 animate.py diff --git a/animate.py b/animate.py deleted file mode 100644 index 860d356..0000000 --- a/animate.py +++ /dev/null @@ -1,160 +0,0 @@ -import re -import json -import importlib -from pathlib import Path - -# from labylib import Cape - -# Don't forget to reflect in .gitignore if you change this -name = "animated-textures" - -class Config: - - textures = f"./{name}/" # Cosmetic textures path - f = f"./{name}/config.json" # JSON Config file - default = '{"PHPSESSID": "","cosmetics": {"cape": {"interval": "15","randomOrder": "False"}}}' # Default config - pattern = "^[-,a-zA-Z0-9]{1,128}$" # PHPSESSID pattern - - def __init__(self): - self.config = None - self.exists = True # Config file already exists - self.load() - - # Example: getCosmetic("cape") - def getCosmetic(self,key): - return self.config["cosmetics"][key] - - # Example: setCosmetic("cape","interval",30) - def setCosmetic(self,cosmetic,key,value): - self.config["cosmetics"][cosmetic][key] = value - self.save() - - def setPHPSESSID(self,phpsessid): - self.config["PHPSESSID"] = phpsessid - self.save() - - # ----------------------------------------------------- - - # (Over)write config file - def save(self): - f = open(Config.f,"w") - f.write(json.dumps(self.config)) - f.close() - - # Create config file from default template - def create(self): - self.exists = False - - Path(Config.textures).mkdir(parents=True,exist_ok=True) - - f = open(Config.f,"w") - f.write(Config.default) - f.close() - - # Load the config file from disk into memory - def load(self): - # Create config file if absent - if(Path(Config.f).is_file() == False): - self.create() - - f = open(Config.f,"r") - self.config = json.load(f) - f.close() - - return True - -class Main: - - def __init__(self): - self.config = Config() - self.init() - - # Guided step-by-step setup - def wizard(self): - # +-----------+ - # | Labylib | - # +-----------+ - def box(string): - charset = ["+","-","|"] # Corner,borderX,borderY - string = f" {string} " # Text padding - - box = charset[0] - # Repeat 'borderX' char for string length - for x in string: - box += charset[1] - box += charset[0] - - # Stitch it all together - string = f"{charset[2]}{string}{charset[2]}" - string = f"{box}\n{string}\n{box}" - - return string - - msgDone = "Done! Closing Wizard" - - print(box("Labylib Setup Wizard")) - print("Make sure you read the README before you begin\n") - - self.config.setPHPSESSID(input("Paste your PHPSESSID here:\n")) - - advanced = input("\nDo you wish to modify the default cosmetic settings? 'y/n'[n]: ") - if(advanced != "y"): - print(box(msgDone)) - self.start() - return - - wizard = self.config.config["cosmetics"] - - # Iterate over all cosmetics in config - for cosmetic in wizard: - print(box("Cosmetic > " + cosmetic.capitalize())) - - # Iterate over every cosmetic setting - for key, default in wizard[cosmetic].items(): - value = input(f"Set value for '{key}'[{default}]: ") - # Ignore input if empty or data type doesn't match default - if(len(value) < 1): - print(f"Input error: Expected data type '{type(default)}'. Falling back to default") - value = default - - self.config.setCosmetic(cosmetic,key,value) - - print(box(msgDone)) - self.start() - - #for cosmetic in wizard: - - def start(self): - phpsessid = self.config.config["PHPSESSID"] - start = input(f"\nStart Labylib for PHPSESSID '{phpsessid}'? 'y/n/config'[y]: ") - - if(start == "n"): - return - - if(start == "config"): - self.wizard() - return - - # TODO: Attach labylib hook here - - def init(self): - print("Labylib 0.0.1\n") - - if(self.config.exists and len(self.config.config["PHPSESSID"]) > 1): - self.start() - return - - for cosmetic in self.config.config["cosmetics"]: - Path(Config.textures + cosmetic).mkdir(parents=True,exist_ok=True) - - # Prompt if user wants to use guided setup - print("-- Labylib Animated Textures --\nSince this is your first time here, would you like to walk through the setup process?\n") - wizard = input("Start guided setup? 'y/n':[y] ") - if(wizard == "n"): - print(f"A config file '{Config.f}' has been created for you. Run this command again when you're ready") - return - - self.wizard() - -# Start Labylib -labylib = Main() \ No newline at end of file diff --git a/animated-textures.py b/animated-textures.py index 92e64a9..860d356 100644 --- a/animated-textures.py +++ b/animated-textures.py @@ -5,13 +5,16 @@ from pathlib import Path # from labylib import Cape +# Don't forget to reflect in .gitignore if you change this +name = "animated-textures" + class Config: - f = ".animate-config.json" + textures = f"./{name}/" # Cosmetic textures path + f = f"./{name}/config.json" # JSON Config file + default = '{"PHPSESSID": "","cosmetics": {"cape": {"interval": "15","randomOrder": "False"}}}' # Default config pattern = "^[-,a-zA-Z0-9]{1,128}$" # PHPSESSID pattern - template = '{\n\t"PHPSESSID": "",\n\t"cosmetics": {\n\t\t"cape": {\n\t\t\t"interval": 15,\n\t\t\t"random": false\n\t\t}\n\t}\n}' - def __init__(self): self.config = None self.exists = True # Config file already exists @@ -38,12 +41,14 @@ class Config: f.write(json.dumps(self.config)) f.close() - # Create config file from template + # Create config file from default template def create(self): self.exists = False + Path(Config.textures).mkdir(parents=True,exist_ok=True) + f = open(Config.f,"w") - f.write(Config.template) + f.write(Config.default) f.close() # Load the config file from disk into memory @@ -55,6 +60,7 @@ class Config: f = open(Config.f,"r") self.config = json.load(f) f.close() + return True class Main: @@ -129,17 +135,20 @@ class Main: self.wizard() return - print("Labylib is running.. (type 'stop' to close Labylib)") + # TODO: Attach labylib hook here def init(self): - print("Labylib 0.0.1") + print("Labylib 0.0.1\n") if(self.config.exists and len(self.config.config["PHPSESSID"]) > 1): self.start() return + for cosmetic in self.config.config["cosmetics"]: + Path(Config.textures + cosmetic).mkdir(parents=True,exist_ok=True) + # Prompt if user wants to use guided setup - print("-- Welcome to Labylib --\nSince this is your first time here, would you like to walk through the setup process?\n") + print("-- Labylib Animated Textures --\nSince this is your first time here, would you like to walk through the setup process?\n") wizard = input("Start guided setup? 'y/n':[y] ") if(wizard == "n"): print(f"A config file '{Config.f}' has been created for you. Run this command again when you're ready") From f799d1d71461ac34baa9f6ea3be9d3e09c18fa27 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Sun, 15 Nov 2020 05:49:06 +0100 Subject: [PATCH 3/4] Completed request constructor Getting cryptic error message from endpoint "Minimum width and height exceeded. The minimum size is 22x17." Testing suggests it has something with the binary encoding of the included file to do. Needs investigation --- .gitignore | 3 +- 2.png | Bin 0 -> 239 bytes labylib/Cape.py | 97 +++++++++++++++++++++++++++++++ lib.py | 5 ++ animated-textures.py => start.py | 2 +- labylib/__init__.py => test.txt | 0 6 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 2.png create mode 100644 labylib/Cape.py create mode 100644 lib.py rename animated-textures.py => start.py (98%) rename labylib/__init__.py => test.txt (100%) diff --git a/.gitignore b/.gitignore index d3a3232..fc77936 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -animated-textures/* \ No newline at end of file +animated-textures/* +*__pycache__ \ No newline at end of file diff --git a/2.png b/2.png new file mode 100644 index 0000000000000000000000000000000000000000..5d92343e7e4c5ed96cfdac10a60c7295e0572783 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0y~yU`z&LVJ2pv$h^M(%|MDLz$e7jy};+o7X~J#U;qFA zPkm6f0w~T{666=m;PC858jv&5)5S5Q;?~>i8+jWHcw8O%J7)@>n4lsQ(xD~DyE8oM z*LCZ2*Dl_i7ykNj+$>2)waF)+2>#41jbl1D%FX42Xq{Rr>mdKI;Vst01eq(Pyhe` literal 0 HcmV?d00001 diff --git a/labylib/Cape.py b/labylib/Cape.py new file mode 100644 index 0000000..94931ac --- /dev/null +++ b/labylib/Cape.py @@ -0,0 +1,97 @@ +import requests +import hashlib +import time + +class BadRequestError(Exception): pass + +class Cape: + + endpoint = "https://www.labymod.net/page/php/cape.php" + + def __init__(self,cookie,img): + self.validate(cookie,img) + + self.body = "" # Initialize request body + self.cookies = dict(PHPSESSID = cookie) + self.boundary = self.boundary() + + 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": "multipart/form-data; boundary=" + self.boundary + } + + self.addFormData("cosmetic","cape") + self.addFormData("file",self.bOpen(img)) + self.closeFormData() + + # ----------------------------------- + + def validate(self,cookie,file): + return True + + # Generate boundary header from MD5-hash of current time + def boundary(self): + seed = str(time.time()) + md5 = hashlib.md5(seed.encode("utf-8")) + + boundary = "----WebKitFormBoundary" + md5.hexdigest() + return boundary + + # Open and return file binary as string + def bOpen(self,file): + f = open(file,"rb") + content = str(f.read()) + f.close() + + length = len(content) - 1 + content = content[2:length] + + return content + + # Append form-data to request body and boundary header + def addFormData(self,name,payload): + body = contentType = "" + eol = "\r\n" + + disposition = f'name="{name}"' + if(name == "file"): + contentType = "Content-Type: image/png" + eol + + # Use current epoch as filename. It has to be different from last request + filename = str(round(time.time())) + ".png" + disposition += f'; filename="{filename}"' + + body += f"--{self.boundary}" + eol # Init data header + body += f"Content-Disposition: form-data; {disposition}" + eol + body += contentType + eol + eol + body += payload + eol + + self.body += body + + # Last form-data has been set, add final post width for boundary header + def closeFormData(self): + self.body += f"--{self.boundary}--\r\n\r\n" + + # ----------------------------------- + + def update(self): + request = requests.post(Cape.endpoint, + headers = self.headers, + cookies = self.cookies, + data = self.body + ) + + if(request.text != "OK"): + raise BadRequestError(request.text) \ No newline at end of file diff --git a/lib.py b/lib.py new file mode 100644 index 0000000..9bfc8c8 --- /dev/null +++ b/lib.py @@ -0,0 +1,5 @@ +from labylib import Cape + +cape = Cape.Cape("76eppb9t0vg3saftu42vf1e223","2.png") +cape.update() +print(cape.body) \ No newline at end of file diff --git a/animated-textures.py b/start.py similarity index 98% rename from animated-textures.py rename to start.py index 860d356..0d16e6b 100644 --- a/animated-textures.py +++ b/start.py @@ -3,7 +3,7 @@ import json import importlib from pathlib import Path -# from labylib import Cape +from labylib import Cape # Don't forget to reflect in .gitignore if you change this name = "animated-textures" diff --git a/labylib/__init__.py b/test.txt similarity index 100% rename from labylib/__init__.py rename to test.txt From 566ccc4a545b3d1cb84a51768bfc69fe99202c4f Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Sun, 15 Nov 2020 15:05:38 +0100 Subject: [PATCH 4/4] Pre-Release 0.1.0 First proof of concept pre-release. --- .gitignore | 1 - 2.png | Bin 239 -> 0 bytes labylib/Cape.py | 53 ++++++++-------- lib.py | 5 -- start.py | 160 ------------------------------------------------ test.txt | 0 6 files changed, 27 insertions(+), 192 deletions(-) delete mode 100644 2.png delete mode 100644 lib.py delete mode 100644 start.py delete mode 100644 test.txt diff --git a/.gitignore b/.gitignore index fc77936..264daca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -animated-textures/* *__pycache__ \ No newline at end of file diff --git a/2.png b/2.png deleted file mode 100644 index 5d92343e7e4c5ed96cfdac10a60c7295e0572783..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 239 zcmeAS@N?(olHy`uVBq!ia0y~yU`z&LVJ2pv$h^M(%|MDLz$e7jy};+o7X~J#U;qFA zPkm6f0w~T{666=m;PC858jv&5)5S5Q;?~>i8+jWHcw8O%J7)@>n4lsQ(xD~DyE8oM z*LCZ2*Dl_i7ykNj+$>2)waF)+2>#41jbl1D%FX42Xq{Rr>mdKI;Vst01eq(Pyhe` diff --git a/labylib/Cape.py b/labylib/Cape.py index 94931ac..fcac83d 100644 --- a/labylib/Cape.py +++ b/labylib/Cape.py @@ -2,16 +2,16 @@ import requests import hashlib import time -class BadRequestError(Exception): pass +class RequestError(Exception): pass -class Cape: +class Texture: endpoint = "https://www.labymod.net/page/php/cape.php" def __init__(self,cookie,img): self.validate(cookie,img) - self.body = "" # Initialize request body + self.body = b"" # Initialize request body self.cookies = dict(PHPSESSID = cookie) self.boundary = self.boundary() @@ -32,9 +32,8 @@ class Cape: "Content-Type": "multipart/form-data; boundary=" + self.boundary } - self.addFormData("cosmetic","cape") - self.addFormData("file",self.bOpen(img)) - self.closeFormData() + self.appendBinaryFormData(b"cosmetic",b"cape") + self.appendBinaryFormData(b"file",self.bOpen(img)) # ----------------------------------- @@ -52,46 +51,48 @@ class Cape: # Open and return file binary as string def bOpen(self,file): f = open(file,"rb") - content = str(f.read()) + content = f.read() f.close() - length = len(content) - 1 - content = content[2:length] - return content # Append form-data to request body and boundary header - def addFormData(self,name,payload): - body = contentType = "" - eol = "\r\n" + def appendBinaryFormData(self,name,payload): + body = contentType = b"" + eol = b"\r\n" - disposition = f'name="{name}"' - if(name == "file"): - contentType = "Content-Type: image/png" + eol + disposition = b'name="' + name + b'"' + if(name == b"file"): + contentType = b"Content-Type: image/png" + eol # Use current epoch as filename. It has to be different from last request - filename = str(round(time.time())) + ".png" - disposition += f'; filename="{filename}"' + filename = str(round(time.time())) + ".png" + filename = filename.encode() + disposition += b'; filename="' + filename + b'"' - body += f"--{self.boundary}" + eol # Init data header - body += f"Content-Disposition: form-data; {disposition}" + eol - body += contentType + eol + eol + body += b"--" + self.boundary.encode() + eol # Init data header + body += b"Content-Disposition: form-data; " + disposition + eol + body += contentType + eol body += payload + eol self.body += body # Last form-data has been set, add final post width for boundary header - def closeFormData(self): - self.body += f"--{self.boundary}--\r\n\r\n" + def closeBinaryFormData(self): + self.body += b"--" + self.boundary.encode() + b"--\r\n\r\n" # ----------------------------------- def update(self): - request = requests.post(Cape.endpoint, + self.closeBinaryFormData() # Add final boundary header + + request = requests.post(Texture.endpoint, headers = self.headers, cookies = self.cookies, data = self.body ) - if(request.text != "OK"): - raise BadRequestError(request.text) \ No newline at end of file + # 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 diff --git a/lib.py b/lib.py deleted file mode 100644 index 9bfc8c8..0000000 --- a/lib.py +++ /dev/null @@ -1,5 +0,0 @@ -from labylib import Cape - -cape = Cape.Cape("76eppb9t0vg3saftu42vf1e223","2.png") -cape.update() -print(cape.body) \ No newline at end of file diff --git a/start.py b/start.py deleted file mode 100644 index 0d16e6b..0000000 --- a/start.py +++ /dev/null @@ -1,160 +0,0 @@ -import re -import json -import importlib -from pathlib import Path - -from labylib import Cape - -# Don't forget to reflect in .gitignore if you change this -name = "animated-textures" - -class Config: - - textures = f"./{name}/" # Cosmetic textures path - f = f"./{name}/config.json" # JSON Config file - default = '{"PHPSESSID": "","cosmetics": {"cape": {"interval": "15","randomOrder": "False"}}}' # Default config - pattern = "^[-,a-zA-Z0-9]{1,128}$" # PHPSESSID pattern - - def __init__(self): - self.config = None - self.exists = True # Config file already exists - self.load() - - # Example: getCosmetic("cape") - def getCosmetic(self,key): - return self.config["cosmetics"][key] - - # Example: setCosmetic("cape","interval",30) - def setCosmetic(self,cosmetic,key,value): - self.config["cosmetics"][cosmetic][key] = value - self.save() - - def setPHPSESSID(self,phpsessid): - self.config["PHPSESSID"] = phpsessid - self.save() - - # ----------------------------------------------------- - - # (Over)write config file - def save(self): - f = open(Config.f,"w") - f.write(json.dumps(self.config)) - f.close() - - # Create config file from default template - def create(self): - self.exists = False - - Path(Config.textures).mkdir(parents=True,exist_ok=True) - - f = open(Config.f,"w") - f.write(Config.default) - f.close() - - # Load the config file from disk into memory - def load(self): - # Create config file if absent - if(Path(Config.f).is_file() == False): - self.create() - - f = open(Config.f,"r") - self.config = json.load(f) - f.close() - - return True - -class Main: - - def __init__(self): - self.config = Config() - self.init() - - # Guided step-by-step setup - def wizard(self): - # +-----------+ - # | Labylib | - # +-----------+ - def box(string): - charset = ["+","-","|"] # Corner,borderX,borderY - string = f" {string} " # Text padding - - box = charset[0] - # Repeat 'borderX' char for string length - for x in string: - box += charset[1] - box += charset[0] - - # Stitch it all together - string = f"{charset[2]}{string}{charset[2]}" - string = f"{box}\n{string}\n{box}" - - return string - - msgDone = "Done! Closing Wizard" - - print(box("Labylib Setup Wizard")) - print("Make sure you read the README before you begin\n") - - self.config.setPHPSESSID(input("Paste your PHPSESSID here:\n")) - - advanced = input("\nDo you wish to modify the default cosmetic settings? 'y/n'[n]: ") - if(advanced != "y"): - print(box(msgDone)) - self.start() - return - - wizard = self.config.config["cosmetics"] - - # Iterate over all cosmetics in config - for cosmetic in wizard: - print(box("Cosmetic > " + cosmetic.capitalize())) - - # Iterate over every cosmetic setting - for key, default in wizard[cosmetic].items(): - value = input(f"Set value for '{key}'[{default}]: ") - # Ignore input if empty or data type doesn't match default - if(len(value) < 1): - print(f"Input error: Expected data type '{type(default)}'. Falling back to default") - value = default - - self.config.setCosmetic(cosmetic,key,value) - - print(box(msgDone)) - self.start() - - #for cosmetic in wizard: - - def start(self): - phpsessid = self.config.config["PHPSESSID"] - start = input(f"\nStart Labylib for PHPSESSID '{phpsessid}'? 'y/n/config'[y]: ") - - if(start == "n"): - return - - if(start == "config"): - self.wizard() - return - - # TODO: Attach labylib hook here - - def init(self): - print("Labylib 0.0.1\n") - - if(self.config.exists and len(self.config.config["PHPSESSID"]) > 1): - self.start() - return - - for cosmetic in self.config.config["cosmetics"]: - Path(Config.textures + cosmetic).mkdir(parents=True,exist_ok=True) - - # Prompt if user wants to use guided setup - print("-- Labylib Animated Textures --\nSince this is your first time here, would you like to walk through the setup process?\n") - wizard = input("Start guided setup? 'y/n':[y] ") - if(wizard == "n"): - print(f"A config file '{Config.f}' has been created for you. Run this command again when you're ready") - return - - self.wizard() - -# Start Labylib -labylib = Main() \ No newline at end of file diff --git a/test.txt b/test.txt deleted file mode 100644 index e69de29..0000000