push for break

parent 2d741e8c
credentials.json
config.json
*.log
*.txt
*.pyc
cogs/__pycache__/
cogs/__pycache__
cogs/__init__.py
cogs/utils/__pycache__/
cogs/utils/tag_manager/__pycache__/
cogs/utils/__pycache__
cogs/utils/tag_manager/__pycache__
cogs/utils/music/__pycache__
avatars/
youtube_cache/
\ No newline at end of file
youtube_cache/
playlist_cache/
snake.db
\ No newline at end of file
import discord, asyncio, math, traceback
from discord.ext import commands
from .utils import checks
opus_loaded = discord.opus.is_loaded()
class VoicePlayer:
def __init__(self, message, player, client):
self.requester = message.author
self.channel = message.channel
self.player = player
self.client = client
def __repr__(self):
duration = self.player.duration
fmt = "**{0.title}** by **{0.uploader}**"
if duration:
fmt += " ({0[0]}m {0[1]}s)".format(divmod(duration, 60))
return fmt.format(self.player)
def __str__(self):
duration = self.player.duration
fmt = "**{0.title}** by **{0.uploader}** in #{1.name}\n{0.likes} \N{THUMBS UP SIGN}\N{EMOJI MODIFIER FITZPATRICK TYPE-1-2} - {0.views} views - {0.dislikes} \N{THUMBS DOWN SIGN}\N{EMOJI MODIFIER FITZPATRICK TYPE-1-2}\nRequested by **{2.display_name}**"
if duration:
fmt += " ({0[0]}m {0[1]}s)".format(divmod(duration, 60))
return fmt.format(self.player, self.client.channel, self.requester)
class VoiceState:
def __init__(self, bot):
self.current = None
self.voice = None
self.bot = bot
self.play_next_song = asyncio.Event()
self.songs = asyncio.Queue()
self.song_list = []
self.skip_votes = set()
self.audio_player = self.bot.loop.create_task(self.audio_player_task())
def is_playing(self):
if self.voice is None or self.current is None:
return False
player = self.current.player
return not player.is_done()
@property
def player(self):
return self.current.player
def skip(self):
if self.is_playing():
self.player.stop()
self.skip_votes.clear()
def toggle_next(self):
self.bot.loop.call_soon_threadsafe(self.play_next_song.set)
async def audio_player_task(self):
while True:
old_volume = self.current.player.volume if self.current else 0.5
self.play_next_song.clear()
if self.current:
self.bot.log.info("Finishing {} in {} #{}".format(repr(self.current), self.current.client.channel.server.name, self.current.client.channel.name))
self.current = await self.songs.get()
self.song_list.pop()
if self.current:
self.bot.log.info("Playing {} in {} #{}".format(repr(self.current), self.current.client.channel.server.name, self.current.client.channel.name))
await self.bot.send_message(self.current.channel, "Playing " + str(self.current))
self.current.player.volume = old_volume
try:
self.current.player.start()
except Exception as e:
print(type(e).__name__, e)
await self.play_next_song.wait()
class Music:
def __init__(self, bot):
self.bot = bot
self.voice_states = {}
async def on_voice_state_update(self, original_member, new_member):
server = new_member.server
state = self.get_voice_state(server)
if state.voice is not None:
listeners = sum(1 for m in state.voice.channel.voice_members if not m.bot)
if listeners == 0:
if state.is_playing():
state.player.stop()
try:
state.audio_player.cancel()
del self.voice_states[server.id]
await state.voice.disconnect()
except Exception as e:
print(type(e).__name__, e)
def get_voice_state(self, server):
state = self.voice_states.get(server.id)
if state is None:
state = VoiceState(self.bot)
self.voice_states[server.id] = state
return state
async def create_client(self, channel):
voice = await self.bot.join_voice_channel(channel)
state = self.get_voice_state(channel.server)
state.voice = voice
def __unload(self):
for state in self.voice_states.values():
try:
state.audio_player.cancel()
if state.voice:
self.bot.loop.create_task(state.voice.disconnect())
except:
pass
def required_votes(self, channel):
member_count = len([m.id for m in channel.voice_members if not m.bot])
user_limit = channel.user_limit or member_count
required_votes = math.ceil(min(user_limit, member_count) / 2)
return required_votes
@commands.command(pass_context=True, no_pm=True, brief="join a voice channel")
@checks.is_owner()
async def join(self, ctx, *, channel : discord.Channel):
try:
await self.create_client(channel)
except discord.ClientException:
await self.bot.say("\N{CROSS MARK} already in a voice channel")
except discord.InvalidArgument:
await self.bot.say("\N{CROSS MARK} no a valid voice channel")
else:
await self.bot.say("Joined **{}** in **{}**".format(channel.name, channel.server.name))
@commands.command(pass_context=True, no_pm=True, brief="join your voice channel")
@checks.is_owner()
async def summon(self, ctx):
summon_channel = ctx.message.author.voice_channel
if summon_channel is None:
await self.bot.say("\N{CROSS MARK} no voice channel available")
return False
state = self.get_voice_state(ctx.message.server)
if state.voice is None:
state.voice = await self.bot.join_voice_channel(summon_channel)
else:
await state.voice.move_to(summon_channel)
return True
@commands.command(pass_context=True, no_pm=True, name="play", brief="play music")
@checks.is_owner()
async def play_music(self, ctx, *, song : str):
state = self.get_voice_state(ctx.message.server)
opts = {
"default_search": "auto",
"quiet": True
}
if state.voice is None:
success = await ctx.invoke(self.summon)
if not success:
return
try:
player = await state.voice.create_ytdl_player(song, ytdl_options=opts, after=state.toggle_next)
except Exception as e:
traceback.print_tb(e.__traceback__)
await self.bot.send_message(ctx.message.channel, "Could not play song: [{}]: {}".format(type(e).__name__, e))
else:
player.volume = 0.5
player_state = VoicePlayer(ctx.message, player, state.voice)
await self.bot.say("Queued **{}**".format(player.title))
await state.songs.put(player_state)
state.song_list.append(player_state)
@commands.command(pass_context=True, no_pm=True, aliases=["vol"], brief="adjust music volume")
async def volume(self, ctx, value : int = None):
state = self.get_voice_state(ctx.message.server)
if state.is_playing():
if value is not None:
player = state.player
player.volume = value / 100
await self.bot.say("Changed volume to {:.0%}".format(player.volume))
else:
await self.bot.say("Volume is {:.0%}".format(player.volume))
@commands.command(pass_context=True, no_pm=True, brief="pause music")
async def pause(self, ctx):
state = self.get_voice_state(ctx.message.server)
if state.is_playing():
state.player.pause()
@commands.command(pass_context=True, no_pm=True, brief="resume music")
async def resume(self, ctx):
state = self.get_voice_state(ctx.message.server)
if state.is_playing():
state.player.resume()
@commands.command(pass_context=True, no_pm=True, brief="leave a voice channel", help="also clears the song queue")
async def leave(self, ctx):
author = ctx.message.author
server = ctx.message.server
state = self.get_voice_state(server)
print((author.id not in [server.owner.id, state.current.requester.id, "163521874872107009"]) or (author.id not in [server.owner.id, state.current.requester.id, "163521874872107009"] and ctx.message.channel.permissions_for(author).administrator is False))
if state.is_playing():
if (author.id not in [server.owner.id, state.current.requester.id, "163521874872107009"]) or (author.id not in [server.owner.id, state.current.requester.id, "163521874872107009"] and ctx.message.channel.permissions_for(author).administrator is False):
await self.bot.say("\N{CROSS MARK} only the song requester can exit the channel while the song is playing")
return
if state.is_playing():
state.player.stop()
try:
state.audio_player.cancel()
del self.voice_states[server.id]
await state.voice.disconnect()
except:
pass
@commands.command(pass_context=True, no_pm=True, brief="stop music")
async def stop(self, ctx):
server = ctx.message.server
voter = ctx.message.author
state = self.get_voice_state(server)
if (voter.id in [server.owner.id, state.current.requester.id, "163521874872107009"]) or (voter.id not in [server.owner.id, state.current.requester.id, "163521874872107009"] and ctx.message.channel.permissions_for(voter).administrator):
if state.is_playing():
state.player.stop()
else:
await self.bot.say("\N{CROSS MARK} only the song requester can stop the song")
@commands.command(pass_context=True, no_pm=True, brief="skip a song")
async def skip(self, ctx):
server = ctx.message.server
state = self.get_voice_state(ctx.message.server)
if not state.is_playing():
await self.bot.say("\N{CROSS MARK} no song to skip")
return
voter = ctx.message.author
if not voter.voice_channel == state.voice.channel:
await self.bot.say("\N{CROSS MARK} you must be listening to the song to skip it")
return
if (voter.id in [server.owner.id, state.current.requester.id, "163521874872107009"]) or (voter.id not in [server.owner.id, state.current.requester.id, "163521874872107009"] and ctx.message.channel.permissions_for(voter).administrator):
await self.bot.say("Skipping **{}**".format(state.current.player.title))
state.skip()
return
if voter.id not in state.skip_votes:
state.skip_votes.add(voter.id)
required_votes = self.required_votes(state.voice.channel)
total_votes = len(state.skip_votes)
if total_votes >= required_votes:
await self.bot.say("Skip vote passed ({}/{}), skipping **{}**".format(total_votes, required_votes, state.current.player.title))
state.skip()
return
else:
await self.bot.say("{} voted to skip. ({}/{})".format(voter.display_name, total_votes, required_votes))
return
else:
await self.bot.say("\N{CROSS MARK} you have already voted to skip this song")
@commands.command(pass_context=True, no_pm=True, brief="see what is playing")
async def playing(self, ctx):
state = self.get_voice_state(ctx.message.server)
if state.current is None:
await self.bot.say("Nothing is playing")
elif state.is_playing():
total_votes = len(state.skip_votes)
required_votes = self.required_votes(state.voice.channel)
await self.bot.say("Now playing {}\n\n{} skips out of {} required".format(str(state.current), total_votes, required_votes))
else:
await self.bot.say("Nothing is playing")
@commands.command(no_pm=True, alises=["songs"], pass_context=True, brief="see the song queue")
async def queue(self, ctx):
state = self.get_voice_state(ctx.message.server)
song_queue = state.song_list
if len(song_queue) > 0:
result = ["Songs Currently Queued In **{}**".format(state.voice.channel.name), '']
for count, song in enumerate(song_queue, start=1):
result.append("{}. {}".format(count, repr(song)))
result = "\n".join(result)
else:
result = "No songs queued in **{}**".format(state.voice.channel.name)
await self.bot.say(result)
def setup(bot):
bot.add_cog(Music(bot))
\ No newline at end of file
......@@ -15,55 +15,37 @@ class Debug:
return "\n".join(code.split("\n")[1:-1])
return code.strip("` \n")
@commands.command(name="globaldebug", aliases=["globdebug", "gdebug"], pass_context=True, brief="eval across shards")
@checks.is_owner()
async def global_debug_statement(self, ctx, *, content:str):
code = self.clean(content)
results = await self.bot.shared.global_eval(code, ctx) # bot method to run code across shards
code_result = "\n".join(f"Shard #**{shard_id}**\n{result}\n" for shard_id, result in results.items()) # comprehension inside f-string expression. messy
await self.bot.say(code_result)
@commands.command(name="globalrun", aliases=["globrun", "grun"], pass_context=True, brief="exec across shards")
@checks.is_owner()
async def global_run_statement(self, ctx, *, content:str):
code = self.clean(content)
results = await self.bot.global_exec(code, ctx) # same thing, just different process
code_result = "\n".join(f"Shard #**{shard_id}**\n{result}\n" for shard_id, result in results.items())
await self.bot.say(code_result)
@commands.command(name="debug", pass_context=True, brief="eval")
@commands.command(name="debug", brief="eval")
@checks.is_owner()
async def debug_statement(self, ctx, *, content:str):
code = self.clean(content)
results = await self.bot.run_eval(code, ctx) # only one shard, so only one output
await self.bot.say(results) # only one shard, no comprehension needed
await ctx.send(results) # only one shard, no comprehension needed
@commands.command(name="run", pass_context=True, brief="exec")
@commands.command(name="run", brief="exec")
@checks.is_owner()
async def run_statement(self, ctx, *, content:str):
code = self.clean(content)
results = await self.bot.run_exec(code, ctx) # just as above
await self.bot.say(results)
await ctx.send(results)
@commands.command(name="psql", pass_context=True, brief="execute sql")
@commands.command(name="sql", brief="execute sql")
@checks.is_owner()
async def run_sql(self, ctx, *, sql:str):
sql_command = self.clean(sql)
if not sql_command.endswith(";"):
print("adding semicolon")
sql_command += ";"
try:
results = await self.bot.loop.run_in_executor(None, partial(self.bot.db.engine.execute, sql_command)) # run blocking function in a non-blocking way
except sqlalchemy.exc.ProgrammingError as e:
await self.bot.send_message(ctx.message.channel, f"```diff\n- {e.orig.message}\n```\n{e.orig.details.get('hint', 'Unknown fix')}\n\nDouble check your query:\n```sql\n{sql_command}\n```")
await self.bot.send_message(ctx.channel, f"```diff\n- {e.orig.message}\n```\n{e.orig.details.get('hint', 'Unknown fix')}\n\nDouble check your query:\n```sql\n{sql_command}\n```")
return
except Exception as e:
await self.bot.say(f"```diff\n- {type(e).__name__}: {e}") # more f-strings
await ctx.send(f"```diff\n- {type(e).__name__}: {e}") # more f-strings
return
if not results.returns_rows:
......@@ -76,11 +58,11 @@ class Debug:
result = f"# Columns: {', '.join(row_names)}\n# {len(result_list)} total rows\n\n{self.newline.join('- ' + clr(arg) for arg in result_list)}" # nasty, horrid messy f-expr
if len(result) > 1900:
gist_result = await self.bot.upload_to_gist(result, 'sql.md', title="SQL Results")
await self.bot.say(f"Output too long. View results at {gist_result}")
await ctx.send(f"Output too long. View results at {gist_result}")
else:
await self.bot.say(f"```md\n{result}\n```")
await ctx.send(f"```md\n{result}\n```")
@commands.command(name="sys", pass_context=True, brief="system terminal")
@commands.command(name="sys", brief="system terminal")
@checks.is_owner()
async def system_terminal(self, ctx, *, command:str):
result = await self.bot.loop.run_in_executor(None, partial( # blocking function in non-blocking way
......@@ -94,9 +76,9 @@ class Debug:
if len(result) > 1900:
gist_result = await self.bot.upload_to_gist(result, 'output.txt')
await self.bot.say(f"Output too long. View results at {gist_result}") # bypass 2000 char limit with gist
await ctx.send(f"Output too long. View results at {gist_result}") # bypass 2000 char limit with gist
else:
await self.bot.say(f"```py\n{result}\n```")
await ctx.send(f"```py\n{result}\n```")
def setup(bot):
bot.add_cog(Debug(bot))
\ No newline at end of file
import discord, aiohttp, re
import discord
import aiohttp
import re
import traceback
from bs4 import BeautifulSoup as b_soup
from datetime import datetime
......@@ -13,39 +16,39 @@ class Misc:
def __init__(self, bot):
self.bot = bot
@commands.command(name="retro", pass_context=True, brief="make retro banners")
@commands.command(name="retro", brief="make retro banners")
@checks.permissions(use_retro=True)
async def make_retro(self, ctx, *, content:str):
texts = [t.strip() for t in content.split("|")]
if len(texts) != 3:
await self.bot.say("\N{CROSS MARK} Sorry! That input couldn't be parsed. Do you have 2 seperators? ( `|` )")
await ctx.send("\N{CROSS MARK} Sorry! That input couldn't be parsed. Do you have 2 seperators? ( `|` )")
return
await self.bot.type()
_tmp_choice = choice([1, 2, 3, 4])
async with ctx.channel.typing():
_tmp_choice = choice([1, 2, 3, 4])
data = dict(
bg=_tmp_choice,
txt=_tmp_choice,
text1=texts[0],
text2=texts[1],
text3=texts[2]
)
data = dict(
bg=_tmp_choice,
txt=_tmp_choice,
text1=texts[0],
text2=texts[1],
text3=texts[2]
)
async with self.bot.aio_session.post("https://photofunia.com/effects/retro-wave", data=data) as response:
if response.status != 200:
await self.bot.say("\N{CROSS MARK} Could not connect to server. Please try again later")
return
async with self.bot.aio_session.post("https://photofunia.com/effects/retro-wave", data=data) as response:
if response.status != 200:
await ctx.send("\N{CROSS MARK} Could not connect to server. Please try again later")
return
soup = b_soup(await response.text(), "lxml")
download_url = soup.find("div", class_="downloads-container").ul.li.a["href"]
soup = b_soup(await response.text(), "lxml")
download_url = soup.find("div", class_="downloads-container").ul.li.a["href"]
result_embed = discord.Embed()
result_embed.set_image(url=download_url)
result_embed = discord.Embed()
result_embed.set_image(url=download_url)
await self.bot.say(embed=result_embed)
await ctx.send(embed=result_embed)
@commands.command(name="xkcd", pass_context=True, brief="fetch xkcd comics")
@commands.command(name="xkcd", brief="fetch xkcd comics")
@checks.permissions(use_xkcd=True)
async def get_xkcd(self, ctx, id : str = None):
comic_url = ""
......@@ -59,7 +62,7 @@ class Misc:
async with self.bot.aio_session.get(comic_data_url) as response:
if response.status != 200:
await self.bot.say("\N{CROSS MARK} Couldn't connect to server.")
await ctx.send("\N{CROSS MARK} Couldn't connect to server.")
return
data = await response.json()
......@@ -68,46 +71,78 @@ class Misc:
result_embed.set_footer(icon_url="https://xkcd.com/favicon.ico", text="Served by XKCD")
result_embed.set_image(url=data["img"])
await self.bot.say(embed=result_embed)
await ctx.send(embed=result_embed)
@commands.command(name="uptime", pass_context=True, brief="show bot uptime")
@commands.command(name="uptime", brief="show bot uptime")
async def show_uptime(self, ctx):
await self.bot.say(f"Snake has been running for **{time.get_elapsed_time(self.bot.start_time, datetime.now())}** ({self.bot.start_time:{time.time_format}})")
@commands.command(name="suggest", pass_context=True, brief="give feedback", no_pm=True)
@commands.cooldown(1, 30, commands.BucketType.user)
async def give_feedback(self, ctx, *, message:str):
author = ctx.message.author
channel = ctx.message.channel
if not await self.bot.check_blacklist("suggest", user_id=int(author.id)):
try:
result = any(await self.bot.shared.post_suggestion(f"Suggestion from **{author.display_name}**#{author.discriminator} [{author.id}]\n**{channel.server.name}** #**{channel.name}**\n\n{message}"))
except Exception as e:
await self.bot.reply(f"Your message could not be delivered. Please report this information to the owners:\n`[{type(e).__name__}]: {e}`")
return
await self.bot.say("\N{WHITE HEAVY CHECK MARK} Your message was delivered successfully!")
await ctx.send(f"Snake has been running for **{time.get_elapsed_time(self.bot.start_time, datetime.now())}** ({self.bot.start_time:{time.time_format}})")
else:
return
@commands.command(name="emoji", pass_context=True, brief="find emoji")
@commands.command(name="emoji", brief="find emoji")
@commands.cooldown(1, 15, commands.BucketType.user)
@checks.permissions(use_emoji=True)
async def get_emoji(self, ctx, *, query:str):
async with self.bot.aio_session.get("https://api.getdango.com/api/emoji", params=dict(q=quote_plus(query))) as response:
if response.status != 200:
await self.bot.say("Could not connect to server")
await ctx.send("Could not connect to server")
return
emojis = await response.json()
await self.bot.say(" ".join(e["text"] for e in emojis["results"]))
@commands.command(name="invite", pass_context=True, brief="find an invite link")
async def get_invite(self, ctx):
permissions = discord.Permissions(permissions=70634561)
await self.bot.say(f"Invite me with this link!\n{discord.utils.oauth_url('181584771510566922', permissions=permissions)}")
await ctx.send(" ".join(e["text"] for e in emojis["results"]))
@commands.group(name="role", brief="manage roles", no_pm=True, invoke_without_command=False)
async def role_group(self, ctx):
print("Role")
@role_group.command(name="get", brief="assign yourself a role", no_pm=True)
async def get_role(self, ctx, *, role_name:str):
if ctx.guild.id == 224187988593213442:
role = discord.utils.get(ctx.guild.roles, name=role_name)
if role is not None:
try:
await ctx.author.add_roles(role, reason="bot command", atomic=True)
await self.bot.post_reaction(ctx.message, success=True)
except Exception as e:
traceback.print_exc()
await self.bot.post_reaction(ctx.message, failure=True)
@role_group.command(name="remove", brief="remove an assigned role from yourself", no_pm=True)
async def remove_role(self, ctx, *, role_name:str):
if ctx.guild.id == 224187988593213442:
role = discord.utils.get(ctx.guild.roles, name=role_name)
if role is not None:
try:
await ctx.author.remove_roles([role.id], reason="bot command", atomic=True)
await self.bot.post_reaction(ctx.message, success=True)
except Exception as e:
traceback.print_exc()
await self.bot.post_reaction(ctx.message, failure=True)
else:
await ctx.send(f"Role '{role_name}' could not be found")
@role_group.command(name="post", brief="post an update for a role", no_pm=True)
@checks.is_owner()
async def role_post(self, ctx, role_name, *, text):
if ctx.guild.id == 224187988593213442:
role = discord.utils.get(ctx.guild.roles, name=role_name)
if role is not None:
try:
await role.edit(mentionable=True)
await ctx.send(f"{role.mention} {text}")
await role.edit(mentionable=False)
await ctx.message.delete()
except Exception as e:
traceback.print_exc()
await self.bot.post_reaction(ctx.message, failure=True)