Re-implement extra commands and remove !reload

master
Nikola Forró 6 years ago
parent be7187d3a7
commit 38b8e04acf

@ -7,13 +7,14 @@ using [HTTP API](https://gitea.brno.mraveniste.cc/turbotraktor/ladylilia.com/src
* `!lastquote` - posts the most recent quote
* `!findquote PATTERN` - searches for quotes matching `PATTERN` and in case multiple matches are found, posts one of them randomly
- `PATTERN` has to be at least 3 characters long and it can be enclosed in double quotes in case it contains spaces
- `PATTERN` has to be at least 3 characters long
* `!bellagram`, `!bellapics`, `!instabella`, `!instagram` - posts a link to a random Instagram picture of Bella
* `!yt QUERY` - queries Lady Lilia's Youtube channel and posts a link to the most relevant result
- `QUERY` can contain `|` (logical **or**) and `-` (logical **not**) operators, for example: `!yt oblivion -nehrim`
* `!clip PATTERN` - searches for Twitch clips matching `PATTERN` and in case multiple matches are found, posts one of them randomly
- `PATTERN` has to be at least 3 characters long and it can be enclosed in double quotes in case it contains spaces
- `PATTERN` has to be at least 3 characters long
### Mod-only commands
* `!syncquotes` - performs synchronization of the quotes database with Twitch VODs
- only master user is allowed to use this command
* `!reload` - reloads the list of extra commands from the config file
- only master user is allowed to use this command
* `!command set COMMAND TEXT` - adds a new extra command or updates an existing one
* `!command unset COMMAND` - removes an existing extra command

@ -4,6 +4,7 @@ import logging
import os
from commands import Commands
from extracommands import ExtraCommands
from clients.discord import DiscordClient
from clients.twitch import TwitchClient
@ -37,19 +38,29 @@ def main():
commands = Commands(config, commands_logger)
extra_commands = ExtraCommands()
async def monitor_extra_commands():
while True:
try:
extra_commands.reload_if_needed()
except Exception as e:
commands_logger.info('Exception', exc_info=e)
await asyncio.sleep(TIMEOUT)
async def run_twitch_client():
twitch_client = TwitchClient(config, twitch_logger, commands)
twitch_client = TwitchClient(config, twitch_logger, commands, extra_commands)
twitch_client.connect_()
while True:
try:
twitch_client.process_data()
await asyncio.sleep(TIMEOUT)
except Exception as e:
twitch_logger.info('Exception', exc_info=e)
await asyncio.sleep(TIMEOUT)
async def run_discord_client():
while True:
discord_client = DiscordClient(config, discord_logger, commands)
discord_client = DiscordClient(config, discord_logger, commands, extra_commands)
try:
await discord_client.start_()
except Exception as e:
@ -58,6 +69,7 @@ def main():
loop = asyncio.get_event_loop()
try:
asyncio.ensure_future(monitor_extra_commands())
asyncio.ensure_future(run_twitch_client())
asyncio.ensure_future(run_discord_client())
loop.run_forever()

@ -31,10 +31,11 @@ def cooldown(retries, timeout, failure):
class DiscordClient(discord.Client):
def __init__(self, config, logger, commands):
def __init__(self, config, logger, commands, extra_commands):
self.config = config
self.logger = logger
self.commands = commands
self.extra_commands = extra_commands
self.supported_commands = [
(re.compile(r'^!lastquote$'), self._do_lastquote),
(re.compile(r'^!findquote\s+(?P<q>")?(?P<filter>.+)(?(q)")$'), self._do_findquote),
@ -57,7 +58,7 @@ class DiscordClient(discord.Client):
m = pattern.match(message.content)
if m:
await action(server, message.author.id, message, **m.groupdict())
for cmd, resp in self.config['Extra Commands'].items():
for cmd, resp in self.extra_commands.items():
if cmd == message.content:
await self.send_message(message.channel, resp)

@ -33,10 +33,11 @@ QUOTE_REMOVED_PATTERN = re.compile(r'''^
class TwitchClient(irc.bot.SingleServerIRCBot):
def __init__(self, config, logger, commands):
def __init__(self, config, logger, commands, extra_commands):
self.config = config
self.logger = logger
self.commands = commands
self.extra_commands = extra_commands
self.patterns = [
(QUOTE_ADDED_PATTERN, self._add_quote),
(QUOTE_EDITED_PATTERN, self._edit_quote),
@ -49,7 +50,9 @@ class TwitchClient(irc.bot.SingleServerIRCBot):
(re.compile(r'^!(bella(gram|pics)|insta(gram|bella))$'), self._do_bellagram),
(re.compile(r'^!yt\s+(?P<q>")?(?P<query>.+)(?(q)")$'), self._do_yt),
(re.compile(r'^!clip\s+(?P<q>")?(?P<filter>.+)(?(q)")$'), self._do_clip),
(re.compile(r'^!reload$'), self._do_reload),
(re.compile(r'^!command\s+set\s+(?P<q1>")?(?P<cmd>.+?)(?(q1)")\s+'
r'(?P<q2>")?(?P<resp>.+)(?(q2)")$'), self._do_command_set),
(re.compile(r'^!command\s+unset\s+(?P<q>")?(?P<cmd>.+)(?(q)")$'), self._do_command_unset),
]
server = self.config['IRC'].get('server')
port = self.config['IRC'].getint('port')
@ -82,6 +85,10 @@ class TwitchClient(irc.bot.SingleServerIRCBot):
def on_whisper(self, connection, event):
self._process_message(connection, event)
def _is_mod(self, tags):
badges = [b.split('/')[0] for b in tags['badges'].split(',')]
return bool(set(badges).intersection(['admin', 'broadcaster', 'moderator']))
def _send_response(self, connection, event, msg):
if event.target.startswith('#'):
connection.privmsg(event.target, msg)
@ -97,7 +104,7 @@ class TwitchClient(irc.bot.SingleServerIRCBot):
m = pattern.match(message)
if m:
action(tags, send_response, **m.groupdict())
for cmd, resp in self.config['Extra Commands'].items():
for cmd, resp in self.extra_commands.items():
if cmd == message:
send_response(resp)
@ -149,9 +156,8 @@ class TwitchClient(irc.bot.SingleServerIRCBot):
send_response('One time, Lilia said this... #{id}: "{text}" [{game}] [{date}]'.format(**quote))
def _do_syncquotes(self, tags, send_response, **kwargs):
master_user_id = self.config['Twitch'].getint('master_user_id')
if int(tags['user-id']) != master_user_id:
respond('Sorry @{0}, you are not allowed to do this'.format(tags['display-name']))
if not self._is_mod(tags):
send_response('Sorry @{0}, you are not allowed to do this'.format(tags['display-name']))
return
try:
messages = self.commands.get_quote_messages()
@ -163,6 +169,7 @@ class TwitchClient(irc.bot.SingleServerIRCBot):
m = pattern.match(message)
if m:
action(tags, send_response, **m.groupdict())
send_response('Sync finished, @{0}'.format(tags['display-name']))
def _do_bellagram(self, tags, send_response, **kwargs):
try:
@ -188,10 +195,28 @@ class TwitchClient(irc.bot.SingleServerIRCBot):
else:
send_response('{0}: {1}'.format(result['title'], result['url']))
def _do_reload(self, tags, send_response, **kwargs):
master_user_id = self.config['Twitch'].getint('master_user_id')
if int(tags['user-id']) != master_user_id:
respond('Sorry @{0}, you are not allowed to do this'.format(tags['display-name']))
def _do_command_set(self, tags, send_response, cmd, resp, **kwargs):
if not self._is_mod(tags):
send_response('Sorry @{0}, you are not allowed to do this'.format(tags['display-name']))
return
self.config.remove_section('Extra Commands')
self.config.read('settings.cfg')
try:
self.extra_commands[cmd] = resp
self.extra_commands.save()
except Exception as e:
self.logger.error('Failed to update extra commands: %s', e)
send_response('Sorry @{0}, failed to set the command'.format(tags['display-name']))
else:
send_response('Command {0} set, @{1}'.format(cmd, tags['display-name']))
def _do_command_unset(self, tags, send_response, cmd, **kwargs):
if not self._is_mod(tags):
send_response('Sorry @{0}, you are not allowed to do this'.format(tags['display-name']))
return
try:
self.extra_commands.pop(cmd, None)
self.extra_commands.save()
except Exception as e:
self.logger.error('Failed to update extra commands: %s', e)
send_response('Sorry @{0}, failed to unset the command'.format(tags['display-name']))
else:
send_response('Command {0} unset, @{1}'.format(cmd, tags['display-name']))

@ -6,5 +6,6 @@ services:
context: .
volumes:
- /bot/settings.cfg:/bot/settings.cfg
- /bot/extra-commands.json:/bot/extra-commands.json
environment:
- DEBUG=0

@ -0,0 +1,27 @@
import json
import os
FILENAME = 'extra-commands.json'
class ExtraCommands(dict):
def __init__(self):
self.last_mtime = 0
def reload(self):
with open(FILENAME) as f:
commands = json.load(f)
self.clear()
self.update(commands)
def reload_if_needed(self):
mtime = os.stat(FILENAME).st_mtime
if mtime > self.last_mtime:
self.last_mtime = mtime
self.reload()
def save(self):
with open(FILENAME, 'w') as f:
json.dump(self, f, indent=4, sort_keys=True)

@ -10,8 +10,6 @@ token = __DISCORD_TOKEN__
[Twitch]
cache_api_url = https://ladylilia.com/twitch-cache/api
token = oauth:__TWITCH_OAUTH_TOKEN__
# nikola_f
master_user_id = 210957066
[Instagram]
username = lilialovesgames
@ -26,6 +24,3 @@ channel_ids = UC5970RJMoEcRNZl0MNp8tlQ,UCHNjavmkFUf2n0uzWSgj16w
api_url = https://ladylilia.com/quotes/api
api_key = __QUOTES_API_KEY__
act_as_proxy = true
[Extra Commands]
;!command = Response Text

Loading…
Cancel
Save