Browse Source

Telecom voice v1

pull/135/head
Andrei 6 years ago
parent
commit
0f89d687c8
No known key found for this signature in database GPG Key ID: 4D2A02C7D500E9D9
  1. 95
      disco/voice.py
  2. 64
      examples/music.py
  3. 2
      setup.py

95
disco/voice.py

@ -0,0 +1,95 @@
from disco.gateway.packets import OPCode
from disco.types.channel import Channel
from telecom import TelecomConnection, AvConvPlayable
class VoiceConnection(object):
def __init__(self, client, guild_id):
self.client = client
self.guild_id = guild_id
self.channel_id = None
self._conn = None
self._voice_server_update_listener = self.client.events.on(
'VoiceServerUpdate',
self._on_voice_server_update,
)
self._mute = False
self._deaf = False
@property
def mute(self):
return self._mute
@property
def deaf(self):
return self._deaf
@mute.setter
def mute(self, value):
if value is self._mute:
return
self._mute = value
self._send_voice_state_update()
@deaf.setter
def deaf(self, value):
if value is self._deaf:
return
self._deaf = value
self._send_voice_state_update()
@classmethod
def from_channel(self, channel):
assert channel.is_voice, 'Cannot connect to a non voice channel'
conn = VoiceConnection(channel.client, channel.guild_id)
conn.connect(channel.id)
return conn
def set_channel(self, channel_or_id):
if channel_or_id and isinstance(channel_or_id, Channel):
channel_or_id = channel_or_id.id
self.channel_id = channel_or_id
self._send_voice_state_update()
def connect(self, channel_id):
assert self._conn is None, 'Already connected'
self.set_channel(channel_id)
self._conn = TelecomConnection(
self.client.state.me.id,
self.guild_id,
self.client.gw.session_id,
)
def disconnect(self):
assert self._conn is not None, 'Not connected'
# Send disconnection
self.set_channel(None)
# Delete our connection so it will get GC'd
del self._conn
self._conn = None
def play_file(self, url):
self._conn.play(AvConvPlayable(url))
def _on_voice_server_update(self, event):
if not self._conn or event.guild_id != self.guild_id:
return
self._conn.update_server_info(event.endpoint, event.token)
def _send_voice_state_update(self):
self.client.gw.send(OPCode.VOICE_STATE_UPDATE, {
'self_mute': self._mute,
'self_deaf': self._deaf,
'self_video': False,
'guild_id': self.guild_id,
'channel_id': self.channel_id,
})

64
examples/music.py

@ -1,56 +1,30 @@
from disco.bot import Plugin from disco.bot import Plugin
from disco.bot.command import CommandError from disco.voice import VoiceConnection
from disco.voice.player import Player
from disco.voice.playable import YoutubeDLInput, BufferedOpusEncoderPlayable
from disco.voice.client import VoiceException
class MusicPlugin(Plugin): class MusicPlugin(Plugin):
def load(self, ctx): def load(self, data):
super(MusicPlugin, self).load(ctx) super(MusicPlugin, self).load(data)
self.guilds = {} self._connections = {}
@Plugin.command('join') @Plugin.command('join')
def on_join(self, event): def on_join(self, event):
if event.guild.id in self.guilds: vs = event.guild.get_member(event.author).get_voice_state()
return event.msg.reply("I'm already playing music here.") if not vs:
return event.msg.reply('you are not in a voice channel')
state = event.guild.get_member(event.author).get_voice_state() if event.guild.id in self._connections:
if not state: if self._connections[event.guild.id].channel_id == vs.channel_id:
return event.msg.reply('You must be connected to voice to use that command.') return event.msg.reply('already in that channel')
else:
self._connections[event.guild.id].set_channel(vs.channel)
return
try: self._connections[event.guild.id] = VoiceConnection.from_channel(vs.channel)
client = state.channel.connect()
except VoiceException as e:
return event.msg.reply('Failed to connect to voice: `{}`'.format(e))
self.guilds[event.guild.id] = Player(client) @Plugin.command('play', '<song:str>')
self.guilds[event.guild.id].complete.wait() def on_play(self, event, song=None):
del self.guilds[event.guild.id] if event.guild.id not in self._connections:
return event.msg.reply('not in voice here')
def get_player(self, guild_id): self._connections[event.guild.id].play_file(song)
if guild_id not in self.guilds:
raise CommandError("I'm not currently playing music here.")
return self.guilds.get(guild_id)
@Plugin.command('leave')
def on_leave(self, event):
player = self.get_player(event.guild.id)
player.disconnect()
@Plugin.command('play', '<url:str>')
def on_play(self, event, url):
item = YoutubeDLInput(url).pipe(BufferedOpusEncoderPlayable)
self.get_player(event.guild.id).queue.append(item)
@Plugin.command('pause')
def on_pause(self, event):
self.get_player(event.guild.id).pause()
@Plugin.command('resume')
def on_resume(self, event):
self.get_player(event.guild.id).resume()
@Plugin.command('kill')
def on_kill(self, event):
self.get_player(event.guild.id).client.ws.sock.shutdown()

2
setup.py

@ -10,7 +10,7 @@ with open('README.md') as f:
readme = f.read() readme = f.read()
extras_require = { extras_require = {
'voice': ['pynacl==1.2.1'], 'voice': ['telecom==0.0.2'],
'http': ['flask==0.12.2'], 'http': ['flask==0.12.2'],
'yaml': ['pyyaml==3.12'], 'yaml': ['pyyaml==3.12'],
'music': ['youtube_dl>=2018.1.21'], 'music': ['youtube_dl>=2018.1.21'],

Loading…
Cancel
Save