Start of the v3 branch
This commit is contained in:
34
README.md
34
README.md
@@ -1,36 +1,6 @@
|
||||
# aikaterna-cogs
|
||||
Cogs for Red-DiscordBot by Twentysix26.
|
||||
v3 Cogs for Red-DiscordBot by Twentysix26.
|
||||
|
||||
autoeconomy - New users that join the server will be automatically given a bank account.
|
||||
|
||||
away - By Paddolicious#8880. Set and unset a user as being "away".
|
||||
|
||||
cah - Cards Against Humanity. A port of CorpBot's module: https://github.com/corpnewt/CorpBot.py
|
||||
|
||||
chatchart - Generates a pie chart to display chat activity over the last 5000 messages. Requested by violetnyte.
|
||||
|
||||
forwarding - Forwards DMs sent to the bot to the owner of the bot. A port of the forwarding module from: https://github.com/jacobcheatley/dankbot
|
||||
|
||||
hunting - By Paddolicious#8880. It hunts birds... and things that fly.
|
||||
|
||||
imgwelcome - Welcome users to your server with a customized image.
|
||||
|
||||
otherbot - Have multiple Red instances and want to know when one goes offline? Edit this cog and load it on your watcher bot.
|
||||
|
||||
pug - Warcraft pug checker. A port of PugBot's module: https://github.com/reznok/PugBot
|
||||
|
||||
radio - A hidden unpublished gem from Paddo, with a couple edits. Plays http audio streams like icecast and mp3 streams.
|
||||
|
||||
riot - an old Fredboat command, requested by Mewleficent.
|
||||
|
||||
seen - By Paddolicious#8880. Check when the user was last active on a server.
|
||||
|
||||
serverlimit - Limit the bot to joining servers with over 25 members.
|
||||
|
||||
|
||||
The chatterbot cog that was previously on this repo has been removed in favor of: https://github.com/Nobleasskicker/GrandeCogs/tree/master/chat
|
||||
|
||||
Q: Why do you have some of Paddo's cogs on your repo?
|
||||
A: He recently made an announcement about finding a new home for a few cogs. I've picked up a couple and I welcome PRs or feature requests. I'm also intending to port these for Red v3 as I can.
|
||||
away - Originally by Paddo, written for v3 by Axas, final tests by aikaterna. Set and unset a user as being "away".
|
||||
|
||||
Feel free to join the server for these cogs if you'd like. https://discord.gg/th6eS3T
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
import asyncio
|
||||
import discord
|
||||
import os
|
||||
from __main__ import send_cmd_help
|
||||
from cogs.utils import checks
|
||||
from cogs.utils.dataIO import dataIO
|
||||
from copy import deepcopy
|
||||
from discord.ext import commands
|
||||
|
||||
default_settings = {"CHANNEL": None,
|
||||
"DEBUG": False,
|
||||
"TOGGLE": False,
|
||||
}
|
||||
|
||||
|
||||
class AutoEconomy:
|
||||
"""Auto-registers new users to the bank. Must have Economy loaded."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.settings = dataIO.load_json('data/autoeconomy/settings.json')
|
||||
self.banksettings = dataIO.load_json('data/economy/settings.json')
|
||||
self.version = "0.1.1b"
|
||||
|
||||
async def save_settings(self):
|
||||
dataIO.save_json('data/autoeconomy/settings.json', self.settings)
|
||||
|
||||
async def _data_check(self, ctx):
|
||||
server = ctx.message.server
|
||||
if server.id not in self.settings:
|
||||
self.settings[server.id] = deepcopy(default_settings)
|
||||
self.settings[server.id]["CHANNEL"] = ctx.message.channel.id
|
||||
await self.save_settings()
|
||||
econ_cog = self.bot.get_cog('Economy')
|
||||
if not econ_cog:
|
||||
await self.bot.say("You must have Economy loaded to use this cog. \nAny settings saved will not work until the cog is loaded.")
|
||||
return
|
||||
|
||||
@checks.admin_or_permissions(manage_server=True)
|
||||
@commands.group(pass_context=True)
|
||||
async def autoeconomy(self, ctx):
|
||||
"""Configuration options for auto-registering Economy accounts."""
|
||||
if ctx.invoked_subcommand is None:
|
||||
await send_cmd_help(ctx)
|
||||
return
|
||||
|
||||
@autoeconomy.command(pass_context=True, name="debug", no_pm=True)
|
||||
async def autoeconomy_debug(self, ctx):
|
||||
"""Toggle autoeconomy debug messages."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]["DEBUG"] = not self.settings[server.id]["DEBUG"]
|
||||
if self.settings[server.id]["DEBUG"]:
|
||||
await self.bot.say("Debug messages on.")
|
||||
else:
|
||||
await self.bot.say("Debug messages off.")
|
||||
await self.save_settings()
|
||||
|
||||
@autoeconomy.command(pass_context=True, name="channel", no_pm=True)
|
||||
async def autoeconomy_channel(self, ctx, channel: discord.Channel):
|
||||
"""Set a channel for the debug messages."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
if not server.me.permissions_in(channel).send_messages:
|
||||
await self.bot.say("No permissions to speak in that channel.")
|
||||
return
|
||||
self.settings[server.id]["CHANNEL"] = channel.id
|
||||
await self.save_settings()
|
||||
await self.bot.send_message(channel, "This channel will be used for debug messages.")
|
||||
|
||||
@autoeconomy.command(pass_context=True, name="toggle", no_pm=True)
|
||||
async def autoeconomy_toggle(self, ctx):
|
||||
"""Toggle autoeconomy on the server."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]["TOGGLE"] = not self.settings[server.id]["TOGGLE"]
|
||||
if self.settings[server.id]["TOGGLE"]:
|
||||
await self.bot.say("New users will automatically be registered for a bank account.")
|
||||
else:
|
||||
await self.bot.say("No longer auto-registering new users.")
|
||||
await self.save_settings()
|
||||
|
||||
@autoeconomy.command(name="version", pass_context=True, hidden=True)
|
||||
async def autoeconomy_version(self):
|
||||
"""Displays the autoeconomy version."""
|
||||
await self.bot.say("autoeconomy version {}.".format(self.version))
|
||||
|
||||
async def on_member_join(self, member):
|
||||
server = member.server
|
||||
if server.id not in self.settings:
|
||||
self.settings[server.id] = deepcopy(default_settings)
|
||||
await self.save_settings()
|
||||
if not self.settings[server.id]["TOGGLE"]:
|
||||
return
|
||||
channel = self.settings[server.id]["CHANNEL"]
|
||||
channel_object = self.bot.get_channel(channel)
|
||||
econ_cog = self.bot.get_cog('Economy')
|
||||
if not econ_cog:
|
||||
return
|
||||
bank = self.bot.get_cog('Economy').bank
|
||||
try:
|
||||
bank.create_account(member)
|
||||
except Exception:
|
||||
if self.settings[server.id]["DEBUG"]:
|
||||
await self.bot.send_message(channel_object, "Economy account already exists for {}.".format(member.name))
|
||||
return
|
||||
if self.banksettings[server.id]["REGISTER_CREDITS"]:
|
||||
reg_credits = self.banksettings[server.id]["REGISTER_CREDITS"]
|
||||
bank.deposit_credits(member, reg_credits)
|
||||
if self.settings[server.id]["DEBUG"]:
|
||||
await self.bot.send_message(channel_object, "Bank account opened for {} and initial credits given.".format(member.name))
|
||||
return
|
||||
|
||||
|
||||
def check_folders():
|
||||
if not os.path.exists('data/autoeconomy/'):
|
||||
os.mkdir('data/autoeconomy/')
|
||||
|
||||
|
||||
def check_files():
|
||||
if not dataIO.is_valid_json('data/autoeconomy/settings.json'):
|
||||
defaults = {}
|
||||
dataIO.save_json('data/autoeconomy/settings.json', defaults)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folders()
|
||||
check_files()
|
||||
bot.add_cog(AutoEconomy(bot))
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna",
|
||||
"INSTALL_MSG" : "Use [p]autoeconomy to change settings.",
|
||||
"NAME" : "autoeconomy",
|
||||
"SHORT" : "Autoregister new users to the bot bank on server join.",
|
||||
"DESCRIPTION" : "Auto-registers new users to the bot bank on server join. You must have the Economy cog loaded for this cog to work.",
|
||||
"TAGS": ["bank", "economy", "register"]
|
||||
}
|
||||
88
away/away.py
88
away/away.py
@@ -1,88 +0,0 @@
|
||||
import os
|
||||
import discord
|
||||
from .utils import checks
|
||||
from discord.ext import commands
|
||||
from cogs.utils.dataIO import dataIO
|
||||
|
||||
|
||||
class Away:
|
||||
"""Le away cog"""
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.data = dataIO.load_json('data/away/away.json')
|
||||
|
||||
async def listener(self, message):
|
||||
tmp = {}
|
||||
server = message.server
|
||||
if server.id not in self.data:
|
||||
for mention in message.mentions:
|
||||
tmp[mention] = True
|
||||
if message.author.id != self.bot.user.id:
|
||||
for author in tmp:
|
||||
if author.id in self.data:
|
||||
try:
|
||||
avatar = author.avatar_url if author.avatar else author.default_avatar_url
|
||||
if self.data[author.id]['MESSAGE']:
|
||||
em = discord.Embed(description=self.data[author.id]['MESSAGE'], color=discord.Color.blue())
|
||||
em.set_author(name='{} is currently away'.format(author.display_name), icon_url=avatar)
|
||||
else:
|
||||
em = discord.Embed(color=discord.Color.blue())
|
||||
em.set_author(name='{} is currently away'.format(author.display_name), icon_url=avatar)
|
||||
await self.bot.send_message(message.channel, embed=em)
|
||||
except:
|
||||
if self.data[author.id]['MESSAGE']:
|
||||
msg = '{} is currently away and has set the following message: `{}`'.format(author.display_name, self.data[author.id]['MESSAGE'])
|
||||
else:
|
||||
msg = '{} is currently away'.format(author.display_name)
|
||||
await self.bot.send_message(message.channel, msg)
|
||||
|
||||
@commands.command(pass_context=True, name="away")
|
||||
async def _away(self, context, *message: str):
|
||||
"""Tell the bot you're away or back."""
|
||||
author = context.message.author
|
||||
if author.id in self.data:
|
||||
del self.data[author.id]
|
||||
msg = 'You\'re now back.'
|
||||
else:
|
||||
self.data[context.message.author.id] = {}
|
||||
if len(str(message)) < 256:
|
||||
self.data[context.message.author.id]['MESSAGE'] = ' '.join(context.message.clean_content.split()[1:])
|
||||
else:
|
||||
self.data[context.message.author.id]['MESSAGE'] = True
|
||||
msg = 'You\'re now set as away.'
|
||||
dataIO.save_json('data/away/away.json', self.data)
|
||||
await self.bot.say(msg)
|
||||
|
||||
@commands.command(pass_context=True, name="toggleaway")
|
||||
@checks.mod_or_permissions(administrator=True)
|
||||
async def _ignore(self, context):
|
||||
server = context.message.server
|
||||
if server.id in self.data:
|
||||
del self.data[server.id]
|
||||
message = 'Not ignoring this server anymore.'
|
||||
else:
|
||||
self.data[server.id] = True
|
||||
message = 'Ignoring this server.'
|
||||
dataIO.save_json('data/away/away.json', self.data)
|
||||
await self.bot.say(message)
|
||||
|
||||
|
||||
def check_folder():
|
||||
if not os.path.exists('data/away'):
|
||||
print('Creating data/away folder...')
|
||||
os.makedirs('data/away')
|
||||
|
||||
|
||||
def check_file():
|
||||
f = 'data/away/away.json'
|
||||
if not dataIO.is_valid_json(f):
|
||||
dataIO.save_json(f, {})
|
||||
print('Creating default away.json...')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folder()
|
||||
check_file()
|
||||
n = Away(bot)
|
||||
bot.add_listener(n.listener, 'on_message')
|
||||
bot.add_cog(n)
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "Paddolicious#8880",
|
||||
"NAME" : "Away",
|
||||
"SHORT" : "Sets and unsets a user away.",
|
||||
"DESCRIPTION" : "Sets the user as away. When someone mentions the users the bot replies with either its own message or a message set by the user that the user is away.",
|
||||
"TAGS": ["away", "member", "tool"]
|
||||
}
|
||||
1690
cah/cah.py
1690
cah/cah.py
File diff suppressed because it is too large
Load Diff
2434
cah/data/deck.json
2434
cah/data/deck.json
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna",
|
||||
"INSTALL_MSG" : "Thanks for installing Cards Against Humanity. I highly advise only playing this game with 3-4 people on one server, on a private bot, because of the high amount of DM's this game generates.",
|
||||
"NAME" : "cah",
|
||||
"SHORT" : "Cards Against Humanity.",
|
||||
"DESCRIPTION" : "This cog was made possible by CorpBot: https://github.com/corpnewt/CorpBot.py"
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
# Lines 54 through 68 are influenced heavily by cacobot's stats module:
|
||||
# https://github.com/Orangestar12/cacobot/blob/master/cacobot/stats.py
|
||||
# Big thanks to Redjumpman for changing the beta version from
|
||||
# Imagemagick/cairosvg to matplotlib.
|
||||
# Thanks to violetnyte for suggesting this cog.
|
||||
import discord
|
||||
import heapq
|
||||
import os
|
||||
from io import BytesIO
|
||||
import matplotlib
|
||||
matplotlib.use('agg')
|
||||
import matplotlib.pyplot as plt
|
||||
plt.switch_backend('agg')
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
class ChatChart:
|
||||
"""Show activity."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
def create_chart(self, top, others):
|
||||
plt.clf()
|
||||
sizes = [x[1] for x in top]
|
||||
labels = ["{} {:g}%".format(x[0], x[1]) for x in top]
|
||||
if len(top) >= 10:
|
||||
sizes = sizes + [others]
|
||||
labels = labels + ["Others {:g}%".format(others)]
|
||||
|
||||
title = plt.title('User activity in the last 5000 messages')
|
||||
title.set_va("top")
|
||||
title.set_ha("left")
|
||||
plt.gca().axis("equal")
|
||||
colors = ['r', 'darkorange', 'gold', 'y', 'olivedrab', 'green', 'darkcyan', 'mediumblue', 'darkblue', 'blueviolet', 'indigo']
|
||||
pie = plt.pie(sizes, colors=colors, startangle=0)
|
||||
plt.legend(pie[0], labels, bbox_to_anchor=(0.7, 0.5), loc="center", fontsize=10,
|
||||
bbox_transform=plt.gcf().transFigure)
|
||||
plt.subplots_adjust(left=0.0, bottom=0.1, right=0.45)
|
||||
image_object = BytesIO()
|
||||
plt.savefig(image_object, format='PNG')
|
||||
image_object.seek(0)
|
||||
return image_object
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.cooldown(1, 10, commands.BucketType.channel)
|
||||
async def chatchart(self, ctx):
|
||||
"""
|
||||
Generates a pie chart, representing the last 5000 messages in this channel.
|
||||
"""
|
||||
channel = ctx.message.channel
|
||||
e = discord.Embed(description="Loading...", colour=0x00ccff)
|
||||
e.set_thumbnail(url="https://i.imgur.com/vSp4xRk.gif")
|
||||
em = await self.bot.say(embed=e)
|
||||
|
||||
history = []
|
||||
async for msg in self.bot.logs_from(channel, 5000):
|
||||
history.append(msg)
|
||||
msg_data = {'total count': 0, 'users': {}}
|
||||
|
||||
for msg in history:
|
||||
if msg.author.bot:
|
||||
pass
|
||||
elif msg.author.name in msg_data['users']:
|
||||
msg_data['users'][msg.author.name]['msgcount'] += 1
|
||||
msg_data['total count'] += 1
|
||||
else:
|
||||
msg_data['users'][msg.author.name] = {}
|
||||
msg_data['users'][msg.author.name]['msgcount'] = 1
|
||||
msg_data['total count'] += 1
|
||||
|
||||
for usr in msg_data['users']:
|
||||
pd = float(msg_data['users'][usr]['msgcount']) / float(msg_data['total count'])
|
||||
msg_data['users'][usr]['percent'] = round(pd * 100, 1)
|
||||
|
||||
top_ten = heapq.nlargest(10, [(x, msg_data['users'][x][y])
|
||||
for x in msg_data['users']
|
||||
for y in msg_data['users'][x]
|
||||
if y == 'percent'], key=lambda x: x[1])
|
||||
others = 100 - sum(x[1] for x in top_ten)
|
||||
img = self.create_chart(top_ten, others)
|
||||
await self.bot.delete_message(em)
|
||||
await self.bot.send_file(channel, img, filename="chart.png")
|
||||
|
||||
|
||||
def check_folders():
|
||||
if not os.path.exists("data/chatchart"):
|
||||
print("Creating data/chatchart folder...")
|
||||
os.makedirs("data/chatchart")
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folders()
|
||||
bot.add_cog(ChatChart(bot))
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna and Redjumpman",
|
||||
"INSTALL_MSG" : "Use [p]chatchart to generate a chart for that channel.",
|
||||
"NAME" : "chatchart",
|
||||
"SHORT" : "Generate a pie chart from the last 5000 messages.",
|
||||
"DESCRIPTION" : "Generate a pie chart from the last 5000 messages in a channel to see who's been talking the most.",
|
||||
"REQUIREMENTS": ["matplotlib"],
|
||||
"TAGS": ["data", "chart", "activity"]
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
# forwarding.py is ported from another bot:
|
||||
# https://github.com/jacobcheatley/dankbot
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from .utils.dataIO import dataIO
|
||||
from .utils import checks
|
||||
|
||||
|
||||
class Forwarding:
|
||||
def __init__(self, bot: commands.Bot):
|
||||
self.bot = bot
|
||||
self.owner = self.get_owner()
|
||||
|
||||
def get_owner(self):
|
||||
owner_id = dataIO.load_json("data/red/settings.json")["OWNER"]
|
||||
return discord.utils.find(lambda m: m.id == owner_id, self.bot.get_all_members())
|
||||
|
||||
async def send_to_owner(self, **kwargs):
|
||||
if self.owner is None:
|
||||
self.owner = self.get_owner()
|
||||
await self.bot.send_message(self.owner, **kwargs)
|
||||
|
||||
async def on_message(self, message: discord.Message):
|
||||
if self.owner is None:
|
||||
self.owner = self.get_owner()
|
||||
if not message.channel.is_private or message.channel.user.id == self.owner.id:
|
||||
return
|
||||
|
||||
embed = discord.Embed()
|
||||
if message.author == self.bot.user:
|
||||
embed.title = 'Sent PM to {}#{} ({}).'.format(message.channel.user.name, message.channel.user.discriminator, message.channel.user.id)
|
||||
else:
|
||||
embed.set_author(name=message.author, icon_url=message.author.avatar_url or message.author.default_avatar_url)
|
||||
embed.title = '{} messaged me:'.format(message.channel.user.id)
|
||||
embed.description = message.content
|
||||
embed.timestamp = message.timestamp
|
||||
|
||||
await self.send_to_owner(embed=embed)
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
async def pm(self, user: discord.User, *, content: str):
|
||||
"""PMs a person."""
|
||||
await self.bot.send_message(user, content)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Forwarding(bot))
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna",
|
||||
"NAME" : "forwarding",
|
||||
"SHORT" : "Forwards DMs sent to the bot to the owner.",
|
||||
"DESCRIPTION" : "Forwards DMs sent to the bot to the owner.",
|
||||
"TAGS": ["message", "dm"]
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
from __main__ import send_cmd_help
|
||||
from .utils.dataIO import dataIO
|
||||
from discord.ext import commands
|
||||
from .utils import checks
|
||||
import datetime
|
||||
import asyncio
|
||||
import discord
|
||||
import random
|
||||
import time
|
||||
import os
|
||||
|
||||
# TODO
|
||||
# Show error when timing intervals are the same
|
||||
|
||||
|
||||
class Hunting:
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.scores = dataIO.load_json('data/hunting/scores.json')
|
||||
self.subscriptions = dataIO.load_json('data/hunting/subscriptions.json')
|
||||
self.settings = dataIO.load_json('data/hunting/settings.json')
|
||||
self.animals = {'duck': ':duck: **_Quack!_**', 'penguin': ':penguin: **_Noot!_**', 'chicken': ':rooster: **_Bah-gawk!_**', 'pigeon': ':dove: **_Coo!_**'}
|
||||
self.in_game = []
|
||||
self.paused_games = []
|
||||
self._latest_message_check_message_limit = 5
|
||||
self._latest_message_check_wait_limit = self.settings['hunt_interval_maximum'] * 2
|
||||
self.next = None
|
||||
|
||||
async def _save_scores(self):
|
||||
dataIO.save_json('data/hunting/scores.json', self.scores)
|
||||
|
||||
async def _save_subscriptions(self):
|
||||
dataIO.save_json('data/hunting/subscriptions.json', self.subscriptions)
|
||||
|
||||
async def _save_settings(self):
|
||||
dataIO.save_json('data/hunting/settings.json', self.settings)
|
||||
|
||||
@commands.group(pass_context=True, no_pm=True, name='hunting')
|
||||
async def _hunting(self, context):
|
||||
"""Hunting, it hunts birds... and things that fly"""
|
||||
if context.invoked_subcommand is None:
|
||||
await send_cmd_help(context)
|
||||
|
||||
@_hunting.command(pass_context=True, no_pm=True, name='start')
|
||||
async def _start(self, context):
|
||||
"""Start the hunt"""
|
||||
server = context.message.server
|
||||
channel = context.message.channel
|
||||
if server.id in self.subscriptions:
|
||||
message = '**We\'re already hunting!**'
|
||||
else:
|
||||
self.subscriptions[server.id] = channel.id
|
||||
message = '**The hunt has started. Good luck to all.**'
|
||||
await self._save_subscriptions()
|
||||
await self.bot.say(message)
|
||||
|
||||
@_hunting.command(pass_context=True, no_pm=True, name='stop')
|
||||
async def _stop(self, context):
|
||||
"""Stop the hunt"""
|
||||
server = context.message.server
|
||||
if server.id not in self.subscriptions:
|
||||
message = '**We\'re not hunting!**'
|
||||
else:
|
||||
del self.subscriptions[server.id]
|
||||
message = '**The hunt has stopped.**'
|
||||
await self._save_subscriptions()
|
||||
await self.bot.say(message)
|
||||
|
||||
@_hunting.command(no_pm=True, name='timing')
|
||||
@checks.is_owner()
|
||||
async def _timing(self, interval_min: int, interval_max: int, bang_timeout: int):
|
||||
"""Change the timing"""
|
||||
if interval_min > interval_max:
|
||||
message = '**`interval_min` needs to be lower than `interval_max`**'
|
||||
elif interval_min < 0 and interval_max < 0 and bang_timeout < 0:
|
||||
message = '**Please no negative numbers!**'
|
||||
elif interval_min == interval_max:
|
||||
message = '**`interval_min` and `interval_max` cannot be the same**'
|
||||
else:
|
||||
self.settings['hunt_interval_minimum'] = interval_min
|
||||
self.settings['hunt_interval_maximum'] = interval_max
|
||||
self.settings['wait_for_bang_timeout'] = bang_timeout
|
||||
await self._save_settings()
|
||||
message = '**Timing has been set.**'
|
||||
await self.bot.say(message)
|
||||
|
||||
@_hunting.command(pass_context=True, no_pm=True, name='next')
|
||||
@checks.is_owner()
|
||||
async def _next(self, context):
|
||||
"""When will the next occurance happen?"""
|
||||
if self.next:
|
||||
time = abs(datetime.datetime.utcnow() - self.next)
|
||||
total_seconds = int(time.total_seconds())
|
||||
hours, remainder = divmod(total_seconds, 60*60)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
message = '**The next occurance will be in {} hours and {} minutes.**'.format(hours, minutes)
|
||||
else:
|
||||
message = '**There is currently no hunt.**'
|
||||
await self.bot.say(message)
|
||||
|
||||
@_hunting.command(pass_context=True, no_pm=True, name='score')
|
||||
async def _score(self, context, member: discord.Member):
|
||||
"""This will show the score of a hunter"""
|
||||
server = context.message.server
|
||||
if server.id in self.scores:
|
||||
if member.id in self.scores[server.id]:
|
||||
message = '**{} shot a total of {} animals ({})**'.format(member.mention, self.scores[server.id][member.id]['total'], ', '.join([str(self.scores[server.id][member.id]['score'][x]) + ' ' + x.capitalize() + 's' for x in self.scores[server.id][member.id]['score']])) # (', '.join([str(self.scores[server.id][member.id]['score'][x]) + ' ' + x.capitalize() + 's' for x in self.scores[server.id][member.id]['score']]))
|
||||
else:
|
||||
message = '**Please shoot something before you can brag about it.**'
|
||||
else:
|
||||
message = '**Please shoot something before you can brag about it.**'
|
||||
await self.bot.say(message)
|
||||
|
||||
@_hunting.command(pass_context=True, no_pm=True, name='clearscore')
|
||||
@checks.serverowner()
|
||||
async def _clearscore(self, context):
|
||||
"""Clear the leaderboard"""
|
||||
server = context.message.server
|
||||
if server.id in self.scores:
|
||||
self.scores[server.id] = {}
|
||||
await self._save_scores()
|
||||
message = 'Leaderboard is cleared'
|
||||
else:
|
||||
message = 'There\'s nothing to clear'
|
||||
await self.bot.say(message)
|
||||
|
||||
@_hunting.command(pass_context=True, no_pm=True, name='leaderboard', aliases=['scores'])
|
||||
async def _huntingboard(self, context):
|
||||
"""This will show the top hunters on this server"""
|
||||
server = context.message.server
|
||||
if server.id in self.scores:
|
||||
p = self.scores[server.id]
|
||||
scores = sorted(p, key=lambda x: (p[x]['total']), reverse=True)
|
||||
message = '```\n{:<4}{:<8}{}\n\n'.format('#', 'TOTAL', 'USERNAME')
|
||||
for i, hunter in enumerate(scores, 1):
|
||||
if i > 10:
|
||||
break
|
||||
message += '{:<4}{:<8}{} ({})\n'.format(i, p[hunter]['total'], p[hunter]['author_name'], ', '.join([str(p[hunter]['score'][x]) + ' ' + x.capitalize() + 's' for x in p[hunter]['score']]))
|
||||
message += '```'
|
||||
else:
|
||||
message = '**Please shoot something before you can brag about it.**'
|
||||
await self.bot.say(message)
|
||||
|
||||
async def add_score(self, server, author, avian):
|
||||
if server.id not in self.scores:
|
||||
self.scores[server.id] = {}
|
||||
if author.id not in self.scores[server.id]:
|
||||
self.scores[server.id][author.id] = {}
|
||||
self.scores[server.id][author.id]['score'] = {}
|
||||
self.scores[server.id][author.id]['total'] = 0
|
||||
self.scores[server.id][author.id]['author_name'] = ''
|
||||
for a in list(self.animals.keys()):
|
||||
self.scores[server.id][author.id]['score'][a] = 0
|
||||
if avian not in self.scores[server.id][author.id]['score']:
|
||||
self.scores[server.id][author.id]['score'][avian] = 0
|
||||
self.scores[server.id][author.id]['author_name'] = author.display_name
|
||||
self.scores[server.id][author.id]['score'][avian] += 1
|
||||
self.scores[server.id][author.id]['total'] += 1
|
||||
await self._save_scores()
|
||||
|
||||
async def _wait_for_bang(self, server, channel):
|
||||
def check(message):
|
||||
return message.content.lower().split(' ')[0] == 'bang' or message.content.lower() == 'b' if message.content else False
|
||||
|
||||
animal = random.choice(list(self.animals.keys()))
|
||||
await self.bot.send_message(channel, self.animals[animal])
|
||||
message = await self.bot.wait_for_message(channel=channel, timeout=self.settings['wait_for_bang_timeout'], check=check)
|
||||
if message:
|
||||
author = message.author
|
||||
if random.randrange(0, 17) > 1:
|
||||
await self.add_score(server, author, animal)
|
||||
msg = '**{} shot a {}!**'.format(author.mention, animal)
|
||||
else:
|
||||
msg = '**{} missed the shot and the {} got away!**'.format(author.mention, animal)
|
||||
else:
|
||||
msg = '**The {} got away!** :confused:'.format(animal)
|
||||
self.in_game.remove(channel.id)
|
||||
await self.bot.send_message(channel, msg)
|
||||
|
||||
async def _latest_message_check(self, channel):
|
||||
async for message in self.bot.logs_from(channel, limit=self._latest_message_check_message_limit, reverse=True):
|
||||
delta = datetime.datetime.utcnow() - message.timestamp
|
||||
if delta.total_seconds() < self._latest_message_check_wait_limit and message.author.id != self.bot.user.id:
|
||||
if channel.id in self.paused_games:
|
||||
self.paused_games.remove(channel.id)
|
||||
return True
|
||||
if channel.id not in self.paused_games:
|
||||
self.paused_games.append(channel.id)
|
||||
await self.bot.send_message(channel, '**It seems there are no hunters here. The hunt will be resumed when someone treads here again.**')
|
||||
return False
|
||||
|
||||
async def _hunting_loop(self):
|
||||
while self == self.bot.get_cog('Hunting'):
|
||||
wait_time = random.randrange(self.settings['hunt_interval_minimum'], self.settings['hunt_interval_maximum'])
|
||||
self.next = datetime.datetime.fromtimestamp(int(time.mktime(datetime.datetime.utcnow().timetuple())) + wait_time)
|
||||
await asyncio.sleep(wait_time)
|
||||
for server in self.subscriptions:
|
||||
if self.subscriptions[server] not in self.in_game:
|
||||
channel = self.bot.get_channel(self.subscriptions[server])
|
||||
server = self.bot.get_server(server)
|
||||
if await self._latest_message_check(channel):
|
||||
self.in_game.append(self.subscriptions[server.id])
|
||||
self.bot.loop = asyncio.get_event_loop()
|
||||
self.bot.loop.create_task(self._wait_for_bang(server, channel))
|
||||
|
||||
|
||||
def check_folder():
|
||||
if not os.path.exists('data/hunting'):
|
||||
print('Creating data/hunting folder...')
|
||||
os.makedirs('data/hunting')
|
||||
|
||||
|
||||
def check_files():
|
||||
f = 'data/hunting/settings.json'
|
||||
if not dataIO.is_valid_json(f):
|
||||
print('Creating empty settings.json...')
|
||||
data = {}
|
||||
data['hunt_interval_minimum'] = 300
|
||||
data['hunt_interval_maximum'] = 600
|
||||
data['wait_for_bang_timeout'] = 30
|
||||
dataIO.save_json(f, data)
|
||||
|
||||
f = 'data/hunting/subscriptions.json'
|
||||
if not dataIO.is_valid_json(f):
|
||||
print('Creating empty subscriptions.json...')
|
||||
dataIO.save_json(f, {})
|
||||
|
||||
f = 'data/hunting/scores.json'
|
||||
if not dataIO.is_valid_json(f):
|
||||
print('Creating empty scores.json...')
|
||||
dataIO.save_json(f, {})
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folder()
|
||||
check_files()
|
||||
cog = Hunting(bot)
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task(cog._hunting_loop())
|
||||
bot.add_cog(cog)
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "Paddolicious#8880",
|
||||
"NAME" : "Hunting",
|
||||
"SHORT" : "Hunting, it hunts birds... and things that fly",
|
||||
"DESCRIPTION" : "Hunting, it hunts birds... and things that fly",
|
||||
"TAGS": ["Hunting", "hunt", "birds", "paddo"]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 KiB |
@@ -1,615 +0,0 @@
|
||||
# _is_hex, _hex_to_rgb, _rgb_to_hex are from Stevy's leveler.py
|
||||
# Also thanks to Stevy for nice, smooth circles.
|
||||
# https://github.com/AznStevy/Maybe-Useful-Cogs
|
||||
# imgwelcomeset_upload is based on code in orels' drawing.py
|
||||
# https://github.com/orels1/ORELS-Cogs
|
||||
# Parts of _create_welcome and on_member_join are from the Welcomer bot:
|
||||
# https://discordbots.org/bot/330416853971107840
|
||||
# Font switcher, font outline, and bonus text announcement toggles
|
||||
# thanks to Sitryk.
|
||||
# Font listing from FlapJack + aikaterna's yet unpublished wordcloud cog.
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import datetime
|
||||
import discord
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from __main__ import send_cmd_help
|
||||
from cogs.utils.dataIO import dataIO
|
||||
from cogs.utils import checks
|
||||
from copy import deepcopy
|
||||
from discord.ext import commands
|
||||
from io import BytesIO
|
||||
from PIL import Image, ImageFont, ImageOps, ImageDraw
|
||||
|
||||
|
||||
default_settings = {"ANNOUNCE": False,
|
||||
"BACKGROUND": "data/imgwelcome/transparent.png",
|
||||
"BONUSES": {"ACCOUNT_WARNINGS": True,
|
||||
"SPECIAL_USERS": True
|
||||
},
|
||||
"BORDER": [255, 255, 255, 230],
|
||||
"CHANNEL": None,
|
||||
"OUTLINE": [0, 0, 0, 255],
|
||||
"SERVERTEXT": [255, 255, 255, 230],
|
||||
"TEXT": [255, 255, 255, 230],
|
||||
"FONT": {"WELCOME_FONT": {"PATH": "data/imgwelcome/fonts/UniSansHeavy.otf",
|
||||
"SIZE": 50},
|
||||
"SERVER_FONT": {"PATH": "data/imgwelcome/fonts/UniSansHeavy.otf",
|
||||
"SIZE": 20},
|
||||
"NAME_FONT": {"PATH": "data/imgwelcome/fonts/UniSansHeavy.otf",
|
||||
"SIZE": {"NORMAL": 30,
|
||||
"MEDIUM": 22,
|
||||
"SMALL": 18,
|
||||
"SMALLEST": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ImgWelcome:
|
||||
"""Welcomes a user to the server with an image."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.settings = dataIO.load_json('data/imgwelcome/settings.json')
|
||||
self.version = "0.1.6"
|
||||
|
||||
async def save_settings(self):
|
||||
dataIO.save_json('data/imgwelcome/settings.json', self.settings)
|
||||
|
||||
async def _create_welcome(self, member, url, test_member_number: int = None):
|
||||
server = member.server
|
||||
wfont = self.settings[server.id]["FONT"]["WELCOME_FONT"]
|
||||
sfont = self.settings[server.id]["FONT"]["SERVER_FONT"]
|
||||
nfont = self.settings[server.id]["FONT"]["NAME_FONT"]
|
||||
welcome_font = ImageFont.truetype(wfont["PATH"], wfont["SIZE"])
|
||||
server_font = ImageFont.truetype(sfont["PATH"], sfont["SIZE"])
|
||||
|
||||
name_font = ImageFont.truetype(nfont["PATH"], nfont["SIZE"]["NORMAL"])
|
||||
name_font_medium = ImageFont.truetype(nfont["PATH"], nfont["SIZE"]["MEDIUM"])
|
||||
name_font_small = ImageFont.truetype(nfont["PATH"], nfont["SIZE"]["SMALL"])
|
||||
name_font_smallest = ImageFont.truetype(nfont["PATH"], nfont["SIZE"]["SMALLEST"])
|
||||
background = Image.open(self.settings[server.id]["BACKGROUND"]).convert('RGBA')
|
||||
no_profile_picture = Image.open("data/imgwelcome/noimage.png")
|
||||
|
||||
global welcome_picture
|
||||
welcome_picture = Image.new("RGBA", (500, 150))
|
||||
welcome_picture = ImageOps.fit(background, (500, 150), centering=(0.5, 0.5))
|
||||
welcome_picture.paste(background)
|
||||
welcome_picture = welcome_picture.resize((500, 150), Image.NEAREST)
|
||||
|
||||
profile_area = Image.new("L", (512, 512), 0)
|
||||
draw = ImageDraw.Draw(profile_area)
|
||||
draw.ellipse(((0, 0), (512, 512)), fill=255)
|
||||
circle_img_size = tuple(self.settings[member.server.id]["CIRCLE"])
|
||||
profile_area = profile_area.resize((circle_img_size), Image.ANTIALIAS)
|
||||
try:
|
||||
url = url.replace('webp?size=1024', 'png')
|
||||
url = url.replace('gif?size=1024', 'png')
|
||||
await self._get_profile(url)
|
||||
profile_picture = Image.open('data/imgwelcome/profilepic.png')
|
||||
except:
|
||||
profile_picture = no_profile_picture
|
||||
profile_area_output = ImageOps.fit(profile_picture, (circle_img_size), centering=(0, 0))
|
||||
profile_area_output.putalpha(profile_area)
|
||||
|
||||
bordercolor = tuple(self.settings[member.server.id]["BORDER"])
|
||||
fontcolor = tuple(self.settings[member.server.id]["TEXT"])
|
||||
servercolor = tuple(self.settings[member.server.id]["SERVERTEXT"])
|
||||
textoutline = tuple(self.settings[server.id]["OUTLINE"])
|
||||
|
||||
mask = Image.new('L', (512, 512), 0)
|
||||
draw_thumb = ImageDraw.Draw(mask)
|
||||
draw_thumb.ellipse((0, 0) + (512, 512), fill=255, outline=0)
|
||||
circle = Image.new("RGBA", (512, 512))
|
||||
draw_circle = ImageDraw.Draw(circle)
|
||||
draw_circle.ellipse([0, 0, 512, 512], fill=(bordercolor[0], bordercolor[1], bordercolor[2], 180), outline=(255, 255, 255, 250))
|
||||
circle_border_size = await self._circle_border(circle_img_size)
|
||||
circle = circle.resize((circle_border_size), Image.ANTIALIAS)
|
||||
circle_mask = mask.resize((circle_border_size), Image.ANTIALIAS)
|
||||
circle_pos = (7 + int((136 - circle_border_size[0]) / 2))
|
||||
border_pos = (11 + int((136 - circle_border_size[0]) / 2))
|
||||
drawtwo = ImageDraw.Draw(welcome_picture)
|
||||
welcome_picture.paste(circle, (circle_pos, circle_pos), circle_mask)
|
||||
welcome_picture.paste(profile_area_output, (border_pos, border_pos), profile_area_output)
|
||||
|
||||
uname = (str(member.name) + "#" + str(member.discriminator))
|
||||
|
||||
def _outline(original_position: tuple, text: str, pixel_displacement: int, font, textoutline):
|
||||
op = original_position
|
||||
pd = pixel_displacement
|
||||
|
||||
left = (op[0] - pd, op[1])
|
||||
right = (op[0] + pd, op[1])
|
||||
up = (op[0], op[1] - pd)
|
||||
down = (op[0], op[1] + pd)
|
||||
|
||||
drawtwo.text(left, text, font=font, fill=(textoutline))
|
||||
drawtwo.text(right, text, font=font, fill=(textoutline))
|
||||
drawtwo.text(up, text, font=font, fill=(textoutline))
|
||||
drawtwo.text(down, text, font=font, fill=(textoutline))
|
||||
|
||||
drawtwo.text(op, text, font=font, fill=(textoutline))
|
||||
|
||||
_outline((150, 16), "Welcome", 1, welcome_font, (textoutline))
|
||||
drawtwo.text((150, 16), "Welcome", font=welcome_font, fill=(fontcolor))
|
||||
|
||||
if len(uname) <= 17:
|
||||
_outline((152, 63), uname, 1, name_font, (textoutline))
|
||||
drawtwo.text((152, 63), uname, font=name_font, fill=(fontcolor))
|
||||
|
||||
if len(uname) > 17:
|
||||
if len(uname) <= 23:
|
||||
_outline((152, 66), uname, 1, name_font_medium, (textoutline))
|
||||
drawtwo.text((152, 66), uname, font=name_font_medium, fill=(fontcolor))
|
||||
|
||||
if len(uname) >= 24:
|
||||
if len(uname) <= 32:
|
||||
_outline((152, 70), uname, 1, name_font_small, (textoutline))
|
||||
drawtwo.text((152, 70), uname, font=name_font_small, fill=(fontcolor))
|
||||
|
||||
if len(uname) >= 33:
|
||||
drawtwo.text((152, 73), uname, 1, name_font_smallest, (textoutline))
|
||||
drawtwo.text((152, 73), uname, font=name_font_smallest, fill=(fontcolor))
|
||||
|
||||
if test_member_number is None:
|
||||
members = sorted(server.members,
|
||||
key=lambda m: m.joined_at).index(member) + 1
|
||||
else:
|
||||
members = test_member_number
|
||||
|
||||
member_number = str(members) + self._get_suffix(members)
|
||||
sname = str(member.server.name) + '!' if len(str(member.server.name)) <= 28 else str(member.server.name)[:23] + '...'
|
||||
|
||||
_outline((152, 96), "You are the " + str(member_number) + " member", 1, server_font, (textoutline))
|
||||
drawtwo.text((152, 96), "You are the " + str(member_number) + " member", font=server_font, fill=(servercolor))
|
||||
_outline((152, 116), 'of ' + sname, 1, server_font, (textoutline))
|
||||
drawtwo.text((152, 116), 'of ' + sname, font=server_font, fill=(servercolor))
|
||||
|
||||
image_object = BytesIO()
|
||||
welcome_picture.save(image_object, format="PNG")
|
||||
image_object.seek(0)
|
||||
return image_object
|
||||
|
||||
async def _circle_border(self, circle_img_size: tuple):
|
||||
border_size = []
|
||||
for i in range(len(circle_img_size)):
|
||||
border_size.append(circle_img_size[0] + 8)
|
||||
return tuple(border_size)
|
||||
|
||||
async def _data_check(self, ctx):
|
||||
server = ctx.message.server
|
||||
if server.id not in self.settings:
|
||||
self.settings[server.id] = deepcopy(default_settings)
|
||||
self.settings[server.id]["CHANNEL"] = ctx.message.channel.id
|
||||
await self.save_settings()
|
||||
|
||||
if "BONUSES" not in self.settings[server.id].keys():
|
||||
self.settings[server.id]["BONUSES"] = {"ACCOUNT_WARNINGS": True,
|
||||
"SPECIAL_USERS": True
|
||||
}
|
||||
await self.save_settings()
|
||||
|
||||
if "CIRCLE" not in self.settings[server.id].keys():
|
||||
self.settings[server.id]["CIRCLE"] = [128, 128]
|
||||
await self.save_settings()
|
||||
|
||||
if "CHANNEL" not in self.settings[server.id].keys():
|
||||
self.settings[server.id]["CHANNEL"] = ctx.message.channel.id
|
||||
await self.save_settings()
|
||||
|
||||
if "FONT" not in self.settings[server.id].keys():
|
||||
self.settings[server.id]["FONT"] = {"WELCOME_FONT": {"PATH": "data/imgwelcome/fonts/UniSansHeavy.otf",
|
||||
"SIZE": 50},
|
||||
"SERVER_FONT": {"PATH": "data/imgwelcome/fonts/UniSansHeavy.otf",
|
||||
"SIZE": 20},
|
||||
"NAME_FONT": {"PATH": "data/imgwelcome/fonts/UniSansHeavy.otf",
|
||||
"SIZE": {"NORMAL": 30,
|
||||
"MEDIUM": 22,
|
||||
"SMALL": 18,
|
||||
"SMALLEST": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if "OUTLINE" not in self.settings[server.id].keys():
|
||||
self.settings[server.id]["OUTLINE"] = [0, 0, 0, 255]
|
||||
await self.save_settings()
|
||||
|
||||
async def _get_profile(self, url):
|
||||
async with aiohttp.get(url) as r:
|
||||
image = await r.content.read()
|
||||
with open('data/imgwelcome/profilepic.png', 'wb') as f:
|
||||
f.write(image)
|
||||
|
||||
def _get_suffix(self, num):
|
||||
suffixes = {1: 'st', 2: 'nd', 3: 'rd'}
|
||||
if 10 <= num % 100 <= 20:
|
||||
suffix = 'th'
|
||||
else:
|
||||
suffix = suffixes.get(num % 10, 'th')
|
||||
return suffix
|
||||
|
||||
def _hex_to_rgb(self, hex_num: str, a: int):
|
||||
h = hex_num.lstrip('#')
|
||||
|
||||
# if only 3 characters are given
|
||||
if len(str(h)) == 3:
|
||||
expand = ''.join([x*2 for x in str(h)])
|
||||
h = expand
|
||||
|
||||
colors = [int(h[i:i+2], 16) for i in (0, 2, 4)]
|
||||
colors.append(a)
|
||||
return tuple(colors)
|
||||
|
||||
def _is_hex(self, color: str):
|
||||
if color is not None and len(color) != 4 and len(color) != 7:
|
||||
return False
|
||||
|
||||
reg_ex = r'^#(?:[0-9a-fA-F]{3}){1,2}$'
|
||||
return re.search(reg_ex, str(color))
|
||||
|
||||
def _rgb_to_hex(self, rgb):
|
||||
rgb = tuple(rgb[:3])
|
||||
return '#%02x%02x%02x' % rgb
|
||||
|
||||
@checks.admin_or_permissions(manage_server=True)
|
||||
@commands.group(pass_context=True)
|
||||
async def imgwelcome(self, ctx):
|
||||
"""Configuration options for the welcome image."""
|
||||
if ctx.invoked_subcommand is None:
|
||||
await send_cmd_help(ctx)
|
||||
return
|
||||
|
||||
@imgwelcome.command(pass_context=True, name="border", no_pm=True)
|
||||
async def imgwelcome_border(self, ctx, bordercolor=None):
|
||||
"""Set the profile image border color.
|
||||
Use hex codes for colors and ‘clear’ for transparent."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
default_a = 230
|
||||
valid = True
|
||||
|
||||
if bordercolor == "clear":
|
||||
self.settings[server.id]["BORDER"] = [0, 0, 0, 0]
|
||||
elif self._is_hex(bordercolor):
|
||||
self.settings[server.id]["BORDER"] = self._hex_to_rgb(bordercolor, default_a)
|
||||
else:
|
||||
await self.bot.say('Border color is invalid. Use #000000 as a format.')
|
||||
valid = False
|
||||
|
||||
if valid:
|
||||
await self.bot.say('The profile border color has been set.')
|
||||
await self.save_settings()
|
||||
|
||||
@imgwelcome.command(pass_context=True, name="channel", no_pm=True)
|
||||
async def imgwelcome_channel(self, ctx, channel: discord.Channel):
|
||||
"""Set the announcement channel."""
|
||||
server = ctx.message.server
|
||||
if not server.me.permissions_in(channel).send_messages:
|
||||
await self.bot.say("No permissions to speak in that channel.")
|
||||
return
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]["CHANNEL"] = channel.id
|
||||
await self.save_settings()
|
||||
await self.bot.send_message(channel, "This channel will be used for welcome messages.")
|
||||
|
||||
@imgwelcome.command(name='clear', pass_context=True, no_pm=True)
|
||||
async def imgwelcome_clear(self, ctx):
|
||||
"""Set the background to transparent."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]['BACKGROUND'] = 'data/imgwelcome/transparent.png'
|
||||
await self.save_settings()
|
||||
await self.bot.say('Welcome image background is now transparent.')
|
||||
|
||||
@imgwelcome.command(pass_context=True, name="outline", no_pm=True)
|
||||
async def imgwelcome_outline(self, ctx, outline=None):
|
||||
"""Set the text outline. White or black."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
valid = True
|
||||
if outline == "white":
|
||||
self.settings[server.id]["OUTLINE"] = [255, 255, 255, 255]
|
||||
await self.save_settings()
|
||||
elif outline == "black":
|
||||
self.settings[server.id]["OUTLINE"] = [0, 0, 0, 255]
|
||||
await self.save_settings()
|
||||
else:
|
||||
await self.bot.say('Outline color is invalid. Use white or black.')
|
||||
valid = False
|
||||
|
||||
if valid:
|
||||
await self.bot.say('The text outline has been set.')
|
||||
|
||||
@imgwelcome.command(name="preview", pass_context=True, no_pm=True)
|
||||
async def imagewelcome_preview(self, ctx, member: discord.Member=None, number: int=None):
|
||||
"""Show a welcome image with the current settings."""
|
||||
server = ctx.message.server
|
||||
channel = ctx.message.channel
|
||||
if member is None:
|
||||
member = ctx.message.author
|
||||
await self._data_check(ctx)
|
||||
channel_object = self.bot.get_channel(channel.id)
|
||||
await self.bot.send_typing(channel_object)
|
||||
image_object = await self._create_welcome(member, member.avatar_url, number)
|
||||
await self.bot.send_file(channel_object, image_object, filename="welcome.png")
|
||||
|
||||
@imgwelcome.command(pass_context=True, name="size", no_pm=True)
|
||||
async def imgwelcome_profilesize(self, ctx, profilesize: int):
|
||||
"""Set the profile size in pixels. Use one number, 128 is recommended."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
if profilesize is 0:
|
||||
await self.bot.say("Profile picture size must be larger than 0.")
|
||||
return
|
||||
else:
|
||||
self.settings[server.id]["CIRCLE"] = [profilesize, profilesize]
|
||||
await self.save_settings()
|
||||
await self.bot.say('The profile picture size has been set.')
|
||||
|
||||
@imgwelcome.command(pass_context=True, name="text", no_pm=True)
|
||||
async def imgwelcome_text(self, ctx, textcolor: str, servercolor: str):
|
||||
"""Set text colors. Use hex code for colors."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
default_a = 230
|
||||
valid = True
|
||||
|
||||
if self._is_hex(textcolor):
|
||||
self.settings[server.id]["TEXT"] = self._hex_to_rgb(textcolor, default_a)
|
||||
else:
|
||||
await self.bot.say('Welcome text color is invalid. Use #000000 as a format.')
|
||||
valid = False
|
||||
|
||||
if self._is_hex(servercolor):
|
||||
self.settings[server.id]["SERVERTEXT"] = self._hex_to_rgb(servercolor, default_a)
|
||||
else:
|
||||
await self.bot.say('Server text color is invalid. Use #000000 as a format.')
|
||||
valid = False
|
||||
|
||||
if valid:
|
||||
await self.bot.say('The text colors have been set.')
|
||||
await self.save_settings()
|
||||
|
||||
@imgwelcome.command(pass_context=True, name="toggle", no_pm=True)
|
||||
async def imgwelcome_toggle(self, ctx):
|
||||
"""Toggle welcome messages on the server."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]["ANNOUNCE"] = not self.settings[server.id]["ANNOUNCE"]
|
||||
if self.settings[server.id]["ANNOUNCE"]:
|
||||
await self.bot.say("Now welcoming new users.")
|
||||
else:
|
||||
await self.bot.say("No longer welcoming new users.")
|
||||
await self.save_settings()
|
||||
|
||||
@imgwelcome.command(name='upload', pass_context=True, no_pm=True)
|
||||
async def imgwelcome_upload(self, ctx, default=None):
|
||||
"""Upload a background through Discord. 500px x 150px.
|
||||
This must be an image file and not a url."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
await self.bot.say("Please send the file to use as a background. File must be 500px x 150px.")
|
||||
answer = await self.bot.wait_for_message(timeout=30, author=ctx.message.author)
|
||||
|
||||
try:
|
||||
bg_url = answer.attachments[0]["url"]
|
||||
success = True
|
||||
except Exception as e:
|
||||
success = False
|
||||
print(e)
|
||||
|
||||
serverimage = Image
|
||||
|
||||
if success:
|
||||
try:
|
||||
async with aiohttp.get(bg_url) as r:
|
||||
image = await r.content.read()
|
||||
if not os.path.exists('data/imgwelcome/{}'.format(server.id)):
|
||||
os.makedirs('data/imgwelcome/{}'.format(server.id))
|
||||
serverbg = 'data/imgwelcome/{}/serverbg.png'.format(server.id)
|
||||
with open(serverbg, 'wb') as f:
|
||||
f.write(image)
|
||||
serverimage = Image.open(serverbg).convert('RGBA')
|
||||
success = True
|
||||
|
||||
except Exception as e:
|
||||
success = False
|
||||
print(e)
|
||||
if success:
|
||||
if serverimage.size == (500, 150):
|
||||
self.settings[server.id]['BACKGROUND'] = "data/imgwelcome/" + ctx.message.server.id + "/serverbg.png"
|
||||
await self.save_settings()
|
||||
else:
|
||||
await self.bot.say("Image needs to be 500x150.")
|
||||
return
|
||||
background_img = ('data/imgwelcome/{}/serverbg.png'.format(server.id))
|
||||
self.settings[server.id]['BACKGROUND'] = (background_img)
|
||||
await self.save_settings()
|
||||
await self.bot.say('Welcome image for this server set to uploaded file.')
|
||||
else:
|
||||
await self.bot.say("Couldn't get the image from Discord.")
|
||||
else:
|
||||
await self.bot.say("Couldn't get the image.")
|
||||
|
||||
@imgwelcome.group(pass_context=True, name='bonus', no_pm=True)
|
||||
async def imgwelcome_bonus(self, ctx):
|
||||
"""Toggle display of additional text welcome messages when a user joins the server."""
|
||||
if ctx.invoked_subcommand is None or isinstance(ctx.invoked_subcommand, commands.Group):
|
||||
await send_cmd_help(ctx)
|
||||
return
|
||||
|
||||
@imgwelcome_bonus.command(pass_context=True, name='user', no_pm=True)
|
||||
async def bonus_user(self, ctx):
|
||||
"""Toggle text announcement when a user is x 100th to join or #1337."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]["BONUSES"]["SPECIAL_USERS"] = not self.settings[server.id]["BONUSES"]["SPECIAL_USERS"]
|
||||
await self.save_settings()
|
||||
if self.settings[server.id]["BONUSES"]["SPECIAL_USERS"]:
|
||||
msg = "I will now announce when special users join."
|
||||
else:
|
||||
msg = "I will no longer announce when special users join."
|
||||
await self.bot.say(msg)
|
||||
|
||||
@imgwelcome_bonus.command(pass_context=True, name='warn', no_pm=True)
|
||||
async def bonus_warn(self, ctx):
|
||||
"""Toggle text announcement when a new user's account is <7d old."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]["BONUSES"]["ACCOUNT_WARNINGS"] = not self.settings[server.id]["BONUSES"]["ACCOUNT_WARNINGS"]
|
||||
await self.save_settings()
|
||||
if self.settings[server.id]["BONUSES"]["ACCOUNT_WARNINGS"]:
|
||||
msg = "I will now announce when new accounts join."
|
||||
else:
|
||||
msg = "I will no longer announce when new accounts join."
|
||||
await self.bot.say(msg)
|
||||
|
||||
@imgwelcome.group(pass_context=True, name='font', no_pm=True)
|
||||
async def imgwelcome_font(self, ctx):
|
||||
"""Place your font files in the data/imgwelcome/fonts/ directory.
|
||||
Valid font areas to change are: welcome, server and name.
|
||||
"""
|
||||
if ctx.invoked_subcommand is None or isinstance(ctx.invoked_subcommand, commands.Group):
|
||||
await send_cmd_help(ctx)
|
||||
return
|
||||
|
||||
@imgwelcome_font.command(pass_context=True, name='list', no_pm=True)
|
||||
async def fontg_list(self, ctx):
|
||||
"""List fonts in the directory."""
|
||||
channel = ctx.message.channel
|
||||
directory = "data/imgwelcome/fonts/"
|
||||
fonts = sorted(os.listdir(directory))
|
||||
|
||||
if len(fonts) == 0:
|
||||
await self.bot.send_message(channel, "No fonts found. Place "
|
||||
"fonts in /data/imgwelcome/fonts/.")
|
||||
return
|
||||
|
||||
pager = commands.formatter.Paginator(prefix='```', suffix='```', max_size=2000)
|
||||
pager.add_line('Current fonts:')
|
||||
for font_name in fonts:
|
||||
pager.add_line(font_name)
|
||||
for page in pager.pages:
|
||||
await self.bot.send_message(channel, page)
|
||||
|
||||
@imgwelcome_font.command(pass_context=True, name='name', no_pm=True)
|
||||
async def fontg_name(self, ctx, font_name: str, size: int=None):
|
||||
"""Change the name text font.
|
||||
e.g. [p]imgwelcome font name "UniSansHeavy.otf"
|
||||
"""
|
||||
await self._data_check(ctx)
|
||||
server = ctx.message.server
|
||||
|
||||
directory = "data/imgwelcome/fonts/"
|
||||
if size is None:
|
||||
size = self.settings[server.id]["FONT"]["NAME_FONT"]["SIZE"]["NORMAL"]
|
||||
|
||||
try:
|
||||
ImageFont.truetype(directory + font_name, size)
|
||||
except:
|
||||
await self.bot.say("I could not find that font file.")
|
||||
return
|
||||
|
||||
self.settings[server.id]["FONT"]["NAME_FONT"]["PATH"] = directory + font_name
|
||||
self.settings[server.id]["FONT"]["NAME_FONT"]["SIZE"]["NORMAL"] = size
|
||||
self.settings[server.id]["FONT"]["NAME_FONT"]["SIZE"]["MEDIUM"] = size - 8
|
||||
self.settings[server.id]["FONT"]["NAME_FONT"]["SIZE"]["SMALL"] = size - 12
|
||||
self.settings[server.id]["FONT"]["NAME_FONT"]["SIZE"]["SMALLEST"] = size - 18
|
||||
await self.save_settings()
|
||||
await self.bot.say("Name font changed to: {}".format(font_name[:-4]))
|
||||
|
||||
@imgwelcome_font.command(pass_context=True, name='server', no_pm=True)
|
||||
async def fontg_server(self, ctx, font_name: str, size: int=None):
|
||||
"""Change the server text font."""
|
||||
await self._data_check(ctx)
|
||||
server = ctx.message.server
|
||||
|
||||
directory = "data/imgwelcome/fonts/"
|
||||
if size is None:
|
||||
size = self.settings[server.id]["FONT"]["SERVER_FONT"]["SIZE"]
|
||||
|
||||
try:
|
||||
ImageFont.truetype(directory + font_name, size)
|
||||
except:
|
||||
await self.bot.say("I could not find that font file.")
|
||||
return
|
||||
|
||||
self.settings[server.id]["FONT"]["SERVER_FONT"]["PATH"] = directory + font_name
|
||||
self.settings[server.id]["FONT"]["SERVER_FONT"]["SIZE"] = size
|
||||
await self.save_settings()
|
||||
await self.bot.say("Server text font changed to: {}".format(font_name[:-4]))
|
||||
pass
|
||||
|
||||
@imgwelcome_font.command(pass_context=True, name='welcome', no_pm=True)
|
||||
async def fontg_welcome(self, ctx, font_name: str, size: int=None):
|
||||
"""Change the welcome text font."""
|
||||
# try open file_name, if fail tell user
|
||||
# if opens change settings, tell user success
|
||||
# if file_name doesn't exist, list available fonts
|
||||
await self._data_check(ctx)
|
||||
server = ctx.message.server
|
||||
|
||||
directory = "data/imgwelcome/fonts/"
|
||||
if size is None:
|
||||
size = self.settings[server.id]["FONT"]["WELCOME_FONT"]["SIZE"]
|
||||
|
||||
try:
|
||||
ImageFont.truetype(directory + font_name, size)
|
||||
except:
|
||||
await self.bot.say("I could not find that font file.")
|
||||
return
|
||||
|
||||
self.settings[server.id]["FONT"]["WELCOME_FONT"]["PATH"] = directory + font_name
|
||||
self.settings[server.id]["FONT"]["WELCOME_FONT"]["SIZE"] = size
|
||||
await self.save_settings()
|
||||
await self.bot.say("Welcome font changed to: {}".format(font_name[:-4]))
|
||||
pass
|
||||
|
||||
@imgwelcome.command(name="version", pass_context=True, hidden=True)
|
||||
async def imagewelcomeset_version(self):
|
||||
"""Displays the imgwelcome version."""
|
||||
await self.bot.say("imgwelcome version {}.".format(self.version))
|
||||
|
||||
async def on_member_join(self, member):
|
||||
server = member.server
|
||||
if server.id not in self.settings:
|
||||
self.settings[server.id] = deepcopy(default_settings)
|
||||
await self.save_settings()
|
||||
if not self.settings[server.id]["ANNOUNCE"]:
|
||||
return
|
||||
channelid = self.settings[server.id]["CHANNEL"]
|
||||
channel_object = self.bot.get_channel(channelid)
|
||||
await self.bot.send_typing(channel_object)
|
||||
image_object = await self._create_welcome(member, member.avatar_url)
|
||||
await self.bot.send_file(channel_object, image_object, filename="welcome.png")
|
||||
if (len(member.server.members) % 100) == 0 or (len(member.server.members) == 1337) and self.settings[server.id]["SPECIAL_USERS"]:
|
||||
msg = "\N{PARTY POPPER} Thanks <@" + member.id + ">, you're the ***" + str(len(member.server.members)) + "*** th user on this server! \N{PARTY POPPER}"
|
||||
await self.bot.send_message(channel_object, msg)
|
||||
date_join = datetime.datetime.strptime(str(member.created_at), "%Y-%m-%d %H:%M:%S.%f")
|
||||
date_now = datetime.datetime.now(datetime.timezone.utc)
|
||||
date_now = date_now.replace(tzinfo=None)
|
||||
since_join = date_now - date_join
|
||||
if since_join.days < 7 and self.settings[server.id]["ACCOUNT_WARNINGS"]:
|
||||
await self.bot.send_message(channel_object, "\N{WARNING SIGN} This account was created less than a week ago (" + str(since_join.days) + " days ago)")
|
||||
|
||||
|
||||
def check_folders():
|
||||
if not os.path.exists('data/imgwelcome/'):
|
||||
os.mkdir('data/imgwelcome/')
|
||||
|
||||
|
||||
def check_files():
|
||||
if not dataIO.is_valid_json('data/imgwelcome/settings.json'):
|
||||
defaults = {}
|
||||
dataIO.save_json('data/imgwelcome/settings.json', defaults)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folders()
|
||||
check_files()
|
||||
bot.add_cog(ImgWelcome(bot))
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna",
|
||||
"INSTALL_MSG" : "Use [p]imgwelcome to change settings.",
|
||||
"NAME" : "imgwelcome",
|
||||
"SHORT" : "Welcome users to your server with an image.",
|
||||
"DESCRIPTION" : "Welcome users to your server with an image.",
|
||||
"REQUIREMENTS": ["Pillow"],
|
||||
"TAGS": ["welcome", "welcome image", "images"]
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import discord
|
||||
|
||||
class OtherbotStatus:
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
async def on_member_update(self, before, after):
|
||||
if after.status == discord.Status.offline and after.id == "000000000000000000": # this is the bot id that you want to watch
|
||||
channel_object = self.bot.get_channel("000000000000000000") # this is the channel id for the watcher bot to scream in
|
||||
await self.bot.send_message(channel_object, "<@000000000000000000>, the bot is offline.") # this is the person to ping and the message
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
def setup(bot):
|
||||
n = OtherbotStatus(bot)
|
||||
bot.add_cog(n)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna",
|
||||
"INSTALL_MSG" : "Use [p]picwelcome to change settings.",
|
||||
"NAME" : "picwelcome",
|
||||
"SHORT" : "Welcome users to your server with a picture.",
|
||||
"DESCRIPTION" : "Welcome users to your server with a picture.",
|
||||
"REQUIREMENTS": ["Pillow"],
|
||||
"TAGS": ["welcome", "welcome image", "images"]
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
# picwelcomeset_upload is based on code in orels' drawing.py
|
||||
# https://github.com/orels1/ORELS-Cogs
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import datetime
|
||||
import discord
|
||||
import os
|
||||
from __main__ import send_cmd_help
|
||||
from cogs.utils.dataIO import dataIO
|
||||
from cogs.utils import checks
|
||||
from copy import deepcopy
|
||||
from discord.ext import commands
|
||||
from PIL import Image
|
||||
|
||||
|
||||
default_settings = {"ANNOUNCE": False,
|
||||
"PICTURE": "data/picwelcome/default.png",
|
||||
"CHANNEL": None,
|
||||
}
|
||||
|
||||
|
||||
class PicWelcome:
|
||||
"""Welcome new users with a static image."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.settings = dataIO.load_json('data/picwelcome/settings.json')
|
||||
self.version = "0.0.1"
|
||||
|
||||
async def save_settings(self):
|
||||
dataIO.save_json('data/picwelcome/settings.json', self.settings)
|
||||
|
||||
async def _data_check(self, ctx):
|
||||
server = ctx.message.server
|
||||
if server.id not in self.settings:
|
||||
self.settings[server.id] = deepcopy(default_settings)
|
||||
self.settings[server.id]["CHANNEL"] = ctx.message.channel.id
|
||||
await self.save_settings()
|
||||
|
||||
@checks.admin_or_permissions(manage_server=True)
|
||||
@commands.group(pass_context=True)
|
||||
async def picwelcome(self, ctx):
|
||||
"""Configuration options for a welcome picture."""
|
||||
if ctx.invoked_subcommand is None:
|
||||
await send_cmd_help(ctx)
|
||||
return
|
||||
|
||||
@picwelcome.command(pass_context=True, name="channel", no_pm=True)
|
||||
async def picwelcome_channel(self, ctx, channel: discord.Channel):
|
||||
"""Set the announcement channel."""
|
||||
server = ctx.message.server
|
||||
if not server.me.permissions_in(channel).send_messages:
|
||||
await self.bot.say("No permissions to speak in that channel.")
|
||||
return
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]["CHANNEL"] = channel.id
|
||||
await self.save_settings()
|
||||
await self.bot.send_message(channel, "This channel will be used for welcome pictures.")
|
||||
|
||||
@picwelcome.command(name='reset', pass_context=True, no_pm=True)
|
||||
async def picwelcome_reset(self, ctx):
|
||||
"""Set the welcome picture back to the default."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]['PICTURE'] = 'data/picwelcome/default.png'
|
||||
await self.save_settings()
|
||||
await self.bot.say('Welcome picture reset to default.')
|
||||
|
||||
@picwelcome.command(name="preview", pass_context=True, no_pm=True)
|
||||
async def picwelcome_preview(self, ctx, member: discord.Member=None, number: int=None):
|
||||
"""Show a the welcome picture with the current settings."""
|
||||
server = ctx.message.server
|
||||
channel = ctx.message.channel
|
||||
if member is None:
|
||||
member = ctx.message.author
|
||||
await self._data_check(ctx)
|
||||
channel_object = self.bot.get_channel(channel.id)
|
||||
await self.bot.send_typing(channel_object)
|
||||
serverpicture = self.settings[server.id]["PICTURE"]
|
||||
await self.bot.send_file(channel_object, serverpicture)
|
||||
|
||||
@picwelcome.command(pass_context=True, name="toggle", no_pm=True)
|
||||
async def picwelcome_toggle(self, ctx):
|
||||
"""Toggle welcome pictures on the server."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
self.settings[server.id]["ANNOUNCE"] = not self.settings[server.id]["ANNOUNCE"]
|
||||
if self.settings[server.id]["ANNOUNCE"]:
|
||||
await self.bot.say("Now welcoming new users with a picture.")
|
||||
else:
|
||||
await self.bot.say("No longer welcoming new users with a picture.")
|
||||
await self.save_settings()
|
||||
|
||||
@picwelcome.command(name='upload', pass_context=True, no_pm=True)
|
||||
async def picwelcome_upload(self, ctx, default=None):
|
||||
"""Upload a picture through Discord.
|
||||
This must be an image file and not a url."""
|
||||
server = ctx.message.server
|
||||
await self._data_check(ctx)
|
||||
await self.bot.say("Please send the file to use as a welcome picture.")
|
||||
answer = await self.bot.wait_for_message(timeout=30, author=ctx.message.author)
|
||||
|
||||
try:
|
||||
bg_url = answer.attachments[0]["url"]
|
||||
success = True
|
||||
except Exception as e:
|
||||
success = False
|
||||
print(e)
|
||||
|
||||
serverimage = Image
|
||||
|
||||
if success:
|
||||
try:
|
||||
async with aiohttp.get(bg_url) as r:
|
||||
image = await r.content.read()
|
||||
if not os.path.exists('data/picwelcome/{}'.format(server.id)):
|
||||
os.makedirs('data/picwelcome/{}'.format(server.id))
|
||||
serverbg = 'data/picwelcome/{}/serverpic.png'.format(server.id)
|
||||
with open(serverbg, 'wb') as f:
|
||||
f.write(image)
|
||||
serverimage = Image.open(serverbg).convert('RGBA')
|
||||
success = True
|
||||
|
||||
except Exception as e:
|
||||
success = False
|
||||
print(e)
|
||||
if success:
|
||||
self.settings[server.id]['PICTURE'] = "data/picwelcome/" + ctx.message.server.id + "/serverpic.png"
|
||||
await self.save_settings()
|
||||
await self.bot.say('Welcome image for this server set to uploaded file.')
|
||||
else:
|
||||
await self.bot.say("Couldn't get the image from Discord.")
|
||||
else:
|
||||
await self.bot.say("Couldn't get the image.")
|
||||
|
||||
@picwelcome.command(name="version", pass_context=True, hidden=True)
|
||||
async def picwelcome_version(self):
|
||||
"""Displays the picwelcome version."""
|
||||
await self.bot.say("picwelcome version {}.".format(self.version))
|
||||
|
||||
async def on_member_join(self, member):
|
||||
server = member.server
|
||||
if server.id not in self.settings:
|
||||
self.settings[server.id] = deepcopy(default_settings)
|
||||
await self.save_settings()
|
||||
if not self.settings[server.id]["ANNOUNCE"]:
|
||||
return
|
||||
channelid = self.settings[server.id]["CHANNEL"]
|
||||
channel_object = self.bot.get_channel(channelid)
|
||||
await self.bot.send_typing(channel_object)
|
||||
serverpicture = self.settings[server.id]["PICTURE"]
|
||||
await self.bot.send_file(channel_object, serverpicture)
|
||||
|
||||
|
||||
def check_folders():
|
||||
if not os.path.exists('data/picwelcome/'):
|
||||
os.mkdir('data/picwelcome/')
|
||||
|
||||
|
||||
def check_files():
|
||||
if not dataIO.is_valid_json('data/picwelcome/settings.json'):
|
||||
defaults = {}
|
||||
dataIO.save_json('data/picwelcome/settings.json', defaults)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folders()
|
||||
check_files()
|
||||
bot.add_cog(PicWelcome(bot))
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna",
|
||||
"INSTALL_MSG" : "Thanks for installing Pug. Now you can check out your Warcraft pugs for raid-readiness through Discord.",
|
||||
"NAME" : "Pug",
|
||||
"SHORT" : "Warcraft character lookup.",
|
||||
"DESCRIPTION" : "This tool lets you check potential group pugs for enchants, gems, and raid completion. It was made possible by PugBot: https://github.com/reznok/PugBot",
|
||||
"TAGS" : ["warcraft", "raiding", "raid"]
|
||||
}
|
||||
313
pug/pug.py
313
pug/pug.py
@@ -1,313 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
from .utils.dataIO import dataIO
|
||||
from __main__ import send_cmd_help
|
||||
from discord.ext import commands
|
||||
from .utils import checks
|
||||
|
||||
|
||||
class Pug:
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.settings = dataIO.load_json("data/pug/config.json")
|
||||
self.fp = "data/pug/config.json"
|
||||
API_KEY = self.settings["blizzard_api_key"]
|
||||
default_region = self.settings["default_region"]
|
||||
|
||||
LEG_WITH_SOCKET = [
|
||||
132369, 132410, 137044, 132444, 132449, 132452, 132460, 133973, 133974, 137037, 137038, 137039, 137040, 137041,
|
||||
137042, 137043, 132378, 137045, 137046, 137047, 137048, 137049, 137050, 137051, 137052, 137054, 137055, 137220,
|
||||
137223, 137276, 137382, 138854
|
||||
]
|
||||
|
||||
ENCHANTABLE_SLOTS = ["neck", "back", "finger1", "finger2"]
|
||||
|
||||
region_locale = {
|
||||
'us': ['us', 'en_US', 'en'],
|
||||
'eu': ['eu', 'en_GB', 'en']
|
||||
# 'kr': ['kr', 'ko_KR', 'ko'],
|
||||
# 'tw': ['tw', 'zh_TW', 'zh'],
|
||||
# 'es': ['es', 'es_MX', 'es'], es lookup is broken until the armory site is migrated to the new format
|
||||
}
|
||||
|
||||
def get_sockets(self, player_dictionary):
|
||||
"""
|
||||
Return dict with total sockets and count of equipped gems and slots that are missing
|
||||
|
||||
:param player_dictionary: Retrieved player dict from API
|
||||
:return: dict()
|
||||
"""
|
||||
sockets = 0
|
||||
equipped_gems = 0
|
||||
|
||||
for item in player_dictionary["items"]:
|
||||
if item in "averageItemLevel" or item in "averageItemLevelEquipped":
|
||||
continue
|
||||
|
||||
if int(player_dictionary["items"][item]["id"]) in self.LEG_WITH_SOCKET:
|
||||
sockets += 1
|
||||
|
||||
for bonus in player_dictionary["items"][item]["bonusLists"]:
|
||||
if bonus == 1808: # 1808 is Legion prismatic socket bonus
|
||||
sockets += 1
|
||||
|
||||
if item in ["neck", "finger1", "finger2"]:
|
||||
if player_dictionary["items"][item]["context"] == "trade-skill":
|
||||
sockets += 1
|
||||
|
||||
for ttip in player_dictionary["items"][item]["tooltipParams"]:
|
||||
if item in "mainHand" or item in "offHand": # Ignore Relic
|
||||
continue
|
||||
if "gem" in ttip: # Equipped gems are listed as gem0, gem1, etc...
|
||||
equipped_gems += 1
|
||||
|
||||
return {"total_sockets": sockets,
|
||||
"equipped_gems": equipped_gems}
|
||||
|
||||
def get_enchants(self, player_dictionary):
|
||||
"""
|
||||
Get count of enchants missing and slots that are missing
|
||||
:param player_dictionary:
|
||||
:return: dict()
|
||||
"""
|
||||
self.missing_enchant_slots = []
|
||||
for slot in self.ENCHANTABLE_SLOTS:
|
||||
if "enchant" not in player_dictionary["items"][slot]["tooltipParams"]:
|
||||
self.missing_enchant_slots.append(slot)
|
||||
|
||||
return {
|
||||
"enchantable_slots": len(self.ENCHANTABLE_SLOTS),
|
||||
"missing_slots": self.missing_enchant_slots,
|
||||
"total_missing": len(self.missing_enchant_slots)
|
||||
}
|
||||
|
||||
def get_raid_progression(self, player_dictionary, raid):
|
||||
r = [x for x in player_dictionary["progression"]
|
||||
["raids"] if x["name"] in raid][0]
|
||||
normal = 0
|
||||
heroic = 0
|
||||
mythic = 0
|
||||
|
||||
for boss in r["bosses"]:
|
||||
if boss["normalKills"] > 0:
|
||||
normal += 1
|
||||
if boss["heroicKills"] > 0:
|
||||
heroic += 1
|
||||
if boss["mythicKills"] > 0:
|
||||
mythic += 1
|
||||
|
||||
return {"normal": normal,
|
||||
"heroic": heroic,
|
||||
"mythic": mythic,
|
||||
"total_bosses": len(r["bosses"])}
|
||||
|
||||
def get_mythic_progression(self, player_dictionary):
|
||||
achievements = player_dictionary["achievements"]
|
||||
plus_two = 0
|
||||
plus_five = 0
|
||||
plus_ten = 0
|
||||
|
||||
if 33096 in achievements["criteria"]:
|
||||
index = achievements["criteria"].index(33096)
|
||||
plus_two = achievements["criteriaQuantity"][index]
|
||||
|
||||
if 33097 in achievements["criteria"]:
|
||||
index = achievements["criteria"].index(33097)
|
||||
plus_five = achievements["criteriaQuantity"][index]
|
||||
|
||||
if 33098 in achievements["criteria"]:
|
||||
index = achievements["criteria"].index(33098)
|
||||
plus_ten = achievements["criteriaQuantity"][index]
|
||||
|
||||
return {
|
||||
"plus_two": plus_two,
|
||||
"plus_five": plus_five,
|
||||
"plus_ten": plus_ten
|
||||
}
|
||||
|
||||
def get_char(self, name, server, target_region):
|
||||
self.settings = dataIO.load_json("data/pug/config.json") # Load Configs
|
||||
API_KEY = self.settings["blizzard_api_key"]
|
||||
r = requests.get("https://%s.api.battle.net/wow/character/%s/%s?fields=items+progression+achievements&locale=%s&apikey=%s" % (
|
||||
self.region_locale[target_region][0], server, name, self.region_locale[target_region][1], API_KEY))
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception("Could not find character (No 200 from API).")
|
||||
|
||||
player_dict = json.loads(r.text)
|
||||
|
||||
r = requests.get(
|
||||
"https://%s.api.battle.net/wow/data/character/classes?locale=%s&apikey=%s" % (
|
||||
self.region_locale[target_region][0], self.region_locale[target_region][1], API_KEY))
|
||||
if r.status_code != 200:
|
||||
raise Exception("Could Not Find Character Classes (No 200 From API)")
|
||||
class_dict = json.loads(r.text)
|
||||
class_dict = {c['id']: c['name'] for c in class_dict["classes"]}
|
||||
|
||||
r = requests.get("https://%s.api.battle.net/wow/character/%s/%s?fields=stats&locale=%s&apikey=%s" % (
|
||||
self.region_locale[target_region][0], server, name, self.region_locale[target_region][1], API_KEY))
|
||||
if r.status_code != 200:
|
||||
raise Exception("Could not find character stats (No 200 From API).")
|
||||
stats_dict = json.loads(r.text)
|
||||
|
||||
health = stats_dict["stats"]["health"]
|
||||
power = stats_dict["stats"]["power"]
|
||||
powertype = stats_dict["stats"]["powerType"]
|
||||
powertypeproper = powertype.title()
|
||||
strength = stats_dict["stats"]["str"]
|
||||
agi = stats_dict["stats"]["agi"]
|
||||
int = stats_dict["stats"]["int"]
|
||||
sta = stats_dict["stats"]["sta"]
|
||||
crit = stats_dict["stats"]["critRating"]
|
||||
critrating = stats_dict["stats"]["crit"]
|
||||
haste = stats_dict["stats"]["hasteRating"]
|
||||
hasterating = stats_dict["stats"]["haste"]
|
||||
mastery = stats_dict["stats"]["masteryRating"]
|
||||
masteryrating = stats_dict["stats"]["mastery"]
|
||||
vers = stats_dict["stats"]["versatility"]
|
||||
versrating = stats_dict["stats"]["versatilityDamageDoneBonus"]
|
||||
equipped_ivl = player_dict["items"]["averageItemLevelEquipped"]
|
||||
sockets = self.get_sockets(player_dict)
|
||||
enchants = self.get_enchants(player_dict)
|
||||
tov_progress = self.get_raid_progression(player_dict, "Trial of Valor")
|
||||
en_progress = self.get_raid_progression(player_dict, "The Emerald Nightmare")
|
||||
nh_progress = self.get_raid_progression(player_dict, "The Nighthold")
|
||||
tos_progress = self.get_raid_progression(player_dict, "Tomb of Sargeras")
|
||||
ant_progress = self.get_raid_progression(player_dict, "Antorus, the Burning Throne")
|
||||
mythic_progress = self.get_mythic_progression(player_dict)
|
||||
|
||||
armory_url = 'http://{}.battle.net/wow/{}/character/{}/{}/advanced'.format(
|
||||
self.region_locale[target_region][0], self.region_locale[target_region][2], server, name)
|
||||
|
||||
return_string = ''
|
||||
return_string += "**%s** - **%s** - **%s %s**\n" % (
|
||||
name.title(), server.title(), player_dict['level'], class_dict[player_dict['class']])
|
||||
return_string += '<{}>\n'.format(armory_url)
|
||||
return_string += '```ini\n' # start Markdown
|
||||
|
||||
# iLvL
|
||||
return_string += "[Equipped Item Level]: %s\n" % equipped_ivl
|
||||
|
||||
# Mythic Progression
|
||||
return_string += "[Mythics]: +2: %s, +5: %s, +10: %s\n" % (mythic_progress["plus_two"],
|
||||
mythic_progress["plus_five"],
|
||||
mythic_progress["plus_ten"])
|
||||
|
||||
# Raid Progression
|
||||
return_string += "[EN]: {1}/{0} (N), {2}/{0} (H), {3}/{0} (M)\n".format(en_progress["total_bosses"],
|
||||
en_progress["normal"],
|
||||
en_progress["heroic"],
|
||||
en_progress["mythic"])
|
||||
return_string += "[TOV]: {1}/{0} (N), {2}/{0} (H), {3}/{0} (M)\n".format(tov_progress["total_bosses"],
|
||||
tov_progress["normal"],
|
||||
tov_progress["heroic"],
|
||||
tov_progress["mythic"])
|
||||
return_string += "[NH]: {1}/{0} (N), {2}/{0} (H), {3}/{0} (M)\n".format(nh_progress["total_bosses"],
|
||||
nh_progress["normal"],
|
||||
nh_progress["heroic"],
|
||||
nh_progress["mythic"])
|
||||
return_string += "[TOS]: {1}/{0} (N), {2}/{0} (H), {3}/{0} (M)\n".format(tos_progress["total_bosses"],
|
||||
tos_progress["normal"],
|
||||
tos_progress["heroic"],
|
||||
tos_progress["mythic"])
|
||||
return_string += "[ANT]: {1}/{0} (N), {2}/{0} (H), {3}/{0} (M)\n".format(ant_progress["total_bosses"],
|
||||
ant_progress["normal"],
|
||||
ant_progress["heroic"],
|
||||
ant_progress["mythic"])
|
||||
# Gems
|
||||
return_string += "[Gems Equipped]: %s/%s\n" % (
|
||||
sockets["equipped_gems"], sockets["total_sockets"])
|
||||
|
||||
# Enchants
|
||||
return_string += "[Enchants]: %s/%s\n" % (enchants["enchantable_slots"] - enchants["total_missing"],
|
||||
enchants["enchantable_slots"])
|
||||
if enchants["total_missing"] > 0:
|
||||
return_string += "[Missing Enchants]: {0}".format(
|
||||
", ".join(enchants["missing_slots"]))
|
||||
|
||||
# Stats
|
||||
return_string += "\n"
|
||||
return_string += "[Health]: {} [{}]: {}\n".format(health, powertypeproper, power)
|
||||
return_string += "[Str]: {} [Agi]: {}\n".format(strength, agi, int, sta)
|
||||
return_string += "[Int]: {} [Sta]: {}\n".format(int, sta)
|
||||
return_string += "[Crit]: {}, {}% [Haste]: {}, {}%\n".format(crit, critrating, haste, hasterating,)
|
||||
return_string += "[Mastery]: {}, {}% [Vers]: {}, {}% bonus damage\n".format(mastery, masteryrating, vers, versrating)
|
||||
|
||||
return_string += '```' # end Markdown
|
||||
return return_string
|
||||
|
||||
@commands.command(name="pug", pass_context=True, no_pm=True)
|
||||
async def _pug(self, ctx, *, message):
|
||||
"""A Warcraft Armory character lookup tool.
|
||||
Use: !pug <name> <server> <region>
|
||||
Hyphenate two-word servers (Ex: Twisting-Nether)."""
|
||||
self.settings = dataIO.load_json("data/pug/config.json") # Load Configs
|
||||
default_region = self.settings["default_region"]
|
||||
target_region = default_region
|
||||
channel = ctx.message.channel
|
||||
try:
|
||||
i = str(ctx.message.content).split(' ')
|
||||
name = i[1]
|
||||
server = i[2]
|
||||
if len(i) == 4 and i[3].lower() in self.region_locale.keys():
|
||||
target_region = i[3].lower()
|
||||
character_info = self.get_char(name, server, target_region)
|
||||
await self.bot.send_message(ctx.message.channel, character_info)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
await self.bot.send_message(ctx.message.channel, "Error with character name or server.")
|
||||
|
||||
@commands.command(pass_context=True, name='pugtoken')
|
||||
@checks.is_owner()
|
||||
async def _pugtoken(self, context, key: str):
|
||||
"""Sets the token for the Blizzard API.
|
||||
You can use this command in a private message to the bot.
|
||||
|
||||
Get an API token at: https://dev.battle.net/member/register"""
|
||||
settings = dataIO.load_json(self.fp)
|
||||
settings['blizzard_api_key'] = key
|
||||
dataIO.save_json(self.fp, settings)
|
||||
await self.bot.say("API key set.")
|
||||
|
||||
@commands.command(pass_context=True, name='pugregion')
|
||||
@checks.is_owner()
|
||||
async def _pugregion(self, context, key: str):
|
||||
"""Sets the default region."""
|
||||
settings = dataIO.load_json(self.fp)
|
||||
settings['default_region'] = key
|
||||
dataIO.save_json(self.fp, settings)
|
||||
await self.bot.say("Default region set.")
|
||||
|
||||
@commands.command()
|
||||
async def pugcredits(self):
|
||||
"""Code credits."""
|
||||
message = await self._credit()
|
||||
await self.bot.say(message)
|
||||
|
||||
async def _credit(self):
|
||||
message = "```This cog is made possible by Pugbot.\n"
|
||||
message+= "Please visit https://github.com/reznok/PugBot for more information.\n"
|
||||
message+= "```"
|
||||
return message
|
||||
|
||||
|
||||
def check_folders():
|
||||
if not os.path.exists("data/pug"):
|
||||
print("Creating data/pug folder...")
|
||||
os.mkdir("data/pug")
|
||||
|
||||
|
||||
def check_files():
|
||||
fp = "data/pug/config.json"
|
||||
if not dataIO.is_valid_json(fp):
|
||||
print("Creating config.json...")
|
||||
dataIO.save_json(fp, {"blizzard_api_key": "", "default_region": "us"})
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folders()
|
||||
check_files()
|
||||
n = Pug(bot)
|
||||
bot.add_cog(n)
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "Paddo, with edits by aikaterna",
|
||||
"NAME" : "radio",
|
||||
"SHORT" : "Plays http streams like icecast or mp3 streams.",
|
||||
"DESCRIPTION" : "This cog can only be used with audio unloaded. To play m3u or pls files, extract the http stream url they contain and use that - this cog can remember urls for later playback.",
|
||||
"TAGS": ["radio", "stream", "icecast"]
|
||||
}
|
||||
161
radio/radio.py
161
radio/radio.py
@@ -1,161 +0,0 @@
|
||||
import os
|
||||
import discord
|
||||
import asyncio
|
||||
from discord.ext import commands
|
||||
from __main__ import send_cmd_help
|
||||
from cogs.utils.dataIO import dataIO
|
||||
|
||||
|
||||
class Radio:
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.players = {}
|
||||
self.memory_path = 'data/radio/memory.json'
|
||||
self.memory = dataIO.load_json(self.memory_path)
|
||||
|
||||
@commands.group(pass_context=True, no_pm=True, name='radio')
|
||||
async def _radio(self, ctx):
|
||||
"""Streaming audio commands."""
|
||||
audio_cog = self.bot.get_cog('Audio')
|
||||
if audio_cog:
|
||||
return await self.bot.say("Please unload the audio cog before using this cog.")
|
||||
if ctx.invoked_subcommand is None:
|
||||
await send_cmd_help(ctx)
|
||||
|
||||
@_radio.command(pass_context=True, no_pm=True, name='stop')
|
||||
async def _leave(self, ctx):
|
||||
"""Stops playback."""
|
||||
server = ctx.message.server
|
||||
voice_client = await self.voice_client(server)
|
||||
await self.stop_playing(server)
|
||||
if voice_client:
|
||||
await voice_client.disconnect()
|
||||
|
||||
@_radio.command(no_pm=True, pass_context=True, name='play')
|
||||
async def _play(self, ctx, url: str):
|
||||
"""Play a http stream."""
|
||||
server = ctx.message.server
|
||||
if server.id in self.players:
|
||||
await self.stop_playing(server)
|
||||
await self.play_stream(ctx, url)
|
||||
await self.bot.say("Now playing: <{}>".format(url))
|
||||
|
||||
@_radio.command(no_pm=True, pass_context=True, name='list')
|
||||
async def _list(self, ctx):
|
||||
"""List saved stream URLs."""
|
||||
server = ctx.message.server
|
||||
message = '```\n'
|
||||
message += '{:<30}{}\n\n'.format('NAME', 'URL')
|
||||
if server.id in self.memory:
|
||||
for stream in self.memory[server.id]:
|
||||
message += '{:<30}{}\n'.format(stream, self.memory[server.id][stream])
|
||||
message += '```'
|
||||
await self.bot.say(message)
|
||||
|
||||
@_radio.command(no_pm=True, pass_context=True, name='add')
|
||||
async def _add(self, ctx, name: str, url: str):
|
||||
"""Add a url to save for radio playback."""
|
||||
server = ctx.message.server
|
||||
await self.add_to_memory(server, name, url)
|
||||
await self.bot.say('Added to memory')
|
||||
|
||||
@_radio.command(no_pm=True, pass_context=True, name='load')
|
||||
async def _load(self, ctx, name: str):
|
||||
"""Load a saved url for radio playback."""
|
||||
server = ctx.message.server
|
||||
if server.id in self.memory:
|
||||
if name.lower() in self.memory[server.id]:
|
||||
url = self.memory[server.id][name.lower()]
|
||||
if server.id in self.players:
|
||||
await self.stop_playing(server)
|
||||
await self.play_stream(ctx, url)
|
||||
await self.bot.say("Now playing: <{}>".format(url))
|
||||
else:
|
||||
await self.bot.say('"{}" is not in memory.'.format(name.lower()))
|
||||
else:
|
||||
await self.bot.say('Nothing in memory yet')
|
||||
|
||||
async def save_memory(self):
|
||||
dataIO.save_json(self.memory_path, self.memory)
|
||||
|
||||
async def add_to_memory(self, server, name, url):
|
||||
if server.id not in self.memory:
|
||||
self.memory[server.id] = {}
|
||||
self.memory[server.id][name.lower()] = url
|
||||
await self.save_memory()
|
||||
|
||||
async def join_voice_channel(self, channel):
|
||||
try:
|
||||
await self.bot.join_voice_channel(channel)
|
||||
return True
|
||||
except discord.InvalidArgument:
|
||||
await self.bot.say('You need to be in a voice channel yourself.')
|
||||
except discord.Forbidden:
|
||||
await self.bot.say('I don\'t have permissions to join this channel.')
|
||||
return False
|
||||
|
||||
async def leave_voice_channel(self, server):
|
||||
voice_client = await self.voice_client(server)
|
||||
if server.id in self.players:
|
||||
self.players[server.id].stop()
|
||||
del self.players[server.id]
|
||||
await self.stop_playing(server)
|
||||
await voice_client.disconnect()
|
||||
|
||||
async def voice_connected(self, server):
|
||||
return self.bot.is_voice_connected(server)
|
||||
|
||||
async def voice_client(self, server):
|
||||
return self.bot.voice_client_in(server)
|
||||
|
||||
async def stop_playing(self, server):
|
||||
if server.id in self.players:
|
||||
self.players[server.id].stop()
|
||||
del self.players[server.id]
|
||||
|
||||
async def start_playing(self, server, url):
|
||||
if server.id not in self.players:
|
||||
voice_client = await self.voice_client(server)
|
||||
audio_player = voice_client.create_ffmpeg_player(url)
|
||||
self.players[server.id] = audio_player
|
||||
self.players[server.id].start()
|
||||
|
||||
async def play_stream(self, ctx, url):
|
||||
server = ctx.message.server
|
||||
channel = ctx.message.author.voice_channel
|
||||
if not ctx.message.channel.is_private:
|
||||
check = True
|
||||
if not await self.voice_connected(server):
|
||||
check = await self.join_voice_channel(channel)
|
||||
if check:
|
||||
await self.start_playing(server, url)
|
||||
|
||||
async def _playing_check(self):
|
||||
while self == self.bot.get_cog('Radio'):
|
||||
for player in self.players:
|
||||
if not self.players[player].is_playing():
|
||||
server = self.bot.get_server(player)
|
||||
await self.leave_voice_channel(server)
|
||||
break
|
||||
await asyncio.sleep(30)
|
||||
|
||||
|
||||
def check_folder():
|
||||
if not os.path.exists('data/radio'):
|
||||
print('Creating data/radio folder...')
|
||||
os.makedirs('data/radio')
|
||||
|
||||
|
||||
def check_file():
|
||||
if not dataIO.is_valid_json('data/radio/memory.json'):
|
||||
print('Creating memory.json...')
|
||||
dataIO.save_json('data/radio/memory.json', {})
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folder()
|
||||
check_file()
|
||||
cog = Radio(bot)
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task(cog._playing_check())
|
||||
bot.add_cog(cog)
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna",
|
||||
"INSTALL_MSG" : "Thanks for installing riot.",
|
||||
"NAME" : "Riot",
|
||||
"SHORT" : "RIOT!",
|
||||
"DESCRIPTION" : "Riot was a feature on the now-extinct Fredboat, requested by Mewleficent.",
|
||||
"TAGS" : ["riot"]
|
||||
}
|
||||
17
riot/riot.py
17
riot/riot.py
@@ -1,17 +0,0 @@
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
|
||||
class Riot:
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
async def riot(self, ctx, *, text: str):
|
||||
"""RIOT!"""
|
||||
await self.bot.say('ヽ༼ຈل͜ຈ༽ノ **' + str(text) + '** ヽ༼ຈل͜ຈ༽ノ')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Riot(bot))
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "Paddolicious#8880",
|
||||
"NAME" : "Seen",
|
||||
"SHORT" : "Check when the user was last active on a server.",
|
||||
"DESCRIPTION" : "Check when the user was last active on a server.",
|
||||
"TAGS": ["Seen", "member", "tools"]
|
||||
}
|
||||
119
seen/seen.py
119
seen/seen.py
@@ -1,119 +0,0 @@
|
||||
from discord.ext import commands
|
||||
from cogs.utils.dataIO import dataIO
|
||||
import discord
|
||||
import os
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
DB_VERSION = 2
|
||||
|
||||
|
||||
class Seen:
|
||||
'''Check when someone was last seen.'''
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.seen = dataIO.load_json('data/seen/seen.json')
|
||||
self.new_data = False
|
||||
|
||||
async def data_writer(self):
|
||||
while self == self.bot.get_cog('Seen'):
|
||||
if self.new_data:
|
||||
dataIO.save_json('data/seen/seen.json', self.seen)
|
||||
self.new_data = False
|
||||
await asyncio.sleep(60)
|
||||
else:
|
||||
await asyncio.sleep(30)
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, name='seen')
|
||||
async def _seen(self, context, username: discord.Member):
|
||||
'''seen <@username>'''
|
||||
server = context.message.server
|
||||
author = username
|
||||
timestamp_now = context.message.timestamp
|
||||
if server.id in self.seen:
|
||||
if author.id in self.seen[server.id]:
|
||||
data = self.seen[server.id][author.id]
|
||||
timestamp_then = datetime.fromtimestamp(data['TIMESTAMP'])
|
||||
timestamp = timestamp_now - timestamp_then
|
||||
days = timestamp.days
|
||||
seconds = timestamp.seconds
|
||||
hours = seconds // 3600
|
||||
seconds = seconds - (hours * 3600)
|
||||
minutes = seconds // 60
|
||||
if sum([days, hours, minutes]) < 1:
|
||||
ts = 'just now'
|
||||
else:
|
||||
ts = ''
|
||||
if days == 1:
|
||||
ts += '{} day, '.format(days)
|
||||
elif days > 1:
|
||||
ts += '{} days, '.format(days)
|
||||
if hours == 1:
|
||||
ts += '{} hour, '.format(hours)
|
||||
elif hours > 1:
|
||||
ts += '{} hours, '.format(hours)
|
||||
if minutes == 1:
|
||||
ts += '{} minute ago'.format(minutes)
|
||||
elif minutes > 1:
|
||||
ts += '{} minutes ago'.format(minutes)
|
||||
em = discord.Embed(color=discord.Color.green())
|
||||
avatar = author.avatar_url if author.avatar else author.default_avatar_url
|
||||
em.set_author(name='{} was seen {}'.format(author.display_name, ts), icon_url=avatar)
|
||||
await self.bot.say(embed=em)
|
||||
else:
|
||||
message = 'I haven\'t seen {} yet.'.format(author.display_name)
|
||||
await self.bot.say('{}'.format(message))
|
||||
else:
|
||||
message = 'I haven\'t seen {} yet.'.format(author.display_name)
|
||||
await self.bot.say('{}'.format(message))
|
||||
|
||||
async def on_message(self, message):
|
||||
if not message.channel.is_private and self.bot.user.id != message.author.id:
|
||||
if not any(message.content.startswith(n) for n in self.bot.settings.prefixes):
|
||||
server = message.server
|
||||
author = message.author
|
||||
ts = message.timestamp.timestamp()
|
||||
data = {}
|
||||
data['TIMESTAMP'] = ts
|
||||
if server.id not in self.seen:
|
||||
self.seen[server.id] = {}
|
||||
self.seen[server.id][author.id] = data
|
||||
self.new_data = True
|
||||
|
||||
|
||||
def check_folder():
|
||||
if not os.path.exists('data/seen'):
|
||||
print('Creating data/seen folder...')
|
||||
os.makedirs('data/seen')
|
||||
|
||||
|
||||
def check_file():
|
||||
data = {}
|
||||
data['db_version'] = DB_VERSION
|
||||
f = 'data/seen/seen.json'
|
||||
if not dataIO.is_valid_json(f):
|
||||
print('Creating seen.json...')
|
||||
dataIO.save_json(f, data)
|
||||
else:
|
||||
check = dataIO.load_json(f)
|
||||
if 'db_version' in check:
|
||||
if check['db_version'] < DB_VERSION:
|
||||
data = {}
|
||||
data['db_version'] = DB_VERSION
|
||||
dataIO.save_json(f, data)
|
||||
print('SEEN: Database version too old, resetting!')
|
||||
else:
|
||||
data = {}
|
||||
data['db_version'] = DB_VERSION
|
||||
dataIO.save_json(f, data)
|
||||
print('SEEN: Database version too old, resetting!')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folder()
|
||||
check_file()
|
||||
n = Seen(bot)
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task(n.data_writer())
|
||||
bot.add_cog(n)
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"AUTHOR" : "aikaterna",
|
||||
"INSTALL_MSG" : "No settings, when loaded the bot will leave servers with under 25 members on join.",
|
||||
"NAME" : "serverlimit",
|
||||
"SHORT" : "Serverlimit",
|
||||
"DESCRIPTION" : "Limits the bot joining servers that have under 25 members.",
|
||||
"TAGS": []
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
# get_default_channel_or_other is from Squid's Admin cog:
|
||||
# https://github.com/tekulvw/Squid-Plugins
|
||||
|
||||
import discord
|
||||
import traceback
|
||||
|
||||
|
||||
class ServerLimit:
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
async def _message(self, server):
|
||||
server_owner = server.owner
|
||||
notice_msg = "Hi, I tried to make an announcement in your "\
|
||||
+ "server, " + server.name + ", but I don't have "\
|
||||
+ "permissions to send messages in the default "\
|
||||
+ "channel there!"
|
||||
await self.bot.send_message(server_owner, notice_msg)
|
||||
await self.bot.leave_server(server)
|
||||
|
||||
async def on_server_join(self, server):
|
||||
chan = self.get_default_channel_or_other(server,
|
||||
discord.ChannelType.text,
|
||||
send_messages=True)
|
||||
me = server.me
|
||||
server_owner = server.owner
|
||||
msg = "I can only join servers which have more than 25 members. "\
|
||||
+ "Please try again later when the server is larger."
|
||||
if len(server.members) <= 25:
|
||||
if chan is not None:
|
||||
if chan.permissions_for(me).send_messages:
|
||||
await self.bot.send_message(chan, msg)
|
||||
await self.bot.leave_server(server)
|
||||
else:
|
||||
await self._message(server)
|
||||
await self.bot.send_message(server_owner, msg)
|
||||
else:
|
||||
await self._message(server)
|
||||
await self.bot.send_message(server_owner, msg)
|
||||
|
||||
def get_default_channel_or_other(self, server,
|
||||
ctype: discord.ChannelType=None,
|
||||
**perms_required):
|
||||
|
||||
perms = discord.Permissions.none()
|
||||
perms.update(**perms_required)
|
||||
if ctype is None:
|
||||
types = [discord.ChannelType.text, discord.ChannelType.voice]
|
||||
elif ctype == discord.ChannelType.text:
|
||||
types = [discord.ChannelType.text]
|
||||
else:
|
||||
types = [discord.ChannelType.voice]
|
||||
try:
|
||||
channel = server.default_channel
|
||||
except Exception:
|
||||
channel = None
|
||||
if channel is not None:
|
||||
if channel.permissions_for(server.me).is_superset(perms):
|
||||
return channel
|
||||
|
||||
chan_list = [c for c in sorted(server.channels,
|
||||
key=lambda ch: ch.position)
|
||||
if c.type in types]
|
||||
for ch in chan_list:
|
||||
if ch.permissions_for(server.me).is_superset(perms):
|
||||
return ch
|
||||
return None
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(ServerLimit(bot))
|
||||
Reference in New Issue
Block a user