1
0
Fork 0
mirror of https://github.com/myned/modufur.git synced 2024-11-01 21:02:38 +00:00

Initial commit

This commit is contained in:
Myned 2017-09-24 03:36:50 -04:00
parent 129f8ad837
commit 0ccbf2b8b6
14 changed files with 835 additions and 0 deletions

110
.gitignore vendored Normal file
View file

@ -0,0 +1,110 @@
# Custom
*.json
*.pyo
*.pyc
*.DS_Store
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
.static_storage/
.media/
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/

0
__init__.py Normal file
View file

0
src/main/__init__.py Normal file
View file

View file

421
src/main/cogs/booru.py Normal file
View file

@ -0,0 +1,421 @@
import asyncio
import discord
import json
import requests
import traceback
from discord import reaction
from discord.ext import commands
from discord.ext.commands import errors
from misc import checks
from misc import exceptions as exc
from utils import formatter, scraper
try:
with open('global_blacklist.json') as infile:
global_blacklist = json.load(infile)
print('\"global_blacklist.json\" loaded.')
except FileNotFoundError:
print('Blacklist file not found: \"global_blacklist.json\" created.')
with open('global_blacklist.json', 'w+') as iofile:
json.dump([], iofile, indent=4, sort_keys=True)
iofile.seek(0)
global_blacklist = json.load(iofile)
try:
with open('guild_blacklist.json') as infile:
guild_blacklist = json.load(infile)
print('\"guild_blacklist.json\" loaded.')
except FileNotFoundError:
print('Blacklist file not found: \"guild_blacklist.json\" created.')
with open('guild_blacklist.json', 'w+') as iofile:
json.dump({}, iofile, indent=4, sort_keys=True)
iofile.seek(0)
guild_blacklist = json.load(iofile)
try:
with open('user_blacklist.json') as infile:
user_blacklist = json.load(infile)
print('\"user_blacklist.json\" loaded.')
except FileNotFoundError:
print('Blacklist file not found: \"user_blacklist.json\" created.')
with open('user_blacklist.json', 'w+') as iofile:
json.dump({}, iofile, indent=4, sort_keys=True)
iofile.seek(0)
user_blacklist = json.load(iofile)
last_command = {}
class MsG:
def __init__(self, bot):
self.bot = bot
# Creates reaction-based paginator for linked pools
@commands.command(brief='e621/e926 Pool selector', description='e621/e926 | NSFW/SFW\nShow pools in a page format', hidden=True)
@checks.del_ctx()
async def pool(self, ctx, url):
pool_urls = []
def check_right(reaction, user):
return user == ctx.message.author and str(reaction.emoji) == '➡️'
def check_left(reaction, user):
return user == ctx.message.author and str(reaction.emoji) == '⬅️'
try:
pool = scraper.find_pool(url)
for link in pool:
pool_urls.append(scraper.find_image_url('https://e621.net' + link))
except exc.PostError:
await ctx.send('' + ctx.message.author.mention + ' **No pool found.**')
except exc.ImageError:
await ctx.send('' + ctx.message.author.mention + ' **No image found.**')
except Exception:
await ctx.send(exc.base)
traceback.print_exc(limit=1)
# Reverse image searches a linked image using the public iqdb
@commands.command(name='reverse', aliases=['rev', 'ris'], brief='e621 Reverse image search', description='e621 | NSFW\nReverse-search an image with given URL')
@checks.del_ctx()
async def reverse_image_search(self, ctx, url):
try:
await ctx.trigger_typing()
await ctx.send('' + ctx.message.author.mention + ' **Probable match:**\n' + scraper.check_match('http://iqdb.harry.lu/?url=' + url))
except exc.MatchError:
await ctx.send('' + ctx.message.author.mention + ' **No probable match.**')
except Exception:
await ctx.send(exc.base)
traceback.print_exc(limit=1)
# Searches for and returns images from e621.net given tags when not blacklisted
@commands.command(aliases=['e6', '6'], brief='e621 | NSFW', description='e621 | NSFW\nTag-based search for e621.net\n\nYou can only search 5 tags and 6 images at once for now.\ne6 [tags...] ([# of images])')
@checks.del_ctx()
@checks.is_nsfw()
async def e621(self, ctx, *args):
global global_blacklist, guild_blacklist, user_blacklist
args = list(args)
try:
await ctx.trigger_typing()
await self.check_send_urls(ctx, 'e621', args)
except exc.TagBlacklisted as e:
await ctx.send('❌ `' + str(e) + '` **blacklisted.**', delete_after=10)
except exc.BoundsError as e:
await ctx.send('❌ `' + str(e) + '` **out of bounds.**', delete_after=10)
except exc.TagBoundsError as e:
await ctx.send('❌ `' + str(e) + '` **out of bounds.** Tags limited to 5, currently.', delete_after=10)
except Exception:
await ctx.send(exc.base)
traceback.print_exc()
@e621.error
async def e621_error(self, ctx, error):
if isinstance(error, errors.CheckFailure):
return await ctx.send('❌ <#' + str(ctx.message.channel.id) + '> **is not an NSFW channel.**', delete_after=10)
# Searches for and returns images from e926.net given tags when not blacklisted
@commands.command(aliases=['e9', '9'], brief='e926 | SFW', description='e926 | SFW\nTag-based search for e926.net\n\nYou can only search 5 tags and 6 images at once for now.\ne9 [tags...] ([# of images])')
@checks.del_ctx()
async def e926(self, ctx, *args):
global global_blacklist, guild_blacklist, user_blacklist
args = list(args)
try:
await ctx.trigger_typing()
await self.check_send_urls(ctx, 'e926', args)
except exc.TagBlacklisted as e:
await ctx.send('❌ `' + str(e) + '` **blacklisted.**', delete_after=10)
except exc.BoundsError as e:
await ctx.send('❌ `' + str(e) + '` **out of bounds.**', delete_after=10)
except exc.TagBoundsError as e:
await ctx.send('❌ `' + str(e) + '` **out of bounds.** Tags limited to 5, currently.', delete_after=10)
except Exception:
await ctx.send(exc.base)
traceback.print_exc(limit=1)
# Messy code that checks image limit and tags in blacklists
async def check_send_urls(self, ctx, booru, args):
global global_blacklist, guild_blacklist, user_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
channel = ctx.message.channel
user = ctx.message.author
urls = []
limit = 1
# Checks if tags are in the file blacklists
if args:
for tag in args:
if tag == 'swf' or tag == 'webm' or tag in global_blacklist or tag in guild_blacklist.get(str(guild.id), {}).get(str(channel.id), []) or tag in user_blacklist.get(str(user.id), []):
raise exc.TagBlacklisted(tag)
if len(args) > 5:
raise exc.TagBoundsError(formatter.tostring(args[5:]))
# Checks for, defines, and removes limit from end of args
if args and len(args[-1]) == 1:
if int(args[-1]) <= 6 and int(args[-1]) >= 1:
limit = int(args[-1])
args.pop()
else:
raise exc.BoundsError(args[-1])
# Checks for blacklisted tags in endpoint blacklists - try/except is for continuing the parent loop
while len(urls) < limit:
request = requests.get('https://' + booru + '.net/post/index.json?limit=6&tags=order:random' + formatter.tostring_commas(args)).json()
for post in request:
if 'swf' in post['file_ext'] or 'webm' in post['file_ext']:
continue
try:
for tag in global_blacklist:
if tag in post['tags']:
raise exc.Continue
for tag in guild_blacklist.get(str(guild.id), {}).get(str(channel.id), []):
if tag in post['tags']:
raise exc.Continue
for tag in user_blacklist.get(str(user.id), []):
if tag in post['tags']:
raise exc.Continue
except exc.Continue:
continue
if post['file_url'] not in urls:
urls.append(post['file_url'])
if len(urls) == limit:
break
for url in urls:
await ctx.send('`' + formatter.tostring(args) + '`\n' + url)
# Umbrella command structure to manage global, channel, and user blacklists
@commands.group(aliases=['bl', 'b'], brief='Manage blacklists', description='Blacklist base command for managing blacklists\n\n`bl get [blacklist]` to show a blacklist\n`bl set [blacklist] [tags]` to replace a blacklist\n`bl clear [blacklist]` to clear a blacklist\n`bl add [blacklist] [tags]` to add tags to a blacklist\n`bl remove [blacklist] [tags]` to remove tags from a blacklist', usage='[flag] [blacklist] ([tags])')
@checks.del_ctx()
async def blacklist(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('❌ **Use a flag to manage blacklists.**\n*Type* `' + ctx.prefix + 'help bl` *for more info.*', delete_after=10)
@blacklist.error
async def blacklist_error(self, ctx, error):
if isinstance(error, commands.CheckFailure):
return await ctx.send('❌ **Insufficient permissions.**', delete_after=10)
if isinstance(error, exc.TagExists):
return await ctx.send('❌ `' + str(exc.TagExists) + '` **already in blacklist.**', delete_after=10)
if isinstance(error, exc.TagError):
return await ctx.send('❌ `' + str(exc.TagError) + '` **not in blacklist.**', delete_after=10)
if isinstance(error, KeyError):
return await ctx.send('❌ **Blacklist does not exist.**', delete_after=10)
@blacklist.command(name='update', aliases=['upd', 'up'])
async def _update_blacklists(self, ctx):
global global_blacklist, guild_blacklist, user_blacklist
with open('global_blacklist.json', 'w') as outfile:
json.dump(global_blacklist, outfile, indent=4, sort_keys=True)
with open('guild_blacklist.json', 'w') as outfile:
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True)
with open('user_blacklist.json', 'w') as outfile:
json.dump(user_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Blacklists updated.**')
@blacklist.group(name='get', aliases=['g'])
async def _get_blacklist(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**')
@_get_blacklist.command(name='global', aliases=['gl', 'g'])
async def __get_global_blacklist(self, ctx):
global global_blacklist
await ctx.send('🚫 **Global blacklist:**\n```' + formatter.tostring(global_blacklist) + '```')
@_get_blacklist.command(name='channel', aliases=['ch', 'c'])
async def __get_channel_blacklist(self, ctx):
global guild_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
channel = ctx.message.channel
await ctx.send('🚫 <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(guild_blacklist.get(str(guild.id), {}).get(str(channel.id), [])) + '```')
@_get_blacklist.command(name='me', aliases=['m'])
async def __get_user_blacklist(self, ctx):
global user_blacklist
user = ctx.message.author
await ctx.send('🚫 ' + user.mention + '**\'s blacklist:**\n```' + formatter.tostring(user_blacklist.get(str(user.id), [])) + '```', delete_after=10)
@_get_blacklist.command(name='here', aliases=['h'])
async def __get_here_blacklists(self, ctx):
global global_blacklist, guild_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
channel = ctx.message.channel
await ctx.send('🚫 **__Blacklisted:__**\n\n**Global:**\n```' + formatter.tostring(global_blacklist) + '```\n**<#' + str(channel.id) + '>:**\n```' + formatter.tostring(guild_blacklist.get(str(guild.id), {}).get(str(channel.id), [])) + '```')
@_get_blacklist.group(name='all', aliases=['a'])
async def __get_all_blacklists(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**')
@__get_all_blacklists.command(name='guild', aliases=['g'])
@commands.has_permissions(manage_channels=True)
async def ___get_all_guild_blacklists(self, ctx):
global guild_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
await ctx.send('🚫 **__' + guild.name + ' blacklists:__**\n\n' + formatter.dict_tostring(guild_blacklist.get(str(guild.id), {})))
@__get_all_blacklists.command(name='user', aliases=['u', 'member', 'm'])
@commands.is_owner()
async def ___get_all_user_blacklists(self, ctx):
global user_blacklist
await ctx.send('🚫 **__User blacklists:__**\n\n' + formatter.dict_tostring(user_blacklist))
@blacklist.group(name='add', aliases=['a'])
async def _add_tags(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**')
@_add_tags.command(name='global', aliases=['gl', 'g'])
@commands.is_owner()
async def __add_global_tags(self, ctx, *tags):
global global_blacklist
for tag in tags:
if tag in global_blacklist:
raise exc.TagExists(tag)
global_blacklist.extend(tags)
with open('global_blacklist.json', 'w') as outfile:
json.dump(global_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Added to global blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
@_add_tags.command(name='channel', aliases=['ch', 'c'])
@commands.has_permissions(manage_channels=True)
async def __add_channel_tags(self, ctx, *tags):
global guild_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
channel = ctx.message.channel
for tag in tags:
if tag in guild_blacklist.get(str(guild.id), {}).get(str(channel.id), []):
raise exc.TagExists(tag)
guild_blacklist.setdefault(str(guild.id), {}).setdefault(str(channel.id), []).extend(tags)
with open('guild_blacklist.json', 'w') as outfile:
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Added to** <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
@_add_tags.command(name='me', aliases=['m'])
async def __add_user_tags(self, ctx, *tags):
global user_blacklist
user = ctx.message.author
for tag in tags:
if tag in user_blacklist.get(str(user.id), []):
raise exc.TagExists(tag)
user_blacklist.setdefault(str(user.id), []).extend(tags)
with open('user_blacklist.json', 'w') as outfile:
json.dump(user_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('' + user.mention + ' **added:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
@blacklist.group(name='remove', aliases=['rm', 'r'])
async def _remove_tags(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**')
@_remove_tags.command(name='global', aliases=['gl', 'g'])
@commands.is_owner()
async def __remove_global_tags(self, ctx, *tags):
global global_blacklist
for tag in tags:
if tag in global_blacklist:
global_blacklist.remove(tag)
else:
raise exc.TagError(tag)
with open('global_blacklist.json', 'w') as outfile:
json.dump(global_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Removed from global blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
@_remove_tags.command(name='channel', aliases=['ch', 'c'])
@commands.has_permissions(manage_channels=True)
async def __remove_channel_tags(self, ctx, *tags):
global guild_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
channel = ctx.message.channel
for tag in tags:
if tag in guild_blacklist.get(str(guild.id), {}).get(str(channel.id), []):
guild_blacklist.get(str(guild.id), {})[str(channel.id)].remove(tag)
else:
raise exc.TagError(tag)
with open('guild_blacklist.json', 'w') as outfile:
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Removed from** <#' + str(channel.id) + '> **blacklist:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
@_remove_tags.command(name='me', aliases=['m'])
async def __remove_user_tags(self, ctx, *tags):
global user_blacklist
user = ctx.message.author
for tag in tags:
if tag in user_blacklist.get(str(user.id), []):
user_blacklist.get[str(user.id)].remove(tag)
else:
raise exc.TagError(tag)
with open('user_blacklist.json', 'w') as outfile:
json.dump(user_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('' + user.mention + ' **removed:**\n```' + formatter.tostring(tags) + '```', delete_after=5)
@blacklist.group(name='set', aliases=['s'])
async def _set_blacklist(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**')
@_set_blacklist.command(name='global', aliases=['gl', 'g'])
@commands.is_owner()
async def __set_global_blacklist(self, ctx, *tags):
global global_blacklist
global_blacklist = tags[:]
with open('global_blacklist.json', 'w') as outfile:
json.dump(global_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Global blacklist set to:**\n```' + formatter.tostring(global_blacklist) + '```', delete_after=10)
@_set_blacklist.command(name='channel', aliases=['ch', 'c'])
@commands.has_permissions(manage_channels=True)
async def __set_channel_blacklist(self, ctx, *tags):
global guild_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
channel = ctx.message.channel
guild_blacklist.setdefault(str(guild.id), {})[str(channel.id)] = tags[:]
with open('guild_blacklist.json', 'w') as outfile:
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ <#' + str(channel.id) + '> **blacklist set to:**\n```' + formatter.tostring(guild_blacklist.get(str(guild.id), {}).get(str(channel.id), [])) + '```', delete_after=10)
@_set_blacklist.command(name='me', aliases=['m'])
async def __set_user_blacklist(self, ctx, *tags):
global user_blacklist
user = ctx.message.author
user_blacklist[str(user.id)] = tags[:]
with open('user_blacklist.json', 'w') as outfile:
json.dump(user_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('' + user.mention + '**\'s blacklist set to:**\n```' + formatter.tostring(user_blacklist.get(str(user.id), [])) + '```', delete_after=10)
@blacklist.group(name='clear', aliases=['cl', 'c'])
async def _clear_blacklist(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('❌ **Invalid blacklist.**')
@_clear_blacklist.command(name='global', aliases=['gl', 'g'])
@commands.is_owner()
async def __clear_global_blacklist(self, ctx):
global global_blacklist
global_blacklist = []
with open('global_blacklist.json', 'w') as outfile:
json.dump(global_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ **Global blacklist cleared.**', delete_after=5)
@_clear_blacklist.command(name='channel', aliases=['ch', 'c'])
@commands.has_permissions(manage_channels=True)
async def __clear_channel_blacklist(self, ctx):
global guild_blacklist
if isinstance(ctx.message.guild, discord.Guild):
guild = ctx.message.guild
else:
guild = ctx.message.channel
channel = ctx.message.channel
guild_blacklist.get(str(guild.id), {})[str(channel.id)] = []
with open('guild_blacklist.json', 'w') as outfile:
json.dump(guild_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('✅ <#' + str(channel.id) + '> **blacklist cleared.**', delete_after=5)
@_clear_blacklist.command(name='me', aliases=['m'])
async def __clear_user_blacklist(self, ctx):
global user_blacklist
user = ctx.message.author
user_blacklist[str(user.id)] = []
with open('user_blacklist.json', 'w') as outfile:
json.dump(user_blacklist, outfile, indent=4, sort_keys=True)
await ctx.send('' + user.mention + '**\'s blacklist cleared.**', delete_after=5)

32
src/main/cogs/info.py Normal file
View file

@ -0,0 +1,32 @@
import asyncio
import discord
import traceback
from discord.ext import commands
from misc import exceptions as exc
class Info:
def __init__(self, bot):
self.bot = bot
@commands.group(name='info', aliases=['i'])
async def info(self, ctx):
if invoked_subcommand is None:
await ctx.send('<embed>BOT INFO</embed>')
@info.command(aliases=['g', 'server', 's'], brief='Provides info about a guild', hidden=True)
async def guild(self, ctx):
try:
guild = ''
except Exception:
await ctx.send(exc.base)
traceback.print_exc(limit=1)
@info.command(aliases=['u', 'member', 'm'], brief='Provides info about a user', hidden=True)
async def user(self, ctx):
try:
user = ''
except Exception:
await ctx.send(exc.base)
traceback.print_exc(limit=1)

58
src/main/cogs/tools.py Normal file
View file

@ -0,0 +1,58 @@
import asyncio
import discord
import traceback
from discord.ext import commands
from cogs import booru
from misc import checks
from misc import exceptions as exc
from utils import formatter
class Utils:
def __init__(self, bot):
self.bot = bot
def last():
pass
@commands.command(name='last', aliases=['l', ','], brief='Reinvokes last command', description='Reinvokes previous command executed', hidden=True)
async def last_command(self, ctx):
try:
# await ctx.invoke(command, args)
await ctx.send('`' + booru.last_command[ctx.message.author.id] + '`')
except Exception:
await ctx.send(exceptions.base)
traceback.print_exc(limit=1)
# [prefix]ping -> Pong!
@commands.command(aliases=['p'], brief='Pong!', description='Returns latency from bot to Discord servers, not to user')
@checks.del_ctx()
async def ping(self, ctx):
try:
await ctx.send(ctx.message.author.mention + ' 🏓 `' + str(int(self.bot.latency * 1000)) + 'ms`', delete_after=5)
except Exception:
await ctx.send(exceptions.base)
traceback.print_exc(limit=1)
@commands.command(aliases=['pre'], brief='List bot prefixes', description='Shows all used prefixes')
@checks.del_ctx()
async def prefix(self, ctx):
try:
await ctx.send('**Prefix:** `,` or ' + ctx.me.mention)
except Exception:
await ctx.send(exceptions.base)
traceback.print_exc(limit=1)
@commands.group(name=',send', aliases=[',s'], hidden=True)
@commands.is_owner()
async def send(self, ctx):
pass
@send.command(name='guild', aliases=['g', 'server', 's'])
@checks.del_ctx()
async def send_guild(self, ctx, guild, channel, *message):
await discord.utils.get(self.bot.get_all_channels(), guild__name=guild, name=channel).send(formatter.tostring(message))
@send.command(name='user', aliases=['u', 'member', 'm'])
@checks.del_ctx()
async def send_user(self, ctx, user, *message):
await discord.utils.get(self.bot.get_all_members(), id=int(user)).send(formatter.tostring(message))

View file

45
src/main/misc/checks.py Normal file
View file

@ -0,0 +1,45 @@
import asyncio
import discord
import json
import traceback
from discord.ext import commands
from discord.ext.commands import errors
with open('config.json') as infile:
config = json.load(infile)
owner_id = config['owner_id']
def is_owner():
async def predicate(ctx):
return ctx.message.author.id == owner_id
return commands.check(predicate)
def is_admin():
def predicate(ctx):
return ctx.message.author.guild_permissions.administrator
return commands.check(predicate)
def is_mod():
def predicate(ctx):
return ctx.message.author.guild_permissions.ban_members
return commands.check(predicate)
def owner(ctx):
return ctx.message.author.id == owner_id
def admin(ctx):
return ctx.message.author.guild_permissions.administrator
def mod(ctx):
return ctx.message.author.guild_permissions.ban_members
def is_nsfw():
def predicate(ctx):
if isinstance(ctx.message.channel, discord.TextChannel):
return ctx.message.channel.is_nsfw()
return True
return commands.check(predicate)
def del_ctx():
async def predicate(ctx):
if isinstance(ctx.message.channel, discord.TextChannel):
await ctx.message.delete()
return True
return commands.check(predicate)

View file

@ -0,0 +1,24 @@
base = '‼️ **An internal error has occurred.** Please notify my master! 🐺'
class PostError(Exception):
pass
class ImageError(Exception):
pass
class MatchError(Exception):
pass
class TagBlacklisted(Exception):
pass
class BoundsError(Exception):
pass
class TagBoundsError(Exception):
pass
class TagExists(Exception):
pass
class TagError(Exception):
pass
class FlagError(Exception):
pass
class BlacklistError(Exception):
pass
class Continue(Exception):
pass

81
src/main/run.py Normal file
View file

@ -0,0 +1,81 @@
import asyncio
import discord
import json
import traceback
from discord import utils
from discord.ext import commands
from cogs import booru, info, tools
from misc import checks
from misc import exceptions as exc
try:
with open('config.json') as infile:
config = json.load(infile)
print('\"config.json\" loaded.')
except FileNotFoundError:
with open('config.json', 'w') as outfile:
json.dump({'client_id': 'int', 'owner_id': 'int', 'permissions': 'int', 'shutdown_channel': 'int', 'startup_channel': 'int',
'token': 'str'}, outfile, indent=4, sort_keys=True)
raise FileNotFoundError('Config file not found: \"config.json\" created with abstract values. Restart \"run.py\" with correct values.')
bot = commands.Bot(command_prefix=commands.when_mentioned_or(','), description='Experimental booru bot')
# Send and print ready message to #testing and console after logon
@bot.event
async def on_ready():
await bot.get_channel(config['startup_channel']).send('Hello how are? **Have day.** 🌈\n<embed>[STARTUP-INFO]</embed>')
print('Connected.')
print('Username: ' + bot.user.name)
print('-------')
# Close connection to Discord - immediate offline
@bot.command(name=',die', aliases=[',d', ',close', ',kill'], brief='Kills the bot', description='BOT OWNER ONLY\nCloses the connections to Discord', hidden=True)
@checks.del_ctx()
@commands.is_owner()
async def die(ctx):
try:
await ctx.send('Am go bye. **Have night.** 💤')
# await bot.get_channel(config['shutdown_channel']).send('<embed>[SHUTDOWN-INFO]</embed>')
await bot.close()
print('-------')
print('Closed.')
except Exception:
await ctx.send(exc.base)
traceback.print_exc(limit=1)
# Invite bot to bot owner's server
@bot.command(name=',invite', aliases=[',inv', ',link'], brief='Invite the bot', description='BOT OWNER ONLY\nInvite the bot to a server (Requires admin)', hidden=True)
@checks.del_ctx()
@commands.is_owner()
async def invite(ctx):
try:
await ctx.send('🔗 ' + utils.oauth_url(config['client_id'], permissions=config['permissions'], guild=ctx.message.guild))
except Exception:
await ctx.send(exc.base)
traceback.print_exc(limit=1)
@bot.command(brief='[IN TESTING]', description='[IN TESTING]', hidden=True)
async def hi(ctx):
try:
hello = 'Hello, ' + ctx.message.author.mention + '.'
if ctx.message.author.id == checks.owner_id:
hello += '.. ***Master.*** uwu'
elif ctx.message.author.guild_permissions.administrator:
hello = hello[:7] + '**Admin** ' + hello[7:]
elif ctx.message.author.guild_permissions.ban_members:
hello = hello[:7] + '**Mod** ' + hello[7:]
await ctx.send(hello)
except Exception:
await ctx.send(exc.base)
traceback.print_exc(limit=1)
@bot.command(hidden=True)
@checks.del_ctx()
async def test(ctx):
pass
bot.add_cog(info.Info(bot))
bot.add_cog(tools.Utils(bot))
bot.add_cog(booru.MsG(bot))
bot.run(config['token'])

View file

View file

@ -0,0 +1,31 @@
def tostring(i):
o = ' '
if i:
for v in i:
o += v + ' '
o = o[1:-1]
return o
def tostring_commas(i):
if i:
o = ','
for v in i:
o += v + ','
return o[:-1]
return ''
def dict_tostring(i):
o = ''
if i:
for k, v in i.items():
o += '**' + k + ':** `' + tostring(v) + '`\n'
return o
def dictelem_tostring(i):
o = ''
if i:
for dic, elem in i.items():
o += '**__' + dic + '__**\n'
for k, v in elem.items():
o += '***' + k + ':*** `' + tostring(v) + '`\n'
return o

33
src/main/utils/scraper.py Normal file
View file

@ -0,0 +1,33 @@
import requests
from bs4 import BeautifulSoup
from lxml import html
from misc import exceptions as exc
def check_match(url):
r = requests.get(url)
soup = BeautifulSoup(r.content, 'html.parser')
value = soup.find_all('a')[1].get('href')
if value != '#':
return value
else:
raise exc.MatchError(value)
def find_pool(url):
r = requests.get(url)
tree = html.fromstring(r.content)
post = tree.xpath('/html/body/div[@id="content"]/div[@id="pool-show"]/div[@style="margin-top: 2em;"]/span/a/@href')
print(post)
if post:
return post
else:
raise exc.PostError(post)
def find_image_url(url):
r = requests.get(url)
tree = html.fromstring(r.content)
image_url = tree.xpath('/html/body/div[@id="content"]/div[@id="post-view"]/div[@class="content"]/div/img/@src')
print(image_url)
if image_url:
return image_url
else:
raise exc.ImageError(image_url)