import traceback
import os
-SOUND_DIR="soundboard/"
-
class HornClient(object):
def __init__(self, config):
self.rabbit_config = config
#exchange.publish(msg, routing_key=self.rabbit_config['exchange'])
-class WigglyDiscordException(Exception):
+class GrahDiscordException(Exception):
pass
-class WigglyDiscordBot(discord.Client, HornClient):
+class GrahDiscordBot(discord.Client, HornClient):
+ AUDIO_FILES = ['mp3', '.ogg']
def process_msg(self, msg):
if msg._properties['content_type'] == 'application/json':
# decode the object from json
def __init__(self, config):
self.config = config
- self.voice = None
+ self.voice = {}
self.player = None
self.used = []
asyncio.async(self.rabbit_connect())
self.loop_forever()
- def terminate_all(self):
- if self.voice:
- if self.player:
- if self.player.is_playing():
- self.player.stop()
+ def terminate_all(self, guild):
+ if self.voice[guild]:
+ if self.voice[guild].is_playing():
+ self.voice[guild].stop()
def get_sample_name(self):
selections = os.listdir(self.config['airhorn_directory'])
- selections = [x for x in selections if '.mp3' in x]
+ selections = [x for x in selections if self.is_audio_file(x)]
sample_name = random.choice(selections)
for index, use in enumerate(self.used):
if use not in selections:
@asyncio.coroutine
async def horn(self, obj, properties):
-
try:
print('Horn! {}'.format(obj))
# exclusive access on each horn or not?
async def on_ready(self):
print('Logged in as {} ({})'.format(self.user.name, self.user.id))
print([x for x in self.get_all_channels()])
- print(list(self.servers))
- print(self.is_voice_connected(list(self.servers)[0]))
+ print(dir(self))
+ print(list(self.guilds))
+ for guild in self.guilds:
+ self.voice[guild] = None
+ print(self.voice_clients)
+# if len(self.voice_clients) > 0:
+# print('Found a preexisting voice client: {}'.format(self.voice_clients))
+# self.voice[guild] = self.voice_clients[0]
+ #print(self.is_voice_connected(list(self.guilds)[0]))
print('------')
@property
def text_channels(self):
return [x for x in self.get_all_channels() if x.type == discord.ChannelType.text]
+ def is_audio_file(self, filename):
+ fn = filename.lower()
+ if any([fn.endswith(y) for y in self.AUDIO_FILES]):
+ return True
+ else:
+ return False
+
+ def name_matches_filename(self, name, filename):
+ name = name.lower()
+ filename = filename.lower()
+ if '.'.join(filename.split('.')[:-1]) == name and self.is_audio_file(filename):
+ return True
+ else:
+ return False
+
@asyncio.coroutine
- async def msg_play_sound(self, name=None):
+ async def msg_play_sound(self, name=None, guild=None):
if name:
- filename = '{}/{}.mp3'.format(self.config['airhorn_directory'], name)
- if not os.path.exists(filename):
- raise WigglyDiscordException("File '{}' not found in airhorn directory".format(name))
- await self.msg_play_filename(filename)
+ filename=None
+ for fn in os.listdir(self.config['airhorn_directory']):
+ if self.name_matches_filename(name, fn):
+ filename = '{}/{}'.format(self.config['airhorn_directory'], fn)
+ break
+ if not filename or not os.path.exists(filename):
+ raise GrahDiscordException("File '{}' not found in airhorn directory".format(name))
+ await self.msg_play_filename(filename, guild=guild)
@asyncio.coroutine
- async def msg_play_filename(self, filename, exclusive=False):
- if self.voice:
- self.terminate_all()
- self.player = self.voice.create_ffmpeg_player(filename)
- self.player.start()
+ async def msg_play_filename(self, filename, exclusive=False, guild=None):
+ if self.voice[guild]:
+ self.terminate_all(guild=guild)
+ self.voice[guild].play(discord.FFmpegPCMAudio(filename))
+ #self.player.start()
else:
print('Was asked to play {} but no voice channel'.format(filename))
- async def msg_join_voice_channel(self, channel_name):
+ async def msg_join_voice_channel(self, channel_name, guild):
print('Called join voice channel')
for vc in self.voice_channels:
- if vc.name == channel_name:
+ if vc.name == channel_name and (not guild or vc.guild == guild):
print('Found a voice channel to join {} {}'.format(vc, type(vc)))
- if self.voice:
- if vc != self.voice.channel:
- self.voice = await self.voice.move_to(vc)
+ if self.voice[guild]:
+ if vc != self.voice[guild].channel:
+ await self.voice[guild].move_to(vc)
else:
- self.voice = await self.join_voice_channel(vc)
- print('Joined voice channel {} (id: {})'.format(vc.name, vc.id))
- print('Voice now {}'.format(self.voice))
+ self.voice[guild] = await vc.connect()
+ print('Joined voice channel {} {} (id: {})'.format(guild, vc.name, vc.id))
+ print('Voice now {}'.format(self.voice[guild]))
print('Exit join voice')
def get_airhorn_filenames(self):
- return sorted([x[:-4] for x in os.listdir(self.config['airhorn_directory']) if 'mp3' in x.lower()])
+ retval = []
+ for x in os.listdir(self.config['airhorn_directory']):
+ if self.is_audio_file(x):
+ retval.append(x.lower())
+ return sorted([x[:-4] for x in retval])
def chunk_it_up(self, filename_list):
@asyncio.coroutine
async def oh_no(self, channel, exc):
+ print("Exception: {}\t{}".format(channel, exc))
exc_string = 'Ruh Roh! {}: {}'.format(type(exc), str(exc))
traceback.print_exc()
- await self.send_message(channel, exc_string)
+ await channel.send(exc_string)
def print_call(self, message):
print('#{} <{}>: {}'.format(message.channel, message.author, message.content))
+
+ def member_guilds(self, member):
+ return [x for x in self.guilds if member in x.members]
+
+ def contextual_guild(self, message):
+ channel = message.channel
+ print(channel)
+ if isinstance(channel, discord.DMChannel):
+ print('Is a DM with {}'.format(channel.recipient))
+ retval = self.member_guilds(channel.recipient)
+ print('Member guilds: {}'.format(retval))
+ return retval
+ else:
+ print('Guild: {}'.format(channel.guild))
+ return [channel.guild]
+
@asyncio.coroutine
async def on_message(self, message):
try:
- if message.content.startswith('!sleep'):
- await asyncio.sleep(5)
- await self.send_message(message.channel, 'Done sleeping')
- elif message.content.startswith('!joinvoice'):
- self.print_call(message)
- print('Was instructed to join {}'.format(message.content.split(' ')[1]))
- await self.msg_join_voice_channel(message.content.split(' ')[1])
- elif message.content.startswith('!play'):
- self.print_call(message)
- print('Was instructed to play {}'.format(message.content.split(' ')[1]))
- await self.msg_play_sound(name=' '.join(message.content.split(' ')[1:]))
- elif message.content.startswith('!listairhorns'):
- self.print_call(message)
- for airhorn_files in self.chunk_it_up(self.get_airhorn_filenames()):
- await self.send_message(message.channel, '```{}```'.format('\n'.join(airhorn_files)))
- elif message.content.startswith('!leavevoice'):
- await self.voice.disconnect()
- self.voice = None
+ if message.author != self.user:
+ guilds = self.contextual_guild(message)
+ if len(guilds) == 0:
+ return
+ elif len(guilds) >1:
+ await message.channel.send('Too many guilds!!!\n{}'.format('\n'.join([str(x) for x in guilds])))
+ return
+ elif len(guilds) == 1:
+ guild = guilds[0]
+
+ if message.content.startswith('!sleep'):
+ await asyncio.sleep(5)
+ await message.channel.send('Done sleeping')
+ elif message.content.startswith('!joinvoice'):
+ self.print_call(message)
+ print('Was instructed to join {} guild {}'.format(message.content.split(' ')[1], str(guild)))
+ await self.msg_join_voice_channel(message.content.split(' ')[1], guild=guild)
+ elif message.content.startswith('!play'):
+ self.print_call(message)
+ print('Was instructed to play {}'.format(message.content.split(' ')[1]))
+ await self.msg_play_sound(name=' '.join(message.content.split(' ')[1:]), guild=guild)
+ elif message.content == '!list':
+ self.print_call(message)
+ for airhorn_files in self.chunk_it_up(self.get_airhorn_filenames()):
+ await message.channel.send('```{}```'.format('\n'.join(airhorn_files)))
+ elif message.content == '!leavevoice':
+ await self.voice[guild].disconnect()
+ self.voice[guild] = None
+ elif message.content == '!help':
+ await message.channel.send('```!joinvoice [channel]\n!play [file]\n!list (for all of them)\n!leavevoice```')
except Exception as e:
await self.oh_no(message.channel, e)
if __name__ == '__main__':
config = json.load(open(sys.argv[1], 'r'))
- bot = WigglyDiscordBot(config)
+ bot = GrahDiscordBot(config)