diff --git a/.gitignore b/.gitignore index ad92649..24d57a8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ utils/__pycache__/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] +env/ +*.pyc # C extensions *.so diff --git a/.vscode/.ropeproject/config.py b/.vscode/.ropeproject/config.py deleted file mode 100644 index dee2d1a..0000000 --- a/.vscode/.ropeproject/config.py +++ /dev/null @@ -1,114 +0,0 @@ -# The default ``config.py`` -# flake8: noqa - - -def set_prefs(prefs): - """This function is called before opening the project""" - - # Specify which files and folders to ignore in the project. - # Changes to ignored resources are not added to the history and - # VCSs. Also they are not returned in `Project.get_files()`. - # Note that ``?`` and ``*`` match all characters but slashes. - # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' - # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' - # '.svn': matches 'pkg/.svn' and all of its children - # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' - # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' - prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', - '.hg', '.svn', '_svn', '.git', '.tox'] - - # Specifies which files should be considered python files. It is - # useful when you have scripts inside your project. Only files - # ending with ``.py`` are considered to be python files by - # default. - # prefs['python_files'] = ['*.py'] - - # Custom source folders: By default rope searches the project - # for finding source folders (folders that should be searched - # for finding modules). You can add paths to that list. Note - # that rope guesses project source folders correctly most of the - # time; use this if you have any problems. - # The folders should be relative to project root and use '/' for - # separating folders regardless of the platform rope is running on. - # 'src/my_source_folder' for instance. - # prefs.add('source_folders', 'src') - - # You can extend python path for looking up modules - # prefs.add('python_path', '~/python/') - - # Should rope save object information or not. - prefs['save_objectdb'] = True - prefs['compress_objectdb'] = False - - # If `True`, rope analyzes each module when it is being saved. - prefs['automatic_soa'] = True - # The depth of calls to follow in static object analysis - prefs['soa_followed_calls'] = 0 - - # If `False` when running modules or unit tests "dynamic object - # analysis" is turned off. This makes them much faster. - prefs['perform_doa'] = True - - # Rope can check the validity of its object DB when running. - prefs['validate_objectdb'] = True - - # How many undos to hold? - prefs['max_history_items'] = 32 - - # Shows whether to save history across sessions. - prefs['save_history'] = True - prefs['compress_history'] = False - - # Set the number spaces used for indenting. According to - # :PEP:`8`, it is best to use 4 spaces. Since most of rope's - # unit-tests use 4 spaces it is more reliable, too. - prefs['indent_size'] = 4 - - # Builtin and c-extension modules that are allowed to be imported - # and inspected by rope. - prefs['extension_modules'] = [] - - # Add all standard c-extensions to extension_modules list. - prefs['import_dynload_stdmods'] = True - - # If `True` modules with syntax errors are considered to be empty. - # The default value is `False`; When `False` syntax errors raise - # `rope.base.exceptions.ModuleSyntaxError` exception. - prefs['ignore_syntax_errors'] = False - - # If `True`, rope ignores unresolvable imports. Otherwise, they - # appear in the importing namespace. - prefs['ignore_bad_imports'] = False - - # If `True`, rope will insert new module imports as - # `from import ` by default. - prefs['prefer_module_from_imports'] = False - - # If `True`, rope will transform a comma list of imports into - # multiple separate import statements when organizing - # imports. - prefs['split_imports'] = False - - # If `True`, rope will remove all top-level import statements and - # reinsert them at the top of the module when making changes. - prefs['pull_imports_to_top'] = True - - # If `True`, rope will sort imports alphabetically by module name instead - # of alphabetically by import statement, with from imports after normal - # imports. - prefs['sort_imports_alphabetically'] = False - - # Location of implementation of - # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general - # case, you don't have to change this value, unless you're an rope expert. - # Change this value to inject you own implementations of interfaces - # listed in module rope.base.oi.type_hinting.providers.interfaces - # For example, you can add you own providers for Django Models, or disable - # the search type-hinting in a class hierarchy, etc. - prefs['type_hinting_factory'] = ( - 'rope.base.oi.type_hinting.factory.default_type_hinting_factory') - - -def project_opened(project): - """This function is called after opening the project""" - # Do whatever you like here! diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..21824c5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "env\\Scripts\\python3.8.exe" +} \ No newline at end of file diff --git a/config-example.json b/config-example.json index d01e716..19a98c2 100644 --- a/config-example.json +++ b/config-example.json @@ -1,43 +1,43 @@ { - "VERSION": "1.9 testing", - "DESCRIPTION": "a minimalist search utility bot for discord, designed by taciturasa.", - "REPO": "https://github.com/taciturasa/searchbot-discord", - "SERVER": "https://discord.gg/4BpReNV", - "TOKEN": "", - "CACHE": false, - "PREFIX": ["search!"], - - "MAINTENANCE": false, - "CASE_INSENSITIVE": true, - "PREFIXLESS_DMS": true, - "MENTION_ASSIST": true, - "CUSTOM_HELP": true, + "VERSION": "1.9 testing", + "DESCRIPTION": "a minimalist search utility bot for discord, designed by taciturasa.", + "REPO": "https://github.com/taciturasa/searchbot-discord", + "SERVER": "https://discord.gg/4BpReNV", + "TOKEN": "", + "CACHE": false, + "PREFIX": ["search!"], - "PERMS": 378944, - "BLOCKED": [], - - "BOTLISTS": { - "DBL": "", - "DBOTS": "", - "BOD": "", - "DBLCOM": "", - "BLSPACE": "", - "TABFT_LINK": "", - "DAD": "" - }, - - "HOOKS": { - "INFO_HOOK": "", - "WARN_HOOK": "", - "ERROR_HOOK": "", - "DEBUG_HOOK": "" - }, - - "RETHINK": { - "DB": "", - "USERNAME": "", - "PASSWORD": "", - "HOST": "", - "PORT": null - } -} \ No newline at end of file + "MAINTENANCE": false, + "CASE_INSENSITIVE": true, + "PREFIXLESS_DMS": true, + "MENTION_ASSIST": true, + "CUSTOM_HELP": true, + + "PERMS": 378944, + "BLOCKED": [], + + "BOTLISTS": { + "DBL": "", + "DBOTS": "", + "BOD": "", + "DBLCOM": "", + "BLSPACE": "", + "TABFT_LINK": "", + "DAD": "" + }, + + "HOOKS": { + "INFO_HOOK": "", + "WARN_HOOK": "", + "ERROR_HOOK": "", + "DEBUG_HOOK": "" + }, + + "RETHINK": { + "DB": "", + "USERNAME": "", + "PASSWORD": "", + "HOST": "", + "PORT": null + } + } \ No newline at end of file diff --git a/extensions/__pycache__/core.cpython-38.pyc b/extensions/__pycache__/core.cpython-38.pyc deleted file mode 100644 index 010de0f..0000000 Binary files a/extensions/__pycache__/core.cpython-38.pyc and /dev/null differ diff --git a/extensions/search.py b/extensions/search.py index 2566f47..cdfa498 100644 --- a/extensions/search.py +++ b/extensions/search.py @@ -9,6 +9,7 @@ import discord from discord.ext import commands import aiohttp import random +from urllib import parse import sys from typing import List @@ -29,7 +30,6 @@ class Search(commands.Cog): with open('searxes.txt') as f: self.instances = f.read().split('\n') - async def _search_logic(self, query: str, is_nsfw: bool = False, category: str = None) -> str: """Provides search logic for all search commands.""" @@ -280,6 +280,178 @@ class Search(commands.Cog): ) await ctx.send(msg) + @commands.command(aliases=['urban', 'ud']) + async def urbandictionary(self, ctx, *, query: str): + """Pull data from Urban Dictionary.""" + + # Handling + async with ctx.typing(): + number = 1 + if " | " in query: + query, number = query.rsplit(" | ", 1) + search = parse.quote(query) + async with aiohttp.ClientSession() as session: + async with session.get(f"http://api.urbandictionary.com/v0/define?term={search}") as resp: + resp = await resp.json() + if not resp["list"]: + await ctx.send(f"`{query}`` couldn't be found on Urban Dictionary.") + else: + try: + top_result = resp["list"][int(number) - 1] + embed = discord.Embed(title=top_result["word"], description=top_result["definition"][0:425] + "...", + url=top_result["permalink"], color=ctx.author.color) + if top_result["example"]: + embed.add_field(name="Example:", + value=top_result["example"][0:100] + "...", inline=False) + embed.add_field(name="👍", value = top_result["thumbs_up"]) + embed.add_field(name="👎", value = top_result["thumbs_down"]) + + + embed.set_author(name=top_result["author"], + icon_url="https://apprecs.org/gp/images/app-icons/300/2f/info.tuohuang.urbandict.jpg") + number = str(int(number) + 1) + embed.set_footer(text=str(len( + resp["list"])) + f" results were found. To see a different result, use {ctx.prefix}ud {query} | {number}.") + try: + + await ctx.send(f"**{top_result['word']}** - <{top_result['permalink']}>", embed=embed) + + except Exception as e: + await ctx.send(top_result["definition"]) + except Exception as e: + print(e) + + @commands.command() + async def anime(self, ctx, *, query: str): + """Lookup anime information online, uses the public API.""" + base = "https://kitsu.io/api/edge/" + # Handling + async with ctx.typing(): + async with aiohttp.ClientSession() as session: + async with session.get(base + "anime", params={"filter[text]": query}) as resp: + resp = await resp.json() + resp = resp['data'] + if not resp: + return await ctx.send("The requested anime coudn't be found") + + anime = resp[0] + title = f'{anime["attributes"]["canonicalTitle"]}' + anime_id = anime["id"] + url = f"https://kitsu.io/anime/{anime_id}" + thing = '' if not anime['attributes'][ + 'endDate'] else f' to {anime["attributes"]["endDate"]}' + + embed = discord.Embed( + title=f"{title}", color=ctx.author.color, url=url) + embed.description = anime["attributes"]["synopsis"][0:425] + "..." + embed.add_field(name="Average Rating", + value=anime["attributes"]["averageRating"]) + embed.add_field(name="Popularity Rank", + value=anime["attributes"]["popularityRank"]) + embed.add_field(name="Age Rating", + value=anime["attributes"]["ageRating"]) + embed.add_field( + name="Status", value=anime["attributes"]["status"]) + + embed.add_field( + name="Aired", value=f"{anime['attributes']['startDate']}{thing}") + embed.add_field(name="Episodes", + value=anime['attributes']["episodeCount"]) + embed.add_field( + name="Type", value=anime['attributes']["showType"]) + embed.set_thumbnail( + url=anime['attributes']["posterImage"]["original"]) + embed.set_footer( + text=f"Requested by {ctx.author.name} | Powered by kitsu.io", icon_url=ctx.author.avatar_url_as(format="png")) + try: + + await ctx.send(f"**{title}** - <{url}>", embed=embed) + + except Exception as e: + + aired = f"{anime['attributes']['startDate']}{thing}" + template = f""" +url: {url} +Title: {title} +Average Rating: {anime["attributes"]["averageRating"]} +Popularity Rank: {anime["attributes"]["popularityRank"]} +Age Rating: {anime["attributes"]["ageRating"]} +Status: {anime["attributes"]["status"]} +Aired: {aired} +Type: {anime['attributes']["showType"]} + + +Powered by kitsu.io""" + await ctx.send(template) + + await session.close() + + @commands.command() + async def manga(self, ctx, *, query: str): + """Lookup manga information online, uses the public API.""" + base = "https://kitsu.io/api/edge/" + # Handling + async with ctx.typing(): + async with aiohttp.ClientSession() as session: + async with session.get(base + "manga", params={"filter[text]": query}) as resp: + resp = await resp.json() + resp = resp['data'] + if not resp: + return await ctx.send("The requested manga coudn't be found") + + manga = resp[0] + title = f'{manga["attributes"]["canonicalTitle"]}' + manga_id = manga["id"] + url = f"https://kitsu.io/manga/{manga_id}" + + embed = discord.Embed( + title=f"{title}", color=ctx.author.color, url=url) + embed.description = manga["attributes"]["synopsis"][0:425] + "..." + if manga["attributes"]["averageRating"]: + embed.add_field(name="Average Rating", + value=manga["attributes"]["averageRating"]) + embed.add_field(name="Popularity Rank", + value=manga["attributes"]["popularityRank"]) + if manga["attributes"]["ageRating"]: + embed.add_field(name="Age Rating", + value=manga["attributes"]["ageRating"]) + embed.add_field( + name="Status", value=manga["attributes"]["status"]) + thing = '' if not manga['attributes'][ + 'endDate'] else f' to {manga["attributes"]["endDate"]}' + embed.add_field( + name="Published", value=f"{manga['attributes']['startDate']}{thing}") + if manga['attributes']['chapterCount']: + embed.add_field(name="Chapters", + value=manga['attributes']["chapterCount"]) + embed.add_field( + name="Type", value=manga['attributes']["mangaType"]) + embed.set_thumbnail( + url=manga['attributes']["posterImage"]["original"]) + + try: + + await ctx.send(f"**{title}** - <{url}>", embed=embed) + + except Exception as e: + + aired = f"{manga['attributes']['startDate']}{thing}" + template = f""" +url: {url} +Title: {title} +Average Rating: {manga["attributes"]["averageRating"]} +Popularity Rank: {manga["attributes"]["popularityRank"]} +Age Rating: {manga["attributes"]["ageRating"]} +Status: {manga["attributes"]["status"]} +Aired: {aired} +Type: {manga['attributes']["showType"]} + + +Powered by kitsu.io""" + await ctx.send(template) + + await session.close() + @commands.command() @commands.is_owner() async def rejson(self, ctx): @@ -332,7 +504,6 @@ class Search(commands.Cog): name="Search Results" ) - # Sends result await ctx.send(msg) diff --git a/extensions/utils/logging.py b/extensions/utils/logging.py index b0b8d23..de531a9 100644 --- a/extensions/utils/logging.py +++ b/extensions/utils/logging.py @@ -129,7 +129,7 @@ class Logging(): async def error(self, error: Exception, ctx: Context, name: Optional[str]): """Logs errors and sends them to the appropriate places.""" - + # Prerequisites error_embed = await self._create_error_embed(error, ctx)