Add radio.py

This commit is contained in:
aikaterna
2018-01-23 20:03:22 -08:00
parent 1195b031cc
commit 60eebc6705
3 changed files with 170 additions and 0 deletions

View File

@@ -19,6 +19,8 @@ otherbot - Have multiple Red instances and want to know when one goes offline? E
pug - Warcraft pug checker. A port of PugBot's module: https://github.com/reznok/PugBot
radio - A hidden unpublished gem from Paddo, with a couple edits. Plays http audio streams like icecast and mp3 streams.
riot - an old Fredboat command, requested by Mewleficent.
seen - By Paddolicious#8880. Check when the user was last active on a server.

7
radio/info.json Normal file
View File

@@ -0,0 +1,7 @@
{
"AUTHOR" : "Paddo, with edits by aikaterna",
"NAME" : "radio",
"SHORT" : "Plays http streams like icecast or mp3 streams.",
"DESCRIPTION" : "This cog can only be used with audio unloaded. To play m3u or pls files, extract the http stream url they contain and use that - this cog can remember urls for later playback.",
"TAGS": ["radio", "stream", "icecast"]
}

161
radio/radio.py Normal file
View File

@@ -0,0 +1,161 @@
import os
import discord
import asyncio
from discord.ext import commands
from __main__ import send_cmd_help
from cogs.utils.dataIO import dataIO
class Radio:
def __init__(self, bot):
self.bot = bot
self.players = {}
self.memory_path = 'data/radio/memory.json'
self.memory = dataIO.load_json(self.memory_path)
@commands.group(pass_context=True, no_pm=True, name='radio')
async def _radio(self, ctx):
"""Streaming audio commands."""
audio_cog = self.bot.get_cog('Audio')
if audio_cog:
return await self.bot.say("Please unload the audio cog before using this cog.")
if ctx.invoked_subcommand is None:
await send_cmd_help(ctx)
@_radio.command(pass_context=True, no_pm=True, name='stop')
async def _leave(self, ctx):
"""Stops playback."""
server = ctx.message.server
voice_client = await self.voice_client(server)
await self.stop_playing(server)
if voice_client:
await voice_client.disconnect()
@_radio.command(no_pm=True, pass_context=True, name='play')
async def _play(self, ctx, url: str):
"""Play a http stream."""
server = ctx.message.server
if server.id in self.players:
await self.stop_playing(server)
await self.play_stream(ctx, url)
await self.bot.say("Now playing: <{}>".format(url))
@_radio.command(no_pm=True, pass_context=True, name='list')
async def _list(self, ctx):
"""List saved stream URLs."""
server = ctx.message.server
message = '```\n'
message += '{:<30}{}\n\n'.format('NAME', 'URL')
if server.id in self.memory:
for stream in self.memory[server.id]:
message += '{:<30}{}\n'.format(stream, self.memory[server.id][stream])
message += '```'
await self.bot.say(message)
@_radio.command(no_pm=True, pass_context=True, name='add')
async def _add(self, ctx, name: str, url: str):
"""Add a url to save for radio playback."""
server = ctx.message.server
await self.add_to_memory(server, name, url)
await self.bot.say('Added to memory')
@_radio.command(no_pm=True, pass_context=True, name='load')
async def _load(self, ctx, name: str):
"""Load a saved url for radio playback."""
server = ctx.message.server
if server.id in self.memory:
if name.lower() in self.memory[server.id]:
url = self.memory[server.id][name.lower()]
if server.id in self.players:
await self.stop_playing(server)
await self.play_stream(ctx, url)
await self.bot.say("Now playing: <{}>".format(url))
else:
await self.bot.say('"{}" is not in memory.'.format(name.lower()))
else:
await self.bot.say('Nothing in memory yet')
async def save_memory(self):
dataIO.save_json(self.memory_path, self.memory)
async def add_to_memory(self, server, name, url):
if server.id not in self.memory:
self.memory[server.id] = {}
self.memory[server.id][name.lower()] = url
await self.save_memory()
async def join_voice_channel(self, channel):
try:
await self.bot.join_voice_channel(channel)
return True
except discord.InvalidArgument:
await self.bot.say('You need to be in a voice channel yourself.')
except discord.Forbidden:
await self.bot.say('I don\'t have permissions to join this channel.')
return False
async def leave_voice_channel(self, server):
voice_client = await self.voice_client(server)
if server.id in self.players:
self.players[server.id].stop()
del self.players[server.id]
await self.stop_playing(server)
await voice_client.disconnect()
async def voice_connected(self, server):
return self.bot.is_voice_connected(server)
async def voice_client(self, server):
return self.bot.voice_client_in(server)
async def stop_playing(self, server):
if server.id in self.players:
self.players[server.id].stop()
del self.players[server.id]
async def start_playing(self, server, url):
if server.id not in self.players:
voice_client = await self.voice_client(server)
audio_player = voice_client.create_ffmpeg_player(url)
self.players[server.id] = audio_player
self.players[server.id].start()
async def play_stream(self, ctx, url):
server = ctx.message.server
channel = ctx.message.author.voice_channel
if not ctx.message.channel.is_private:
check = True
if not await self.voice_connected(server):
check = await self.join_voice_channel(channel)
if check:
await self.start_playing(server, url)
async def _playing_check(self):
while self == self.bot.get_cog('Radio'):
for player in self.players:
if not self.players[player].is_playing():
server = self.bot.get_server(player)
await self.leave_voice_channel(server)
break
await asyncio.sleep(30)
def check_folder():
if not os.path.exists('data/radio'):
print('Creating data/radio folder...')
os.makedirs('data/radio')
def check_file():
if not dataIO.is_valid_json('data/radio/memory.json'):
print('Creating memory.json...')
dataIO.save_json('data/radio/memory.json', {})
def setup(bot):
check_folder()
check_file()
cog = Radio(bot)
loop = asyncio.get_event_loop()
loop.create_task(cog._playing_check())
bot.add_cog(cog)