import sys
import discord
+import socket
+import random
+import ssl
+import asynqp
import discord.voice_client
+import datetime
import asyncio
import json
import traceback
import os
+SOUND_DIR="soundboard/"
+
+class HornClient(object):
+ def __init__(self, config):
+ self.rabbit_config = config
+
+ def process_msg(self, msg):
+ print('>> {}'.format(msg.body))
+
+ @asyncio.coroutine
+ async def rabbit_connect(self):
+ # CREATE SOCKET
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ # WRAP SOCKET
+ sock = ssl.wrap_socket(sock)
+ sock.connect((self.rabbit_config['host'], int(self.rabbit_config['port'])))
+
+ connection = await asynqp.connect(virtual_host=self.rabbit_config['vhost'], username=self.rabbit_config['user'], password=self.rabbit_config['password'], sock=sock)
+ channel = await connection.open_channel()
+ exchange = await channel.declare_exchange(self.rabbit_config['exchange'], 'topic', passive=True)
+
+ # we have 10 users. Set up a queue for each of them
+ # use different channels to avoid any interference
+ # during message consumption, just in case.
+ self.channel = await connection.open_channel()
+ self.queue = await self.channel.declare_queue('horn_listener')
+ await self.queue.bind(exchange, routing_key=self.rabbit_config['exchange'])
+ await self.queue.consume(self.process_msg, no_ack=True)
+
+ # deliver 10 messages to each user
+ while (True):
+ await asyncio.sleep(1)
+ #msg = asynqp.Message("omg here is the time {}".format(datetime.datetime.now()))
+ #exchange.publish(msg, routing_key=self.rabbit_config['exchange'])
+
class WigglyDiscordException(Exception):
pass
-class WigglyDiscordBot(discord.Client):
+
+
+class WigglyDiscordBot(discord.Client, HornClient):
+ def process_msg(self, msg):
+ if msg._properties['content_type'] == 'application/json':
+ # decode the object from json
+ obj = json.loads(msg.body.decode(msg._properties['content_encoding']))
+ else:
+ obj = msg.body
+
+ if 'output_type' in obj and obj['output_type'] == 'discord':
+ print('Received a horn for us! {}'.format(msg.body))
+ asyncio.async(self.horn(dict(sample_name=obj['sample_name']), properties=None))
+ else:
+ print('Received a horn not for us: {}'.format(msg.body))
+
def __init__(self, config):
self.config = config
self.voice = None
self.player = None
+ self.used = []
+
+ self.loop = asyncio.get_event_loop()
+ #self.horn_client = HornClient('config-piege.json')
+ HornClient.__init__(self, config)
+ discord.Client.__init__(self, loop=self.loop)
+ 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()
- super().__init__()
- self.run(self.config['token'])
+ def get_sample_name(self):
+ selections = os.listdir(self.config['airhorn_directory'])
+ selections = [x for x in selections if '.mp3' in x]
+ sample_name = random.choice(selections)
+ for index, use in enumerate(self.used):
+ if use not in selections:
+ self.used.pop(use)
+ while len(self.used) < len(selections) and sample_name in self.used:
+ print('already used, researching')
+ sample_name = random.choice(selections)
+ self.used.append(sample_name)
+ if len(self.used) == len(selections):
+ self.used = []
+ sample_name = "{}/{}".format(self.config['airhorn_directory'], sample_name)
+ print('{} selected'.format(sample_name))
+ return sample_name
+
+ @asyncio.coroutine
+ async def horn(self, obj, properties):
+
+ try:
+ print('Horn! {}'.format(obj))
+ # exclusive access on each horn or not?
+ if 'exclusive' in obj:
+ exclusive = obj['exclusive']
+ else:
+ exclusive = False
+
+ if obj['sample_name'] == 'random':
+ sample_name = self.get_sample_name()
+ elif obj['sample_name'] == 'terminate':
+ self.terminate_all()
+ return None
+ else:
+ sample_name = '{}/{}'.format(self.config['airhorn_directory'], obj['sample_name'])
+ except:
+ traceback.print_exc()
+ print('Error object was: {}'.format(obj))
+ else:
+ await self.msg_play_filename(sample_name, exclusive=exclusive)
+
+
+
+
+ # for further manipulation if we want to do funky stuff
+ def loop_forever(self):
+ try:
+ self.loop.run_until_complete(self.start(self.config['token']))
+ except KeyboardInterrupt:
+ self.loop.run_until_complete(self.logout())
+ pending = asyncio.Task.all_tasks(loop=self.loop)
+ gathered = asyncio.gather(*pending, loop=self.loop)
+ try:
+ gathered.cancel()
+ self.loop.run_until_complete(gathered)
+
+ # we want to retrieve any exceptions to make sure that
+ # they don't nag us about it being un-retrieved.
+ gathered.exception()
+ except:
+ pass
+ finally:
+ self.loop.close()
@asyncio.coroutine
async def on_ready(self):
- print('Logged in as')
- print(self.user.name)
- print(self.user.id)
+ 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]))
def text_channels(self):
return [x for x in self.get_all_channels() if x.type == discord.ChannelType.text]
-
@asyncio.coroutine
async def msg_play_sound(self, name=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)
+
+ @asyncio.coroutine
+ async def msg_play_filename(self, filename, exclusive=False):
if self.voice:
- if self.player:
- if self.player.is_playing():
- self.player.stop()
- 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))
- else:
- filename = '{}/coool.mp3'.format(self.config['airhorn_directory'])
+ self.terminate_all()
self.player = self.voice.create_ffmpeg_player(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):