diff --git a/__pycache__/jokeapi.cpython-39.pyc b/__pycache__/jokeapi.cpython-39.pyc new file mode 100644 index 0000000..7a77ae2 Binary files /dev/null and b/__pycache__/jokeapi.cpython-39.pyc differ diff --git a/jokeapi.py b/jokeapi.py new file mode 100644 index 0000000..e7f8a59 --- /dev/null +++ b/jokeapi.py @@ -0,0 +1,292 @@ +import urllib3 +import urllib +import urllib.request +import simplejson as json +import re + + +class CategoryError(Exception): + pass + + +class BlacklistError(Exception): + pass + + +class ResponseTypeError(Exception): + pass + + +class JokeTypeError(Exception): + pass + + +class Jokes: + def __init__(self): + self.http = urllib3.PoolManager() + self.info = self.http.request("GET", "https://sv443.net/jokeapi/v2/info") + self.info = json.loads(self.info.data.decode("utf-8"))["jokes"] + + def build_request( + self, + category=[], + blacklist=[], + response_format="json", + joke_type="Any", + search_string="", + id_range=[], + amount=1, + safe_mode=False, + lang="en", + ): + r = "https://sv443.net/jokeapi/v2/joke/" + + if len(category): + for c in category: + if not c.title() in self.info["categories"]: + raise CategoryError( + f'''Invalid category selected. + You selected {c}. + Available categories are: + {""" + """.join(self.info["categories"])} + Leave blank for any.''' + ) + + cats = ",".join(category) + else: + cats = "Any" + + if type(blacklist) in [list, tuple]: + if len(blacklist) > 0: + for b in blacklist: + if b not in self.info["flags"]: + raise BlacklistError( + f''' + You have blacklisted flags which are not available. + Available flags are: + {""" + """.join(self.info["flags"])} + ''' + ) + return + blacklistFlags = ",".join(blacklist) + else: + blacklistFlags = None + else: + raise BlacklistError(f"""blacklist must be a list or tuple.""") + + if response_format not in ["json", "xml", "yaml", "txt"]: + raise ResponseTypeError( + "Response format must be either json, xml, txt or yaml." + ) + if joke_type: + if joke_type not in ["single", "twopart", "Any"]: + raise JokeTypeError( + """Invalid joke type. + Available options are "single" or "twopart".""" + ) + return + else: + joke_type = "Any" + + if search_string: + if not isinstance(search_string, str): + raise ValueError("search_string must be a string.") + return + else: + search_string = urllib.parse.quote(search_string) + range_limit = self.info["totalCount"] + + if len(id_range) and (id_range[1] - id_range[0] > range_limit): + raise ValueError( + "id_range must be no longer than 2 items, \ + id_range[0] must be greater than or equal to 0 and \ + id_range[1] must be less than or equal to {range_limit-1}." + ) + + if amount > 10: + raise ValueError( + f"amount parameter must be no greater than 10. \ + you passed {amount}." + ) + + r += cats + + r += f"?format={response_format}" + + if blacklistFlags: + r += f"&blacklistFlags={blacklistFlags}" + + r += f"&type={joke_type}" + + if search_string: + r += f"&contains={search_string}" + if id_range: + r += f"i&dRange={id_range[0]}-{id_range[1]}" + if amount > 10: + raise ValueError( + f"amount parameter must be no greater than 10. you passed {amount}." + ) + r += f"&amount={amount}" + + r += f"&lang={lang}" + + r += f"{'&safe-mode'*safe_mode}" + + return r + + def send_request( + self, request, response_format, return_headers, auth_token, user_agent + ): + returns = [] + + if auth_token: + r = self.http.request( + "GET", + request, + headers={ + "Authorization": str(auth_token), + "user-agent": str(user_agent), + "accept-encoding": "gzip", + }, + ) + else: + r = self.http.request( + "GET", + request, + headers={"user-agent": str(user_agent), "accept-encoding": "gzip"}, + ) + + data = r.data.decode("utf-8") + + if response_format == "json": + try: + data = json.loads(data) + except: + print(data) + raise + else: + if ( + len( + " ".join(re.split("error", data.lower())[0:][1:]) + .replace("<", "") + .replace("/", "") + .replace(" ", "") + .replace(":", "") + .replace(">", "") + ) + == 4 + ): + raise Exception( + f"API returned an error. \ + Full response: \n\n {data}" + ) + + headers = ( + str(r.headers) + .replace(r"\n", "") + .replace("\n", "") + .replace(r"\\", "") + .replace(r"\'", "")[15:-1] + ) + + returns.append(data) + if return_headers: + returns.append(headers) + + if auth_token: + returns.append( + {"Token-Valid": bool(int(re.split(r"Token-Valid", headers)[1][4]))} + ) + + if len(returns) > 1: + return returns + return returns[0] + + def get_joke( + self, + category=[], + blacklist=[], + response_format="json", + joke_type="Any", + search_string="", + id_range=[], + amount=1, + safe_mode=False, + lang="en", + auth_token=None, + user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) \ + Gecko/20100101 Firefox/77.0", + return_headers=False, + ): + r = self.build_request( + category, + blacklist, + response_format, + joke_type, + search_string, + id_range, + amount, + safe_mode, + lang, + ) + + response = self.send_request( + r, response_format, return_headers, auth_token, user_agent + ) + return response + + def submit_joke(self, category, joke, flags, lang="en", dry_run=False): + request = {"formatVersion": 3} + + if category not in self.info["categories"]: + raise CategoryError( + f'''Invalid category selected. + You selected {category}. + Available categories are: + {""" + """.join(self.info["categories"])}''' + ) + request["category"] = category + + if type(joke) in [list, tuple]: + if len(joke) > 1: + request["type"] = "twopart" + request["setup"] = joke[0] + request["delivery"] = joke[1] + else: + request["type"] = "single" + request["joke"] = joke[0] + else: + request["type"] = "single" + request["joke"] = joke + + for key in flags.keys(): + if key not in self.info["flags"]: + raise BlacklistError( + f''' + You have blacklisted flags which are not available. + Available flags are: + {""" + """.join(self.info["flags"])} + ''' + ) + request["flags"] = flags + request["lang"] = lang + + data = str(request).replace("'", '"') + data = data.replace(": True", ": true").replace(": False", ": false") + data = data.encode("ascii") + url = f"https://sv443.net/jokeapi/v2/submit{'?dry-run'*dry_run}" + + try: + response = urllib.request.urlopen(url, data=data) + data = response.getcode() + + return data + except urllib.error.HTTPError as e: + body = e.read().decode() # Read the body of the error response + + _json = json.loads(body) + return _json diff --git a/lol.py b/lol.py new file mode 100644 index 0000000..f21c657 --- /dev/null +++ b/lol.py @@ -0,0 +1,10 @@ +from jokeapi import Jokes # Import the Jokes class + +j = Jokes() # Initialise the class +joke = j.get_joke(category=['programming', 'dark']) # Retrieve a random joke +if joke["type"] == "single": # Print the joke + print(joke["joke"]) +else: + print(joke["setup"]) + print(joke["delivery"]) +