diff --git a/sopel_modules/SpiceBot/Gif.py b/sopel_modules/SpiceBot/Gif.py index 2a725b9..ea9ff51 100644 --- a/sopel_modules/SpiceBot/Gif.py +++ b/sopel_modules/SpiceBot/Gif.py @@ -222,6 +222,9 @@ class BotGif(): url += str(self.valid_api[currentapi]['sfw']) # api key url += str(self.valid_api[currentapi]['key']) + str(self.valid_api[currentapi]['apikey']) + # additional parts + if "additional_url" in list(self.valid_api[currentapi].keys()): + url += str(self.valid_api[currentapi]['additional_url']) return url diff --git a/sopel_modules/SpiceBot/Prerun.py b/sopel_modules/SpiceBot/Prerun.py index d299f97..7a5e5c7 100644 --- a/sopel_modules/SpiceBot/Prerun.py +++ b/sopel_modules/SpiceBot/Prerun.py @@ -439,6 +439,9 @@ def trigger_cant_run(bot, trigger, botcom, message=None): def updatable_content(bot, botcom, trigger): # commands that can be updated + if "updates_enabled" not in list(botcom.dict["dict"][botcom.dict["responsekey"]].keys()): + botcom.dict["dict"][botcom.dict["responsekey"]]["updates_enabled"] = False + if botcom.dict["dict"][botcom.dict["responsekey"]]["updates_enabled"]: customresponses = [] if botcom.dict["dict"][botcom.dict["responsekey"]]["updates_enabled"] == "shared": @@ -462,6 +465,9 @@ def updatable_content(bot, botcom, trigger): def special_handling(botcom): botcom.dict["responsekey"] = "?default" + if "nonstockoptions" not in list(botcom.dict["dict"].keys()): + botcom.dict["dict"]["nonstockoptions"] = [] + # handling for special cases posscom = spicemanip(botcom.dict['args'], 1) if posscom.lower() in [command.lower() for command in botcom.dict["dict"]["nonstockoptions"]]: @@ -470,12 +476,25 @@ def special_handling(botcom): posscom = command botcom.dict["responsekey"] = posscom + botcom = dictkey_defaults(botcom) + if botcom.dict["responsekey"] != "?default": botcom.dict['args'] = spicemanip(botcom.dict['args'], '2+', 'list') return botcom +def dictkey_defaults(botcom): + botcom.dict["dict"]["hardcoded_channel_block"] = [] + if botcom.dict["responsekey"] not in list(botcom.dict["dict"].keys()): + botcom.dict["dict"][botcom.dict["responsekey"]] = {} + if "selection_allowed" not in list(botcom.dict["dict"][botcom.dict["responsekey"]].keys()): + botcom.dict["dict"][botcom.dict["responsekey"]]["selection_allowed"] = True + if "responses" not in list(botcom.dict["dict"][botcom.dict["responsekey"]].keys()): + botcom.dict["dict"][botcom.dict["responsekey"]]["responses"] = [] + return botcom + + def trigger_hyphen_args(botcom): hyphen_args = [] diff --git a/sopel_modules/SpiceBot/Read.py b/sopel_modules/SpiceBot/Read.py index 8014766..c69894c 100644 --- a/sopel_modules/SpiceBot/Read.py +++ b/sopel_modules/SpiceBot/Read.py @@ -240,11 +240,15 @@ class BotRead(): else: dict_from_file = {} - dict_from_file = self.command_defaults(dict_from_file) + # if len(list(dict_from_file.keys())): + # dict_from_file = self.command_defaults(dict_from_file) return dict_from_file def command_defaults(self, dict_from_file): + if "?default" not in list(dict_from_file.keys()): + dict_from_file["?default"] = {} + # the command must have an author if "author" not in list(dict_from_file.keys()): dict_from_file["author"] = "deathbybandaid" @@ -283,13 +287,25 @@ class BotRead(): # check that type is set, use cases will inherit this if not set if "type" not in list(dict_from_file.keys()): - dict_from_file["type"] = 'module' + dict_from_file["type"] = dict_from_file["foldername"] dict_from_file["nonstockoptions"] = ["?default"] for command in list(dict_from_file.keys()): if command not in prerun_shared.stockoptions: dict_from_file["nonstockoptions"].append(command) + ignorelist = [] + if dict_from_file["type"] == "SpiceBot_Gif": + ignorelist.extend(["url", "query", "limit", "id", "api_id", "key", "nsfw", "sfw", "sfw", "results", "cururl", "additional_url"]) + elif dict_from_file["type"] == "SpiceBot_Search": + ignorelist.extend(["url", "query", "additional_url"]) + elif dict_from_file["type"] == "SpiceBot_Sherlock": + ignorelist.extend(["url", "errorType", "errorMsg", "noPeriod", "errorUrl"]) + + for ignoreitem in ignorelist: + if ignoreitem in dict_from_file["nonstockoptions"]: + dict_from_file["nonstockoptions"].remove(ignoreitem) + for specialcase in dict_from_file["nonstockoptions"]: # All of the above need to be in the dict if not diff --git a/sopel_modules/SpiceBot/Search.py b/sopel_modules/SpiceBot/Search.py index 7e51827..6dfba82 100644 --- a/sopel_modules/SpiceBot/Search.py +++ b/sopel_modules/SpiceBot/Search.py @@ -5,10 +5,13 @@ from __future__ import unicode_literals, absolute_import, division, print_functi import requests import urllib from fake_useragent import UserAgent +import re from sopel.config.types import StaticSection, ValidatedAttribute from .Config import config as botconfig +from .Read import read as botread +from .Commands import commands as botcommands # TODO add a cache flush @@ -22,12 +25,25 @@ class Search(): def __init__(self): self.header = {'User-Agent': str(UserAgent().chrome)} self.setup_search() - self.cache = { - "info": {}, - "maps": {}, - "youtube": {}, - "spiceworks": {}, - } + self.dir_to_scan = botread.get_config_dirs("SpiceBot_Search") + valid_search_api_dict = botread.json_to_dict_simple(self.dir_to_scan, "Search API", "SpiceBot_Search") + self.valid_api = {} + + self.cache = {} + + for search_api in list(valid_search_api_dict.keys()): + + self.valid_api[search_api] = valid_search_api_dict[search_api] + self.valid_api[search_api]["apikey"] = None + self.valid_api[search_api]["cache"] = dict() + + self.valid_api[search_api]["comtype"] = "search_prefix" + self.valid_api[search_api]["validcoms"] = [self.valid_api[search_api]["filename"]] + botcommands.register(self.valid_api[search_api]) + + # check cache + if search_api not in list(self.cache.keys()): + self.cache[search_api] = dict() def setup_search(self): botconfig.define_section("SpiceBot_Search", SpiceBot_Search_MainSection, validate=False) @@ -36,15 +52,18 @@ class Search(): # list of defaults query_defaults = { - "query": None, - "query_type": "info", - "query_url": None + "query": '', + "query_type": "google", + "nsfw": False, } # set defaults if they don't exist for key in query_defaults: if key not in list(searchdict.keys()): searchdict[key] = query_defaults[key] + for key in list(self.valid_api[searchdict["query_type"]].keys()): + if key not in list(searchdict.keys()): + searchdict[key] = self.valid_api[searchdict["query_type"]][key] # Replace spaces in search query searchdict["searchquery"] = urllib.request.pathname2url(searchdict["query"]) @@ -56,28 +75,38 @@ class Search(): # check cache if searchdict["query_type"] not in list(self.cache.keys()): self.cache[searchdict["query_type"]] = dict() - if searchdict["query_type"] != "custom": - if searchdict["query"].lower() in self.cache[searchdict["query_type"]]: - return self.cache[searchdict["query_type"]][searchdict["query"]] - if searchdict["query_type"] == 'maps': - returnurl = self.search_maps_google(searchdict) - elif searchdict["query_type"] == 'youtube': - returnurl = self.search_youtube(searchdict) - elif searchdict["query_type"] == 'custom': - returnurl = self.search_info_custom(searchdict) - else: - returnurl = self.search_info_google(searchdict) + if searchdict["query"].lower() in self.cache[searchdict["query_type"]]: + return self.cache[searchdict["query_type"]][searchdict["query"]] - if returnurl and searchdict["query_type"] != 'custom': + searchdict["searchurl"] = self.search_url_assemble(searchdict) + returnurl = self.search_handler(searchdict) + + if returnurl: self.cache[searchdict["query_type"]][searchdict["query"].lower()] = str(returnurl) return returnurl - def search_info_custom(self, searchdict): - lookfor = searchdict["searchquery"] + def search_handler(self, searchdict): + if searchdict["query_type"] in ["urban"]: + return self.search_urban(searchdict) + else: + return self.search_url(searchdict) + + def search_url_assemble(self, searchdict): + # url base + url = str(searchdict["url"]) + # query + url += str(self.valid_api[searchdict["query_type"]]["query_param"]) + str(searchdict["query"]) + # nsfw search? TODO + # additional parts + if "additional_url" in list(self.valid_api[searchdict["query_type"]].keys()): + url += str(self.valid_api[searchdict["query_type"]]['additional_url']) + return url + + def search_url(self, searchdict): try: - var = requests.get(r'' + searchdict["query_url"] + lookfor, headers=self.header) + var = requests.get(searchdict["searchurl"], headers=self.header) except Exception as e: var = e var = None @@ -85,47 +114,17 @@ class Search(): return None return var.url - def search_info_google(self, searchdict, retry=False): - lookfor = searchdict["searchquery"] - if not botconfig.SpiceBot_Search.search_api or retry: + def search_urban(self, searchdict): + query = requests.get(searchdict["searchurl"]).json() + if query: try: - var = requests.get(r'http://www.google.com/search?q=' + lookfor + '&btnI', headers=self.header) + _definition = query['list'][0]['definition'].strip().replace(' ', ' ') + definition = re.sub(r"\[*\]*", "", _definition) + definition = re.findall('(\d\.[^\d]*)', definition) + return str(definition[0]) except Exception as e: - var = e - var = None - if not var or not var.url: + definition = e return None - return var.url - else: - return self.search_info_google(searchdict, retry=True) - - def search_maps_google(self, searchdict, retry=False): - lookfor = searchdict["searchquery"] - if not botconfig.SpiceBot_Search.search_api or retry: - try: - var = requests.get(r'http://www.google.com/maps/place/' + lookfor, headers=self.header) - except Exception as e: - var = e - var = None - if not var or not var.url: - return None - return var.url - else: - return self.search_maps_google(searchdict, retry=True) - - def search_youtube(self, searchdict, retry=False): - lookfor = searchdict["searchquery"] - if not botconfig.SpiceBot_Search.search_api or retry: - try: - var = requests.get(r'https://www.youtube.com/search?q=' + lookfor + '&btnI', headers=self.header) - except Exception as e: - var = e - var = None - if not var or not var.url: - return None - return var.url - else: - return self.search_youtube(searchdict, retry=True) search = Search() diff --git a/sopel_modules/SpiceBot_Configs/SpiceBot_DictComs/search/spiceworks.json b/sopel_modules/SpiceBot_Configs/SpiceBot_DictComs/search/spiceworks.json deleted file mode 100644 index 1fc801a..0000000 --- a/sopel_modules/SpiceBot_Configs/SpiceBot_DictComs/search/spiceworks.json +++ /dev/null @@ -1,8 +0,0 @@ -{ -"?default": { - "type": "search", - "responses": ["http://community.spiceworks.com/search?query="], - "blank_fail": ["https://www.spiceworks.com/"], - "search_fail": ["No Spiceworks forum posts found!"], - }, -} diff --git a/sopel_modules/SpiceBot_Configs/SpiceBot_Search/gmaps.json b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/gmaps.json new file mode 100644 index 0000000..6a75151 --- /dev/null +++ b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/gmaps.json @@ -0,0 +1,4 @@ +{ +"url": "http://www.google.com/maps/place/", +"query_param": '', +} diff --git a/sopel_modules/SpiceBot_Configs/SpiceBot_Search/google.json b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/google.json new file mode 100644 index 0000000..5d1b270 --- /dev/null +++ b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/google.json @@ -0,0 +1,5 @@ +{ +"url": "http://www.google.com/search?", +"query_param": 'q=', +"additional_url": "&btnI", +} diff --git a/sopel_modules/SpiceBot_Configs/SpiceBot_Search/spiceworks.json b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/spiceworks.json new file mode 100644 index 0000000..b69aafc --- /dev/null +++ b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/spiceworks.json @@ -0,0 +1,4 @@ +{ +"url": "http://community.spiceworks.com/search?", +"query_param": 'query=', +} diff --git a/sopel_modules/SpiceBot_Configs/SpiceBot_Search/urban.json b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/urban.json new file mode 100644 index 0000000..5640878 --- /dev/null +++ b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/urban.json @@ -0,0 +1,4 @@ +{ +"url": "http://api.urbandictionary.com/v0/define?", +"query_param": 'term=', +} diff --git a/sopel_modules/SpiceBot_Configs/SpiceBot_Search/youtube.json b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/youtube.json new file mode 100644 index 0000000..ff11913 --- /dev/null +++ b/sopel_modules/SpiceBot_Configs/SpiceBot_Search/youtube.json @@ -0,0 +1,5 @@ +{ +"url": "http://www.youtube.com/search?", +"query_param": 'q=', +"additional_url": "&btnI", +} diff --git a/sopel_modules/SpiceBot_Core_Commands/AI.py b/sopel_modules/SpiceBot_Core_Commands/AI.py index 3dbf8c8..3ba0e6a 100644 --- a/sopel_modules/SpiceBot_Core_Commands/AI.py +++ b/sopel_modules/SpiceBot_Core_Commands/AI.py @@ -176,7 +176,7 @@ def bot_command_rule_ai(bot, trigger): if searchterm: if trigger_args[0].lower() == "where": searchdict = { - "type": "maps", + "type": "gmaps", "query": searchterm, } searchreturn = SpiceBot.search.search(searchdict) @@ -186,12 +186,11 @@ def bot_command_rule_ai(bot, trigger): } searchreturn = SpiceBot.search.search(searchdict) if not searchreturn: - bot.osd('I cannot find anything about that') + searchreturn = 'I cannot find anything about that' + if trigger_args[0].lower() == "where": + bot.osd(["[Location search for " + str(searchterm) + "]", str(searchreturn)]) else: - if trigger_args[0].lower() == "where": - bot.osd(["[Location search for " + str(searchterm) + "]", str(searchreturn)]) - else: - bot.osd(["[Information search for '" + str(searchterm) + "']", str(searchreturn)]) + bot.osd(["[Information search for '" + str(searchterm) + "']", str(searchreturn)]) return elif trigger_args[0].lower() in ["can", "have"] and trigger_args[1].lower() in ["you"] and trigger_args[2].lower() in ["see", "seen"]: diff --git a/sopel_modules/SpiceBot_Core_Commands/DictComs.py b/sopel_modules/SpiceBot_Core_Commands/DictComs.py index dbad838..f0dba90 100644 --- a/sopel_modules/SpiceBot_Core_Commands/DictComs.py +++ b/sopel_modules/SpiceBot_Core_Commands/DictComs.py @@ -298,12 +298,11 @@ def bot_dictcom_search(bot, trigger, botcom): botcom.dict["dict"][botcom.dict["responsekey"]]["responses"] = botcom.dict["dict"][botcom.dict["responsekey"]]["blank_fail"] return bot_dictcom_reply_shared(bot, trigger, botcom) - searchurl = botcom.dict["dict"][botcom.dict["responsekey"]]["responses"][0] + query_type = botcom.dict["dict"][botcom.dict["responsekey"]]["responses"][0] searchterm = botcom.dict["completestring"] searchdict = { - "query_type": "custom", - "query_url": searchurl, + "query_type": query_type, "query": searchterm, } @@ -311,12 +310,12 @@ def bot_dictcom_search(bot, trigger, botcom): if not searchreturn: botcom.dict["success"] = False - failmessage = ['I cannot find anything about that'] + failmessage = ["[" + searchdict["query_type"].title() + " search for '" + str(searchterm) + "']" + 'I cannot find anything about that'] if botcom.dict["dict"][botcom.dict["responsekey"]]["search_fail"]: failmessage = botcom.dict["dict"][botcom.dict["responsekey"]]["search_fail"] botcom.dict["dict"][botcom.dict["responsekey"]]["responses"] = failmessage else: - botcom.dict["dict"][botcom.dict["responsekey"]]["responses"] = ["[Search for '" + str(searchterm) + "'] " + str(searchreturn)] + botcom.dict["dict"][botcom.dict["responsekey"]]["responses"] = ["[" + searchdict["query_type"].title() + " search for '" + str(searchterm) + "'] " + str(searchreturn)] botcom.dict["specified"] = False bot_dictcom_reply_shared(bot, trigger, botcom) diff --git a/sopel_modules/SpiceBot_Core_Tools/Search.py b/sopel_modules/SpiceBot_Core_Tools/Search.py index 42419ad..e9233a5 100644 --- a/sopel_modules/SpiceBot_Core_Tools/Search.py +++ b/sopel_modules/SpiceBot_Core_Tools/Search.py @@ -11,7 +11,7 @@ import sopel_modules.SpiceBot as SpiceBot @SpiceBot.prerun('module') -@sopel.module.commands('search', 'find', 'google', 'lookup') +@sopel.module.commands('search', 'find', 'googled', 'lookup') def search_main(bot, trigger, botcom): searchterm = spicemanip(botcom.dict['args'], 0) or None @@ -25,11 +25,35 @@ def search_main(bot, trigger, botcom): searchreturn = SpiceBot.search.search(searchdict) if not searchreturn: - SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], 'I cannot find anything about that') + SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], "[Information search for '" + str(searchterm) + "'] " + 'I cannot find anything about that') else: bot.osd(["[Information search for '" + str(searchterm) + "']", str(searchreturn)]) +@SpiceBot.prerun('module', "search_prefix") +@sopel.module.commands('(.*)') +def gifapi_triggers(bot, trigger, botcom): + + if botcom.dict['com'] not in list(SpiceBot.search.valid_api.keys()): + return + + searchterm = spicemanip(botcom.dict['args'], 0) or None + if not searchterm: + SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], "Not sure what you want me to look for.") + return + + searchdict = { + "query": searchterm, + "query_type": botcom.dict["realcom"], + } + + searchreturn = SpiceBot.search.search(searchdict) + if not searchreturn: + SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], "[" + botcom.dict["realcom"].title() + " search for '" + str(searchterm) + "'] " + 'I cannot find anything about that') + else: + bot.osd(["[" + botcom.dict["realcom"].title() + " search for '" + str(searchterm) + "']", str(searchreturn)]) + + @SpiceBot.prerun('module') @sopel.module.commands("where", "whereis") def search_where(bot, trigger, botcom): @@ -40,12 +64,12 @@ def search_where(bot, trigger, botcom): return searchdict = { "query": searchterm, - "query_type": "maps", + "query_type": "gmaps", } searchreturn = SpiceBot.search.search(searchdict) if not searchreturn: - SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], 'I cannot find anything about that') + SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], "[Location search for " + str(searchterm) + "] " + 'I cannot find anything about that') else: bot.osd(["[Location search for " + str(searchterm) + "]", str(searchreturn)]) @@ -64,13 +88,13 @@ def search_what(bot, trigger, botcom): searchreturn = SpiceBot.search.search(searchdict) if not searchreturn: - SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], 'I cannot find anything about that') + SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], "[Information search for '" + str(searchterm) + "'] " + 'I cannot find anything about that') else: bot.osd(["[Information search for '" + str(searchterm) + "']", str(searchreturn)]) @SpiceBot.prerun('module') -@sopel.module.commands("youtube", "video") +@sopel.module.commands("youtubes", "video") def search_video(bot, trigger, botcom): searchterm = spicemanip(botcom.dict['args'], 0) or None @@ -84,6 +108,6 @@ def search_video(bot, trigger, botcom): searchreturn = SpiceBot.search.search(searchdict) if not searchreturn: - SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], 'I cannot find anything about that') + SpiceBot.messagelog.messagelog_error(botcom.dict["log_id"], "[Youtube search for '" + str(searchterm) + "'] " + 'I cannot find anything about that') else: bot.osd(["[Youtube search for '" + str(searchterm) + "']", str(searchreturn)])