Compare commits

..

No commits in common. "main" and "0.1" have entirely different histories.
main ... 0.1

6 changed files with 27 additions and 73 deletions

View file

@ -1,4 +1,7 @@
version=0.1
token=OT..
channel_text=123
channel_voice=456
url=http://example.net
passes=2
bitrate=48000

2
.gitignore vendored
View file

@ -1,2 +1,2 @@
# Internal
*.env
.env

View file

@ -5,9 +5,7 @@ RUN apt-get -yq install ffmpeg build-essential
RUN pip --no-cache-dir install \
discord.py[voice] \
pynacl \
httplib2 \
urllib3
pynacl
WORKDIR /app

View file

@ -4,13 +4,12 @@
* Live radio re-streaming to voice channels.
* Automatically turned on/off when someone joins/leaves the bound channel.
* Shows ICY StreamTitle
* Other cool things.
## Running using Docker from the repo
1. `sudo apt install docker-compose`
2. `cp radiobot.env.dist radiobot.env`
3. `vim radiobot.env`
2. `cp .env.dist .env`
3. `vim .env`
4. `docker-compose up -d --build --remove-orphans`
5. `docker-compose logs --follow --tail 100 --timestamps`
5. `docker-compose logs --follow --tail 100`

View file

@ -6,6 +6,6 @@ services:
context: .
dockerfile: Dockerfile
env_file:
- radiobot.env
- .env
command: python3 -u main.py
restart: always

82
main.py
View file

@ -1,31 +1,28 @@
import os
import sys
import re
import struct
import discord
from discord.ext import commands
import asyncio
from subprocess import Popen
import discord
from discord.ext import commands
import urllib.request as urllib2
bot_version = os.environ['version']
print('radiobot ' + bot_version + ' starting')
login_token = os.environ['token']
voice_channel_id = os.environ['channel_voice']
text_channel_id = os.environ['channel_text']
source = os.environ['url']
# Configure the bot
description = '''Radiobot'''
bot = commands.Bot(command_prefix='!', description=description)
# Initialize opus
#if not discord.opus.is_loaded():
# discord.opus.load_opus('opus')
# Initialize some global variables
voice_client = None
text_channel = None
isConnected = False
encoding = 'latin1'
bot_version = '0.2'
print('[INFO] radiobot ' + bot_version + ' starting')
@bot.event
async def on_ready():
@ -38,7 +35,8 @@ async def on_ready():
print("[WARN] No voice channel " + voice_channel_id + " found!")
if not debug_channel:
print("[WARN] No text channel " + text_channel_id + " found!")
await debug_channel.send('] ready! :satellite_orbital:')
await debug_channel.send('] ready.')
@bot.event
async def on_message(message):
@ -51,31 +49,8 @@ async def on_message(message):
print('<' + message.author.nick + '> ' + message.content)
if message.content == '!help':
await message.channel.send('] radiobot commands: help, version, song :star:')
if message.content == '!version':
await message.channel.send('] radiobot ' + bot_version + ' - python ' + os.environ['PYTHON_VERSION'] + ' - github.com/deflax/radiobot :purple_heart:')
if message.content == '!song':
request = urllib2.Request(source, headers={'Icy-MetaData': 1}) # request metadata
response = urllib2.urlopen(request)
metaint = int(response.headers['icy-metaint'])
for _ in range(10): # # title may be empty initially, try several times
response.read(metaint) # skip to metadata
metadata_length = struct.unpack('B', response.read(1))[0] * 16 # length byte
metadata = response.read(metadata_length).rstrip(b'\0')
m = re.search(br"StreamTitle='([^']*)';", metadata)
if m:
title = m.group(1)
if title:
break
else:
print('no title found')
return
meta = title.decode(encoding, errors='replace')
metasplit = meta.split('*', 1)[0]
await message.channel.send('] ' + metasplit + ' :musical_note:')
await message.channel.send('] radiobot ' + bot_version + ' - python ' + os.environ['PYTHON_VERSION'])
@bot.event
async def on_voice_state_update(member, before, after):
@ -92,49 +67,28 @@ async def on_voice_state_update(member, before, after):
"""
global isConnected
FFMPEG_OPTS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
member_msg = None
if member.bot:
#print("[INFO] self event detection")
return
debug_channel = await bot.fetch_channel(text_channel_id)
voice_channel = await bot.fetch_channel(voice_channel_id)
debug_channel = await bot.fetch_channel(text_channel_id)
member_ids = len(voice_channel.voice_states.keys())
if before.channel is None:
prev_chan = "not_found"
else:
prev_chan = str(before.channel.id)
#if prev_chan == str(voice_channel_id):
# member_msg = str(member.nick) + ' is back in the void :cyclone:'
#await debug_channel.send('] voice #' + voice_channel_id + ' member count: ' + str(member_ids))
if after.channel is None:
next_chan = "not_found"
else:
next_chan = str(after.channel.id)
if next_chan == str(voice_channel_id):
member_msg = str(member.nick) + ' enjoys! :satellite:'
if prev_chan == next_chan:
#print('[INFO] ' + str(member.nick) + ' activity')
pass
else:
if member_msg is not None:
print('[INFO] ' + member_msg)
await debug_channel.send('] ' + member_msg)
if member_ids > 0 and isConnected == False:
if member_ids == 1 and isConnected == False:
isConnected = True
await debug_channel.send('] connecting to #' + voice_channel_id)
voice_client = await voice_channel.connect()
voice_client.play(discord.FFmpegPCMAudio(source, **FFMPEG_OPTS))
voice_client.source = discord.PCMVolumeTransformer(voice_client.source)
voice_client.source.volume = 0.3
player = voice_client.play(discord.FFmpegPCMAudio(os.environ['url'], **FFMPEG_OPTS))
return
if member_ids == 1 and isConnected == True:
isConnected = False
#await debug_channel.send('] sleeping. :satellite_orbital:')
await debug_channel.send('] disconnecting from #' + voice_channel_id)
for voice_client in bot.voice_clients:
await voice_client.disconnect()
return