Update to work with updated database
This commit is contained in:
parent
5612f6e25a
commit
fc1ed00b96
12
bot.py
12
bot.py
|
@ -50,12 +50,10 @@ async def process_command(ctx):
|
|||
server = ctx.message.server
|
||||
command = ctx.command
|
||||
|
||||
r_filter = {'command': command.qualified_name}
|
||||
command_usage = await utils.get_content('command_usage', r_filter)
|
||||
command_usage = await utils.get_content('command_usage', key=command.qualified_name)
|
||||
if command_usage is None:
|
||||
command_usage = {'command': command.qualified_name}
|
||||
else:
|
||||
command_usage = command_usage[0]
|
||||
|
||||
# Add one to the total usage for this command, basing it off 0 to start with (obviously)
|
||||
total_usage = command_usage.get('total_usage', 0) + 1
|
||||
command_usage['total_usage'] = total_usage
|
||||
|
@ -67,15 +65,15 @@ async def process_command(ctx):
|
|||
command_usage['member_usage'] = total_member_usage
|
||||
|
||||
# Add one to the server's usage for this command
|
||||
if ctx.message.server is not None:
|
||||
if ctx.message.guild is not None:
|
||||
total_server_usage = command_usage.get('server_usage', {})
|
||||
server_usage = total_server_usage.get(server.id, 0) + 1
|
||||
total_server_usage[server.id] = server_usage
|
||||
command_usage['server_usage'] = total_server_usage
|
||||
|
||||
# Save all the changes
|
||||
if not await utils.update_content('command_usage', command_usage, r_filter):
|
||||
await utils.add_content('command_usage', command_usage, r_filter)
|
||||
if not await utils.update_content('command_usage', command_usage, command.qualified_name):
|
||||
await utils.add_content('command_usage', command_usage)
|
||||
|
||||
|
||||
@bot.event
|
||||
|
|
|
@ -132,10 +132,9 @@ class Core:
|
|||
await self.bot.say(fmt)
|
||||
else:
|
||||
try:
|
||||
r_filter = pendulum.parse(date)
|
||||
motd = await utils.get_content('motd', r_filter)
|
||||
date = motd[0]['date']
|
||||
motd = motd[0]['motd']
|
||||
motd = await utils.get_content('motd', str(pendulum.parse(date).date()))
|
||||
date = motd['date']
|
||||
motd = motd['motd']
|
||||
fmt = "Message of the day for {}:\n\n{}".format(date, motd)
|
||||
await self.bot.say(fmt)
|
||||
# This one will be hit if we return None for that day
|
||||
|
@ -185,7 +184,7 @@ class Core:
|
|||
cal = calendar.TextCalendar().formatmonth(year, month)
|
||||
await self.bot.say("```\n{}```".format(cal))
|
||||
|
||||
@commands.command()
|
||||
@commands.command(enabled=False)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def info(self):
|
||||
"""This command can be used to print out some of my information"""
|
||||
|
|
166
cogs/da.py
166
cogs/da.py
|
@ -1,166 +0,0 @@
|
|||
import aiohttp
|
||||
import asyncio
|
||||
import discord
|
||||
import traceback
|
||||
import logging
|
||||
|
||||
from discord.ext import commands
|
||||
|
||||
from . import utils
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
|
||||
class Deviantart:
|
||||
def __init__(self, bot):
|
||||
self.base_url = "https://www.deviantart.com/api/v1/oauth2/gallery/all"
|
||||
self.bot = bot
|
||||
self.headers = {"User-Agent": utils.user_agent}
|
||||
self.session = aiohttp.ClientSession()
|
||||
self.token = None
|
||||
self.params = None
|
||||
bot.loop.create_task(self.token_task())
|
||||
bot.loop.create_task(self.post_task())
|
||||
|
||||
async def token_task(self):
|
||||
while True:
|
||||
expires_in = await self.get_token()
|
||||
await asyncio.sleep(expires_in)
|
||||
|
||||
async def post_task(self):
|
||||
await asyncio.sleep(5)
|
||||
# Lets start the task a few seconds after, to ensure our token gets set
|
||||
while True:
|
||||
await self.check_posts()
|
||||
await asyncio.sleep(300)
|
||||
|
||||
async def get_token(self):
|
||||
# We need a token to create requests, it doesn't seem this token goes away
|
||||
# To get this token, we need to make a request and retrieve that
|
||||
url = 'https://www.deviantart.com/oauth2/token'
|
||||
params = {'client_id': utils.da_id,
|
||||
'client_secret': utils.da_secret,
|
||||
'grant_type': 'client_credentials'}
|
||||
|
||||
data = await utils.request(url, payload=params)
|
||||
|
||||
self.token = data.get('access_token', None)
|
||||
self.params = {'access_token': self.token}
|
||||
# Make sure we refresh our token, based on when they tell us it expires
|
||||
# Ensure we call it a few seconds earlier, to give us enough time to set the new token
|
||||
# If there was an issue, lets call this in a minute again
|
||||
return data.get('expires_in', 65) - 5
|
||||
|
||||
async def check_posts(self):
|
||||
content = await utils.get_content('deviantart')
|
||||
# People might sub to the same person, so lets cache every person and their last update
|
||||
cache = {}
|
||||
|
||||
try:
|
||||
for entry in content:
|
||||
user = discord.utils.get(self.bot.get_all_members(), id=entry['member_id'])
|
||||
|
||||
# If we're sharded, we might not be able to find this user.
|
||||
# If the bot is not in the server with the member either
|
||||
if user is None:
|
||||
continue
|
||||
|
||||
params = self.params.copy()
|
||||
# Now loop through the subscriptions
|
||||
for da_name in entry['subbed']:
|
||||
# Check what the last updated content we sent to this user was
|
||||
# Since we cannot go back in time, if this doesn't match the last uploaded from the user
|
||||
# Assume we need to notify the user of this post
|
||||
last_updated_id = entry['last_updated'].get(da_name, None)
|
||||
# Check if this user has been requested already, if so we don't need to make another request
|
||||
result = cache.get(da_name, None)
|
||||
if result is None:
|
||||
params['username'] = da_name
|
||||
data = await utils.request(self.base_url, payload=params)
|
||||
if data is None:
|
||||
continue
|
||||
elif not data['results']:
|
||||
continue
|
||||
|
||||
result = data['results'][0]
|
||||
cache[da_name] = result
|
||||
|
||||
# This means that our last update to this user, for this author, is not the same
|
||||
if last_updated_id != result['deviationid']:
|
||||
# First lets check if the last updated ID was None, if so...then we haven't alerted them yet
|
||||
# We don't want to alert them in this case
|
||||
# We just want to act like the artist's most recent update was the last notified
|
||||
# So just notify the user if this is not None
|
||||
if last_updated_id is not None:
|
||||
fmt = "There has been a new post by an artist you are subscribed to!\n\n" \
|
||||
"**Title:** {}\n**User:** {}\n**URL:** {}".format(
|
||||
result['title'],
|
||||
result['author']['username'],
|
||||
result['url'])
|
||||
await self.bot.send_message(user, fmt)
|
||||
# Now we can update the user's last updated for this DA
|
||||
# We want to do this whether or not our last if statement was met
|
||||
r_filter = {'member_id': user.id}
|
||||
update = {'last_updated': {da_name: result['deviationid']}}
|
||||
await utils.update_content('deviantart', update, r_filter)
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
fmt = "{1}\n{0.__class__.__name__}: {0}".format(tb, e)
|
||||
log.error(fmt)
|
||||
|
||||
@commands.group()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def da(self):
|
||||
"""This provides a sort of 'RSS' feed for subscribed to artists.
|
||||
Subscribe to artists, and I will PM you when new posts come out from these artists"""
|
||||
pass
|
||||
|
||||
@da.command(pass_context=True, name='sub', aliases=['add', 'subscribe'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def da_sub(self, ctx, *, username):
|
||||
"""This can be used to add a feed to your notifications.
|
||||
Provide a username, and when posts are made from this user, you will be notified
|
||||
|
||||
EXAMPLE: !da sub MyFavoriteArtistEva<3
|
||||
RESULT: Notifications of amazing pics c:"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
content = await utils.get_content('deviantart', r_filter)
|
||||
# TODO: Ensure the user provided is a real user
|
||||
|
||||
if content is None:
|
||||
entry = {'member_id': ctx.message.author.id, 'subbed': [username], 'last_updated': {}}
|
||||
await utils.add_content('deviantart', entry, r_filter)
|
||||
await self.bot.say("You have just subscribed to {}!".format(username))
|
||||
elif content[0]['subbed'] is None or username not in content[0]['subbed']:
|
||||
if content[0]['subbed'] is None:
|
||||
sub_list = [username]
|
||||
else:
|
||||
content[0]['subbed'].append(username)
|
||||
sub_list = content[0]['subbed']
|
||||
await utils.update_content('deviantart', {'subbed': sub_list}, r_filter)
|
||||
await self.bot.say("You have just subscribed to {}!".format(username))
|
||||
else:
|
||||
await self.bot.say("You are already subscribed to that user!")
|
||||
|
||||
@da.command(pass_context=True, name='unsub', aliases=['delete', 'remove', 'unsubscribe'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def da_unsub(self, ctx, *, username):
|
||||
"""This command can be used to unsub from the specified user
|
||||
|
||||
EXAMPLE: !da unsub TheArtistWhoBetrayedMe
|
||||
RESULT: No more pics from that terrible person!"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
content = await utils.get_content('deviantart', r_filter)
|
||||
|
||||
if content is None or content[0]['subbed'] is None:
|
||||
await self.bot.say("You are not subscribed to anyone at the moment!")
|
||||
elif username in content[0]['subbed']:
|
||||
content[0]['subbed'].remove(username)
|
||||
await utils.update_content('deviantart', {'subbed': content[0]['subbed']}, r_filter)
|
||||
await self.bot.say("You have just unsubscribed from {}!".format(username))
|
||||
else:
|
||||
await self.bot.say("You are not subscribed to that user!")
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Deviantart(bot))
|
|
@ -20,6 +20,8 @@ class StatsUpdate:
|
|||
self.bot.loop.create_task(self.session.close())
|
||||
|
||||
async def update(self):
|
||||
# Currently disabled
|
||||
return
|
||||
server_count = 0
|
||||
data = await config.get_content('bot_data')
|
||||
|
||||
|
@ -48,6 +50,7 @@ class StatsUpdate:
|
|||
log.info('bots.discord.pw statistics returned {} for {}'.format(resp.status, payload))
|
||||
|
||||
async def on_server_join(self, server):
|
||||
return
|
||||
r_filter = {'shard_id': config.shard_id}
|
||||
server_count = len(self.bot.servers)
|
||||
member_count = len(set(self.bot.get_all_members()))
|
||||
|
@ -58,6 +61,7 @@ class StatsUpdate:
|
|||
self.bot.loop.create_task(self.update())
|
||||
|
||||
async def on_server_leave(self, server):
|
||||
return
|
||||
r_filter = {'shard_id': config.shard_id}
|
||||
server_count = len(self.bot.servers)
|
||||
member_count = len(set(self.bot.get_all_members()))
|
||||
|
@ -68,6 +72,7 @@ class StatsUpdate:
|
|||
self.bot.loop.create_task(self.update())
|
||||
|
||||
async def on_ready(self):
|
||||
return
|
||||
r_filter = {'shard_id': config.shard_id}
|
||||
server_count = len(self.bot.servers)
|
||||
member_count = len(set(self.bot.get_all_members()))
|
||||
|
@ -79,16 +84,15 @@ class StatsUpdate:
|
|||
|
||||
async def on_member_join(self, member):
|
||||
server = member.server
|
||||
r_filter = {'server_id': server.id}
|
||||
notifications = await config.get_content('user_notifications', r_filter)
|
||||
server_settings = await config.get_content('server_settings', server.id)
|
||||
|
||||
try:
|
||||
channel_id = notifications[0]['channel_id']
|
||||
except TypeError:
|
||||
return
|
||||
|
||||
# By default, notifications should be off unless explicitly turned on
|
||||
if not channel_id:
|
||||
join_leave_on = server_settings['join_leave']
|
||||
if join_leave_on:
|
||||
channel_id = server_settings.get('notification_channel') or member.server.id
|
||||
else:
|
||||
return
|
||||
except (IndexError, TypeError, KeyError):
|
||||
return
|
||||
|
||||
channel = server.get_channel(channel_id)
|
||||
|
@ -96,22 +100,19 @@ class StatsUpdate:
|
|||
|
||||
async def on_member_remove(self, member):
|
||||
server = member.server
|
||||
r_filter = {'server_id': server.id}
|
||||
notifications = await config.get_content('user_notifications', r_filter)
|
||||
server_settings = await config.get_content('server_settings', server.id)
|
||||
|
||||
try:
|
||||
channel_id = notifications[0]['channel_id']
|
||||
except TypeError:
|
||||
return
|
||||
|
||||
# By default, notifications should be off unless explicitly turned on
|
||||
if not channel_id:
|
||||
join_leave_on = server_settings['join_leave']
|
||||
if join_leave_on:
|
||||
channel_id = server_settings.get('notification_channel') or member.server.id
|
||||
else:
|
||||
return
|
||||
except (IndexError, TypeError, KeyError):
|
||||
return
|
||||
|
||||
channel = server.get_channel(channel_id)
|
||||
await self.bot.send_message(channel,
|
||||
"{0} has left the server, I hope it wasn't because of something I said :c".format(
|
||||
member.display_name))
|
||||
await self.bot.send_message(channel, "{0} has left the server, I hope it wasn't because of something I said :c".format(member.display_name))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -258,20 +258,20 @@ class Interaction:
|
|||
await self.bot.say("Why the heck are you booping me? Get away from me >:c")
|
||||
return
|
||||
|
||||
r_filter = {'member_id': booper.id}
|
||||
boops = await utils.get_content('boops', r_filter)
|
||||
key = booper.id
|
||||
boops = await utils.get_content('boops', key)
|
||||
if boops is not None:
|
||||
boops = boops[0]['boops']
|
||||
boops = boops['boops']
|
||||
# If the booper has never booped the member provided, assure it's 0
|
||||
amount = boops.get(boopee.id, 0) + 1
|
||||
boops[boopee.id] = amount
|
||||
|
||||
await utils.update_content('boops', {'boops': boops}, r_filter)
|
||||
await utils.update_content('boops', {'boops': boops}, key)
|
||||
else:
|
||||
entry = {'member_id': booper.id,
|
||||
'boops': {boopee.id: 1}}
|
||||
|
||||
await utils.add_content('boops', entry, r_filter)
|
||||
await utils.add_content('boops', entry)
|
||||
amount = 1
|
||||
|
||||
fmt = "{0.mention} has just booped {1.mention}{3}! That's {2} times now!"
|
||||
|
|
|
@ -27,9 +27,8 @@ class Links:
|
|||
url = "https://www.google.com/search"
|
||||
|
||||
# Turn safe filter on or off, based on whether or not this is a nsfw channel
|
||||
r_filter = {'channel_id': ctx.message.channel.id}
|
||||
nsfw_channels = await utils.get_content("nsfw_channels", r_filter)
|
||||
safe = 'off' if nsfw_channels else 'on'
|
||||
nsfw = await utils.channel_is_nsfw(ctx.message.channel)
|
||||
safe = 'off' if nsfw else 'on'
|
||||
|
||||
params = {'q': query,
|
||||
'safe': safe,
|
||||
|
@ -181,12 +180,11 @@ class Links:
|
|||
query = ' '.join(value for value in search if not re.search('&?filter_id=[0-9]+', value))
|
||||
params = {'q': query}
|
||||
|
||||
r_filter = {'channel_id': ctx.message.channel.id}
|
||||
nsfw_channels = await utils.get_content("nsfw_channels", r_filter)
|
||||
nsfw = await utils.channel_is_nsfw(ctx.message.channel)
|
||||
# If this is a nsfw channel, we just need to tack on 'explicit' to the terms
|
||||
# Also use the custom filter that I have setup, that blocks some certain tags
|
||||
# If the channel is not nsfw, we don't need to do anything, as the default filter blocks explicit
|
||||
if nsfw_channels is not None:
|
||||
if nsfw:
|
||||
params['q'] += ", (explicit OR suggestive)"
|
||||
params['filter_id'] = 95938
|
||||
else:
|
||||
|
@ -256,12 +254,11 @@ class Links:
|
|||
# Due to this, send a message saying we're looking up the information first
|
||||
await self.bot.say("Looking up an image with those tags....")
|
||||
|
||||
r_filter = {'channel_id': ctx.message.channel.id}
|
||||
nsfw_channels = await utils.get_content("nsfw_channels", r_filter)
|
||||
nsfw = await utils.channel_is_nsfw(ctx.message.channel)
|
||||
|
||||
# e621 by default does not filter explicit content, so tack on
|
||||
# safe/explicit based on if this channel is nsfw or not
|
||||
params['tags'] += " rating:explicit" if nsfw_channels else " rating:safe"
|
||||
params['tags'] += " rating:explicit" if nsfw else " rating:safe"
|
||||
|
||||
data = await utils.request(url, payload=params)
|
||||
|
||||
|
|
177
cogs/mod.py
177
cogs/mod.py
|
@ -119,19 +119,22 @@ class Mod:
|
|||
except discord.HTTPException:
|
||||
await self.bot.say("Sorry, I failed to ban that user!")
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True, aliases=['alerts'], pass_context=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def alerts(self, ctx, channel: discord.Channel):
|
||||
async def notifications(self, ctx, channel: discord.Channel):
|
||||
"""This command is used to set a channel as the server's 'notifications' channel
|
||||
Any notifications (like someone going live on Twitch, or Picarto) will go to that channel
|
||||
|
||||
EXAMPLE: !alerts #alerts
|
||||
RESULT: No more alerts spammed in #general!"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
entry = {'server_id': ctx.message.server.id,
|
||||
'channel_id': channel.id}
|
||||
if not await utils.add_content('server_alerts', entry, r_filter):
|
||||
await utils.update_content('server_alerts', entry, r_filter)
|
||||
if str(channel.type) != "text":
|
||||
await self.bot.say("The notifications channel must be a text channel!")
|
||||
return
|
||||
|
||||
key = ctx.message.server.id
|
||||
entry = {'server_id': key,
|
||||
'notification_channel': channel.id}
|
||||
if not await utils.update_content('server_settings', entry, key):
|
||||
await utils.add_content('server_settings', entry)
|
||||
await self.bot.say("I have just changed this server's 'notifications' channel"
|
||||
"\nAll notifications will now go to `{}`".format(channel))
|
||||
|
||||
|
@ -139,55 +142,71 @@ class Mod:
|
|||
@utils.custom_perms(kick_members=True)
|
||||
async def usernotify(self, ctx, on_off: str):
|
||||
"""This command can be used to set whether or not you want user notificaitons to show
|
||||
This will save what channel you run this command in, that will be the channel used to send the notification to
|
||||
Provide on, yes, or true to set it on; otherwise it will be turned off
|
||||
|
||||
EXAMPLE: !usernotify on
|
||||
RESULT: Annying join/leave notifications! Yay!"""
|
||||
# Join/Leave notifications can be kept separate from normal alerts
|
||||
# So we base this channel on it's own and not from alerts
|
||||
# When mod logging becomes available, that will be kept to it's own channel if wanted as well
|
||||
on_off = ctx.message.channel.id if re.search("(on|yes|true)", on_off.lower()) else None
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
entry = {'server_id': ctx.message.server.id,
|
||||
'channel_id': on_off}
|
||||
if not await utils.add_content('user_notifications', entry, r_filter):
|
||||
await utils.update_content('user_notifications', entry, r_filter)
|
||||
on_off = True if re.search("(on|yes|true)", on_off.lower()) else False
|
||||
key = ctx.message.server.id
|
||||
entry = {'server_id': key,
|
||||
'join_leave': on_off}
|
||||
if not await utils.update_content('server_settings', entry, key):
|
||||
await utils.add_content('server_settings', entry)
|
||||
|
||||
fmt = "notify" if on_off else "not notify"
|
||||
await self.bot.say("This server will now {} if someone has joined or left".format(fmt))
|
||||
|
||||
@commands.group(pass_context=True)
|
||||
async def nsfw(self, ctx):
|
||||
"""Handles adding or removing a channel as a nsfw channel"""
|
||||
# This command isn't meant to do anything, so just send an error if an invalid subcommand is passed
|
||||
if ctx.invoked_subcommand is None:
|
||||
await self.bot.say('Invalid subcommand passed: {0.subcommand_passed}'.format(ctx))
|
||||
pass
|
||||
|
||||
@nsfw.command(name="add", pass_context=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def nsfw_add(self, ctx):
|
||||
"""Registers this channel as a 'nsfw' channel
|
||||
|
||||
EXAMPLE: !nsfw add
|
||||
RESULT: ;)"""
|
||||
r_filter = {'channel_id': ctx.message.channel.id}
|
||||
if await utils.add_content('nsfw_channels', r_filter, r_filter):
|
||||
await self.bot.say("This channel has just been registered as 'nsfw'! Have fun you naughties ;)")
|
||||
key = ctx.message.server.id
|
||||
entry = {'server_id': key,
|
||||
'nsfw_channels': [ctx.message.channel.id]}
|
||||
update = {'nsfw_channels': r.row['nsfw_channels'].append(ctx.message.channel.id)}
|
||||
|
||||
server_settings = await utils.get_content('server_settings', key)
|
||||
if server_settings and 'nsfw_channels' in server_settings.keys():
|
||||
await utils.update_content('server_settings', update, key)
|
||||
elif server_settings:
|
||||
await utils.update_content('server_settings', entry, key)
|
||||
else:
|
||||
await self.bot.say("This channel is already registered as 'nsfw'!")
|
||||
await utils.add_content('server_settings', entry)
|
||||
|
||||
await self.bot.say("This channel has just been registered as 'nsfw'! Have fun you naughties ;)")
|
||||
|
||||
@nsfw.command(name="remove", aliases=["delete"], pass_context=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def nsfw_remove(self, ctx):
|
||||
"""Removes this channel as a 'nsfw' channel
|
||||
|
||||
EXAMPLE: !nsfw remove
|
||||
RESULT: ;("""
|
||||
r_filter = {'channel_id': ctx.message.channel.id}
|
||||
if await utils.remove_content('nsfw_channels', r_filter):
|
||||
await self.bot.say("This channel has just been unregistered as a nsfw channel")
|
||||
else:
|
||||
await self.bot.say("This channel is not registered as a ''nsfw' channel!")
|
||||
|
||||
key = ctx.message.server.id
|
||||
server_settings = await utils.get_content('server_settings', key)
|
||||
channel = ctx.message.channel.id
|
||||
try:
|
||||
channels = server_settings['nsfw_channels']
|
||||
if channel in channels:
|
||||
channels.remove(channel)
|
||||
|
||||
entry = {'nsfw_channels': channels}
|
||||
await utils.update_content('server_settings', entry, key)
|
||||
await self.bot.say("This channel has just been unregistered as a nsfw channel")
|
||||
return
|
||||
except (TypeError, IndexError):
|
||||
pass
|
||||
|
||||
await self.bot.say("This channel is not registered as a 'nsfw' channel!")
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
|
@ -208,7 +227,6 @@ class Mod:
|
|||
async def perms(self, ctx, *, command: str = None):
|
||||
"""This command can be used to print the current allowed permissions on a specific command
|
||||
This supports groups as well as subcommands; pass no argument to print a list of available permissions
|
||||
|
||||
EXAMPLE: !perms help RESULT: Hopefully a result saying you just need send_messages permissions; otherwise lol
|
||||
this server's admin doesn't like me """
|
||||
if command is None:
|
||||
|
@ -216,18 +234,18 @@ class Mod:
|
|||
"Valid permissions are: ```\n{}```".format("\n".join("{}".format(i) for i in valid_perms)))
|
||||
return
|
||||
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
server_perms = await utils.get_content('custom_permissions', r_filter)
|
||||
try:
|
||||
server_perms = server_perms[0]
|
||||
except TypeError:
|
||||
server_perms = {}
|
||||
cmd = self.find_command(command)
|
||||
cmd = utils.find_command(self.bot, command)
|
||||
|
||||
if cmd is None:
|
||||
await self.bot.say("That is not a valid command!")
|
||||
return
|
||||
|
||||
server_settings = await utils.get_content('server_settings', ctx.message.server.id)
|
||||
try:
|
||||
server_perms = server_settings['permissions']
|
||||
except (TypeError, IndexError, KeyError):
|
||||
server_perms = {}
|
||||
|
||||
perms_value = server_perms.get(cmd.qualified_name)
|
||||
if perms_value is None:
|
||||
# If we don't find custom permissions, get the required permission for a command
|
||||
|
@ -238,7 +256,7 @@ class Mod:
|
|||
# Loop through and check if there is a check called is_owner
|
||||
# If we loop through and don't find one, this means that the only other choice is to be
|
||||
# Able to manage the server (for the utils on perm commands)
|
||||
for func in cmd.utils:
|
||||
for func in cmd.checks:
|
||||
if "is_owner" in func.__qualname__:
|
||||
await self.bot.say("You need to own the bot to run this command")
|
||||
return
|
||||
|
@ -265,7 +283,6 @@ class Mod:
|
|||
"""Sets up custom permissions on the provided command
|
||||
Format must be 'perms add <command> <permission>'
|
||||
If you want to open the command to everyone, provide 'none' as the permission
|
||||
|
||||
EXAMPLE: !perms add skip ban_members
|
||||
RESULT: No more random people voting to skip a song"""
|
||||
|
||||
|
@ -278,6 +295,13 @@ class Mod:
|
|||
"`perms add <command> <permission>`")
|
||||
return
|
||||
|
||||
cmd = utils.find_command(self.bot, command)
|
||||
|
||||
if cmd is None:
|
||||
await self.bot.say(
|
||||
"That command does not exist! You can't have custom permissions on a non-existant command....")
|
||||
return
|
||||
|
||||
# If a user can run a command, they have to have send_messages permissions; so use this as the base
|
||||
if permissions.lower() == "none":
|
||||
permissions = "send_messages"
|
||||
|
@ -293,35 +317,22 @@ class Mod:
|
|||
return
|
||||
perm_value = perm_obj.value
|
||||
|
||||
cmd = self.find_command(command)
|
||||
|
||||
if cmd is None:
|
||||
await self.bot.say(
|
||||
"That command does not exist! You can't have custom permissions on a non-existant command....")
|
||||
return
|
||||
|
||||
# Two cases I use should never have custom permissions setup on them, is_owner for obvious reasons
|
||||
# The other case is if I'm using the default has_permissions case
|
||||
# Which means I do not want to check custom permissions at all
|
||||
# Currently the second case is only on adding and removing permissions, to avoid abuse on these
|
||||
for check in cmd.checks:
|
||||
if "is_owner" == check.__name__ or re.search("has_permissions", str(check)) is not None:
|
||||
if "is_owner" == check.__name__ or "has_permissions" in str(check):
|
||||
await self.bot.say("This command cannot have custom permissions setup!")
|
||||
return
|
||||
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
entry = {'server_id': ctx.message.server.id,
|
||||
cmd.qualified_name: perm_value}
|
||||
key = ctx.message.server.id
|
||||
entry = {'server_id': key,
|
||||
'permissions': {cmd.qualified_name: perm_value}}
|
||||
|
||||
# In all other cases, I've used add_content before update_content
|
||||
# In this case, I'm going the other way around, to make the least queries
|
||||
# As custom permissions are probably going to be ran multiple times per server
|
||||
# Whereas in most other cases, the command is probably going to be ran once/few times per server
|
||||
if not await utils.update_content('custom_permissions', entry, r_filter):
|
||||
await utils.add_content('custom_permissions', entry, r_filter)
|
||||
if not await utils.update_content('server_settings', entry, key):
|
||||
await utils.add_content('server_settings', entry)
|
||||
|
||||
# Same case as prefixes, for now, trigger a manual update
|
||||
self.bot.loop.create_task(utils.cache['custom_permissions'].update())
|
||||
await self.bot.say("I have just added your custom permissions; "
|
||||
"you now need to have `{}` permissions to use the command `{}`".format(permissions, command))
|
||||
|
||||
|
@ -333,20 +344,17 @@ class Mod:
|
|||
EXAMPLE: !perms remove play
|
||||
RESULT: Freedom!"""
|
||||
|
||||
cmd = self.find_command(command)
|
||||
cmd = utils.find_command(self.bot, command)
|
||||
|
||||
if cmd is None:
|
||||
await self.bot.say(
|
||||
"That command does not exist! You can't have custom permissions on a non-existant command....")
|
||||
return
|
||||
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
await utils.replace_content('custom_permissions', r.row.without(cmd.qualified_name), r_filter)
|
||||
update = {'permissions': {cmd.qualified_name: None}}
|
||||
await utils.update_content('server_settings', update, ctx.message.server.id)
|
||||
await self.bot.say("I have just removed the custom permissions for {}!".format(cmd))
|
||||
|
||||
# Same case as prefixes, for now, trigger a manual update
|
||||
self.bot.loop.create_task(utils.cache['custom_permissions'].update())
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@utils.custom_perms(manage_server=True)
|
||||
async def prefix(self, ctx, *, prefix: str):
|
||||
|
@ -354,15 +362,15 @@ class Mod:
|
|||
|
||||
EXAMPLE: !prefix new_prefix
|
||||
RESULT: You probably screwing it up and not realizing you now need to do new_prefixprefix"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
key = ctx.message.server.id
|
||||
if prefix.lower().strip() == "none":
|
||||
prefix = None
|
||||
|
||||
entry = {'server_id': ctx.message.server.id,
|
||||
entry = {'server_id': key,
|
||||
'prefix': prefix}
|
||||
|
||||
if not await utils.add_content('prefixes', entry, r_filter):
|
||||
await utils.update_content('prefixes', entry, r_filter)
|
||||
if not await utils.update_content('server_settings', entry, key):
|
||||
await utils.add_content('server_settings', entry)
|
||||
|
||||
if prefix is None:
|
||||
fmt = "I have just cleared your custom prefix, the default prefix will have to be used now"
|
||||
|
@ -390,7 +398,7 @@ class Mod:
|
|||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@utils.custom_perms(manage_messages=True)
|
||||
async def prune(self, ctx, limit = None):
|
||||
async def prune(self, ctx, limit=None):
|
||||
"""This command can be used to prune messages from certain members
|
||||
Mention any user you want to prune messages from; if no members are mentioned, the messages removed will be mine
|
||||
If no limit is provided, then 100 will be used. This is also the max limit we can use
|
||||
|
@ -458,14 +466,10 @@ class Mod:
|
|||
|
||||
EXAMPLE: !rules 5
|
||||
RESULT: Rule 5 is printed"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
rules = await utils.get_content('rules', r_filter)
|
||||
try:
|
||||
rules = rules[0]['rules']
|
||||
except TypeError:
|
||||
await self.bot.say("This server currently has no rules on it! I see you like to live dangerously...")
|
||||
return
|
||||
if len(rules) == 0:
|
||||
server_settings = await utils.get_content('server_settings', ctx.message.server.id)
|
||||
rules = server_settings.get('rules')
|
||||
|
||||
if not rules or len(rules) == 0:
|
||||
await self.bot.say("This server currently has no rules on it! I see you like to live dangerously...")
|
||||
return
|
||||
|
||||
|
@ -491,12 +495,18 @@ class Mod:
|
|||
|
||||
EXAMPLE: !rules add No fun allowed in this server >:c
|
||||
RESULT: No more fun...unless they break the rules!"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
entry = {'server_id': ctx.message.server.id,
|
||||
key = ctx.message.server.id
|
||||
entry = {'server_id': key,
|
||||
'rules': [rule]}
|
||||
update = {'rules': r.row['rules'].append(rule)}
|
||||
if not await utils.update_content('rules', update, r_filter):
|
||||
await utils.add_content('rules', entry, r_filter)
|
||||
|
||||
server_settings = await utils.get_content('server_settings', key)
|
||||
if server_settings and 'rules' in server_settings.keys():
|
||||
await utils.update_content('server_settings', update, key)
|
||||
elif server_settings:
|
||||
await utils.update_content('server_settings', entry, key)
|
||||
else:
|
||||
await utils.add_content('server_settings', entry)
|
||||
|
||||
await self.bot.say("I have just saved your new rule, use the rules command to view this server's current rules")
|
||||
|
||||
|
@ -508,9 +518,8 @@ class Mod:
|
|||
|
||||
EXAMPLE: !rules delete 5
|
||||
RESULT: Freedom from opression!"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
update = {'rules': r.row['rules'].delete_at(rule - 1)}
|
||||
if not await utils.update_content('rules', update, r_filter):
|
||||
if not await utils.update_content('server_settings', update, ctx.message.server.id):
|
||||
await self.bot.say("That is not a valid rule number, try running the command again.")
|
||||
else:
|
||||
await self.bot.say("I have just removed that rule from your list of rules!")
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
from .utils import config
|
||||
from .utils import checks
|
||||
from .utils import images
|
||||
from . import utils
|
||||
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
import aiohttp
|
||||
|
||||
base_url = "https://api.owapi.net/api/v3/u/"
|
||||
BASE_URL = "https://api.owapi.net/api/v3/u/"
|
||||
# This is a list of the possible things that we may want to retrieve from the stats
|
||||
# The API returns something if it exists, and leaves it out of the data returned entirely if it does not
|
||||
# For example if you have not won with a character, wins will not exist in the list
|
||||
|
@ -15,7 +11,6 @@ base_url = "https://api.owapi.net/api/v3/u/"
|
|||
check_g_stats = ["eliminations", "deaths", 'kpd', 'wins', 'losses', 'time_played',
|
||||
'cards', 'damage_done', 'healing_done', 'multikills']
|
||||
check_o_stats = ['wins']
|
||||
MAX_RETRIES = 5
|
||||
|
||||
|
||||
class Overwatch:
|
||||
|
@ -23,29 +18,6 @@ class Overwatch:
|
|||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.headers = {"User-Agent": config.user_agent}
|
||||
self.session = aiohttp.ClientSession()
|
||||
|
||||
async def _request(self, payload, endpoint):
|
||||
"""Handles requesting to the API"""
|
||||
|
||||
# Format the URL we'll need based on the base_url, and the endpoint we want to hit
|
||||
url = "{}{}".format(base_url, endpoint)
|
||||
|
||||
# Attempt to connect up to our max retries
|
||||
for x in range(MAX_RETRIES):
|
||||
try:
|
||||
async with aiohttp.ClientSession(headers=self.headers) as session:
|
||||
async with session.get(url, params=payload) as r:
|
||||
# If we failed to connect, attempt again
|
||||
if r.status != 200:
|
||||
continue
|
||||
|
||||
data = await r.json()
|
||||
return data
|
||||
# If any error happened when making the request, attempt again
|
||||
except:
|
||||
continue
|
||||
|
||||
@commands.group(no_pm=True)
|
||||
async def ow(self):
|
||||
|
@ -56,28 +28,28 @@ class Overwatch:
|
|||
pass
|
||||
|
||||
@ow.command(name="stats", pass_context=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def ow_stats(self, ctx, user: discord.Member = None, hero: str = ""):
|
||||
"""Prints out a basic overview of a member's stats
|
||||
Provide a hero after the member to get stats for that specific hero
|
||||
|
||||
EXAMPLE: !ow stats @OtherPerson Junkrat
|
||||
RESULT: Whether or not you should unfriend this person because they're a dirty rat"""
|
||||
|
||||
user = user or ctx.message.author
|
||||
r_filter = {'member_id': user.id}
|
||||
ow_stats = await config.get_content('overwatch', r_filter)
|
||||
ow_stats = await utils.get_content('overwatch', user.id)
|
||||
|
||||
if ow_stats is None:
|
||||
await self.bot.say("I do not have this user's battletag saved!")
|
||||
return
|
||||
# This API sometimes takes a while to look up information, so send a message saying we're processing
|
||||
await self.bot.say("Searching profile information....")
|
||||
|
||||
bt = ow_stats[0]['battletag']
|
||||
bt = ow_stats['battletag']
|
||||
|
||||
if hero == "":
|
||||
# If no hero was provided, we just want the base stats for a player
|
||||
data = await self._request(None, "{}/stats".format(bt))
|
||||
url = BASE_URL + "{}/stats".format(bt)
|
||||
data = await utils.request(url)
|
||||
region = [x for x in data.keys() if data[x] is not None][0]
|
||||
stats = data[region]['stats']['quickplay']
|
||||
|
||||
|
@ -86,8 +58,8 @@ class Overwatch:
|
|||
else:
|
||||
# If there was a hero provided, search for a user's data on that hero
|
||||
hero = hero.lower().replace('-', '')
|
||||
endpoint = "{}/heroes".format(bt)
|
||||
data = await self._request(None, endpoint)
|
||||
url = BASE_URL + "{}/heroes".format(bt)
|
||||
data = await utils.request(url)
|
||||
|
||||
region = [x for x in data.keys() if data[x] is not None][0]
|
||||
stats = data[region]['heroes']['stats']['quickplay'].get(hero)
|
||||
|
@ -104,52 +76,51 @@ class Overwatch:
|
|||
for k, r in stats['hero_stats'].items():
|
||||
output_data.append((k.title().replace("_", " "), r))
|
||||
try:
|
||||
banner = await images.create_banner(user, "Overwatch", output_data)
|
||||
banner = await utils.create_banner(user, "Overwatch", output_data)
|
||||
await self.bot.upload(banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
fmt = "\n".join("{}: {}".format(k, r) for k, r in output_data)
|
||||
await self.bot.say("Overwatch stats for {}: ```py\n{}```".format(user.name, fmt))
|
||||
|
||||
@ow.command(pass_context=True, name="add")
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def add(self, ctx, bt: str):
|
||||
"""Saves your battletag for looking up information
|
||||
|
||||
EXAMPLE: !ow add Username#1234
|
||||
RESULT: Your battletag is now saved"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
# Battletags are normally provided like name#id
|
||||
# However the API needs this to be a -, so repliace # with - if it exists
|
||||
bt = bt.replace("#", "-")
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
key = ctx.message.author.id
|
||||
|
||||
# This API sometimes takes a while to look up information, so send a message saying we're processing
|
||||
await self.bot.say("Looking up your profile information....")
|
||||
# All we're doing here is ensuring that the status is 200 when looking up someone's general information
|
||||
# If it's not, let them know exactly how to format their tag
|
||||
endpoint = "{}/stats".format(bt)
|
||||
data = await self._request(None, endpoint)
|
||||
url = BASE_URL + "{}/stats".format(bt)
|
||||
data = await utils.request(url)
|
||||
if data is None:
|
||||
await self.bot.say("Profile does not exist! Battletags are picky, "
|
||||
"format needs to be `user#xxxx`. Capitalization matters")
|
||||
return
|
||||
await self.bot.say("Profile does not exist! Battletags are picky, "
|
||||
"format needs to be `user#xxxx`. Capitalization matters")
|
||||
return
|
||||
|
||||
# Now just save the battletag
|
||||
entry = {'member_id': ctx.message.author.id, 'battletag': bt}
|
||||
entry = {'member_id': key, 'battletag': bt}
|
||||
update = {'battletag': bt}
|
||||
# Try adding this first, if that fails, update the saved entry
|
||||
if not await config.add_content('overwatch', entry, r_filter):
|
||||
await config.update_content('overwatch', update, r_filter)
|
||||
if not await utils.add_content('overwatch', entry):
|
||||
await utils.update_content('overwatch', update, key)
|
||||
await self.bot.say("I have just saved your battletag {}".format(ctx.message.author.mention))
|
||||
|
||||
@ow.command(pass_context=True, name="delete", aliases=['remove'])
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def delete(self, ctx):
|
||||
"""Removes your battletag from the records
|
||||
|
||||
EXAMPLE: !ow delete
|
||||
RESULT: Your battletag is no longer saved"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
if await config.remove_content('overwatch', r_filter):
|
||||
if await utils.remove_content('overwatch', ctx.message.author.id):
|
||||
await self.bot.say("I no longer have your battletag saved {}".format(ctx.message.author.mention))
|
||||
else:
|
||||
await self.bot.say("I don't even have your battletag saved {}".format(ctx.message.author.mention))
|
||||
|
|
|
@ -22,12 +22,12 @@ class Owner:
|
|||
async def motd_push(self, *, message):
|
||||
"""Used to push a new message to the message of the day"""
|
||||
date = pendulum.utcnow().to_date_string()
|
||||
r_filter = {'date': date}
|
||||
key = date
|
||||
entry = {'motd': message, 'date': date}
|
||||
# Try to add this, if there's an entry for that date, lets update it to make sure only one motd is sent a day
|
||||
# I should be managing this myself, more than one should not be sent in a day
|
||||
if await utils.add_content('motd', entry, r_filter):
|
||||
await utils.update_content('motd', entry, r_filter)
|
||||
if await utils.add_content('motd', entry):
|
||||
await utils.update_content('motd', entry, key)
|
||||
await self.bot.say("New motd update for {}!".format(date))
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
|
|
222
cogs/picarto.py
222
cogs/picarto.py
|
@ -11,159 +11,143 @@ from discord.ext import commands
|
|||
from . import utils
|
||||
|
||||
log = logging.getLogger()
|
||||
base_url = 'https://ptvappapi.picarto.tv'
|
||||
BASE_URL = 'https://ptvappapi.picarto.tv'
|
||||
|
||||
# This is a public key for use, I don't care if this is seen
|
||||
key = '03e26294-b793-11e5-9a41-005056984bd4'
|
||||
|
||||
|
||||
async def online_users():
|
||||
try:
|
||||
# Someone from picarto contacted me and told me their database queries are odd
|
||||
# It is more efficent on their end to make a query for all online users, and base checks off that
|
||||
# In place of requesting for /channel and checking if that is online currently, for each channel
|
||||
# This method is in place to just return all online_users
|
||||
url = '{}/online/all?key={}'.format(base_url, key)
|
||||
with aiohttp.ClientSession(headers={"User-Agent": utils.user_agent}) as s:
|
||||
async with s.get(url) as response:
|
||||
return await response.json()
|
||||
except:
|
||||
return {}
|
||||
|
||||
|
||||
def check_online(online_channels, channel):
|
||||
# online_channels is the dictionary of all users online currently
|
||||
# And channel is the name we are checking against that
|
||||
# This creates a list of all users that match this channel name (should only ever be 1)
|
||||
# And returns True as long as it is more than 0
|
||||
matches = [stream for stream in online_channels if stream['channel_name'].lower() == channel.lower()]
|
||||
return len(matches) > 0
|
||||
api_key = '03e26294-b793-11e5-9a41-005056984bd4'
|
||||
|
||||
|
||||
class Picarto:
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.headers = {"User-Agent": utils.user_agent}
|
||||
self.session = aiohttp.ClientSession()
|
||||
|
||||
async def get_online_users(self):
|
||||
# This method is in place to just return all online users so we can compare against it
|
||||
url = BASE_URL + '/online/all'
|
||||
payload = {'key': api_key}
|
||||
self.online_channels = await utils.request(url, payload=payload)
|
||||
|
||||
def channel_online(self, channel):
|
||||
# Channel is the name we are checking against that
|
||||
# This creates a list of all users that match this channel name (should only ever be 1)
|
||||
# And returns True as long as it is more than 0
|
||||
channel = re.search("(?<=picarto.tv/)(.*)", channel).group(1)
|
||||
matches = [stream for stream in self.online_channels if stream['channel_name'].lower() == channel.lower()]
|
||||
return len(matches) > 0
|
||||
|
||||
async def check_channels(self):
|
||||
await self.bot.wait_until_ready()
|
||||
# This is a loop that runs every 30 seconds, checking if anyone has gone online
|
||||
try:
|
||||
while not self.bot.is_closed:
|
||||
r_filter = {'notifications_on': 1}
|
||||
picarto = await utils.get_content('picarto', r_filter)
|
||||
# Get all online users before looping, so that only one request is needed
|
||||
online_users_list = await online_users()
|
||||
old_online_users = {data['member_id']: data for data in picarto if data['live']}
|
||||
old_offline_users = {data['member_id']: data for data in picarto if not data['live']}
|
||||
|
||||
for m_id, result in old_offline_users.items():
|
||||
# Get their url and their user based on that url
|
||||
url = result['picarto_url']
|
||||
user = re.search("(?<=picarto.tv/)(.*)", url).group(1)
|
||||
# Check if they are online right now
|
||||
if check_online(online_users_list, user):
|
||||
for server_id in result['servers']:
|
||||
# Get the channel to send the message to, based on the saved alert's channel
|
||||
server = self.bot.get_server(server_id)
|
||||
await self.get_online_users()
|
||||
picarto = await utils.filter_content('picarto', {'notifications_on': 1})
|
||||
for data in picarto:
|
||||
m_id = data['member_id']
|
||||
url = data['picarto_url']
|
||||
# Check if they are online
|
||||
online = self.channel_online(url)
|
||||
# If they're currently online, but saved as not then we'll send our notification
|
||||
if online and data['live'] == 0:
|
||||
for s_id in data['servers']:
|
||||
server = self.bot.get_server(s_id)
|
||||
if server is None:
|
||||
continue
|
||||
server_alerts = await utils.get_content('server_alerts', {'server_id': server_id})
|
||||
try:
|
||||
channel_id = server_alerts[0]['channel_id']
|
||||
except (IndexError, TypeError):
|
||||
channel_id = server_id
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
# Get the member that has just gone live
|
||||
member = discord.utils.get(server.members, id=m_id)
|
||||
member = server.get_member(m_id)
|
||||
if member is None:
|
||||
continue
|
||||
|
||||
fmt = "{} has just gone live! View their stream at {}".format(member.display_name, url)
|
||||
await self.bot.send_message(channel, fmt)
|
||||
await utils.update_content('picarto', {'live': 1}, {'member_id': m_id})
|
||||
for m_id, result in old_online_users.items():
|
||||
# Get their url and their user based on that url
|
||||
url = result['picarto_url']
|
||||
user = re.search("(?<=picarto.tv/)(.*)", url).group(1)
|
||||
# Check if they are online right now
|
||||
if not check_online(online_users_list, user):
|
||||
for server_id in result['servers']:
|
||||
# Get the channel to send the message to, based on the saved alert's channel
|
||||
server = self.bot.get_server(server_id)
|
||||
server_settings = await utils.get_content('server_settings', s_id)
|
||||
if server_settings is not None:
|
||||
channel_id = server_settings.get('notification_channel', s_id)
|
||||
else:
|
||||
channel_id = s_id
|
||||
channel = server.get_channel(channel_id)
|
||||
await self.bot.send_message(channel, "{} has just gone live! View their stream at <{}>".format(member.display_name, data['picarto_url']))
|
||||
self.bot.loop.create_task(utils.update_content('picarto', {'live': 1}, m_id))
|
||||
elif not online and data['live'] == 1:
|
||||
for s_id in data['servers']:
|
||||
server = self.bot.get_server(s_id)
|
||||
if server is None:
|
||||
continue
|
||||
server_alerts = await utils.get_content('server_alerts', {'server_id': server_id})
|
||||
try:
|
||||
channel_id = server_alerts[0]['channel_id']
|
||||
except (IndexError, TypeError):
|
||||
channel_id = server_id
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
# Get the member that has just gone live
|
||||
member = discord.utils.get(server.members, id=m_id)
|
||||
fmt = "{} has just gone offline! Catch them next time they stream at {}".format(
|
||||
member.display_name, url)
|
||||
await self.bot.send_message(channel, fmt)
|
||||
await utils.update_content('picarto', {'live': 0}, {'member_id': m_id})
|
||||
member = server.get_member(m_id)
|
||||
if member is None:
|
||||
continue
|
||||
server_settings = await utils.get_content('server_settings', s_id)
|
||||
if server_settings is not None:
|
||||
channel_id = server_settings.get('notification_channel', s_id)
|
||||
else:
|
||||
channel_id = s_id
|
||||
channel = server.get_channel(channel_id)
|
||||
await self.bot.send_message(channel, "{} has just gone offline! View their stream next time at <{}>".format(member.display_name, data['picarto_url']))
|
||||
self.bot.loop.create_task(utils.update_content('picarto', {'live': 0}, m_id))
|
||||
await asyncio.sleep(30)
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
fmt = "{1}\n{0.__class__.__name__}: {0}".format(tb, e)
|
||||
log.error(fmt)
|
||||
|
||||
@commands.group(pass_context=True, invoke_without_command=True, no_pm=True)
|
||||
@commands.group(invoke_without_command=True, no_pm=True, pass_context=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def picarto(self, ctx, member: discord.Member = None):
|
||||
"""This command can be used to view Picarto stats about a certain member
|
||||
|
||||
EXAMPLE: !picarto @otherPerson
|
||||
RESULT: Info about their picarto stream"""
|
||||
|
||||
# If member is not given, base information on the author
|
||||
member = member or ctx.message.author
|
||||
r_filter = {'member_id': member.id}
|
||||
picarto_entry = await utils.get_content('picarto', r_filter)
|
||||
picarto_entry = await utils.get_content('picarto', member.id)
|
||||
if picarto_entry is None:
|
||||
await self.bot.say("That user does not have a picarto url setup!")
|
||||
return
|
||||
member_url = picarto_entry[0]['picarto_url']
|
||||
|
||||
member_url = picarto_entry['picarto_url']
|
||||
|
||||
# Use regex to get the actual username so that we can make a request to the API
|
||||
stream = re.search("(?<=picarto.tv/)(.*)", member_url).group(1)
|
||||
url = '{}/channel/{}?key={}'.format(base_url, stream, key)
|
||||
async with self.session.get(url, headers=self.headers) as response:
|
||||
data = await response.json()
|
||||
url = BASE_URL + '/channel/{}'.format(stream)
|
||||
payload = {'key': api_key}
|
||||
|
||||
data = await utils.request(url, payload=payload)
|
||||
if data is None:
|
||||
await self.bot.say("I couldn't connect to Picarto!")
|
||||
return
|
||||
|
||||
# Not everyone has all these settings, so use this as a way to print information if it does, otherwise ignore it
|
||||
things_to_print = ['channel', 'commissions_enabled', 'is_nsfw', 'program', 'tablet', 'followers',
|
||||
'content_type']
|
||||
# Using title and replace to provide a nice way to print the data
|
||||
fmt = "\n".join(
|
||||
"{}: {}".format(i.title().replace("_", " "), result) for i, result in data.items() if i in things_to_print)
|
||||
|
||||
embed = discord.Embed(title='{}\'s Picarto'.format(data['channel']), url=url)
|
||||
if data['avatar_url']:
|
||||
embed.set_thumbnail(url=data['avatar_url'])
|
||||
|
||||
for i, result in data.items():
|
||||
if i in things_to_print and str(result):
|
||||
i = i.title().replace('_', ' ')
|
||||
embed.add_field(name=i, value=str(result))
|
||||
|
||||
# Social URL's can be given if a user wants them to show
|
||||
# Print them if they exist, otherwise don't try to include them
|
||||
social_links = data.get('social_urls')
|
||||
if social_links:
|
||||
fmt2 = "\n".join(
|
||||
"\t{}: {}".format(i.title().replace("_", " "), result) for i, result in social_links.items())
|
||||
fmt = "{}\nSocial Links:\n{}".format(fmt, fmt2)
|
||||
await self.bot.say("Picarto stats for {}: ```\n{}```".format(member.display_name, fmt))
|
||||
for i, result in data['social_urls'].items():
|
||||
embed.add_field(name=i.title(), value=result)
|
||||
|
||||
@picarto.command(name='add', pass_context=True, no_pm=True)
|
||||
await self.bot.say(embed=embed)
|
||||
|
||||
@picarto.command(name='add', no_pm=True, pass_context=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def add_picarto_url(self, ctx, url: str):
|
||||
"""Saves your user's picarto URL
|
||||
|
||||
EXAMPLE: !picarto add MyUsername
|
||||
RESULT: Your picarto stream is saved, and notifications should go to this server"""
|
||||
|
||||
# This uses a lookbehind to check if picarto.tv exists in the url given
|
||||
# If it does, it matches picarto.tv/user and sets the url as that
|
||||
# Then (in the else) add https://www. to that
|
||||
# Otherwise if it doesn't match, we'll hit an AttributeError due to .group(0)
|
||||
# This means that the url was just given as a user (or something complete invalid)
|
||||
# So set URL as https://www.picarto.tv/[url]
|
||||
# Even if this was invalid such as https://www.picarto.tv/twitch.tv/user
|
||||
# Even if this was invalid such as https://www.picarto.tv/picarto.tv/user
|
||||
# For example, our next check handles that
|
||||
try:
|
||||
url = re.search("((?<=://)?picarto.tv/)+(.*)", url).group(0)
|
||||
|
@ -171,43 +155,42 @@ class Picarto:
|
|||
url = "https://www.picarto.tv/{}".format(url)
|
||||
else:
|
||||
url = "https://www.{}".format(url)
|
||||
channel = re.search("https://www.picarto.tv/(.*)", url).group(1)
|
||||
api_url = BASE_URL + '/channel/{}'.format(channel)
|
||||
payload = {'key': api_key}
|
||||
|
||||
api_url = '{}/channel/{}?key={}'.format(base_url, re.search("https://www.picarto.tv/(.*)", url).group(1), key)
|
||||
data = await utils.request(api_url, payload=payload)
|
||||
if not data:
|
||||
await self.bot.say("That Picarto user does not exist! What would be the point of adding a nonexistant "
|
||||
"Picarto user? Silly")
|
||||
return
|
||||
|
||||
# Check if we can find a user with the provided information, if we can't just return
|
||||
async with self.session.get(api_url, headers=self.headers) as response:
|
||||
if not response.status == 200:
|
||||
await self.bot.say("That Picarto user does not exist! "
|
||||
"What would be the point of adding a nonexistant Picarto user? Silly")
|
||||
return
|
||||
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
key = ctx.message.author.id
|
||||
entry = {'picarto_url': url,
|
||||
'servers': [ctx.message.server.id],
|
||||
'notifications_on': 1,
|
||||
'live': 0,
|
||||
'member_id': ctx.message.author.id}
|
||||
if await utils.add_content('picarto', entry, r_filter):
|
||||
'member_id': key}
|
||||
if await utils.add_content('picarto', entry):
|
||||
await self.bot.say(
|
||||
"I have just saved your Picarto URL {}, this server will now be notified when you go live".format(
|
||||
ctx.message.author.mention))
|
||||
else:
|
||||
await utils.update_content('picarto', {'picarto_url': url}, r_filter)
|
||||
await utils.update_content('picarto', {'picarto_url': url}, key)
|
||||
await self.bot.say("I have just updated your Picarto URL")
|
||||
|
||||
@picarto.command(name='remove', aliases=['delete'], pass_context=True, no_pm=True)
|
||||
@picarto.command(name='remove', aliases=['delete'], no_pm=True, pass_context=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def remove_picarto_url(self, ctx):
|
||||
"""Removes your picarto URL"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
if await utils.remove_content('picarto', r_filter):
|
||||
if await utils.remove_content('picarto', ctx.message.author.id):
|
||||
await self.bot.say("I am no longer saving your picarto URL {}".format(ctx.message.author.mention))
|
||||
else:
|
||||
await self.bot.say(
|
||||
"I do not have your picarto URL added {}. You can save your picarto url with {}picarto add".format(
|
||||
ctx.message.author.mention, ctx.prefix))
|
||||
|
||||
@picarto.group(pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@picarto.group(no_pm=True, invoke_without_command=True, pass_context=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify(self, ctx):
|
||||
"""This can be used to turn picarto notifications on or off
|
||||
|
@ -215,29 +198,27 @@ class Picarto:
|
|||
|
||||
EXAMPLE: !picarto notify
|
||||
RESULT: This server will now be notified of you going live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
result = await utils.get_content('picarto', r_filter)
|
||||
key = ctx.message.author.id
|
||||
result = await utils.get_content('picarto', key)
|
||||
# Check if this user is saved at all
|
||||
if result is None:
|
||||
await self.bot.say(
|
||||
"I do not have your Picarto URL added {}. You can save your Picarto url with !picarto add".format(
|
||||
ctx.message.author.mention))
|
||||
# Then check if this server is already added as one to notify in
|
||||
elif ctx.message.server.id in result[0]['servers']:
|
||||
elif ctx.message.server.id in result['servers']:
|
||||
await self.bot.say("I am already set to notify in this server...")
|
||||
else:
|
||||
await utils.update_content('picarto', {'servers': r.row['servers'].append(ctx.message.server.id)},
|
||||
r_filter)
|
||||
await utils.update_content('picarto', {'servers': r.row['servers'].append(ctx.message.server.id)}, key)
|
||||
|
||||
@notify.command(name='on', aliases=['start,yes'], pass_context=True, no_pm=True)
|
||||
@notify.command(name='on', aliases=['start,yes'], no_pm=True, pass_context=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify_on(self, ctx):
|
||||
"""Turns picarto notifications on
|
||||
|
||||
EXAMPLE: !picarto notify on
|
||||
RESULT: Notifications are sent when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
await utils.update_content('picarto', {'notifications_on': 1}, r_filter)
|
||||
await utils.update_content('picarto', {'notifications_on': 1}, ctx.message.author.id)
|
||||
await self.bot.say("I will notify if you go live {}, you'll get a bajillion followers I promise c:".format(
|
||||
ctx.message.author.mention))
|
||||
|
||||
|
@ -248,8 +229,7 @@ class Picarto:
|
|||
|
||||
EXAMPLE: !picarto notify off
|
||||
RESULT: No more notifications sent when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
await utils.update_content('picarto', {'notifications_on': 0}, r_filter)
|
||||
await utils.update_content('picarto', {'notifications_on': 0}, ctx.message.author.id)
|
||||
await self.bot.say(
|
||||
"I will not notify if you go live anymore {}, "
|
||||
"are you going to stream some lewd stuff you don't want people to see?~".format(
|
||||
|
@ -259,4 +239,4 @@ class Picarto:
|
|||
def setup(bot):
|
||||
p = Picarto(bot)
|
||||
bot.loop.create_task(p.check_channels())
|
||||
bot.add_cog(Picarto(bot))
|
||||
bot.add_cog(Picarto(bot))
|
|
@ -1,7 +1,7 @@
|
|||
from discord.ext import commands
|
||||
from .utils import config
|
||||
from .utils import checks
|
||||
from . import utils
|
||||
|
||||
import discord
|
||||
import random
|
||||
import pendulum
|
||||
import re
|
||||
|
@ -27,7 +27,7 @@ class Raffle:
|
|||
async def check_raffles(self):
|
||||
# This is used to periodically check the current raffles, and see if they have ended yet
|
||||
# If the raffle has ended, we'll pick a winner from the entrants
|
||||
raffles = await config.get_content('raffles')
|
||||
raffles = await utils.get_content('raffles')
|
||||
|
||||
if raffles is None:
|
||||
return
|
||||
|
@ -73,22 +73,25 @@ class Raffle:
|
|||
|
||||
# No matter which one of these matches were met, the raffle has ended and we want to remove it
|
||||
# We don't have to wait for it however, so create a task for it
|
||||
r_filter = {'id': raffle_id}
|
||||
self.bot.loop.create_task(config.remove_content('raffles', r_filter))
|
||||
self.bot.loop.create_task(utils.remove_content('raffles', raffle_id ))
|
||||
|
||||
server_settings = await utils.get_content('server_settings', str(server.id))
|
||||
channel_id = server_settings.get('notification_channel', server.id)
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
try:
|
||||
await self.bot.send_message(server, fmt)
|
||||
await channel.send(fmt)
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def raffles(self, ctx):
|
||||
"""Used to print the current running raffles on the server
|
||||
|
||||
EXAMPLE: !raffles
|
||||
RESULT: A list of the raffles setup on this server"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
raffles = await config.get_content('raffles', r_filter)
|
||||
raffles = await utils.filter_content('raffles', r_filter)
|
||||
if raffles is None:
|
||||
await self.bot.say("There are currently no raffles setup on this server!")
|
||||
return
|
||||
|
@ -101,7 +104,7 @@ class Raffle:
|
|||
await self.bot.say(fmt)
|
||||
|
||||
@commands.group(pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def raffle(self, ctx, raffle_id: int = 0):
|
||||
"""Used to enter a raffle running on this server
|
||||
If there is more than one raffle running, provide an ID of the raffle you want to enter
|
||||
|
@ -113,7 +116,7 @@ class Raffle:
|
|||
r_filter = {'server_id': ctx.message.server.id}
|
||||
author = ctx.message.author
|
||||
|
||||
raffles = await config.get_content('raffles', r_filter)
|
||||
raffles = await utils.filter_content('raffles', r_filter)
|
||||
if raffles is None:
|
||||
await self.bot.say("There are currently no raffles setup on this server!")
|
||||
return
|
||||
|
@ -130,9 +133,8 @@ class Raffle:
|
|||
entrants.append(author.id)
|
||||
|
||||
# Since we have no good thing to filter things off of, lets use the internal rethinkdb id
|
||||
r_filter = {'id': raffles[0]['id']}
|
||||
update = {'entrants': entrants}
|
||||
await config.update_content('raffles', update, r_filter)
|
||||
await utils.update_content('raffles', update, raffles[0]['id'])
|
||||
await self.bot.say("{} you have just entered the raffle!".format(author.mention))
|
||||
# Otherwise, make sure the author gave a valid raffle_id
|
||||
elif raffle_id in range(raffle_count - 1):
|
||||
|
@ -144,10 +146,8 @@ class Raffle:
|
|||
return
|
||||
entrants.append(author.id)
|
||||
|
||||
# Since we have no good thing to filter things off of, lets use the internal rethinkdb id
|
||||
r_filter = {'id': raffles[raffle_id]['id']}
|
||||
update = {'entrants': entrants}
|
||||
await config.update_content('raffles', update, r_filter)
|
||||
await utils.update_content('raffles', update, raffles[raffle_id]['id'])
|
||||
await self.bot.say("{} you have just entered the raffle!".format(author.mention))
|
||||
else:
|
||||
fmt = "Please provide a valid raffle ID, as there are more than one setup on the server! " \
|
||||
|
@ -156,7 +156,7 @@ class Raffle:
|
|||
await self.bot.say(fmt)
|
||||
|
||||
@raffle.command(pass_context=True, no_pm=True, name='create', aliases=['start', 'begin', 'add'])
|
||||
@checks.custom_perms(kick_members=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def raffle_create(self, ctx):
|
||||
"""This is used in order to create a new server raffle
|
||||
|
||||
|
@ -231,7 +231,7 @@ class Raffle:
|
|||
'server_id': server.id}
|
||||
|
||||
# We don't want to pass a filter to this, because we can have multiple raffles per server
|
||||
await config.add_content('raffles', entry)
|
||||
await utils.add_content('raffles', entry)
|
||||
await self.bot.say("I have just saved your new raffle!")
|
||||
|
||||
|
||||
|
|
|
@ -74,16 +74,13 @@ class Stats:
|
|||
|
||||
EXAMPLE: !command stats play
|
||||
RESULT: The realization that this is the only reason people use me ;-;"""
|
||||
cmd = self.find_command(command)
|
||||
cmd = self.bot.get_command(command)
|
||||
if cmd is None:
|
||||
await self.bot.say("`{}` is not a valid command".format(command))
|
||||
return
|
||||
|
||||
r_filter = {'command': cmd.qualified_name}
|
||||
command_stats = await utils.get_content('command_usage', r_filter)
|
||||
try:
|
||||
command_stats = command_stats[0]
|
||||
except TypeError:
|
||||
command_stats = await utils.get_content('command_usage', cmd.qualified_name)
|
||||
if command_stats is None:
|
||||
await self.bot.say("That command has never been used! You know I worked hard on that! :c")
|
||||
return
|
||||
|
||||
|
@ -97,7 +94,7 @@ class Stats:
|
|||
("Your Usage", member_usage),
|
||||
("This Server's Usage", server_usage)]
|
||||
banner = await utils.create_banner(ctx.message.author, "Command Stats", data)
|
||||
await self.bot.upload(banner)
|
||||
await self.bot.upload(file=banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
fmt = "The command {} has been used a total of {} times\n" \
|
||||
"{} times on this server\n" \
|
||||
|
@ -158,14 +155,13 @@ class Stats:
|
|||
|
||||
EXAMPLE: !mostboops
|
||||
RESULT: You've booped @OtherPerson 351253897120935712093572193057310298 times!"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
boops = await utils.get_content('boops', r_filter)
|
||||
boops = await utils.get_content('boops', ctx.message.author.id)
|
||||
if boops is None:
|
||||
await self.bot.say("You have not booped anyone {} Why the heck not...?".format(ctx.message.author.mention))
|
||||
return
|
||||
|
||||
# Just to make this easier, just pay attention to the boops data, now that we have the right entry
|
||||
boops = boops[0]['boops']
|
||||
boops = boops['boops']
|
||||
|
||||
# First get a list of the ID's of all members in this server, for use in list comprehension
|
||||
server_member_ids = [member.id for member in ctx.message.server.members]
|
||||
|
@ -189,14 +185,13 @@ class Stats:
|
|||
|
||||
EXAMPLE: !listboops
|
||||
RESULT: The list of your booped members!"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
boops = await utils.get_content('boops', r_filter)
|
||||
boops = await utils.get_content('boops', ctx.message.author.id)
|
||||
if boops is None:
|
||||
await self.bot.say("You have not booped anyone {} Why the heck not...?".format(ctx.message.author.mention))
|
||||
return
|
||||
|
||||
# Just to make this easier, just pay attention to the boops data, now that we have the right entry
|
||||
boops = boops[0]['boops']
|
||||
boops = boops['boops']
|
||||
|
||||
# Same concept as the mostboops method
|
||||
server_member_ids = [member.id for member in ctx.message.server.members]
|
||||
|
|
|
@ -40,8 +40,7 @@ class Strawpoll:
|
|||
RESULT: A list of all polls setup on this server"""
|
||||
# Strawpolls cannot be 'deleted' so to handle whether a poll is running or not on a server
|
||||
# Just save the poll, which can then be removed when it should not be "running" anymore
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
polls = await config.get_content('strawpolls', r_filter)
|
||||
polls = await config.get_content('strawpolls', ctx.message.server.id)
|
||||
# Check if there are any polls setup on this server
|
||||
try:
|
||||
polls = polls[0]['polls']
|
||||
|
|
25
cogs/tags.py
25
cogs/tags.py
|
@ -17,7 +17,7 @@ class Tags:
|
|||
|
||||
EXAMPLE: !tags
|
||||
RESULT: All tags setup on this server"""
|
||||
tags = await config.get_content('tags', {'server_id': ctx.message.server.id})
|
||||
tags = await config.get_content('tags', ctx.message.server.id)
|
||||
# Simple generator that adds a tag to the list to print, if the tag is for this server
|
||||
try:
|
||||
fmt = "\n".join("{}".format(tag['tag']) for tag in tags)
|
||||
|
@ -72,13 +72,10 @@ class Tags:
|
|||
entry = {'server_id': ctx.message.server.id, 'tag': tag, 'result': tag_result}
|
||||
r_filter = lambda row: (row['server_id'] == ctx.message.server.id) & (row['tag'] == tag)
|
||||
# Try to create new entry first, if that fails (it already exists) then we update it
|
||||
if await config.add_content('tags', entry, r_filter):
|
||||
await self.bot.say(
|
||||
"I have just added the tag `{0}`! You can call this tag by entering !tag {0}".format(tag))
|
||||
else:
|
||||
await config.update_content('tags', entry, r_filter)
|
||||
await self.bot.say(
|
||||
"I have just updated the tag `{0}`! You can call this tag by entering !tag {0}".format(tag))
|
||||
if not await config.update_content('tags', entry, r_filter):
|
||||
await config.add_content('tags', entry)
|
||||
await self.bot.say(
|
||||
"I have just updated the tag `{0}`! You can call this tag by entering !tag {0}".format(tag))
|
||||
|
||||
@tag.command(name='delete', aliases=['remove', 'stop'], pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
|
@ -88,12 +85,14 @@ class Tags:
|
|||
|
||||
EXAMPLE: !tag delete stupid_tag
|
||||
RESULT: Deletes that stupid tag"""
|
||||
r_filter = lambda row: (row['server_id'] == ctx.message.server.id) & (row['tag'] == tag)
|
||||
if await config.remove_content('tags', r_filter):
|
||||
await self.bot.say('I have just removed the tag `{}`'.format(tag))
|
||||
await self.bot.say("Temporarily disabled")
|
||||
# TODO: Fix tags, this will inherently fix this method
|
||||
"""r_filter = lambda row: (row['server_id'] == ctx.message.guild.id) & (row['tag'] == tag)
|
||||
if await utils.remove_content('tags', r_filter):
|
||||
await ctx.send('I have just removed the tag `{}`'.format(tag))
|
||||
else:
|
||||
await self.bot.say(
|
||||
"The tag {} does not exist! You can't remove something if it doesn't exist...".format(tag))
|
||||
await ctx.send(
|
||||
"The tag {} does not exist! You can't remove something if it doesn't exist...".format(tag))"""
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
166
cogs/twitch.py
166
cogs/twitch.py
|
@ -5,7 +5,6 @@ from . import utils
|
|||
import aiohttp
|
||||
import asyncio
|
||||
import discord
|
||||
import json
|
||||
import re
|
||||
import rethinkdb as r
|
||||
import traceback
|
||||
|
@ -23,11 +22,10 @@ class Twitch:
|
|||
self.bot = bot
|
||||
self.key = utils.twitch_key
|
||||
self.params = {'client_id': self.key}
|
||||
self.headers = {"User-Agent": utils.user_agent,
|
||||
"Client-ID": self.key}
|
||||
|
||||
async def channel_online(self, channel: str):
|
||||
async def channel_online(self, twitch_url: str):
|
||||
# Check a specific channel's data, and get the response in text format
|
||||
channel = re.search("(?<=twitch.tv/)(.*)", twitch_url).group(1)
|
||||
url = "https://api.twitch.tv/kraken/streams/{}".format(channel)
|
||||
|
||||
response = await utils.request(url, payload=self.params)
|
||||
|
@ -46,100 +44,96 @@ class Twitch:
|
|||
# Loop through as long as the bot is connected
|
||||
try:
|
||||
while not self.bot.is_closed:
|
||||
twitch = await utils.get_content('twitch', {'notifications_on': 1})
|
||||
# Online/offline is based on whether they are set to such, in the utils file
|
||||
# This means they were detected as online/offline before and we check for a change
|
||||
online_users = {data['member_id']: data for data in twitch if data['live']}
|
||||
offline_users = {data['member_id']: data for data in twitch if not data['live']}
|
||||
for m_id, result in offline_users.items():
|
||||
# Get their url and their user based on that url
|
||||
url = result['twitch_url']
|
||||
user = re.search("(?<=twitch.tv/)(.*)", url).group(1)
|
||||
# Check if they are online right now
|
||||
if await self.channel_online(user):
|
||||
for server_id in result['servers']:
|
||||
# Get the channel to send the message to, based on the saved alert's channel
|
||||
server = self.bot.get_server(server_id)
|
||||
twitch = await utils.filter_content('twitch', {'notifications_on': 1})
|
||||
for data in twitch:
|
||||
m_id = data['member_id']
|
||||
url = data['twitch_url']
|
||||
# Check if they are online
|
||||
online = await self.channel_online(url)
|
||||
# If they're currently online, but saved as not then we'll send our notification
|
||||
if online and data['live'] == 0:
|
||||
for s_id in data['servers']:
|
||||
server = self.bot.get_server(s_id)
|
||||
if server is None:
|
||||
continue
|
||||
server_alerts = await utils.get_content('server_alerts', {'server_id': server_id})
|
||||
try:
|
||||
channel_id = server_alerts[0]['channel_id']
|
||||
except (IndexError, TypeError):
|
||||
channel_id = server_id
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
# Get the member that has just gone live
|
||||
member = discord.utils.get(server.members, id=m_id)
|
||||
member = server.get_member(m_id)
|
||||
if member is None:
|
||||
continue
|
||||
|
||||
fmt = "{} has just gone live! View their stream at {}".format(member.display_name, url)
|
||||
await self.bot.send_message(channel, fmt)
|
||||
await utils.update_content('twitch', {'live': 1}, {'member_id': m_id})
|
||||
for m_id, result in online_users.items():
|
||||
# Get their url and their user based on that url
|
||||
url = result['twitch_url']
|
||||
user = re.search("(?<=twitch.tv/)(.*)", url).group(1)
|
||||
# Check if they are online right now
|
||||
if not await self.channel_online(user):
|
||||
for server_id in result['servers']:
|
||||
# Get the channel to send the message to, based on the saved alert's channel
|
||||
server = self.bot.get_server(server_id)
|
||||
server_settings = await utils.get_content('server_settings', s_id)
|
||||
if server_settings is not None:
|
||||
channel_id = server_settings.get('notification_channel', s_id)
|
||||
else:
|
||||
channel_id = s_id
|
||||
channel = server.get_channel(channel_id)
|
||||
await self.bot.send_message(channel, "{} has just gone live! View their stream at <{}>".format(member.display_name, data['twitch_url']))
|
||||
self.bot.loop.create_task(utils.update_content('twitch', {'live': 1}, m_id))
|
||||
elif not online and data['live'] == 1:
|
||||
for s_id in data['servers']:
|
||||
server = self.bot.get_server(s_id)
|
||||
if server is None:
|
||||
continue
|
||||
server_alerts = await utils.get_content('server_alerts', {'server_id': server_id})
|
||||
channel_id = server_id
|
||||
if server_alerts is not None and len(server_alerts) > 0:
|
||||
channel_id = server_alerts[0].get('channel_id')
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
# Get the member that has just gone live
|
||||
member = discord.utils.get(server.members, id=m_id)
|
||||
fmt = "{} has just gone offline! Catch them next time they stream at {}".format(
|
||||
member.display_name, url)
|
||||
await self.bot.send_message(channel, fmt)
|
||||
await utils.update_content('twitch', {'live': 0}, {'member_id': m_id})
|
||||
member = server.get_member(m_id)
|
||||
if member is None:
|
||||
continue
|
||||
server_settings = await utils.get_content('server_settings', s_id)
|
||||
if server_settings is not None:
|
||||
channel_id = server_settings.get('notification_channel', s_id)
|
||||
else:
|
||||
channel_id = s_id
|
||||
channel = server.get_channel(channel_id)
|
||||
await self.bot.send_message(channel, "{} has just gone offline! View their stream next time at <{}>".format(member.display_name, data['twitch_url']))
|
||||
self.bot.loop.create_task(utils.update_content('twitch', {'live': 0}, m_id))
|
||||
await asyncio.sleep(30)
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
fmt = "{1}\n{0.__class__.__name__}: {0}".format(tb, e)
|
||||
log.error(fmt)
|
||||
|
||||
@commands.group(no_pm=True, invoke_without_command=True, pass_context=True)
|
||||
@commands.group(no_pm=True, invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def twitch(self, ctx, *, member: discord.Member = None):
|
||||
"""Use this command to check the twitch info of a user
|
||||
|
||||
EXAMPLE: !twitch @OtherPerson
|
||||
RESULT: Information about their twitch URL"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
if member is None:
|
||||
member = ctx.message.author
|
||||
|
||||
result = await utils.get_content('twitch', {'member_id': member.id})
|
||||
result = await utils.get_content('twitch', member.id)
|
||||
if result is None:
|
||||
await self.bot.say("{} has not saved their twitch URL yet!".format(member.name))
|
||||
return
|
||||
|
||||
result = result[0]
|
||||
url = result['twitch_url']
|
||||
user = re.search("(?<=twitch.tv/)(.*)", url).group(1)
|
||||
twitch_url = "https://api.twitch.tv/kraken/channels/{}?client_id={}".format(user, self.key)
|
||||
with aiohttp.ClientSession() as s:
|
||||
async with s.get(twitch_url) as response:
|
||||
data = await response.json()
|
||||
twitch_url = "https://api.twitch.tv/kraken/channels/{}".format(user)
|
||||
payload = {'client_id': self.key}
|
||||
data = await utils.request(twitch_url, payload=payload)
|
||||
|
||||
fmt = "Username: {}".format(data['display_name'])
|
||||
fmt += "\nStatus: {}".format(data['status'])
|
||||
fmt += "\nFollowers: {}".format(data['followers'])
|
||||
fmt += "\nURL: {}".format(url)
|
||||
await self.bot.say("```\n{}```".format(fmt))
|
||||
embed = discord.Embed(title=data['display_name'], url=url)
|
||||
if data['logo']:
|
||||
embed.set_thumbnail(url=data['logo'])
|
||||
|
||||
@twitch.command(name='add', pass_context=True, no_pm=True)
|
||||
embed.add_field(name='Title', value=data['status'])
|
||||
embed.add_field(name='Followers', value=data['followers'])
|
||||
embed.add_field(name='Views', value=data['views'])
|
||||
if data['game']:
|
||||
embed.add_field(name='Game', value=data['game'])
|
||||
embed.add_field(name='Language', value=data['broadcaster_language'])
|
||||
|
||||
await self.bot.say(embed=embed)
|
||||
|
||||
@twitch.command(name='add', no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def add_twitch_url(self, ctx, url: str):
|
||||
"""Saves your user's twitch URL
|
||||
|
||||
EXAMPLE: !twitch add MyTwitchName
|
||||
RESULT: Saves your twitch URL; notifications will be sent to this server when you go live"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
# This uses a lookbehind to check if twitch.tv exists in the url given
|
||||
# If it does, it matches twitch.tv/user and sets the url as that
|
||||
# Then (in the else) add https://www. to that
|
||||
|
@ -156,29 +150,28 @@ class Twitch:
|
|||
url = "https://www.{}".format(url)
|
||||
|
||||
# Try to find the channel provided, we'll get a 404 response if it does not exist
|
||||
with aiohttp.ClientSession() as s:
|
||||
async with s.get(url) as response:
|
||||
if not response.status == 200:
|
||||
await self.bot.say("That twitch user does not exist! "
|
||||
"What would be the point of adding a nonexistant twitch user? Silly")
|
||||
return
|
||||
status = await utils.request(url, attr='status')
|
||||
if not status == 200:
|
||||
await self.bot.say("That twitch user does not exist! "
|
||||
"What would be the point of adding a nonexistant twitch user? Silly")
|
||||
return
|
||||
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
key = ctx.message.author.id
|
||||
entry = {'twitch_url': url,
|
||||
'servers': [ctx.message.server.id],
|
||||
'notifications_on': 1,
|
||||
'live': 0,
|
||||
'member_id': ctx.message.author.id}
|
||||
'member_id': key}
|
||||
update = {'twitch_url': url}
|
||||
|
||||
# Check to see if this user has already saved a twitch URL
|
||||
# If they have, update the URL, otherwise create a new entry
|
||||
# Assuming they're not live, and notifications should be on
|
||||
if not await utils.add_content('twitch', entry, r_filter):
|
||||
await utils.update_content('twitch', update, r_filter)
|
||||
if not await utils.add_content('twitch', entry):
|
||||
await utils.update_content('twitch', update, key)
|
||||
await self.bot.say("I have just saved your twitch url {}".format(ctx.message.author.mention))
|
||||
|
||||
@twitch.command(name='remove', aliases=['delete'], pass_context=True, no_pm=True)
|
||||
@twitch.command(name='remove', aliases=['delete'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def remove_twitch_url(self, ctx):
|
||||
"""Removes your twitch URL
|
||||
|
@ -186,11 +179,10 @@ class Twitch:
|
|||
EXAMPLE: !twitch remove
|
||||
RESULT: I stop saving your twitch URL"""
|
||||
# Just try to remove it, if it doesn't exist, nothing is going to happen
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
await utils.remove_content('twitch', r_filter)
|
||||
await utils.remove_content('twitch', ctx.message.author.id)
|
||||
await self.bot.say("I am no longer saving your twitch URL {}".format(ctx.message.author.mention))
|
||||
|
||||
@twitch.group(pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@twitch.group(no_pm=True, invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify(self, ctx):
|
||||
"""This can be used to modify notification settings for your twitch user
|
||||
|
@ -198,43 +190,41 @@ class Twitch:
|
|||
|
||||
EXAMPLE: !twitch notify
|
||||
RESULT: This server will now be notified when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
result = await utils.get_content('twitch', r_filter)
|
||||
key = ctx.message.author.id
|
||||
result = await utils.get_content('twitch', key)
|
||||
# Check if this user is saved at all
|
||||
if result is None:
|
||||
await self.bot.say(
|
||||
"I do not have your twitch URL added {}. You can save your twitch url with !twitch add".format(
|
||||
ctx.message.author.mention))
|
||||
# Then check if this server is already added as one to notify in
|
||||
elif ctx.message.server.id in result[0]['servers']:
|
||||
elif ctx.message.server.id in result['servers']:
|
||||
await self.bot.say("I am already set to notify in this server...")
|
||||
else:
|
||||
await utils.update_content('twitch', {'servers': r.row['servers'].append(ctx.message.server.id)}, r_filter)
|
||||
await utils.update_content('twitch', {'servers': r.row['servers'].append(ctx.message.server.id)}, key)
|
||||
await self.bot.say("This server will now be notified if you go live")
|
||||
|
||||
@notify.command(name='on', aliases=['start,yes'], pass_context=True, no_pm=True)
|
||||
@notify.command(name='on', aliases=['start,yes'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify_on(self, ctx):
|
||||
"""Turns twitch notifications on
|
||||
|
||||
EXAMPLE: !twitch notify on
|
||||
RESULT: Notifications will be sent when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
if await utils.update_content('twitch', {"notifications_on": 1}, r_filter):
|
||||
if await utils.update_content('twitch', {"notifications_on": 1}, ctx.message.author.id):
|
||||
await self.bot.say("I will notify if you go live {}, you'll get a bajillion followers I promise c:".format(
|
||||
ctx.message.author.mention))
|
||||
else:
|
||||
await self.bot.say("I can't notify if you go live if I don't know your twitch URL yet!")
|
||||
|
||||
@notify.command(name='off', aliases=['stop,no'], pass_context=True, no_pm=True)
|
||||
@notify.command(name='off', aliases=['stop,no'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify_off(self, ctx):
|
||||
"""Turns twitch notifications off
|
||||
|
||||
EXAMPLE: !twitch notify off
|
||||
RESULT: Notifications will not be sent when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
if await utils.update_content('twitch', {"notifications_on": 1}, r_filter):
|
||||
if await utils.update_content('twitch', {"notifications_on": 0}, ctx.message.author.id):
|
||||
await self.bot.say(
|
||||
"I will not notify if you go live anymore {}, "
|
||||
"are you going to stream some lewd stuff you don't want people to see?~".format(
|
||||
|
@ -247,4 +237,4 @@ class Twitch:
|
|||
def setup(bot):
|
||||
t = Twitch(bot)
|
||||
bot.loop.create_task(t.check_channels())
|
||||
bot.add_cog(Twitch(bot))
|
||||
bot.add_cog(Twitch(bot))
|
|
@ -5,6 +5,7 @@ import inspect
|
|||
from . import config
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def convert_to_jpeg(pfile):
|
||||
# Open the file given
|
||||
img = Image.open(pfile)
|
||||
|
@ -16,6 +17,7 @@ def convert_to_jpeg(pfile):
|
|||
new_file.seek(0)
|
||||
return new_file
|
||||
|
||||
|
||||
def get_all_commands(bot):
|
||||
"""Returns a list of all command names for the bot"""
|
||||
# First lets create a set of all the parent names
|
||||
|
@ -31,6 +33,7 @@ def get_all_commands(bot):
|
|||
|
||||
return all_commands
|
||||
|
||||
|
||||
def get_subcommands(command):
|
||||
yield command.qualified_name
|
||||
try:
|
||||
|
@ -40,6 +43,19 @@ def get_subcommands(command):
|
|||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
async def channel_is_nsfw(channel):
|
||||
server = channel.server.id
|
||||
channel = channel.id
|
||||
|
||||
server_settings = await config.get_content('server_settings', server)
|
||||
|
||||
try:
|
||||
return channel in server_settings['nsfw_channels']
|
||||
except (TypeError, IndexError, KeyError):
|
||||
return False
|
||||
|
||||
|
||||
def find_command(bot, command):
|
||||
"""Finds a command (be it parent or sub command) based on string given"""
|
||||
# This method ensures the command given is valid. We need to loop through commands
|
||||
|
@ -64,6 +80,7 @@ def find_command(bot, command):
|
|||
|
||||
return cmd
|
||||
|
||||
|
||||
async def download_image(url):
|
||||
"""Returns a file-like object based on the URL provided"""
|
||||
headers = {'User-Agent': config.user_agent}
|
||||
|
@ -76,6 +93,7 @@ async def download_image(url):
|
|||
image = BytesIO(bts)
|
||||
return image
|
||||
|
||||
|
||||
async def request(url, *, headers=None, payload=None, method='GET', attr='json'):
|
||||
# Make sure our User Agent is what's set, and ensure it's sent even if no headers are passed
|
||||
if headers == None:
|
||||
|
@ -112,6 +130,7 @@ async def request(url, *, headers=None, payload=None, method='GET', attr='json')
|
|||
except:
|
||||
continue
|
||||
|
||||
|
||||
async def update_records(key, winner, loser):
|
||||
# We're using the Harkness scale to rate
|
||||
# http://opnetchessclub.wikidot.com/harkness-rating-system
|
||||
|
|
Loading…
Reference in a new issue