Compare commits

...

25 commits
0.1 ... main

Author SHA1 Message Date
a5a5b2c7de enable ready motd 2022-03-29 04:40:18 +00:00
259fbf3e1e update docs 2022-03-28 18:46:23 -04:00
0ced89e88a remove internal relay 2022-03-28 18:45:24 -04:00
f3f6d2d2ea add relay env file 2022-03-28 17:11:57 -04:00
2d0b08975f add icecast relay 2022-03-28 17:09:47 -04:00
1bb6fdb032 disable voice chans verbosity 2022-03-28 16:56:13 -04:00
2669aef9c2 remove the ready spam 2022-03-28 13:07:31 -04:00
9b9e161098 lower volume to 30% 2022-03-28 13:06:41 -04:00
bc6e15b8c8 implement volume control 2022-03-28 13:02:22 -04:00
2204b088bd check if we have message existing before sending to debug 2022-03-28 12:55:13 -04:00
1f8688d8a6 add emojis and hide join/connect of the bot itself 2022-03-28 12:31:46 -04:00
aa63d3c781 add some emoji flex 2022-03-28 12:21:45 -04:00
42f2016482 represent chaos with cyclone 2022-03-28 12:15:52 -04:00
fc3b530ff5 print member_msg to debug channel 2022-03-28 12:12:38 -04:00
cf4585e647 check channel type and show join/quits 2022-03-28 12:09:45 -04:00
40df1726da show join/quits 2022-03-28 11:46:45 -04:00
3168c77ba7 send welcome message on join 2022-03-28 11:40:05 -04:00
8e1e5c1aa5 update log title 2022-03-28 11:21:01 -04:00
97220407f1 update docs 2022-03-28 11:17:25 -04:00
dd672053f1 fine tune connect condition 2022-03-28 11:15:12 -04:00
99adfa7384 remove https from version url 2022-03-28 11:12:55 -04:00
5ab98b1b0c remove extra env variables 2022-03-28 11:11:47 -04:00
585094b818 split song correctly 2022-03-28 11:08:55 -04:00
9438a24131 show stream title 2022-03-28 10:52:08 -04:00
c8cb8746b3 add 💜 2022-03-28 08:50:36 -04:00
6 changed files with 73 additions and 27 deletions

2
.gitignore vendored
View file

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

View file

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

View file

@ -4,12 +4,13 @@
* 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 .env.dist .env`
3. `vim .env`
2. `cp radiobot.env.dist radiobot.env`
3. `vim radiobot.env`
4. `docker-compose up -d --build --remove-orphans`
5. `docker-compose logs --follow --tail 100`
5. `docker-compose logs --follow --tail 100 --timestamps`

View file

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

82
main.py
View file

@ -1,28 +1,31 @@
import os
import discord
from discord.ext import commands
import sys
import re
import struct
import asyncio
from subprocess import Popen
bot_version = os.environ['version']
print('radiobot ' + bot_version + ' starting')
import discord
from discord.ext import commands
import urllib.request as urllib2
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():
@ -35,8 +38,7 @@ 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.')
await debug_channel.send('] ready! :satellite_orbital:')
@bot.event
async def on_message(message):
@ -49,8 +51,31 @@ 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'])
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:')
@bot.event
async def on_voice_state_update(member, before, after):
@ -67,28 +92,49 @@ 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
voice_channel = await bot.fetch_channel(voice_channel_id)
debug_channel = await bot.fetch_channel(text_channel_id)
voice_channel = await bot.fetch_channel(voice_channel_id)
member_ids = len(voice_channel.voice_states.keys())
#await debug_channel.send('] voice #' + voice_channel_id + ' member count: ' + str(member_ids))
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:'
if member_ids == 1 and isConnected == False:
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:
isConnected = True
await debug_channel.send('] connecting to #' + voice_channel_id)
voice_client = await voice_channel.connect()
player = voice_client.play(discord.FFmpegPCMAudio(os.environ['url'], **FFMPEG_OPTS))
voice_client.play(discord.FFmpegPCMAudio(source, **FFMPEG_OPTS))
voice_client.source = discord.PCMVolumeTransformer(voice_client.source)
voice_client.source.volume = 0.3
return
if member_ids == 1 and isConnected == True:
isConnected = False
await debug_channel.send('] disconnecting from #' + voice_channel_id)
#await debug_channel.send('] sleeping. :satellite_orbital:')
for voice_client in bot.voice_clients:
await voice_client.disconnect()
return

View file

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