42 Commits

Author SHA1 Message Date
aikaterna
a7fd5930f9 [YouTube] Gotta pass that context on
just keep on movin on
2020-08-04 17:07:50 -07:00
aikaterna
fd199aea93 Update README.md 2020-08-04 17:04:32 -07:00
aikaterna
e894bf21bc [YouTube] Backport from v3 2020-08-04 20:02:42 -04:00
aikaterna
9de37b1fd1 [V2 Chatchart] Escape dollar signs 2019-03-23 20:36:25 -07:00
aikaterna
e31efdba0c Update README.md 2019-02-18 11:00:05 -08:00
aikaterna
492e9244d6 Update README.md 2019-02-18 10:59:13 -08:00
aikaterna
01aa67fa9a [V2 Wolfram] Escape mass mentions
Escaped mass mentions in the returned message. Added slightly more friendly API key interaction and Black formatting.
2018-09-29 00:42:44 -07:00
aikaterna
adb3efa746 [V2 Tools] Initial commit
Well, this was at least 2 years in the making. Thanks to Sitryk who did the most work on this, and thanks to Axas for writing the original find/cmd_lookup command.
2018-09-08 12:54:00 -07:00
aikaterna
2cc04c3ac0 Update readme 2018-08-06 20:40:01 -07:00
aikaterna
b2384eb7df [V2] Add modclean
Thanks sitryk.
2018-08-06 20:35:40 -07:00
aikaterna
4d66912fa2 [v2 Autoeconomy] No massregister in DMs 2018-07-05 08:12:31 -07:00
aikaterna
f0f3a4171a [V2 Chatchart] No chatchart in DMs 2018-06-30 18:57:07 -07:00
aikaterna
7f227e762c [v2 Wolfram] Set to Paddo's original version
Sorry Yukirin, I uploaded your version by mistake.
2018-06-30 15:11:46 -07:00
aikaterna
f5b089f3ec Create info.json for wolfram 2018-06-21 09:51:18 -07:00
aikaterna
ea207bccb0 Update README.md
Update for wolfram
2018-06-21 09:49:42 -07:00
aikaterna
cbd9901857 Upload wolfram.py
Paddo's old unsupported Wolfram cog, now with a shiny new home
2018-06-21 09:48:35 -07:00
aikaterna
74901f5e37 Add radio remove for removing saved stations
Fulfills #18
2018-05-22 10:47:03 -07:00
aikaterna
d13075f0c6 Sort radio list alphabetically
Fulfills request of issue #15
2018-05-13 09:47:14 -07:00
aikaterna
76559c6b25 Update readme for post cog 2018-05-04 10:20:03 -07:00
aikaterna
deaba0dde0 Create post.py 2018-05-04 10:19:00 -07:00
aikaterna
f33671601b Fix bonus messages 2018-04-19 08:06:53 -07:00
aikaterna
7dd97fb2c0 Update picwelcome to use other image types
Picwelcome can now use GIF images.
2018-04-01 11:49:24 -07:00
aikaterna
eaee1acf21 Add discriminator to user name, shorten by length 2018-03-18 15:50:08 -07:00
aikaterna
02ebcf7192 Merge pull request #14 from TaliZorahVasNormandy/master
Several improvements to ChatChart
2018-03-18 15:31:10 -07:00
aikaterna
567fb3077c Add channel permission checks, format channel name 2018-03-18 15:29:47 -07:00
TaliZorahVasNormandy
829308f42a Added ability to specify target channels as argument; Specify target channel in plot title; Increased display number from top10 to top20; integrated Discord Dark Theme 2018-03-12 13:58:56 +01:00
aikaterna
4e4f26f2db Merge pull request #13 from Sitryk/patch-3 2018-03-06 23:12:21 -08:00
James
2d8cf0a1e4 Update autoeconomy.py
fixed some setting pointers
2018-03-07 13:50:09 +13:00
aikaterna
a372ff997e Fix outline on usernames > 33 chars 2018-02-28 09:25:18 -08:00
aikaterna
f209aa2975 Merge pull request #11 from mikeshardmind/mass-register
add mass register to autoeconomy
2018-02-03 15:05:38 -08:00
aikaterna
f8a501285f Update version, fix initial balance, update help 2018-02-03 13:47:03 -08:00
michael
3112153c57 don't load economy's setting's through json this
leads to having a different set of settings
if updated through economy after autoeconomy is loaded
reference settings object in economy cog instead
2018-02-02 19:00:43 -05:00
aikaterna
d2291ba7a9 Merge pull request #12 from skeith/patch-1
Let's not be deprecated again
2018-01-31 20:00:52 -08:00
aikaterna
2a1231f42f Update version 2018-01-31 20:00:24 -08:00
Yukirin
2b5e99b403 Let's not be deprecated again
Changed `aiohttp.get` to use `aiohttp.ClientSession()`
2018-02-01 06:12:59 +08:00
michael
48132fe5b8 outdent exit status 2018-01-31 13:59:41 -05:00
michael
8f23276ad2 use the initial_credits parameter when making an account 2018-01-31 13:58:58 -05:00
michael
ae1567425c Move return statement for exit code
Verify a bank exists before trying to register people at it
2018-01-30 18:48:59 -05:00
michael
115144d9e3 massregister is an explicit command, should reflect that in handling of the toggle 2018-01-30 18:08:04 -05:00
michael
37c808a9a1 check if massregistering before issuing debug messages 2018-01-30 18:03:23 -05:00
michael
fa0b3a6389 add mass register 2018-01-30 16:30:54 -05:00
aikaterna
93465b2140 Update readme 2018-01-28 17:15:00 -08:00
15 changed files with 1169 additions and 56 deletions

View File

@@ -1,5 +1,12 @@
# aikaterna-cogs
Cogs for Red-DiscordBot by Twentysix26.
**v2 cogs support has ended. I will still provide bugfixes on these cogs if it is significant enough, but no new features will be added.**
**Red v3 cogs can be found on the v3 branch of this repo. (https://github.com/aikaterna/aikaterna-cogs/tree/v3)**
________________
Cogs for v2 Red-DiscordBot by Twentysix26.
autoeconomy - New users that join the server will be automatically given a bank account.
@@ -15,8 +22,12 @@ hunting - By Paddolicious#8880. It hunts birds... and things that fly.
imgwelcome - Welcome users to your server with a customized image.
modclean - Clean the last 100 entries in the mod-log of Discord invite names.
otherbot - Have multiple Red instances and want to know when one goes offline? Edit this cog and load it on your watcher bot.
post - Upload a saved audio playlist to the chat channel, or upload a cog. Owner only.
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.
@@ -27,10 +38,8 @@ 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.
wolfram - Paddolicious#8880's old wolfram cog.
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.
youtube - Paddolicious#8880's old youtube cog, backported from my v3 version.
Feel free to join the server for these cogs if you'd like. https://discord.gg/th6eS3T

View File

@@ -19,8 +19,7 @@ class AutoEconomy:
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"
self.version = "0.1.2"
async def save_settings(self):
dataIO.save_json('data/autoeconomy/settings.json', self.settings)
@@ -85,31 +84,64 @@ class AutoEconomy:
"""Displays the autoeconomy version."""
await self.bot.say("autoeconomy version {}.".format(self.version))
async def on_member_join(self, member):
@autoeconomy.command(name="massregister", pass_context=True, no_pm=True)
async def massregister(self, ctx):
"""Mass register existing users."""
econ_cog = self.bot.get_cog('Economy')
if not econ_cog:
return await self.bot.say("This requires economy to be loaded.")
server = ctx.message.server
if server.id not in econ_cog.bank.accounts:
return await self.bot.say(
"I can't register people for a bank that doesn't exist yet."
)
count = 0
for member in server.members:
init_balance = econ_cog.settings[server.id].get("REGISTER_CREDITS", 0)
try:
econ_cog.bank.create_account(member, initial_balance=init_balance)
except Exception:
continue
else:
count += 1
await self.bot.say(
"I've opened up new economy entries for "
"{}/{} members.".format(count, len(server.members))
)
async def on_member_join(self, member, mass_register=False):
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"]:
if not (self.settings[server.id]["TOGGLE"] or mass_register):
return
channel = self.settings[server.id]["CHANNEL"]
channel_object = self.bot.get_channel(channel)
econ_cog = self.bot.get_cog('Economy')
if server.id not in econ_cog.bank.accounts:
return
if not econ_cog:
return
bank = self.bot.get_cog('Economy').bank
init_balance = econ_cog.settings[server.id].get("REGISTER_CREDITS", 0)
try:
bank.create_account(member)
bank.create_account(member, initial_balance=init_balance)
except Exception:
if self.settings[server.id]["DEBUG"]:
if self.settings[server.id]["DEBUG"] and not mass_register:
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"]:
return False
else:
if self.settings[server.id]["DEBUG"] and not mass_register:
await self.bot.send_message(channel_object, "Bank account opened for {} and initial credits given.".format(member.name))
return
return True
def check_folders():

View File

@@ -20,67 +20,83 @@ class ChatChart:
def __init__(self, bot):
self.bot = bot
def create_chart(self, top, others):
def create_chart(self, top, others, channel):
plt.clf()
sizes = [x[1] for x in top]
labels = ["{} {:g}%".format(x[0], x[1]) for x in top]
if len(top) >= 10:
if len(top) >= 20:
sizes = sizes + [others]
labels = labels + ["Others {:g}%".format(others)]
title = plt.title('User activity in the last 5000 messages')
if len(channel.name) >= 19:
channel_name = '{}...'.format(channel.name[:19])
else:
channel_name = channel.name
title = plt.title("Stats in #{}".format(channel_name), color="white")
title.set_va("top")
title.set_ha("left")
title.set_ha("center")
plt.gca().axis("equal")
colors = ['r', 'darkorange', 'gold', 'y', 'olivedrab', 'green', 'darkcyan', 'mediumblue', 'darkblue', 'blueviolet', 'indigo']
colors = ['r', 'darkorange', 'gold', 'y', 'olivedrab', 'green', 'darkcyan', 'mediumblue', 'darkblue', 'blueviolet', 'indigo', 'orchid', 'mediumvioletred', 'crimson', 'chocolate', 'yellow', 'limegreen','forestgreen','dodgerblue','slateblue','gray']
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)
bbox_transform=plt.gcf().transFigure, facecolor='#ffffff')
plt.subplots_adjust(left=0.0, bottom=0.1, right=0.45)
image_object = BytesIO()
plt.savefig(image_object, format='PNG')
plt.savefig(image_object, format='PNG', facecolor='#36393E')
image_object.seek(0)
return image_object
@commands.command(pass_context=True)
@commands.command(pass_context=True, no_pm=True)
@commands.cooldown(1, 10, commands.BucketType.channel)
async def chatchart(self, ctx):
async def chatchart(self, ctx, channel: discord.Channel=None):
"""
Generates a pie chart, representing the last 5000 messages in this channel.
Generates a pie chart, representing the last 5000 messages in the specified 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)
if channel is None:
channel = ctx.message.channel
history = []
async for msg in self.bot.logs_from(channel, 5000):
history.append(msg)
if not channel.permissions_for(ctx.message.author).read_messages == True:
await self.bot.delete_message(em)
return await self.bot.say("You're not allowed to access that channel.")
try:
async for msg in self.bot.logs_from(channel, 5000):
history.append(msg)
except discord.errors.Forbidden:
await self.bot.delete_message(em)
return await self.bot.say("No permissions to read that channel.")
msg_data = {'total count': 0, 'users': {}}
for msg in history:
if len(msg.author.name) >= 20:
short_name = '{}...'.format(msg.author.name[:20]).replace("$", "\$")
else:
short_name = msg.author.name.replace("$", "\$")
whole_name = '{}#{}'.format(short_name, msg.author.discriminator)
if msg.author.bot:
pass
elif msg.author.name in msg_data['users']:
msg_data['users'][msg.author.name]['msgcount'] += 1
elif whole_name in msg_data['users']:
msg_data['users'][whole_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['users'][whole_name] = {}
msg_data['users'][whole_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])
top_ten = heapq.nlargest(20, [(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)
img = self.create_chart(top_ten, others, channel)
await self.bot.delete_message(em)
await self.bot.send_file(channel, img, filename="chart.png")
await self.bot.send_file(ctx.message.channel, img, filename="chart.png")
def check_folders():

View File

@@ -55,7 +55,11 @@ class ImgWelcome:
def __init__(self, bot):
self.bot = bot
self.settings = dataIO.load_json('data/imgwelcome/settings.json')
self.version = "0.1.6"
self.version = "0.1.8"
self.session = aiohttp.ClientSession()
def __unload(self):
self.session.close()
async def save_settings(self):
dataIO.save_json('data/imgwelcome/settings.json', self.settings)
@@ -152,7 +156,7 @@ class ImgWelcome:
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))
_outline((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:
@@ -220,7 +224,7 @@ class ImgWelcome:
await self.save_settings()
async def _get_profile(self, url):
async with aiohttp.get(url) as r:
async with self.session.get(url) as r:
image = await r.content.read()
with open('data/imgwelcome/profilepic.png', 'wb') as f:
f.write(image)
@@ -407,7 +411,7 @@ class ImgWelcome:
if success:
try:
async with aiohttp.get(bg_url) as r:
async with self.session.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))
@@ -587,14 +591,14 @@ class ImgWelcome:
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"]:
if ((len(member.server.members) % 100) == 0 or (len(member.server.members) == 1337)) and self.settings[server.id]["BONUSES"]["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"]:
if since_join.days < 7 and self.settings[server.id]["BONUSES"]["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)")

8
modclean/info.json Normal file
View File

@@ -0,0 +1,8 @@
{
"AUTHOR" : "aikaterna and sitryk",
"INSTALL_MSG" : "Use `[p]modclean #mod-log` to clean your mod log channel. Edits out Discord invite links from banned or kicked users.",
"NAME" : "modclean",
"SHORT" : "Clean your mod log channel of Discord invite names.",
"DESCRIPTION" : "Clean your mod log channel of Discord invite names.",
"TAGS": ["modlog"]
}

40
modclean/modclean.py Normal file
View File

@@ -0,0 +1,40 @@
import discord
import re
from cogs.utils import checks
from discord.ext import commands
class ModClean:
def __init__(self, bot):
self.bot = bot
@commands.command(no_pm=True, pass_context=True)
@checks.is_owner()
async def modclean(self, ctx, modchannel: discord.Channel = None):
"""Clean a v2 mod-log channel of invite names."""
if not modchannel:
return await self.bot.say(
"Please use the mod channel in the command. ({}modclean #channelname)".format(
ctx.prefix
)
)
IL_raw = r"(discordapp.com/invite|discord.me|discord.gg)(?:/#)?(?:/invite)?/([a-z0-9\-]+)"
InvLink = re.compile(IL_raw, re.I)
try:
async for m in self.bot.logs_from(modchannel, 100):
if not (m.author == ctx.message.server.me):
continue
elif InvLink.search(m.content) is None:
continue
else:
new_cont = InvLink.sub("[REMOVED LINK]", m.content)
await self.bot.edit_message(m, new_cont)
except discord.errors.Forbidden:
return await self.bot.say("No permissions to read that channel.")
await self.bot.say("Done.")
def setup(bot):
bot.add_cog(ModClean(bot))

View File

@@ -109,24 +109,24 @@ class PicWelcome:
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)
file_suffix = bg_url.rsplit('.', 1)[1]
serverbg = 'data/picwelcome/{}/serverpic.{}'.format(server.id, file_suffix)
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"
self.settings[server.id]['PICTURE'] = "data/picwelcome/{}/serverpic.{}".format(ctx.message.server.id, file_suffix)
await self.save_settings()
await self.bot.say('Welcome image for this server set to uploaded file.')
else:
@@ -152,12 +152,10 @@ class PicWelcome:
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 = {}

31
post/post.py Normal file
View File

@@ -0,0 +1,31 @@
from discord.ext import commands
from .utils import checks
class Post:
def __init__(self,bot):
self.bot = bot
@commands.command(no_pm=True, pass_context=True)
@checks.is_owner()
async def postsongs(self, ctx, playlist):
"""Posts a playlist."""
try:
await self.bot.send_file(ctx.message.channel, 'data/audio/playlists/{}/{}.txt'.format(ctx.message.server.id, playlist))
except FileNotFoundError:
try:
await self.bot.send_file(ctx.message.channel, 'data/audio/playlists/{}.txt'.format(playlist))
except FileNotFoundError:
await self.bot.say("No playlist named {}.".format(playlist))
@commands.command(no_pm=True, pass_context=True)
@checks.is_owner()
async def postcog(self, ctx, cogname):
"""Posts a cog."""
try:
await self.bot.send_file(ctx.message.channel, 'cogs/{}.py'.format(cogname))
except FileNotFoundError:
await self.bot.say("No cog named {}.".format(cogname))
def setup(bot):
n = Post(bot)
bot.add_cog(n)

View File

@@ -44,13 +44,18 @@ class Radio:
async def _list(self, ctx):
"""List saved stream URLs."""
server = ctx.message.server
message = '```\n'
message += '{:<30}{}\n\n'.format('NAME', 'URL')
message_list = []
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)
message = '{:<30}{}\n'.format(stream, self.memory[server.id][stream])
message_list.append(message)
sorted_list = sorted(message_list, key=str.lower)
msg = '```'
msg += '{:<30}{}\n\n'.format('NAME', 'URL')
for sorted_msg in sorted_list:
msg += sorted_msg
msg += '```'
await self.bot.say(msg)
@_radio.command(no_pm=True, pass_context=True, name='add')
async def _add(self, ctx, name: str, url: str):
@@ -75,6 +80,13 @@ class Radio:
else:
await self.bot.say('Nothing in memory yet')
@_radio.command(no_pm=True, pass_context=True, name='remove')
async def _remove(self, ctx, name: str):
"""Remove a saved radio stream."""
server = ctx.message.server
await self.remove_from_memory(server, name)
await self.bot.say('Removed {} from memory.'.format(name))
async def save_memory(self):
dataIO.save_json(self.memory_path, self.memory)
@@ -84,6 +96,10 @@ class Radio:
self.memory[server.id][name.lower()] = url
await self.save_memory()
async def remove_from_memory(self, server, name):
del self.memory[server.id][name.lower()]
await self.save_memory()
async def join_voice_channel(self, channel):
try:
await self.bot.join_voice_channel(channel)

9
tools/info.json Normal file
View File

@@ -0,0 +1,9 @@
{
"AUTHOR" : "aikaterna, Sitryk, and Axas",
"INSTALL_MSG" : "Thanks for installing.",
"NAME" : "tools",
"SHORT" : "A collection of tools for mods.",
"DESCRIPTION" : "A collection of channel, user, and server tools for mods.",
"REQUIREMENTS": ["tabulate"],
"TAGS": ["tools"]
}

813
tools/tools.py Normal file
View File

@@ -0,0 +1,813 @@
# Most of these tools are thanks to Sitryk.
# Credit for the findcog/cmd_lookup command belongs to Axas, thanks for the inspiration for
# the findcog command in Red v3.
from discord.ext import commands
from .utils.chat_formatting import pagify, box, escape_mass_mentions
from .utils.dataIO import dataIO
from .utils import checks
from __main__ import send_cmd_help
from tabulate import tabulate
import discord
import glob
import os
import datetime
import asyncio
import discord
import random
import inspect
ini = "```ini\n{0}\n```"
class Tools:
"""Mod and Admin tools."""
def __init__(self, bot):
self.bot = bot
@checks.mod_or_permissions(manage_messages=True)
@commands.group(pass_context=True, no_pm=True)
async def access(self, ctx):
"""Check channel access."""
if ctx.invoked_subcommand is None:
await send_cmd_help(ctx)
return
@checks.mod_or_permissions(manage_messages=True)
@access.command(pass_context=True)
async def compare(self, ctx, user: discord.User, server: discord.Server = None):
"""Compare channel access with [user]"""
author = ctx.message.author
if user is None:
return
if server is None:
server = ctx.message.server
text_channels = [c for c in server.channels if str(c.type) == "text"]
voice_channels = [c for c in server.channels if str(c.type) == "voice"]
author_text_channels = [
c.name for c in text_channels if c.permissions_for(author).read_messages is True
]
author_voice_channels = [
c.name for c in voice_channels if c.permissions_for(author).connect is True
]
user_text_channels = [
c.name for c in text_channels if c.permissions_for(user).read_messages is True
]
user_voice_channels = [
c.name for c in voice_channels if c.permissions_for(user).connect is True
]
author_only_t = set(author_text_channels) - set(
user_text_channels
) # text channels only the author has access to
author_only_v = set(author_voice_channels) - set(
user_voice_channels
) # voice channels only the author has access to
user_only_t = set(user_text_channels) - set(
author_text_channels
) # text channels only the user has access to
user_only_v = set(user_voice_channels) - set(
author_voice_channels
) # voice channels only the user has access to
common_t = list(
set(text_channels) - author_only_t - user_only_t
) # text channels that author and user have in common
common_v = list(
set(voice_channels) - author_only_v - user_only_v
) # voice channels that author and user have in common
msg = "```ini\n"
msg += "{} [TEXT CHANNELS IN COMMON]:\n\n{}\n\n".format(
len(common_t), ", ".join([c.name for c in common_t])
)
msg += "{} [TEXT CHANNELS {} HAS ACCESS TO]:\n\n{}\n\n".format(
len(user_only_t), user.name.upper(), ", ".join(list(user_only_t))
)
msg += "{} [TEXT CHANNELS YOU HAVE ACCESS TO]:\n\n{}\n\n".format(
len(author_only_t), ", ".join(list(author_only_t))
)
msg += "{} [VOICE CHANNELS IN COMMON]:\n\n{}\n\n".format(
len(common_v), ", ".join([c.name for c in common_v])
)
msg += "{} [VOICE CHANNELS {} HAS ACCESS TO]:\n\n{}\n\n".format(
len(user_only_v), user.name.upper(), ", ".join(list(user_only_v))
)
msg += "{} [VOICE CHANNELS YOU HAVE ACCESS TO]:\n\n{}\n\n".format(
len(author_only_v), ", ".join(list(author_only_v))
)
msg += "```"
await self.bot.say(msg)
@checks.mod_or_permissions(manage_messages=True)
@access.command(pass_context=True)
async def text(self, ctx, user: discord.Member = None, server: discord.Server = None):
"""Fetch which text channels you have access to."""
author = ctx.message.author
if server is None:
server = ctx.message.server
if user is None:
user = author
can_access = [
c.name
for c in server.channels
if c.permissions_for(user).read_messages == True and str(c.type) == "text"
]
text_channels = [c.name for c in server.channels if str(c.type) == "text"]
prefix = "You have" if user.id == author.id else user.name + " has"
msg = "```ini\n[{} access to {} out of {} text channels]\n\n".format(
prefix, len(can_access), len(text_channels)
)
msg += "[ACCESS]:\n{}\n\n".format(", ".join(can_access))
msg += "[NO ACCESS]:\n{}\n```".format(
", ".join(list(set(text_channels) - set(can_access)))
)
await self.bot.say(msg)
@checks.mod_or_permissions(manage_messages=True)
@access.command(pass_context=True)
async def voice(self, ctx, user: discord.Member = None, server: discord.Server = None):
"""Fetch which voice channels you have access to."""
author = ctx.message.author
if server is None:
server = ctx.message.server
if user is None:
user = author
can_access = [
c.name
for c in server.channels
if c.permissions_for(user).connect is True and str(c.type) == "voice"
]
voice_channels = [c.name for c in server.channels if str(c.type) == "voice"]
prefix = "You have" if user.id == author.id else user.name + " has"
msg = "```ini\n[{} access to {} out of {} voice channels]\n\n".format(
prefix, len(can_access), len(voice_channels)
)
msg += "[ACCESS]:\n{}\n\n".format(", ".join(can_access))
msg += "[NO ACCESS]:\n{}\n```".format(
", ".join(list(set(voice_channels) - set(can_access)))
)
await self.bot.say(msg)
@commands.command(pass_context=True)
@checks.admin_or_permissions(manage_server=True)
async def banlist(self, ctx):
"""Displays the server's banlist."""
try:
banlist = await self.bot.get_bans(ctx.message.server)
except discord.errors.Forbidden:
await self.bot.say("I do not have the `Ban Members` permission.")
return
bancount = len(banlist)
if bancount == 0:
banlist = "No users are banned from this server."
else:
banlist = ", ".join(map(str, banlist))
for page in pagify(banlist, ["\n"], shorten_by=13, page_length=2000):
await self.bot.say(box(page, "ini"))
@commands.command(pass_context=True, no_pm=True)
async def cid(self, ctx, channel: discord.Channel = None):
"""Shows the channel ID."""
if not channel:
channel = ctx.message.channel
await self.bot.say("**#{0.name} ID:** {0.id}".format(channel))
@commands.command(pass_context=True)
async def cinfo(self, ctx, channel: discord.Channel = None):
"""Shows channel information. Defaults to current text channel."""
yesno = {True: "Yes", False: "No"}
if not channel:
channel = ctx.message.channel
load = "```\nLoading channel info...```"
waiting = await self.bot.say(load)
try:
caller = inspect.currentframe().f_back.f_code.co_name
except:
pass
data = "```ini\n"
if caller == "whatis":
data == "[Server]: {}\n".format(channel.server.name)
data += "[Name]: {}\n".format(escape_mass_mentions(str(channel)))
data += "[ID]: {}\n".format(channel.id)
data += "[Default]: {}\n".format(yesno[channel.is_default])
data += "[Private]: {}\n".format(yesno[channel.is_private])
if str(channel.type) == "text" and channel.topic != "":
data += "[Topic]: {}\n".format(channel.topic)
data += "[Position]: {}\n".format(channel.position)
data += "[Created]: {} ago\n".format(self._dynamic_time(channel.created_at))
data += "[Type]: {}\n".format(channel.type)
if str(channel.type) == "voice":
data += "[Users]: {}\n".format(len(channel.voice_members))
data += "[User limit]: {}\n".format(channel.user_limit)
data += "[Bitrate]: {}\n".format(channel.bitrate)
data += "```"
await asyncio.sleep(2)
await self.bot.edit_message(waiting, data)
@commands.command(pass_context=True)
@checks.is_owner()
async def ecogs(self, ctx):
"""Lists status of installed cogs"""
owner_cog = self.bot.get_cog("Owner")
total_cogs = owner_cog._list_cogs()
loaded = [c.__module__.split(".")[1] for c in self.bot.cogs.values()]
unloaded = [c.split(".")[1] for c in total_cogs if c.split(".")[1] not in loaded]
if not unloaded:
unloaded = ["None"]
items = {
0: {
"cogs": sorted(loaded),
"msg": "**{} loaded:**\n".format(len(loaded)),
"colour": discord.Colour.dark_green(),
},
1: {
"cogs": sorted(unloaded),
"msg": "**{} unloaded:**\n".format(len(unloaded)),
"colour": discord.Colour.dark_red(),
},
}
for index, em in enumerate(items):
e = discord.Embed(
description=items[index]["msg"] + ", ".join(items[index]["cogs"]),
colour=items[index]["colour"],
)
await self.bot.say(embed=e)
@commands.command(pass_context=True)
async def eid(self, ctx, emoji):
"""Get an id for a custom emoji."""
if emoji[0] != "<":
await self.bot.say(
"I could not an ID for this emoji, this may be because it is not a custom emoji."
)
return
id = emoji.split(":")[2][:-1]
await self.bot.say(id)
@checks.is_owner()
@commands.command(aliases=["find", "cmd_lookup"])
async def findcog(self, command: str):
"""Cog search by command.
This is only applicable for loaded cogs that were installed through [p]cog install."""
try:
cog_name = self.bot.get_cog(self.bot.get_command(command).cog_name).__module__[5:]
except:
await self.bot.say(
"Either that command doesn't exist, or the cog this command belongs to wasn't added through the downloader cog."
)
return
repos = dataIO.load_json("data/downloader/repos.json")
cog_path = (
lambda x: "\n".join(
[
filename
for filename in glob.iglob("data/downloader/**/*.py", recursive=True)
if "{}.py".format(x) == filename[((len("{}.py".format(x))) * -1) :]
]
)
)(cog_name)
if not cog_path:
await self.bot.say("This is a command that's in a cog that's not published in a repo.")
return
if os.name == "nt":
repo = cog_path.split(os.sep)[1]
else:
repo = cog_path.split(os.sep)[2]
if "url" not in repos[repo]:
with open("data/downloader/" + repo + "/.git/config", "r") as f:
url = re.findall(r"(http(s)?:\/\/[a-zA-Z0-9\:\.\-\_\/\?\=\%]*)", f.read())[0][0]
else:
url = repos[repo]["url"]
await self.bot.say(
box(
"Command name: {}\nMade by: {}\nRepo: {}\nCog Name: {}.py".format(
command, url.split("/")[3], url, cog_name
)
)
)
@checks.admin_or_permissions(manage_roles=True)
@commands.command(pass_context=True)
async def inrole(self, ctx, *, rolename):
"""Check members in the role specified."""
await self.bot.send_typing(ctx.message.channel)
role = discord.utils.find(
lambda r: r.name.lower() == rolename.lower(), ctx.message.server.roles
)
if role is None:
roles = []
for r in ctx.message.server.roles:
if rolename.lower() in r.name.lower():
roles.append(r)
if len(roles) == 1:
role = roles[0]
elif len(roles) < 1:
await self.bot.say("no roles found")
return
else:
msg = "**Roles found with** {} **in the name.**\n\n".format(rolename)
tbul8 = []
for num, role in enumerate(roles):
tbul8.append([num + 1, role.name])
m1 = await self.bot.say(msg + tabulate(tbul8, tablefmt="plain"))
response = await self.bot.wait_for_message(
author=ctx.message.author, channel=ctx.message.channel, timeout=25
)
if response is None:
await self.bot.delete_message(m1)
return
elif response.content.isdigit():
await self.bot.delete_message(m1)
return
else:
response = int(response.content)
if response not in range(0, len(roles) + 1):
await self.bot.delete_message(m1)
return
elif response == 0:
await self.bot.delete_message(m1)
return
else:
role = roles[response - 1]
if (
role is not None
and len([m for m in ctx.message.server.members if role in m.roles]) < 50
):
awaiter = await self.bot.say(
embed=discord.Embed(description="Getting member names...")
)
await asyncio.sleep(2.5)
role_member = discord.Embed(
description="**{1} users found in the {0} role.**\n".format(
role.name, len([m for m in ctx.message.server.members if role in m.roles])
)
)
role_users = [m.display_name for m in ctx.message.server.members if role in m.roles]
if not role_users:
role_member.add_field(name="Users", value="None.")
else:
role_member.add_field(name="Users", value="\n".join(role_users))
await self.bot.edit_message(awaiter, embed=role_member)
elif len([m for m in ctx.message.server.members if role in m.roles]) > 50:
awaiter = await self.bot.say(
embed=discord.Embed(description="Getting member names...")
)
await asyncio.sleep(2.5)
await self.bot.edit_message(
awaiter,
embed=discord.Embed(
description="List is too long for **{0}** role, **{1}** members found.\n".format(
role.name, len([m.mention for m in server.members if role in m.roles])
)
),
)
else:
embed = discord.Embed(description="Role was not found.")
await self.bot.edit_message(embed=embed)
@commands.command(pass_context=True, no_pm=True)
@checks.mod_or_permissions(manage_messages=True)
async def newusers(self, ctx, count: int = 5, server: discord.Server = None):
"""Lists the newest 5 members."""
if server is None:
server = ctx.message.server
count = max(min(count, 25), 5)
members = sorted(server.members, key=lambda m: m.joined_at, reverse=True)[:count]
e = discord.Embed(title="New Members")
for member in members:
msg = "**Joined Server:** {} ago\n**Account created:** {} ago".format(
self._dynamic_time(member.joined_at), self._dynamic_time(member.created_at)
)
e.add_field(
name="{0.display_name} (ID: {0.id})".format(member), value=msg, inline=False
)
await self.bot.say(embed=e)
@commands.command(pass_context=True, no_pm=True)
async def sid(self, ctx):
"""Shows the server ID."""
await self.bot.say("**{0.name} ID:** {0.id}".format(ctx.message.server))
@commands.command(pass_context=True)
@checks.mod_or_permissions(manage_messages=True)
async def userstats(self, ctx, this_server: bool = False):
"""A small amount of user stats."""
embeds = {}
if this_server:
members = set([x for x in ctx.message.server.members])
else:
members = set([x for x in self.bot.get_all_members()])
items = {
2: {
"users": len([e.name for e in members if e.status == discord.Status.idle]),
"colour": discord.Colour.orange(),
},
3: {
"users": len([e.name for e in members if e.status == discord.Status.dnd]),
"colour": discord.Colour.red(),
},
4: {
"users": len([e.name for e in members if e.status == discord.Status.offline]),
"colour": discord.Colour.dark_grey(),
},
1: {
"users": len([e.name for e in members if e.status == discord.Status.online]),
"colour": discord.Colour.green(),
},
0: {
"users": len([e.name for e in members if e.game and e.game.url]),
"colour": discord.Colour.dark_purple(),
},
}
for item in items:
embeds[item] = discord.Embed(
description="Users: {}".format(items[item]["users"]), colour=items[item]["colour"]
)
for i, em in enumerate(embeds):
await self.bot.say(embed=embeds[i])
@commands.command(pass_context=True, no_pm=True)
async def sinfo(self, ctx, server: discord.Server = None):
"""Shows server information."""
if server is None:
server = ctx.message.server
online = str(
len(
[
m.status
for m in server.members
if str(m.status) == "online" or str(m.status) == "idle"
]
)
)
total_users = str(len(server.members))
text_channels = [x for x in server.channels if str(x.type) == "text"]
voice_channels = [x for x in server.channels if str(x.type) == "voice"]
load = "```\nLoading server info...```"
waiting = await self.bot.say(load)
data = "```ini\n"
data += "[Name]: {}\n".format(server.name)
data += "[ID]: {}\n".format(server.id)
data += "[Region]: {}\n".format(server.region)
data += "[Owner]: {}\n".format(server.owner)
data += "[Users]: {}/{}\n".format(online, total_users)
data += "[Text]: {} channels\n".format(len(text_channels))
data += "[Voice]: {} channels\n".format(len(voice_channels))
data += "[Emojis]: {}\n".format(len(server.emojis))
data += "[Roles]: {} \n".format(len(server.roles))
data += "[Created]: {} ago\n```".format(self._dynamic_time(server.created_at))
await asyncio.sleep(3)
await self.bot.edit_message(waiting, data)
@commands.command(pass_context=True, no_pm=True)
@checks.mod_or_permissions(manage_messages=True)
async def perms(self, ctx, user: discord.Member = None):
"""Fetch a specific user's permissions."""
if user is None:
user = ctx.message.author
perms = iter(ctx.message.channel.permissions_for(user))
perms_we_have = "```diff\n"
perms_we_dont = ""
for x in perms:
if "True" in str(x):
perms_we_have += "+\t{0}\n".format(str(x).split("'")[1])
else:
perms_we_dont += "-\t{0}\n".format(str(x).split("'")[1])
await self.bot.say("{0}{1}```".format(perms_we_have, perms_we_dont))
@commands.command(pass_context=True)
async def rid(self, ctx, rolename):
"""Shows the id of a role, use quotes on the role."""
await self.bot.send_typing(ctx.message.channel)
if rolename is discord.Role:
role = rolename
else:
role = self._role_from_string(ctx.message.server, rolename)
if role is None:
return await self.bot.say(embed=discord.Embed(description="Cannot find role."))
await self.bot.say(
embed=discord.Embed(description="**{}** ID: {}".format(rolename, role.id))
)
@commands.command(pass_context=True)
async def rinfo(self, ctx, rolename):
"""Shows role info, use quotes on the role."""
server = ctx.message.server
colour = str(random.randint(0, 0xFFFFFF))
colour = int(colour, 16)
await self.bot.send_typing(ctx.message.channel)
try:
caller = inspect.currentframe().f_back.f_code.co_name
except:
pass
if type(rolename) is not discord.Role:
role = discord.utils.find(
lambda r: r.name.lower() == rolename.lower(), ctx.message.server.roles
)
else:
role = rolename
if role is None:
await self.bot.say("That role cannot be found.")
return
if role is not None:
perms = iter(role.permissions)
perms_we_have = ""
perms_we_dont = ""
for x in perms:
if "True" in str(x):
perms_we_have += "{0}\n".format(str(x).split("'")[1])
else:
perms_we_dont += "{0}\n".format(str(x).split("'")[1])
msg = discord.Embed(description="Gathering role stats...", colour=role.color)
if role.color is None:
role.color = discord.Colour(value=colour)
msg2 = await self.bot.say(embed=msg)
em = discord.Embed(colour=role.colour)
if caller == "whatis":
em.add_field(name="Server", value=role.server.name)
em.add_field(name="Role Name", value=role.name)
em.add_field(name="Created", value=self._dynamic_time(role.created_at))
em.add_field(
name="Users in Role",
value=len([m for m in ctx.message.server.members if role in m.roles]),
)
em.add_field(name="Id", value=role.id)
em.add_field(name="Color", value=role.color)
em.add_field(name="Position", value=role.position)
em.add_field(name="Valid Permissons", value="{}".format(perms_we_have))
em.add_field(name="Invalid Permissons", value="{}".format(perms_we_dont))
em.set_thumbnail(url=role.server.icon_url)
try:
await self.bot.edit_message(msg2, embed=em)
except discord.HTTPException:
perms_msg = "```diff\n"
role = discord.utils.find(
lambda r: r.name.lower() == rolename.lower(), ctx.message.server.roles
)
if role is None:
await bot.say("That role cannot be found.")
return
if role is not None:
perms = iter(role.permissions)
perms_we_have2 = ""
perms_we_dont2 = ""
for x in perms:
if "True" in str(x):
perms_we_have2 += "+{0}\n".format(str(x).split("'")[1])
else:
perms_we_dont2 += "-{0}\n".format(str(x).split("'")[1])
await self.bot.say(
"{}Name: {}\nCreated: {}\nUsers in Role : {}\nId : {}\nColor : {}\nPosition : {}\nValid Perms : \n{}\nInvalid Perms : \n{}```".format(
perms_msg,
role.name,
self._dynamic_time(role.created_at),
len([m for m in server.members if role in m.roles]),
role.id,
role.color,
role.position,
perms_we_have2,
perms_we_dont2,
)
)
await self.bot.delete_message(msg2)
@commands.command(pass_context=True, hidden=True)
@checks.mod_or_permissions(manage_messages=True)
async def sharedservers(self, ctx, user: discord.Member = None):
"""Shows shared server info. Defaults to author."""
author = ctx.message.author
server = ctx.message.server
if not user:
user = author
seen = len(
set(
[
member.server.name
for member in self.bot.get_all_members()
if member.name == user.name
]
)
)
sharedservers = str(
set(
[
member.server.name
for member in self.bot.get_all_members()
if member.name == user.name
]
)
)
for shared in sharedservers:
shared = "".strip("'").join(sharedservers).strip("'")
shared = shared.strip("{").strip("}")
data = "[Servers]: {} shared\n".format(seen)
data += "[In Servers]: {}\n".format(shared)
for page in pagify(data, ["\n"], shorten_by=13, page_length=2000):
await self.bot.say(box(page, "ini"))
@commands.command(pass_context=True)
async def uinfo(self, ctx, user: discord.Member = None):
"""Shows user information. Defaults to author."""
if not user:
user = ctx.message.author
try:
caller = inspect.currentframe().f_back.f_code.co_name
except:
pass
roles = [x.name for x in user.roles if x.name != "@everyone"]
if not roles:
roles = ["None"]
seen = str(
len(
set(
[
member.server.name
for member in self.bot.get_all_members()
if member.id == user.id
]
)
)
)
load = "```\nLoading user info...```"
waiting = await self.bot.say(load)
data = "```ini\n"
data += "[Name]: {}\n".format(escape_mass_mentions(str(user)))
data += "[Nickname]: {}\n".format(escape_mass_mentions(str(user.nick)))
data += "[ID]: {}\n".format(user.id)
data += "[Status]: {}\n".format(user.status)
data += "[Servers]: {} shared\n".format(seen)
if user.game is None:
pass
elif user.game.url is None:
data += "[Playing]: {}\n".format(escape_mass_mentions(str(user.game)))
else:
data += "[Streaming]: [{}]({})\n".format(
escape_mass_mentions(str(user.game)), escape_mass_mentions(user.game.url)
)
passed = (ctx.message.timestamp - user.created_at).days
data += "[Created]: {} ago\n".format(self._dynamic_time(user.created_at))
joined_at = self.fetch_joined_at(user, ctx.message.server)
if caller != "whatis":
data += "[Joined]: {} ago\n".format(self._dynamic_time(joined_at))
data += "[Roles]: {}\n".format(", ".join(roles))
data += "[In Voice]: {}\n".format(str(user.voice_channel))
data += "[AFK]: {}\n".format(user.is_afk)
data += "```"
await asyncio.sleep(3)
await self.bot.edit_message(waiting, data)
@commands.command(pass_context=True)
async def whatis(self, ctx, id):
"""What is it?"""
server = ctx.message.server
channel = ctx.message.channel
author = ctx.message.author
it_is = False
msg = False
if server.id == id:
it_is = server
elif channel.id == id:
it_is = channel
elif author.id == id:
it_is = author
if not it_is:
for server in self.bot.servers:
if server.id == id:
it_is = server
break
if not it_is:
for emoji in self.bot.get_all_emojis():
if emoji.id == id:
it_is = emoji
break
if not it_is:
for server in self.bot.servers:
for role in server.roles:
if role.id == id:
it_is = role
break
if not it_is:
for member in self.bot.get_all_members():
if member.id == id:
it_is = member
break
if not it_is:
for channel in self.bot.get_all_channels():
if channel.id == id:
it_is = channel
break
if not msg:
if type(it_is) == discord.Channel:
await ctx.invoke(self.cinfo, it_is)
elif type(it_is) == discord.Server:
await ctx.invoke(self.sinfo, it_is)
elif type(it_is) == discord.User or type(it_is) == discord.Member:
await ctx.invoke(self.uinfo, it_is)
elif type(it_is) == discord.Role:
await ctx.invoke(self.roleinfo, it_is)
elif type(it_is) == discord.Emoji:
await self.bot.say(
"<:{0.name}:{0.id}>\n```ini\n[NAME]: {0.name}\n[SERVER]: {0.server}\n[URL]: {0.url}```".format(
it_is
)
)
else:
await self.bot.say(
"I could not find anything for this ID, I do not support Message IDs"
)
else:
await self.bot.say("```\nNothing found for this ID```")
@staticmethod
def _dynamic_time(time):
date_join = datetime.datetime.strptime(str(time), "%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
m, s = divmod(int(since_join.total_seconds()), 60)
h, m = divmod(m, 60)
d, h = divmod(h, 24)
if d > 0:
msg = "{0}d {1}h"
elif d == 0 and h > 0:
msg = "{1}h {2}m"
elif d == 0 and h == 0 and m > 0:
msg = "{2}m {3}s"
elif d == 0 and h == 0 and m == 0 and s > 0:
msg = "{3}s"
else:
msg = ""
return msg.format(d, h, m, s)
def fetch_joined_at(self, user, server):
return user.joined_at
def _role_from_string(self, server, rolename, roles=None):
if roles is None:
roles = server.roles
role = discord.utils.find(lambda r: r.name.lower() == rolename.lower(), roles)
return role
def setup(bot):
cmds = [
"access",
"banlist",
"cid",
"cinfo",
"ecogs",
"eid",
"findcog",
"inrole",
"newusers",
"perms",
"rid",
"rinfo",
"sid",
"sinfo",
"uinfo",
"userstatst",
"whatis",
]
for cmd in cmds:
bot.remove_command(cmd)
bot.add_cog(Tools(bot))

7
wolfram/info.json Normal file
View File

@@ -0,0 +1,7 @@
{
"AUTHOR" : "Paddolicious#8880",
"NAME" : "wolfram",
"SHORT" : "Query Wolfram|Alpha.",
"DESCRIPTION" : "A cog to query Wolfram|Alpha.",
"TAGS": ["wolfram"]
}

82
wolfram/wolfram.py Normal file
View File

@@ -0,0 +1,82 @@
import os
import aiohttp
from discord.ext import commands
import xml.etree.ElementTree as ET
from cogs.utils.dataIO import dataIO
from .utils import checks
from .utils.chat_formatting import escape_mass_mentions
from .utils.chat_formatting import box
from __main__ import send_cmd_help
class Wolfram:
def __init__(self, bot):
self.bot = bot
self.settings = dataIO.load_json("data/wolfram/settings.json")
@commands.command(pass_context=True, name="wolfram", aliases=["ask"])
async def _wolfram(self, ctx, *arguments: str):
"""
Ask Wolfram Alpha any question
"""
api_key = self.settings["WOLFRAM_API_KEY"]
if api_key:
url = "http://api.wolframalpha.com/v2/query?"
query = " ".join(arguments)
payload = {"input": query, "appid": api_key}
headers = {"user-agent": "Red-cog/1.0.0"}
conn = aiohttp.TCPConnector(verify_ssl=False)
session = aiohttp.ClientSession(connector=conn)
async with session.get(url, params=payload, headers=headers) as r:
result = await r.text()
session.close()
root = ET.fromstring(result)
a = []
for pt in root.findall(".//plaintext"):
if pt.text:
a.append(pt.text.capitalize())
if len(a) < 1:
message = "There is as yet insufficient data for a meaningful answer."
else:
message = "\n".join(a[0:3])
else:
message = (
"No API key set for Wolfram Alpha. Get one at http://products.wolframalpha.com/api/"
)
message = escape_mass_mentions(message)
await self.bot.say(box(message))
@commands.command(pass_context=True, name="setwolframapi", aliases=["setwolfram"])
@checks.is_owner()
async def _setwolframapi(self, ctx, key: str):
"""
Set the api-key
"""
if key:
self.settings["WOLFRAM_API_KEY"] = key
dataIO.save_json("data/wolfram/settings.json", self.settings)
await self.bot.say("Key set.")
else:
await send_cmd_help(ctx)
def check_folder():
if not os.path.exists("data/wolfram"):
print("Creating data/wolfram folder...")
os.makedirs("data/wolfram")
def check_file():
data = {}
data["WOLFRAM_API_KEY"] = False
f = "data/wolfram/settings.json"
if not dataIO.is_valid_json(f):
print("Creating default settings.json...")
dataIO.save_json(f, data)
def setup(bot):
check_folder()
check_file()
n = Wolfram(bot)
bot.add_cog(n)

7
youtube/info.json Normal file
View File

@@ -0,0 +1,7 @@
{
"AUTHOR" : "Paddolicious#8880 and aikaterna#1393",
"NAME" : "youtube",
"SHORT" : "Look up videos on YouTube.",
"DESCRIPTION" : "Look up videos on YouTube.",
"TAGS": ["youtube"]
}

41
youtube/youtube.py Normal file
View File

@@ -0,0 +1,41 @@
from discord.ext import commands
import aiohttp
import re
class YouTube:
"""Le YouTube Cog"""
def __init__(self, bot):
self.bot = bot
self.session = aiohttp.ClientSession()
async def _youtube_results(self, query: str):
try:
headers = {"user-agent": "Red-cog/2.0"}
async with self.session.get("https://www.youtube.com/results", params={"search_query": query}, headers=headers) as r:
result = await r.text()
yt_find = re.findall(r"{\"videoId\":\"(.{11})", result)
url_list = []
for track in yt_find:
url = "https://www.youtube.com/watch?v={}".format(track)
if url not in url_list:
url_list.append(url)
except Exception as e:
url_list = ["Something went terribly wrong! [{}]".format(e)]
return url_list
@commands.command(pass_context=True)
async def youtube(self, ctx, *, query: str):
"""Search on Youtube."""
result = await self._youtube_results(query)
if result:
await self.bot.say(result[0])
else:
await self.bot.say("Nothing found. Try again later.")
def setup(bot):
n = YouTube(bot)
bot.add_cog(n)