2021-01-14 09:38:32 +00:00
import util
import discord
from discord . oggparse import OggStream
# requests is for synchronous HTTP. This would be quite awful to use in the rest of the code, but is probably okay since voice code is in a separate thread
# This should, arguably, run in a separate process given python's GIL etc. but this would involve significant effort probably
import requests
import io
from discord . ext import commands
class HTTPSource ( discord . AudioSource ) :
def __init__ ( self , url ) :
self . url = url
async def start ( self ) :
bytestream = requests . get ( self . url , stream = True ) . raw
self . packets = OggStream ( io . BufferedReader ( bytestream , buffer_size = 2 * * 10 ) ) . iter_packets ( )
def read ( self ) : return next ( self . packets , b " " )
def is_opus ( self ) : return True
def setup ( bot ) :
# experimental, thus limit to me only
@bot.group ( )
@commands.check ( util . admin_check )
async def radio ( ctx ) : pass
@radio.command ( )
2021-03-31 21:45:27 +00:00
async def connect ( ctx , thing = " main " , channel_id : int = None ) :
2021-01-14 09:38:32 +00:00
thing_url = util . config [ " radio_urls " ] . get ( thing , None )
if thing_url == None : return await ctx . send ( embed = util . error_embed ( " No such radio thing. " ) )
2021-03-31 21:45:27 +00:00
if channel_id :
channel = await bot . fetch_channel ( channel_id )
if not channel : return await ctx . send ( embed = util . error_embed ( " No such channel. " ) )
else :
voice = ctx . author . voice
if not voice : return await ctx . send ( embed = util . error_embed ( " You are not in a voice channel. " ) )
if voice . mute : return await ctx . send ( embed = util . error_embed ( " You are muted. " ) )
channel = voice . channel
2021-01-14 09:38:32 +00:00
existing = ctx . guild . voice_client
if existing : await existing . disconnect ( )
2021-03-31 21:45:27 +00:00
vc = await channel . connect ( )
2021-01-14 09:38:32 +00:00
src = HTTPSource ( thing_url )
await src . start ( )
vc . play ( src )
@radio.command ( )
async def disconnect ( ctx ) :
if ctx . guild . voice_client :
ctx . guild . voice_client . stop ( )
await ctx . guild . voice_client . disconnect ( )
def teardown ( bot ) :
for guild in bot . guilds :
if guild . voice_client :
guild . voice_client . stop ( )