Merge branch 'rewrite' of https://github.com/Phxntxm/Bonfire into rewrite
This commit is contained in:
commit
b13d6510a4
7
bot.py
7
bot.py
|
@ -80,7 +80,10 @@ async def on_command_error(ctx, error):
|
|||
try:
|
||||
if isinstance(error.original, discord.Forbidden):
|
||||
return
|
||||
elif isinstance(error.original, discord.HTTPException) and ('empty message' in str(error.original) or 'INTERNAL SERVER ERROR' in str(error.original)):
|
||||
elif isinstance(error.original, discord.HTTPException) and (
|
||||
'empty message' in str(error.original) or
|
||||
'INTERNAL SERVER ERROR' in str(error.original) or
|
||||
'REQUEST ENTITY TOO LARGE' in str(error.original)):
|
||||
return
|
||||
elif isinstance(error.original, aiohttp.ClientOSError):
|
||||
return
|
||||
|
@ -93,7 +96,7 @@ async def on_command_error(ctx, error):
|
|||
await ctx.message.channel.send(fmt)
|
||||
elif isinstance(error, commands.CheckFailure):
|
||||
fmt = "You can't tell me what to do!"
|
||||
#await ctx.message.channel.send(fmt)
|
||||
# await ctx.message.channel.send(fmt)
|
||||
elif isinstance(error, commands.CommandOnCooldown):
|
||||
m, s = divmod(error.retry_after, 60)
|
||||
fmt = "This command is on cooldown! Hold your horses! >:c\nTry again in {} minutes and {} seconds" \
|
||||
|
|
78
cogs/misc.py
78
cogs/misc.py
|
@ -171,52 +171,68 @@ class Miscallaneous:
|
|||
# in this command is changed
|
||||
|
||||
# Create the original embed object
|
||||
opts = {'title': 'Dev Server',
|
||||
'description': 'Join the server above for any questions/suggestions about me.',
|
||||
'url': utils.dev_server}
|
||||
embed = discord.Embed(**opts)
|
||||
# Set the description include dev server (should be required) and the optional patreon link
|
||||
description = "[Dev Server]({})".format(utils.dev_server)
|
||||
if utils.patreon_link:
|
||||
description += "\n[Patreon]({})".format(utils.patreon_link)
|
||||
# Now creat the object
|
||||
opts = {'title': 'Bonfire',
|
||||
'description': description,
|
||||
'colour': discord.Colour.green()}
|
||||
|
||||
# Set the owner
|
||||
embed = discord.Embed(**opts)
|
||||
if hasattr(self.bot, 'owner'):
|
||||
embed.set_author(name=str(self.bot.owner), icon_url=self.bot.owner.avatar_url)
|
||||
|
||||
# Setup the process statistics
|
||||
name = "Process stats"
|
||||
value = ""
|
||||
|
||||
memory_usage = self.process.memory_full_info().uss / 1024 ** 2
|
||||
cpu_usage = self.process.cpu_percent() / psutil.cpu_count()
|
||||
value += 'Memory: {:.2f} MiB'.format(memory_usage)
|
||||
value += '\nCPU: {}%'.format(cpu_usage)
|
||||
if hasattr(self.bot, 'uptime'):
|
||||
value += "\nUptime: {}".format((pendulum.utcnow() - self.bot.uptime).in_words())
|
||||
embed.add_field(name=name, value=value, inline=False)
|
||||
|
||||
# Setup the user and guild statistics
|
||||
name = "User/Guild stats"
|
||||
value = ""
|
||||
|
||||
value += "Channels: {}".format(len(list(self.bot.get_all_channels())))
|
||||
value += "\nUsers: {}".format(len(self.bot.users))
|
||||
value += "\nServers: {}".format(len(self.bot.guilds))
|
||||
embed.add_field(name=name, value=value, inline=False)
|
||||
|
||||
# The game statistics
|
||||
name = "Game statistics"
|
||||
# To get the newlines right, since we're not sure what will and won't be included
|
||||
# Lets make this one a list and join it at the end
|
||||
value = []
|
||||
|
||||
# Add the normal values
|
||||
embed.add_field(name='Total Servers', value=len(self.bot.guilds))
|
||||
embed.add_field(name='Total Members', value=len(self.bot.users))
|
||||
hm = self.bot.get_cog('Hangman')
|
||||
ttt = self.bot.get_cog('TicTacToe')
|
||||
bj = self.bot.get_cog('Blackjack')
|
||||
interaction = self.bot.get_cog('Blackjack')
|
||||
interaction = self.bot.get_cog('Interaction')
|
||||
music = self.bot.get_cog('Music')
|
||||
|
||||
# Count the variable values; hangman, tictactoe, etc.
|
||||
if hm:
|
||||
hm_games = len(hm.games)
|
||||
if hm_games:
|
||||
embed.add_field(name='Total Hangman games running', value=hm_games)
|
||||
value.append("Hangman games: {}".format(len(hm.games)))
|
||||
if ttt:
|
||||
ttt_games = len(ttt.boards)
|
||||
if ttt_games:
|
||||
embed.add_field(name='Total TicTacToe games running', value=ttt_games)
|
||||
value.append("TicTacToe games: {}".format(len(ttt.boards)))
|
||||
if bj:
|
||||
bj_games = len(bj.games)
|
||||
if bj_games:
|
||||
embed.add_field(name='Total blackjack games running', value=bj_games)
|
||||
value.append("Blackjack games: {}".format(len(bj.games)))
|
||||
if interaction:
|
||||
count_battles = 0
|
||||
for battles in self.bot.get_cog('Interaction').battles.values():
|
||||
count_battles += len(battles)
|
||||
if count_battles:
|
||||
embed.add_field(name='Total battles games running', value=count_battles)
|
||||
value.append("Battles running: {}".format(len(bj.games)))
|
||||
if music:
|
||||
songs = len([x for x in music.voice_states.values() if x.playing])
|
||||
if songs:
|
||||
embed.add_field(name='Total songs playing', value=songs)
|
||||
|
||||
if hasattr(self.bot, 'uptime'):
|
||||
embed.add_field(name='Uptime', value=(pendulum.utcnow() - self.bot.uptime).in_words())
|
||||
|
||||
memory_usage = self.process.memory_full_info().uss / 1024 ** 2
|
||||
cpu_usage = self.process.cpu_percent() / psutil.cpu_count()
|
||||
embed.add_field(name='Memory Usage', value='{:.2f} MiB'.format(memory_usage))
|
||||
embed.add_field(name='CPU Usage', value='{}%'.format(cpu_usage))
|
||||
embed.set_footer(text=self.bot.description)
|
||||
value.append("Total songs playing: {}".format(songs))
|
||||
embed.add_field(name=name, value="\n".join(value), inline=False)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from .voice_utilities import *
|
||||
from discord import FFmpegPCMAudio, PCMVolumeTransformer
|
||||
from discord import PCMVolumeTransformer
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
@ -21,7 +21,7 @@ if not discord.opus.is_loaded():
|
|||
|
||||
|
||||
class VoiceState:
|
||||
def __init__(self, guild, bot, user_queue=False):
|
||||
def __init__(self, guild, bot, user_queue=False, volume=None):
|
||||
self.guild = guild
|
||||
self.songs = Playlist(bot)
|
||||
self.djs = deque()
|
||||
|
@ -31,7 +31,7 @@ class VoiceState:
|
|||
self.skip_votes = set()
|
||||
self.user_queue = user_queue
|
||||
self.loop = bot.loop
|
||||
self._volume = .5
|
||||
self._volume = volume or .5
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
|
@ -377,8 +377,10 @@ class Music:
|
|||
|
||||
# If we have connnected, create our voice state
|
||||
queue_type = self.bot.db.load('server_settings', key=channel.guild.id, pluck='queue_type')
|
||||
volume = self.bot.db.load('server_settings', key=channel.guild.id, pluck='volume')
|
||||
user_queue = queue_type == "user"
|
||||
self.voice_states[channel.guild.id] = VoiceState(channel.guild, self.bot, user_queue=user_queue)
|
||||
self.voice_states[channel.guild.id] = VoiceState(channel.guild, self.bot, user_queue=user_queue,
|
||||
volume=volume)
|
||||
|
||||
# If we can send messages, edit it to let the channel know we have succesfully joined
|
||||
if msg:
|
||||
|
@ -469,7 +471,8 @@ class Music:
|
|||
"""Imports a song into the current voice queue"""
|
||||
# If we don't have a voice state yet, create one
|
||||
if not self.bot.db.load('server_settings', key=ctx.message.guild.id, pluck='playlists_allowed'):
|
||||
await ctx.send("You cannot import playlists at this time; the {}allowplaylists command can be used to change this setting".format(ctx.prefix))
|
||||
await ctx.send("You cannot import playlists at this time; the {}allowplaylists command can be used to "
|
||||
"change this setting".format(ctx.prefix))
|
||||
return
|
||||
if ctx.message.guild.id not in self.voice_states:
|
||||
if not await ctx.invoke(self.join):
|
||||
|
@ -490,7 +493,16 @@ class Music:
|
|||
return
|
||||
|
||||
song = re.sub('[<>\[\]]', '', song)
|
||||
await self.import_playlist(song, ctx)
|
||||
# Check if we've got the list variable in the URL, if so lets just use this
|
||||
playlist_id = re.search(r'list=(.+)', song)
|
||||
if playlist_id:
|
||||
song = playlist_id.group(1)
|
||||
try:
|
||||
await self.import_playlist(song, ctx)
|
||||
except WrongEntryTypeError:
|
||||
await ctx.send("This URL is not a playlist! If you want to play this song just use `play`")
|
||||
except ExtractionError:
|
||||
await ctx.send("Failed to download {}! If this is not a playlist, use the `play` command".format(song))
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
|
@ -537,6 +549,9 @@ class Music:
|
|||
|
||||
try:
|
||||
entry = await self.add_entry(song, ctx)
|
||||
# This error only happens if Discord has derped, and the voice state didn't get created succesfully
|
||||
except KeyError:
|
||||
await ctx.send("Sorry, but I failed to connect! Please try again!")
|
||||
except LiveStreamError as e:
|
||||
await ctx.send(str(e))
|
||||
except WrongEntryTypeError:
|
||||
|
@ -586,6 +601,8 @@ class Music:
|
|||
await ctx.send("Sorry but the max volume is 100%")
|
||||
else:
|
||||
state.volume = value
|
||||
entry = {'server_id': str(ctx.message.guild.id), 'volume': value}
|
||||
self.bot.db.save('server_settings', entry)
|
||||
await ctx.send('Set the volume to {:.0%}'.format(state.volume))
|
||||
|
||||
@commands.command()
|
||||
|
@ -633,7 +650,7 @@ class Music:
|
|||
# Then stop playing, and disconnect
|
||||
if voice:
|
||||
voice.stop()
|
||||
await voice.disconnect()
|
||||
await voice.disconnect(force=True)
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
|
|
135
cogs/raffle.py
135
cogs/raffle.py
|
@ -8,7 +8,6 @@ import pendulum
|
|||
import re
|
||||
import asyncio
|
||||
import traceback
|
||||
import rethinkdb as r
|
||||
|
||||
|
||||
class Raffle:
|
||||
|
@ -36,63 +35,66 @@ class Raffle:
|
|||
|
||||
for raffle in raffles:
|
||||
server = self.bot.get_guild(int(raffle['server_id']))
|
||||
title = raffle['title']
|
||||
entrants = raffle['entrants']
|
||||
raffle_id = raffle['id']
|
||||
for r in raffle['raffles']:
|
||||
title = r['title']
|
||||
entrants = r['entrants']
|
||||
raffle_id = r['id']
|
||||
|
||||
# Check to see if this cog can find the server in question
|
||||
if server is None:
|
||||
await self.bot.db.query(r.table('raffles').get(raffle_id).delete())
|
||||
continue
|
||||
# Check to see if this cog can find the server in question
|
||||
if server is None:
|
||||
await self.bot.db.query(r.table('raffles').get(raffle_id).delete())
|
||||
continue
|
||||
|
||||
now = pendulum.utcnow()
|
||||
expires = pendulum.parse(raffle['expires'])
|
||||
now = pendulum.utcnow()
|
||||
expires = pendulum.parse(r['expires'])
|
||||
|
||||
# Now lets compare and see if this raffle has ended, if not just continue
|
||||
if expires > now:
|
||||
continue
|
||||
# Now lets compare and see if this raffle has ended, if not just continue
|
||||
if expires > now:
|
||||
continue
|
||||
|
||||
# Make sure there are actually entrants
|
||||
if len(entrants) == 0:
|
||||
fmt = 'Sorry, but there were no entrants for the raffle `{}`!'.format(title)
|
||||
else:
|
||||
winner = None
|
||||
count = 0
|
||||
while winner is None:
|
||||
winner = server.get_member(int(random.SystemRandom().choice(entrants)))
|
||||
|
||||
# Lets make sure we don't get caught in an infinite loop
|
||||
# Realistically having more than 50 random entrants found that aren't in the server anymore
|
||||
# Isn't something that should be an issue, but better safe than sorry
|
||||
count += 1
|
||||
if count >= 50:
|
||||
break
|
||||
|
||||
if winner is None:
|
||||
fmt = 'I couldn\'t find an entrant that is still in this server, for the raffle `{}`!'.format(title)
|
||||
# Make sure there are actually entrants
|
||||
if len(entrants) == 0:
|
||||
fmt = 'Sorry, but there were no entrants for the raffle `{}`!'.format(title)
|
||||
else:
|
||||
fmt = 'The raffle `{}` has just ended! The winner is {}!'.format(title, winner.display_name)
|
||||
winner = None
|
||||
count = 0
|
||||
while winner is None:
|
||||
winner = server.get_member(int(random.SystemRandom().choice(entrants)))
|
||||
|
||||
# Get the notifications settings, get the raffle setting
|
||||
notifications = self.bot.db.load('server_settings', key=server.id, pluck='notifications') or {}
|
||||
# Set our default to either the one set, or the default channel of the server
|
||||
default_channel_id = notifications.get('default') or server.id
|
||||
# If it is has been overriden by picarto notifications setting, use this
|
||||
channel_id = notifications.get('raffle') or default_channel_id
|
||||
channel = self.bot.get_channel(int(channel_id))
|
||||
if channel is None:
|
||||
channel = server.default_channel
|
||||
try:
|
||||
await channel.send(fmt)
|
||||
except (discord.Forbidden, AttributeError):
|
||||
pass
|
||||
# Lets make sure we don't get caught in an infinite loop
|
||||
# Realistically having more than 50 random entrants found that aren't in the server anymore
|
||||
# Isn't something that should be an issue, but better safe than sorry
|
||||
count += 1
|
||||
if count >= 50:
|
||||
break
|
||||
|
||||
# No matter which one of these matches were met, the raffle has ended and we want to remove it
|
||||
await self.bot.db.query(r.table('raffles').get(raffle_id).delete())
|
||||
# Now...this is an ugly idea yes, but due to the way raffles are setup currently (they'll be changed in
|
||||
# the future) The cache does not update, and leaves behind this deletion....so we need to manually update
|
||||
# the cache here
|
||||
await self.bot.db.cache.get('raffles').refresh()
|
||||
if winner is None:
|
||||
fmt = 'I couldn\'t find an entrant that is still in this server, for the raffle `{}`!'.format(
|
||||
title)
|
||||
else:
|
||||
fmt = 'The raffle `{}` has just ended! The winner is {}!'.format(title, winner.display_name)
|
||||
|
||||
# Get the notifications settings, get the raffle setting
|
||||
notifications = self.bot.db.load('server_settings', key=server.id, pluck='notifications') or {}
|
||||
# Set our default to either the one set, or the default channel of the server
|
||||
default_channel_id = notifications.get('default') or server.id
|
||||
# If it is has been overriden by picarto notifications setting, use this
|
||||
channel_id = notifications.get('raffle') or default_channel_id
|
||||
channel = self.bot.get_channel(int(channel_id))
|
||||
if channel is None:
|
||||
channel = server.default_channel
|
||||
try:
|
||||
await channel.send(fmt)
|
||||
except (discord.Forbidden, AttributeError):
|
||||
pass
|
||||
|
||||
# No matter which one of these matches were met, the raffle has ended and we want to remove it
|
||||
raffle['raffles'].remove(r)
|
||||
entry = {
|
||||
'server_id': raffle['server_id'],
|
||||
'raffles': raffle['raffles']
|
||||
}
|
||||
self.bot.db.save('raffles', entry)
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
|
@ -103,8 +105,7 @@ class Raffle:
|
|||
|
||||
EXAMPLE: !raffles
|
||||
RESULT: A list of the raffles setup on this server"""
|
||||
r_filter = {'server_id': str(ctx.message.guild.id)}
|
||||
raffles = self.bot.db.load('raffles', table_filter=r_filter)
|
||||
raffles = self.bot.db.load('raffles', key=ctx.message.guild.id, pluck='raffles')
|
||||
if not raffles:
|
||||
await ctx.send("There are currently no raffles setup on this server!")
|
||||
return
|
||||
|
@ -133,19 +134,15 @@ class Raffle:
|
|||
RESULT: You've entered the first raffle!"""
|
||||
# Lets let people use 1 - (length of raffles) and handle 0 base ourselves
|
||||
raffle_id -= 1
|
||||
r_filter = {'server_id': str(ctx.message.guild.id)}
|
||||
author = ctx.message.author
|
||||
key = str(ctx.message.guild.id)
|
||||
|
||||
raffles = self.bot.db.load('raffles', table_filter=r_filter)
|
||||
raffles = self.bot.db.load('raffles', key=key, pluck='raffles')
|
||||
if raffles is None:
|
||||
await ctx.send("There are currently no raffles setup on this server!")
|
||||
return
|
||||
|
||||
if isinstance(raffles, list):
|
||||
raffle_count = len(raffles)
|
||||
else:
|
||||
raffles = [raffles]
|
||||
raffle_count = 1
|
||||
raffle_count = len(raffles)
|
||||
|
||||
# There is only one raffle, so use the first's info
|
||||
if raffle_count == 1:
|
||||
|
@ -157,8 +154,8 @@ class Raffle:
|
|||
entrants.append(str(author.id))
|
||||
|
||||
update = {
|
||||
'entrants': entrants,
|
||||
'id': raffles[0]['id']
|
||||
'raffles': raffles,
|
||||
'server_id': key
|
||||
}
|
||||
self.bot.db.save('raffles', update)
|
||||
await ctx.send("{} you have just entered the raffle!".format(author.mention))
|
||||
|
@ -175,8 +172,8 @@ class Raffle:
|
|||
# Since we have no good thing to filter things off of, lets use the internal rethinkdb id
|
||||
|
||||
update = {
|
||||
'entrants': entrants,
|
||||
'id': raffles[raffle_id]['id']
|
||||
'raffles': raffles,
|
||||
'server_id': key
|
||||
}
|
||||
self.bot.db.save('raffles', update)
|
||||
await ctx.send("{} you have just entered the raffle!".format(author.mention))
|
||||
|
@ -270,11 +267,15 @@ class Raffle:
|
|||
'expires': expires.to_datetime_string(),
|
||||
'entrants': [],
|
||||
'author': str(author.id),
|
||||
'server_id': str(server.id)
|
||||
}
|
||||
|
||||
# We don't want to pass a filter to this, because we can have multiple raffles per server
|
||||
self.bot.db.save('raffles', entry)
|
||||
raffles = self.bot.db.load('raffles', key=server.id, pluck='raffles') or []
|
||||
raffles.append(entry)
|
||||
update = {
|
||||
'server_id': str(server.id),
|
||||
'raffles': raffles
|
||||
}
|
||||
self.bot.db.save('raffles', update)
|
||||
await ctx.send("I have just saved your new raffle!")
|
||||
|
||||
@raffle.command(name='alerts')
|
||||
|
|
|
@ -4,6 +4,7 @@ from discord.ext import commands
|
|||
from . import utils
|
||||
|
||||
import re
|
||||
import asyncio
|
||||
|
||||
|
||||
class Stats:
|
||||
|
@ -11,6 +12,53 @@ class Stats:
|
|||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.donators = []
|
||||
self.bot.loop.create_task(self.donator_task())
|
||||
|
||||
async def donator_task(self):
|
||||
while True:
|
||||
await self.get_donators()
|
||||
await asyncio.sleep(60)
|
||||
|
||||
async def get_donators(self):
|
||||
# Set our base URL for the pagination task
|
||||
url = "https://api.patreon.com/oauth2/api/campaigns/{}/pledges".format(utils.patreon_id)
|
||||
# Set our headers with our bearer token
|
||||
headers = {'Authorization': 'Bearer {}'.format(utils.patreon_key)}
|
||||
# We need the names of all of them, and the names are embeded a bit so lets append while looping
|
||||
names = []
|
||||
# We need to page through, so lets create a loop and break when we find out we're done
|
||||
while True:
|
||||
# Simply get data based on the URL
|
||||
data = await utils.request(url, headers=headers, force_content_type_json=True)
|
||||
# First check if the data failed to retrieve, if so just return
|
||||
if data is None:
|
||||
return
|
||||
|
||||
# Loop through the includes, as that's all we need
|
||||
for include in data['included']:
|
||||
# We only carry about the user's
|
||||
if include['type'] != 'user':
|
||||
continue
|
||||
# This check checks the user's connected campaign (should only exist for *our* user) and checks if it
|
||||
# matches
|
||||
if include.get('relationshipos', {}).get('campaign', {}).get('data', {}).get('id', {}) == str(
|
||||
utils.patreon_id):
|
||||
continue
|
||||
|
||||
# Otherwise the only way this user was included, was if they are a patron, so include them
|
||||
name = include['attributes']['full_name']
|
||||
if name:
|
||||
names.append(name)
|
||||
|
||||
# Now, lets get our "next" link and request that
|
||||
url = data['links'].get('next')
|
||||
# If there is no None, that means there should only be a "first" and our pagination is done
|
||||
if url is None:
|
||||
break
|
||||
|
||||
# Now just set the names
|
||||
self.donators = names
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
|
@ -277,6 +325,20 @@ class Stats:
|
|||
fmt = fmt.format(member.display_name, record, server_rank, overall_rank, rating)
|
||||
await ctx.send('```\n{}```'.format(fmt))
|
||||
|
||||
@commands.command(aliases=['donators'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
@utils.check_restricted()
|
||||
async def patrons(self, ctx):
|
||||
"""Prints a list of all the patrons for Bonfire
|
||||
|
||||
EXAMPLE: !donators
|
||||
RESULT: A list of the donators"""
|
||||
try:
|
||||
pages = utils.Pages(self.bot, message=ctx.message, entries=self.donators)
|
||||
await pages.paginate()
|
||||
except utils.CannotPaginate as e:
|
||||
await ctx.send(str(e))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Stats(bot))
|
||||
|
|
|
@ -1,98 +1,102 @@
|
|||
import ruamel.yaml as yaml
|
||||
import asyncio
|
||||
import rethinkdb as r
|
||||
import pendulum
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
global_config = {}
|
||||
|
||||
# Ensure that the required config.yml file actually exists
|
||||
try:
|
||||
with open("config.yml", "r") as f:
|
||||
global_config = yaml.safe_load(f)
|
||||
global_config = {k: v for k, v in global_config.items() if v}
|
||||
except FileNotFoundError:
|
||||
print("You have no config file setup! Please use config.yml.sample to setup a valid config file")
|
||||
quit()
|
||||
|
||||
try:
|
||||
bot_token = global_config["bot_token"]
|
||||
except KeyError:
|
||||
print("You have no bot_token saved, this is a requirement for running a bot.")
|
||||
print("Please use config.yml.sample to setup a valid config file")
|
||||
quit()
|
||||
|
||||
|
||||
# Default bot's description
|
||||
bot_description = global_config.get("description")
|
||||
# Bot's default prefix for commands
|
||||
default_prefix = global_config.get("command_prefix", "!")
|
||||
# The key for bots.discord.pw and carbonitex
|
||||
discord_bots_key = global_config.get('discord_bots_key', "")
|
||||
carbon_key = global_config.get('carbon_key', "")
|
||||
# The client ID for twitch requsets
|
||||
twitch_key = global_config.get('twitch_key', "")
|
||||
# The key for youtube API calls
|
||||
youtube_key = global_config.get("youtube_key", "")
|
||||
# The key for Osu API calls
|
||||
osu_key = global_config.get('osu_key', '')
|
||||
# The key for League of Legends API calls
|
||||
lol_key = global_config.get('lol_key', '')
|
||||
# The keys needed for deviant art calls
|
||||
# The invite link for the server made for the bot
|
||||
dev_server = global_config.get("dev_server", "")
|
||||
# The User-Agent that we'll use for most requests
|
||||
user_agent = global_config.get('user_agent', None)
|
||||
# The URL to proxy youtube_dl's requests through
|
||||
ytdl_proxy = global_config.get('youtube_dl_proxy', None)
|
||||
# The extensions to load
|
||||
extensions = [
|
||||
'cogs.interaction',
|
||||
'cogs.misc',
|
||||
'cogs.mod',
|
||||
'cogs.admin',
|
||||
'cogs.images',
|
||||
'cogs.owner',
|
||||
'cogs.stats',
|
||||
'cogs.picarto',
|
||||
'cogs.overwatch',
|
||||
'cogs.links',
|
||||
'cogs.roles',
|
||||
'cogs.tictactoe',
|
||||
'cogs.hangman', 'cogs.events', 'cogs.raffle',
|
||||
'cogs.twitch',
|
||||
'cogs.blackjack',
|
||||
'cogs.osu',
|
||||
'cogs.tags',
|
||||
'cogs.roulette',
|
||||
'cogs.music',
|
||||
'cogs.polls',
|
||||
'cogs.playlist',
|
||||
'cogs.dj'
|
||||
]
|
||||
|
||||
|
||||
# The default status the bot will use
|
||||
default_status = global_config.get("default_status", None)
|
||||
# The rethinkdb hostname
|
||||
db_host = global_config.get('db_host', 'localhost')
|
||||
# The rethinkdb database name
|
||||
db_name = global_config.get('db_name', 'Discord_Bot')
|
||||
# The rethinkdb certification
|
||||
db_cert = global_config.get('db_cert', '')
|
||||
# The rethinkdb port
|
||||
db_port = global_config.get('db_port', 28015)
|
||||
# The user and password assigned
|
||||
db_user = global_config.get('db_user', 'admin')
|
||||
db_pass = global_config.get('db_pass', '')
|
||||
# We've set all the options we need to be able to connect
|
||||
# so create a dictionary that we can use to unload to connect
|
||||
# db_opts = {'host': db_host, 'db': db_name, 'port': db_port, 'ssl':
|
||||
# {'ca_certs': db_cert}, 'user': db_user, 'password': db_pass}
|
||||
db_opts = {'host': db_host, 'db': db_name, 'port': db_port, 'user': db_user, 'password': db_pass}
|
||||
|
||||
|
||||
def command_prefix(bot, message):
|
||||
if not message.guild:
|
||||
return default_prefix
|
||||
return bot.db.load('server_settings', key=message.guild.id, pluck='prefix') or default_prefix
|
||||
import ruamel.yaml as yaml
|
||||
import asyncio
|
||||
import rethinkdb as r
|
||||
import pendulum
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
global_config = {}
|
||||
|
||||
# Ensure that the required config.yml file actually exists
|
||||
try:
|
||||
with open("config.yml", "r") as f:
|
||||
global_config = yaml.safe_load(f)
|
||||
global_config = {k: v for k, v in global_config.items() if v}
|
||||
except FileNotFoundError:
|
||||
print("You have no config file setup! Please use config.yml.sample to setup a valid config file")
|
||||
quit()
|
||||
|
||||
try:
|
||||
bot_token = global_config["bot_token"]
|
||||
except KeyError:
|
||||
print("You have no bot_token saved, this is a requirement for running a bot.")
|
||||
print("Please use config.yml.sample to setup a valid config file")
|
||||
quit()
|
||||
|
||||
# Default bot's description
|
||||
bot_description = global_config.get("description")
|
||||
# Bot's default prefix for commands
|
||||
default_prefix = global_config.get("command_prefix", "!")
|
||||
# The key for bots.discord.pw and carbonitex
|
||||
discord_bots_key = global_config.get('discord_bots_key', "")
|
||||
carbon_key = global_config.get('carbon_key', "")
|
||||
# The client ID for twitch requsets
|
||||
twitch_key = global_config.get('twitch_key', "")
|
||||
# The key for youtube API calls
|
||||
youtube_key = global_config.get("youtube_key", "")
|
||||
# The key for Osu API calls
|
||||
osu_key = global_config.get('osu_key', '')
|
||||
# The key for League of Legends API calls
|
||||
lol_key = global_config.get('lol_key', '')
|
||||
# The keys needed for deviant art calls
|
||||
# The invite link for the server made for the bot
|
||||
dev_server = global_config.get("dev_server", "")
|
||||
# The User-Agent that we'll use for most requests
|
||||
user_agent = global_config.get('user_agent', None)
|
||||
# The URL to proxy youtube_dl's requests through
|
||||
ytdl_proxy = global_config.get('youtube_dl_proxy', None)
|
||||
# The patreon key, as well as the patreon ID to use
|
||||
patreon_key = global_config.get('patreon_key', None)
|
||||
patreon_id = global_config.get('patreon_id', None)
|
||||
patreon_link = global_config.get('patreon_link', None)
|
||||
|
||||
# The extensions to load
|
||||
extensions = [
|
||||
'cogs.interaction',
|
||||
'cogs.misc',
|
||||
'cogs.mod',
|
||||
'cogs.admin',
|
||||
'cogs.images',
|
||||
'cogs.owner',
|
||||
'cogs.stats',
|
||||
'cogs.picarto',
|
||||
'cogs.overwatch',
|
||||
'cogs.links',
|
||||
'cogs.roles',
|
||||
'cogs.tictactoe',
|
||||
'cogs.hangman', 'cogs.events', 'cogs.raffle',
|
||||
'cogs.twitch',
|
||||
'cogs.blackjack',
|
||||
'cogs.osu',
|
||||
'cogs.tags',
|
||||
'cogs.roulette',
|
||||
'cogs.music',
|
||||
'cogs.polls',
|
||||
'cogs.playlist',
|
||||
'cogs.dj'
|
||||
]
|
||||
|
||||
|
||||
# The default status the bot will use
|
||||
default_status = global_config.get("default_status", None)
|
||||
# The rethinkdb hostname
|
||||
db_host = global_config.get('db_host', 'localhost')
|
||||
# The rethinkdb database name
|
||||
db_name = global_config.get('db_name', 'Discord_Bot')
|
||||
# The rethinkdb certification
|
||||
db_cert = global_config.get('db_cert', '')
|
||||
# The rethinkdb port
|
||||
db_port = global_config.get('db_port', 28015)
|
||||
# The user and password assigned
|
||||
db_user = global_config.get('db_user', 'admin')
|
||||
db_pass = global_config.get('db_pass', '')
|
||||
# We've set all the options we need to be able to connect
|
||||
# so create a dictionary that we can use to unload to connect
|
||||
# db_opts = {'host': db_host, 'db': db_name, 'port': db_port, 'ssl':
|
||||
# {'ca_certs': db_cert}, 'user': db_user, 'password': db_pass}
|
||||
db_opts = {'host': db_host, 'db': db_name, 'port': db_port, 'user': db_user, 'password': db_pass}
|
||||
|
||||
|
||||
def command_prefix(bot, message):
|
||||
if not message.guild:
|
||||
return default_prefix
|
||||
return bot.db.load('server_settings', key=message.guild.id, pluck='prefix') or default_prefix
|
||||
|
|
|
@ -92,7 +92,8 @@ async def create_banner(member, image_title, data):
|
|||
stat_offset = draw.textsize(text, font=font, spacing=0)
|
||||
|
||||
font = ImageFont.truetype(whitneyMedium, 96)
|
||||
draw.text((360, -4), text, (255, 255, 255), font=font, align="center")
|
||||
# draw.text((360, -4), text, (255, 255, 255), font=font, align="center")
|
||||
draw.text((360, -4), text, (255, 255, 255), font=font)
|
||||
draw.text((360 + stat_offset[0], -4), stat_text, (0, 402, 504), font=font)
|
||||
save_me = text_bar.resize((350, 20), Image.ANTIALIAS)
|
||||
offset += 20
|
||||
|
|
|
@ -60,7 +60,7 @@ async def download_image(url):
|
|||
return image
|
||||
|
||||
|
||||
async def request(url, *, headers=None, payload=None, method='GET', attr='json'):
|
||||
async def request(url, *, headers=None, payload=None, method='GET', attr='json', force_content_type_json=False):
|
||||
# Make sure our User Agent is what's set, and ensure it's sent even if no headers are passed
|
||||
if headers is None:
|
||||
headers = {}
|
||||
|
@ -83,7 +83,13 @@ async def request(url, *, headers=None, payload=None, method='GET', attr='json')
|
|||
return_value = getattr(response, attr)
|
||||
# Next check if this can be called
|
||||
if callable(return_value):
|
||||
return_value = return_value()
|
||||
# This is use for json; it checks the mimetype instead of checking if the actual data
|
||||
# This causes some places with different mimetypes to fail, even if it's valid json
|
||||
# This check allows us to force the content_type to use whatever content type is given
|
||||
if force_content_type_json:
|
||||
return_value = return_value(content_type=response.headers['content-type'])
|
||||
else:
|
||||
return_value = return_value()
|
||||
# If this is awaitable, await it
|
||||
if inspect.isawaitable(return_value):
|
||||
return_value = await return_value
|
||||
|
|
|
@ -51,11 +51,7 @@ class Playlist(EventEmitter):
|
|||
Imports the songs from `playlist_url` and queues them to be played.
|
||||
|
||||
Returns a list of `entries` that have been enqueued.
|
||||
|
||||
:param playlist_url: The playlist url to be cut into individual urls and added to the playlist
|
||||
"""
|
||||
position = len(self.entries) + 1
|
||||
entry_list = []
|
||||
|
||||
try:
|
||||
info = await self.downloader.safe_extract_info(self.loop, playlist_url, download=False)
|
||||
|
@ -65,6 +61,9 @@ class Playlist(EventEmitter):
|
|||
if not info:
|
||||
raise ExtractionError('Could not extract information from %s' % playlist_url)
|
||||
|
||||
if info.get('playlist') is None:
|
||||
raise WrongEntryTypeError('This is not a playlist!')
|
||||
|
||||
# Once again, the generic extractor fucks things up.
|
||||
if info.get('extractor', None) == 'generic':
|
||||
url_field = 'url'
|
||||
|
|
|
@ -3,9 +3,10 @@ import time
|
|||
import asyncio
|
||||
|
||||
from .exceptions import ExtractionError, WrongEntryTypeError, LiveStreamError
|
||||
from .entry import get_header
|
||||
|
||||
|
||||
class YoutubeDLSource(discord.FFmpegPCMAudio):
|
||||
|
||||
def __init__(self, playlist, url):
|
||||
self.playlist = playlist
|
||||
self.loop = playlist.loop
|
||||
|
@ -14,7 +15,6 @@ class YoutubeDLSource(discord.FFmpegPCMAudio):
|
|||
self.info = None
|
||||
self.ready = False
|
||||
self.error = False
|
||||
asyncio.run_coroutine_threadsafe(self.download(), self.loop)
|
||||
|
||||
async def get_info(self):
|
||||
try:
|
||||
|
@ -33,10 +33,10 @@ class YoutubeDLSource(discord.FFmpegPCMAudio):
|
|||
# Otherwise get the first result
|
||||
else:
|
||||
info = info['entries'][0]
|
||||
self.url = info['webpage_url']
|
||||
# If this isn't a search, then it is a playlist, this can't be done
|
||||
else:
|
||||
raise WrongEntryTypeError("This is a playlist.", True, info.get('webpage_url', None) or info.get('url', None))
|
||||
raise WrongEntryTypeError("This is a playlist.", True,
|
||||
info.get('webpage_url', None) or info.get('url', None))
|
||||
|
||||
if info['extractor'] in ['generic', 'Dropbox']:
|
||||
try:
|
||||
|
@ -55,7 +55,6 @@ class YoutubeDLSource(discord.FFmpegPCMAudio):
|
|||
if headers.get('ice-audio-info'):
|
||||
raise LiveStreamError("Cannot download from a livestream")
|
||||
|
||||
|
||||
if info.get('is_live', False):
|
||||
raise LiveStreamError("Cannot download from a livestream")
|
||||
|
||||
|
@ -64,6 +63,7 @@ class YoutubeDLSource(discord.FFmpegPCMAudio):
|
|||
|
||||
async def prepare(self):
|
||||
await self.get_info()
|
||||
asyncio.run_coroutine_threadsafe(self.download(), self.loop)
|
||||
return self.info
|
||||
|
||||
async def download(self):
|
||||
|
@ -78,7 +78,7 @@ class YoutubeDLSource(discord.FFmpegPCMAudio):
|
|||
'before_options': '-nostdin',
|
||||
'options': '-vn -b:a 128k'
|
||||
}
|
||||
super().__init__(self.downloader.ytdl.prepare_filename(result), **opts)
|
||||
super().__init__(self.downloader.ytdl.prepare_filename(self.info), **opts)
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
beautifulsoup4==4.6.0
|
||||
Pillow==3.4.1
|
||||
Pillow==4.2.0
|
||||
rethinkdb==2.3.0.post6
|
||||
ruamel.yaml==0.14.12
|
||||
youtube-dl
|
||||
|
|
Loading…
Reference in a new issue