From 3060b107ef962f28fad2ed758e111d9e6092f57a Mon Sep 17 00:00:00 2001 From: jweigele Date: Mon, 24 Jul 2017 18:01:53 -0700 Subject: [PATCH] Further iteration on audio, now obeys the airhorn webpage if it's fed an output_type of "discord" in the rabbitmq message. --- wigglydiscord.py | 162 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 146 insertions(+), 16 deletions(-) diff --git a/wigglydiscord.py b/wigglydiscord.py index 6d7413d..40e2850 100755 --- a/wigglydiscord.py +++ b/wigglydiscord.py @@ -2,30 +2,159 @@ 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])) @@ -40,21 +169,22 @@ class WigglyDiscordBot(discord.Client): 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): -- 2.30.2