-
-
Save mickael9/fc4b28566a4f06a964dd3807f4a80777 to your computer and use it in GitHub Desktop.
IRC to Voxygen TTS with streaming to Icecast
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio | |
import binascii | |
import re | |
import subprocess | |
import time | |
import threading | |
import json | |
import random | |
from queue import Queue | |
import requests | |
import irc3 | |
from irc3.plugins.command import command | |
API_URL = 'https://www.voxygen.fr/sites/all/modules/voxygen_voices/assets/proxy/index.php' | |
VOICES =[ | |
"Emma", | |
"Matteo", | |
"Michel", | |
"Fabienne", | |
"Agnes", | |
"Becool", | |
"Electra", | |
"Helene", | |
"Loic", | |
"Melodine", | |
"Philippe", | |
"Sorciere", | |
"Moussa", | |
"Mendoo" | |
] | |
REPLACEMENTS = ( | |
(r'[a-z]{3,6}://[^\s]*', 'URL'), | |
(r':-?DDD+', 'sourire magistral'), | |
(r':-?DD', 'énorme sourire'), | |
(r':-?D', 'grand sourire'), | |
(r':-?\)', 'sourire'), | |
(r':-?\(', 'triste'), | |
(r":-?'", 'pleure'), | |
(r':-?p', 'tire la langue'), | |
(r'/', 'slash'), | |
) | |
REPLACEMENTS = tuple( | |
(re.compile(regex, flags=re.I), (', ' + repl + ', )')) | |
for regex, repl in REPLACEMENTS | |
) | |
DATA_FILE = 'data.json' | |
@irc3.plugin | |
class TTSPlugin: | |
requires = [ | |
'irc3.plugins.core', | |
'irc3.plugins.command', | |
] | |
def __init__(self, bot): | |
self.bot = bot | |
self.streamer = Streamer() | |
try: | |
self.load_data(DATA_FILE) | |
except: | |
self.data = {} | |
self.data['voices'] = self.data.get('voices', {}) | |
self.data['seed'] = self.data.get('seed', random.getrandbits(32)) | |
self.init_voices() | |
def init_voices(self): | |
random.seed(self.data['seed']) | |
random.shuffle(VOICES) | |
def load_data(self, data_file): | |
with open(data_file, 'r', encoding='utf-8') as f: | |
self.data = json.load(f) | |
def save_data(self, data_file): | |
with open(data_file, 'w', encoding='utf-8') as f: | |
json.dump(self.data, f) | |
@command | |
def reroll(self, mask, target, args): | |
"""Re-roll voices | |
%%reroll | |
""" | |
if target not in self.bot.config['autojoins']: | |
return | |
self.data['seed'] = random.getrandbits(32) | |
self.init_voices() | |
self.save_data(DATA_FILE) | |
self.bot.privmsg(target, 'Voices shuffled') | |
@command | |
def setvoice(self, mask, target, args): | |
"""Set your TTS voice | |
%%setvoice <voice> | |
""" | |
nick = mask.nick | |
voice = args['<voice>'] | |
if voice not in VOICES: | |
self.bot.privmsg(target, "No such voice") | |
else: | |
self.data['voices'][mask] = voice | |
self.save_data(DATA_FILE) | |
self.bot.privmsg(target, "Your voice was set to %s" % voice) | |
@irc3.event(irc3.rfc.PRIVMSG) | |
def on_privmsg(self, mask=None, data=None, target=None, **kw): | |
if target not in self.bot.config['autojoins']: | |
return | |
for regex, repl in REPLACEMENTS: | |
data = regex.sub(repl, data) | |
text = data | |
if mask in self.data['voices']: | |
voice = self.data['voices'][mask] | |
else: | |
voice = VOICES[(binascii.crc32(mask.nick.encode('utf8'))) % len(VOICES)] | |
r = requests.get(API_URL, params={ | |
'text': text, | |
'voice': voice, | |
'ts': int(time.time()), | |
'method': 'redirect', | |
}) | |
self.streamer.add_data(r.content) | |
class Streamer: | |
def __init__(self): | |
self.queue = Queue() | |
self.thread = threading.Thread(target=self.run, daemon=True) | |
self.thread.start() | |
def run(self): | |
while True: | |
data = self.queue.get() | |
p = subprocess.Popen(['ezstream', '-c', 'ezstream_mp3.xml'], | |
stdin=subprocess.PIPE, | |
stdout=subprocess.DEVNULL, | |
stderr=subprocess.DEVNULL) | |
p.communicate(data) | |
def add_data(self, data): | |
self.queue.put(data) | |
def main(): | |
import sys | |
nick = sys.argv[1] | |
chan = sys.argv[2] | |
loop = asyncio.get_event_loop() | |
config = { | |
'autojoins': [chan], | |
'host': 'irc.freenode.net', 'port': 7000, 'ssl': True, | |
'includes': [ | |
'irc3.plugins.core', | |
__name__, | |
], | |
'loop': loop | |
} | |
irc3.IrcBot(nick=nick, **config).run(forever=False) | |
loop.run_forever() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment