### # Copyright (c) 2013, spline # Copyright (c) 2020, oddluck # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions, and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the author of this software nor the name of # contributors to this software may be used to endorse or promote products # derived from this software without specific prior written consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ### from __future__ import unicode_literals # my libs import json import re # supybot libs import supybot.utils as utils from supybot.commands import * import supybot.plugins as plugins import supybot.ircutils as ircutils import supybot.callbacks as callbacks from supybot.i18n import PluginInternationalization, internationalizeDocstring _ = PluginInternationalization("UrbanDictionary") @internationalizeDocstring class UrbanDictionary(callbacks.Plugin): """Add the help for "@plugin help UrbanDictionary" here This should describe *how* to use this plugin.""" threaded = True ###################### # INTERNAL FUNCTIONS # ###################### def _red(self, string): """return a red string.""" return ircutils.mircColor(string, "red") def _bu(self, string): """bold and underline string.""" return ircutils.bold(ircutils.underline(string)) def cleanjson(self, s): """clean up json and return.""" s = s.replace("\n", "") s = s.replace("\r", "") s = s.replace("\t", "") s = s.strip() # return return s #################### # PUBLIC FUNCTIONS # #################### def urbandictionary(self, irc, msg, args, optlist, optterm): """[--disableexamples | --showvotes | --num # | --showtags] Fetches definition for on UrbanDictionary.com Use --disableexamples to not display examples. Use --showvotes to show votes [default: off] Use --num # to limit the number of definitions. [default:10] Use --showtags to display tags (if available) """ # default args for output. can manip via --getopts. args = { "showExamples": True, "numberOfDefinitions": self.registryValue("maxNumberOfDefinitions"), "showVotes": False, "showTags": False, } # optlist to change args. if optlist: for (key, value) in optlist: if key == "disableexamples": args["showExamples"] = False if key == "showvotes": args["showVotes"] = True if key == "showtags": args["showTags"] = True if key == "num": # if number is >, default to config var. if 0 <= value <= self.registryValue("maxNumberOfDefinitions"): args["numberOfDefinitions"] = value # build and fetch url. url = "http://api.urbandictionary.com/v0/define?term=%s" % utils.web.urlquote( optterm ) try: html = utils.web.getUrl(url) except utils.web.Error as e: self.log.error("ERROR opening {0} message: {1}".format(url, e)) irc.reply("ERROR: could not open {0} message: {1}".format(url, e)) return # try parsing json. # irc.reply("{0}".format(self._repairjson(html.decode('utf-8')))) try: # jsondata = self._repairjson(html.decode('utf-8')) # decode utf-8. fix \r\n that ud puts in below. jsondata = html.decode() jsondata = json.loads(jsondata) # odds chars in UD. except Exception as e: self.log.error("Error parsing JSON from UD: {0}".format(e)) irc.reply("ERROR: Failed to parse json data. Check logs for error") return # process json. results = jsondata.get("result_type") # exact, no_results, fulltext . if not results: # assume exact i guess... results = "exact" definitions = jsondata.get("list") # prep output now depending on results. if results == "exact": # we did not find anything. outdefs = [] for i in definitions[ 0 : args["numberOfDefinitions"] ]: # iterate through each def. # clean these up. definition = self.cleanjson( "".join(i["definition"]) ) # .encode('utf-8') example = self.cleanjson("".join(i["example"])) # now add outputstring = "{0}".format(definition) # default string. if args["showExamples"]: # show examples? outputstring += " {0} {1} {2}".format( self._bu("[ex:]"), example, self._bu("[/ex]") ) if args["showVotes"]: # show votes? outputstring += " (+{0}/-{1})".format( i["thumbs_up"], i["thumbs_down"] ) outdefs.append(outputstring) # add to our list. output = " | ".join( [item for item in outdefs] ) # create string with everything. elif results == "fulltext": # not direct. yields related terms. output = " | ".join( sorted(set([item["word"] for item in definitions])) ) # sorted, unique words. # output time. if results == "no_results" or len(definitions) == 0: # NOTHING FOUND. irc.reply("ERROR: '{0}' not defined on UrbanDictionary.".format(optterm)) return else: # we have definitions, so we're gonna output. # check if we should add tags. if args["showTags"]: # display tags. tags = jsondata.get("tags") if tags: # we have tags. add it to optterm. tags = " | ".join([i for i in tags]) else: tags = False else: tags = False # now lets output. if self.registryValue("disableANSI"): # disable formatting. if tags: irc.reply( "{0} :: {1} :: {2}".format( optterm, tags, ircutils.stripFormatting(output) ) ) else: irc.reply( "{0} :: {1}".format(optterm, ircutils.stripFormatting(output)) ) else: # colors. if tags: irc.reply( "{0} :: {1} :: {2}".format(self._red(optterm), tags, output) ) else: irc.reply("{0} :: {1}".format(self._red(optterm), output)) urbandictionary = wrap( urbandictionary, [ getopts( {"showtags": "", "showvotes": "", "num": "int", "disableexamples": ""} ), "text", ], ) Class = UrbanDictionary # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=250: