mirror of
http://aero2k.de/t/repos/urlbot-native.git
synced 2017-09-06 15:25:38 +02:00
Merge branch 'master' of rootie:./urlbot-native
This commit is contained in:
24
common.py
24
common.py
@@ -5,6 +5,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
import requests
|
import requests
|
||||||
from urllib.error import URLError
|
from urllib.error import URLError
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
BUFSIZ = 8192
|
BUFSIZ = 8192
|
||||||
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64; rv:31.0) ' \
|
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64; rv:31.0) ' \
|
||||||
@@ -96,11 +97,24 @@ def giphy(subject, api_key):
|
|||||||
|
|
||||||
|
|
||||||
def get_nick_from_object(message_obj):
|
def get_nick_from_object(message_obj):
|
||||||
"""
|
|
||||||
not quite correct yet, also the private property access isn't nice.
|
if isinstance(message_obj, sleekxmpp.Message):
|
||||||
"""
|
msg_type = message_obj.getType()
|
||||||
nick = message_obj['mucnick'] or message_obj['from']._jid[2]
|
|
||||||
return nick
|
if msg_type == "groupchat":
|
||||||
|
return message_obj.getMucnick()
|
||||||
|
elif msg_type == "chat":
|
||||||
|
jid = message_obj.getFrom()
|
||||||
|
return jid.resource
|
||||||
|
else:
|
||||||
|
raise Exception("Message, but not groupchat/chat")
|
||||||
|
|
||||||
|
elif isinstance(message_obj, sleekxmpp.Presence):
|
||||||
|
jid = message_obj.getFrom()
|
||||||
|
return jid.resource
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise Exception("Message type is: " + str(type(message_obj)))
|
||||||
|
|
||||||
|
|
||||||
def else_command(args):
|
def else_command(args):
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
vars:
|
vars:
|
||||||
- botrepo: http://aero2k.de/t/repos/urlbot-native.git
|
- botrepo: http://aero2k.de/t/repos/urlbot-native.git
|
||||||
- pypi_mirror: http://pypi.fcio.net/simple/
|
- pypi_mirror: http://pypi.fcio.net/simple/
|
||||||
|
- systemd: true
|
||||||
tasks:
|
tasks:
|
||||||
- include_vars: credentials.yml
|
- include_vars: credentials.yml
|
||||||
tags: [render_config]
|
tags: [render_config]
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
shell: virtualenv -p python3 --system-site-packages ~/botenv creates=~/botenv/bin/activate
|
shell: virtualenv -p python3 --system-site-packages ~/botenv creates=~/botenv/bin/activate
|
||||||
- name: virtualenv for supervisord
|
- name: virtualenv for supervisord
|
||||||
shell: virtualenv -p python2 ~/svenv creates=~/svenv/bin/activate
|
shell: virtualenv -p python2 ~/svenv creates=~/svenv/bin/activate
|
||||||
|
when: not systemd
|
||||||
- name: clone repository
|
- name: clone repository
|
||||||
git: repo="{{botrepo}}" dest=~/urlbot force=yes update=yes
|
git: repo="{{botrepo}}" dest=~/urlbot force=yes update=yes
|
||||||
register: source_code
|
register: source_code
|
||||||
@@ -34,6 +36,7 @@
|
|||||||
pip: requirements="~/urlbot/requirements.txt" virtualenv=~/botenv extra_args="-i {{pypi_mirror}}"
|
pip: requirements="~/urlbot/requirements.txt" virtualenv=~/botenv extra_args="-i {{pypi_mirror}}"
|
||||||
- name: install supervisor
|
- name: install supervisor
|
||||||
pip: name=supervisor virtualenv=~/svenv extra_args="-i {{pypi_mirror}}"
|
pip: name=supervisor virtualenv=~/svenv extra_args="-i {{pypi_mirror}}"
|
||||||
|
when: not systemd
|
||||||
|
|
||||||
- name: set configuration
|
- name: set configuration
|
||||||
lineinfile: dest=~/urlbot/local_config.ini create=yes line="{{item.key}} = {{item.value}}" regexp="^{{item.key}}.="
|
lineinfile: dest=~/urlbot/local_config.ini create=yes line="{{item.key}} = {{item.value}}" regexp="^{{item.key}}.="
|
||||||
@@ -60,29 +63,94 @@
|
|||||||
- name: create supervisor config
|
- name: create supervisor config
|
||||||
copy: src=supervisord.conf dest=~/supervisord.conf
|
copy: src=supervisord.conf dest=~/supervisord.conf
|
||||||
register: supervisord
|
register: supervisord
|
||||||
|
when: not systemd
|
||||||
|
|
||||||
|
- name: create directory for systemd unit file
|
||||||
|
shell: mkdir -p ~/.config/systemd/user/ creates=~/.config/systemd/user/
|
||||||
|
when: systemd
|
||||||
|
|
||||||
|
- name: create unitfile
|
||||||
|
copy: src=urlbug@.service dest=~/.config/systemd/user/urlbug@.service
|
||||||
|
when: systemd
|
||||||
|
register: unitfile
|
||||||
|
|
||||||
|
# crapshit does not work
|
||||||
|
- name: reload unitfiles
|
||||||
|
become: true
|
||||||
|
shell: systemctl daemon-reload
|
||||||
|
when: unitfile.changed
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: enable services
|
||||||
|
shell: "systemctl --user enable urlbug@{{item}}.service"
|
||||||
|
with_items:
|
||||||
|
- idlebot
|
||||||
|
- urlbot
|
||||||
|
when: systemd
|
||||||
|
|
||||||
- name: verify supervisor running
|
- name: verify supervisor running
|
||||||
shell: nc -z 127.0.0.1 9004; echo $? executable=/bin/bash
|
shell: nc -z 127.0.0.1 9004; echo $? executable=/bin/bash
|
||||||
register: supervisor_running
|
register: supervisor_running
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
when: not systemd
|
||||||
|
|
||||||
- name: start supervisord
|
- name: start supervisord
|
||||||
shell: source ~/svenv/bin/activate && supervisord executable=/bin/bash
|
shell: source ~/svenv/bin/activate && supervisord executable=/bin/bash
|
||||||
register: start_supervisor
|
register: start_supervisor
|
||||||
when: supervisord.changed or supervisor_running.stdout == "1"
|
when:
|
||||||
|
- not systemd
|
||||||
|
- supervisord.changed or supervisor_running.stdout == "1"
|
||||||
#changed_when: "'already listening' not in start_supervisor.stdout"
|
#changed_when: "'already listening' not in start_supervisor.stdout"
|
||||||
|
|
||||||
- name: activate supervisord changes
|
- name: activate supervisord changes
|
||||||
when: supervisord.changed
|
|
||||||
shell: source ~/svenv/bin/activate && supervisorctl reload executable=/bin/bash
|
shell: source ~/svenv/bin/activate && supervisorctl reload executable=/bin/bash
|
||||||
|
when:
|
||||||
|
- not systemd
|
||||||
|
- supervisord.changed
|
||||||
|
|
||||||
- name: idlebot started
|
- name: idlebot started
|
||||||
supervisorctl: name=idlebot state=restarted supervisorctl_path=~/svenv/bin/supervisorctl
|
supervisorctl: name=idlebot state=restarted supervisorctl_path=~/svenv/bin/supervisorctl
|
||||||
when: (source_code.changed or urlbot_config.changed) and not supervisord.changed
|
when:
|
||||||
|
- not systemd
|
||||||
|
- (source_code.changed or urlbot_config.changed) and not supervisord.changed
|
||||||
|
|
||||||
- pause: seconds=30
|
# following tasks are workaround for missing ansible systemd-user support
|
||||||
when: (source_code.changed or urlbot_config.changed) and not supervisord.changed
|
- name: get systemd unit status
|
||||||
|
shell: systemctl --user status urlbug.slice
|
||||||
|
register: systemd_unit_status
|
||||||
|
|
||||||
|
- debug: var=systemd_unit_status
|
||||||
|
- debug: msg="{{'{{item}}.service' not in systemd_unit_status.stdout}}"
|
||||||
|
with_items:
|
||||||
|
- idlebot
|
||||||
|
- urlbot
|
||||||
|
|
||||||
|
- name: bots started
|
||||||
|
shell: "systemctl --user start urlbug@{{item}}.service && sleep 20"
|
||||||
|
with_items:
|
||||||
|
- idlebot
|
||||||
|
- urlbot
|
||||||
|
when: systemd and '{{item}}.service' not in systemd_unit_status.stdout
|
||||||
|
register: started_bots
|
||||||
|
|
||||||
|
- debug: var=started_bots
|
||||||
|
|
||||||
|
- name: bots restarted
|
||||||
|
shell: "systemctl --user restart urlbug@{{item}}.service && sleep 10"
|
||||||
|
with_items:
|
||||||
|
- idlebot
|
||||||
|
- urlbot
|
||||||
|
when:
|
||||||
|
- systemd
|
||||||
|
- source_code.changed or urlbot_config.changed
|
||||||
|
|
||||||
|
- pause: seconds=20
|
||||||
|
when:
|
||||||
|
- not systemd
|
||||||
|
- (source_code.changed or urlbot_config.changed) and not supervisord.changed
|
||||||
|
|
||||||
- name: urlbot started
|
- name: urlbot started
|
||||||
supervisorctl: name=bot state=restarted supervisorctl_path=~/svenv/bin/supervisorctl
|
supervisorctl: name=bot state=restarted supervisorctl_path=~/svenv/bin/supervisorctl
|
||||||
when: (source_code.changed or urlbot_config.changed) and not supervisord.changed
|
when:
|
||||||
|
- not systemd
|
||||||
|
- (source_code.changed or urlbot_config.changed) and not supervisord.changed
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
[bots]
|
[bots]
|
||||||
aero2k.de ansible_host=2a01:4f8:d16:130c::2
|
aero2k.de ansible_host=2a01:4f8:d16:130c::2 ansible_become_method=su
|
||||||
|
|||||||
2
deploy/requirements-deploy.yml
Normal file
2
deploy/requirements-deploy.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ansible
|
||||||
|
markupsafe
|
||||||
12
deploy/urlbug@.service
Normal file
12
deploy/urlbug@.service
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=jabber bot entertaining and supporting activity on jabber MUCs
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/home/jabberbot/botenv/bin/python3 /home/jabberbot/urlbot/%i.py
|
||||||
|
WorkingDirectory=/home/jabberbot/urlbot/
|
||||||
|
StandardOutput=journal+console
|
||||||
|
StandardError=journal+console
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
11
events.py
11
events.py
@@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
import sched
|
import sched
|
||||||
import threading
|
import threading
|
||||||
@@ -8,7 +9,7 @@ EVENTLOOP_DELAY = 0.100 # seconds
|
|||||||
event_list = sched.scheduler(time.time, time.sleep)
|
event_list = sched.scheduler(time.time, time.sleep)
|
||||||
|
|
||||||
|
|
||||||
def register_active_event(t, callback, args, action_runner, plugin, msg_obj):
|
def register_active_event(t, callback, args, action_runner, plugin, msg_obj, mutex=None):
|
||||||
"""
|
"""
|
||||||
Execute a callback at a given time and react on the output
|
Execute a callback at a given time and react on the output
|
||||||
|
|
||||||
@@ -24,10 +25,14 @@ def register_active_event(t, callback, args, action_runner, plugin, msg_obj):
|
|||||||
action = callback(*func_args)
|
action = callback(*func_args)
|
||||||
if action:
|
if action:
|
||||||
action_runner(action=action, plugin=plugin, msg_obj=msg_obj)
|
action_runner(action=action, plugin=plugin, msg_obj=msg_obj)
|
||||||
event_list.enterabs(t, 0, func, args)
|
register_event(t, func, args, mutex=mutex)
|
||||||
|
|
||||||
|
|
||||||
def register_event(t, callback, args):
|
def register_event(t, callback, args, **kwargs):
|
||||||
|
for pending_event in event_list.queue:
|
||||||
|
if kwargs.get('mutex') and pending_event.kwargs.get('mutex', None) == kwargs.get('mutex'):
|
||||||
|
logging.debug("Dropped event: %s", kwargs.get('mutex'))
|
||||||
|
return
|
||||||
event_list.enterabs(t, 0, callback, args)
|
event_list.enterabs(t, 0, callback, args)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
idlebot.py
10
idlebot.py
@@ -20,6 +20,8 @@ class IdleBot(ClientXMPP):
|
|||||||
self.add_event_handler('session_start', self.session_start)
|
self.add_event_handler('session_start', self.session_start)
|
||||||
self.add_event_handler('groupchat_message', self.muc_message)
|
self.add_event_handler('groupchat_message', self.muc_message)
|
||||||
self.add_event_handler('disconnected', self.disconnected)
|
self.add_event_handler('disconnected', self.disconnected)
|
||||||
|
self.add_event_handler('presence_error', self.disconnected)
|
||||||
|
self.add_event_handler('session_end', self.disconnected)
|
||||||
self.priority = 0
|
self.priority = 0
|
||||||
self.status = None
|
self.status = None
|
||||||
self.show = None
|
self.show = None
|
||||||
@@ -29,7 +31,8 @@ class IdleBot(ClientXMPP):
|
|||||||
self.add_event_handler('muc::%s::got_offline' % room, self.muc_offline)
|
self.add_event_handler('muc::%s::got_offline' % room, self.muc_offline)
|
||||||
|
|
||||||
def disconnected(self, _):
|
def disconnected(self, _):
|
||||||
exit(0)
|
self.logger.warn("Disconnected! dbg: {}".format(str(_)))
|
||||||
|
self.disconnect(wait=True)
|
||||||
|
|
||||||
def session_start(self, _):
|
def session_start(self, _):
|
||||||
self.get_roster()
|
self.get_roster()
|
||||||
@@ -81,8 +84,7 @@ class IdleBot(ClientXMPP):
|
|||||||
"""
|
"""
|
||||||
disconnect and exit
|
disconnect and exit
|
||||||
"""
|
"""
|
||||||
self.disconnect()
|
self.disconnect(wait=True)
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def start(botclass, active=False):
|
def start(botclass, active=False):
|
||||||
@@ -105,6 +107,8 @@ def start(botclass, active=False):
|
|||||||
|
|
||||||
bot.connect()
|
bot.connect()
|
||||||
bot.register_plugin('xep_0045')
|
bot.register_plugin('xep_0045')
|
||||||
|
bot.register_plugin('xep_0199', {'keepalive': True})
|
||||||
|
bot.register_plugin('xep_0308')
|
||||||
bot.process()
|
bot.process()
|
||||||
|
|
||||||
config.runtimeconf_set('start_time', -time.time())
|
config.runtimeconf_set('start_time', -time.time())
|
||||||
|
|||||||
@@ -6,28 +6,48 @@ from plugin_system import pluginfunction, ptypes
|
|||||||
from rate_limit import RATE_FUN, RATE_GLOBAL
|
from rate_limit import RATE_FUN, RATE_GLOBAL
|
||||||
|
|
||||||
|
|
||||||
|
def give_item(user, item_name, search_word=None):
|
||||||
|
if not search_word:
|
||||||
|
search_word = item_name
|
||||||
|
return {'msg': '{} for {}: {}'.format(item_name, user, giphy(search_word, 'dc6zaTOxFJmzC'))}
|
||||||
|
|
||||||
|
|
||||||
|
def cake_excuse(user):
|
||||||
|
return {
|
||||||
|
'msg': '{}: {}'.format(user, random.choice(cakes))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction('cake', 'displays a cake ASCII art', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
@pluginfunction('cake', 'displays a cake ASCII art', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
||||||
def command_cake(argv, **args):
|
def command_cake(argv, **args):
|
||||||
if {'please', 'bitte'}.intersection(set(argv)):
|
if {'please', 'bitte'}.intersection(set(argv)):
|
||||||
return {
|
return give_item(args['reply_user'], 'cake')
|
||||||
'msg': 'cake for {}: {}'.format(args['reply_user'], giphy('cake', 'dc6zaTOxFJmzC'))
|
else:
|
||||||
}
|
return cake_excuse(args['reply_user'])
|
||||||
|
|
||||||
return {
|
|
||||||
'msg': args['reply_user'] + ': %s' % random.choice(cakes)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction('keks', 'keks!', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
@pluginfunction('keks', 'keks!', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
||||||
def command_cookie(argv, **args):
|
def command_cookie(argv, **args):
|
||||||
if {'please', 'bitte'}.intersection(set(argv)):
|
if {'please', 'bitte'}.intersection(set(argv)):
|
||||||
return {
|
return give_item(args['reply_user'], 'keks', 'cookie')
|
||||||
'msg': 'keks für {}: {}'.format(args['reply_user'], giphy('cookie', 'dc6zaTOxFJmzC'))
|
else:
|
||||||
}
|
return cake_excuse(args['reply_user'])
|
||||||
|
|
||||||
return {
|
|
||||||
'msg': args['reply_user'] + ': %s' % random.choice(cakes)
|
@pluginfunction('schnitzel', 'schnitzel!', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
||||||
}
|
def command_schnitzel(argv, **args):
|
||||||
|
if {'please', 'bitte'}.intersection(set(argv)):
|
||||||
|
return give_item(args['reply_user'], 'schnitzel')
|
||||||
|
else:
|
||||||
|
return cake_excuse(args['reply_user'])
|
||||||
|
|
||||||
|
|
||||||
|
@pluginfunction('kaffee', 'kaffee!', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
||||||
|
def command_coffee(argv, **args):
|
||||||
|
if {'please', 'bitte'}.intersection(set(argv)):
|
||||||
|
return give_item(args['reply_user'], 'kaffee', 'coffee')
|
||||||
|
else:
|
||||||
|
return cake_excuse(args['reply_user'])
|
||||||
|
|
||||||
|
|
||||||
cakes = [
|
cakes = [
|
||||||
@@ -46,4 +66,3 @@ cakes = [
|
|||||||
"I'm going to kill you, and all the cake is gone.",
|
"I'm going to kill you, and all the cake is gone.",
|
||||||
"Who's gonna make the cake when I'm gone? You?"
|
"Who's gonna make the cake when I'm gone? You?"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import re
|
||||||
import events
|
import events
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
@@ -15,6 +16,7 @@ import config
|
|||||||
from common import VERSION
|
from common import VERSION
|
||||||
from rate_limit import RATE_FUN, RATE_GLOBAL, RATE_INTERACTIVE, RATE_NO_SILENCE, RATE_NO_LIMIT
|
from rate_limit import RATE_FUN, RATE_GLOBAL, RATE_INTERACTIVE, RATE_NO_SILENCE, RATE_NO_LIMIT
|
||||||
from plugin_system import pluginfunction, ptypes, plugin_storage, plugin_enabled_get, plugin_enabled_set
|
from plugin_system import pluginfunction, ptypes, plugin_storage, plugin_enabled_get, plugin_enabled_set
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -92,7 +94,6 @@ def command_plugin_activation(argv, **args):
|
|||||||
|
|
||||||
@pluginfunction('list', 'list plugin and parser status', ptypes.COMMAND)
|
@pluginfunction('list', 'list plugin and parser status', ptypes.COMMAND)
|
||||||
def command_list(argv, **args):
|
def command_list(argv, **args):
|
||||||
|
|
||||||
log.info('list plugin called')
|
log.info('list plugin called')
|
||||||
|
|
||||||
if 'enabled' in argv and 'disabled' in argv:
|
if 'enabled' in argv and 'disabled' in argv:
|
||||||
@@ -279,20 +280,189 @@ def command_dice(argv, **args):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pluginfunction('xchoose', 'chooses randomly between nested option groups', ptypes.COMMAND, ratelimit_class=RATE_INTERACTIVE)
|
||||||
|
def command_xchoose(argv, **args):
|
||||||
|
|
||||||
|
class ChooseTree():
|
||||||
|
def __init__(self, item=None):
|
||||||
|
self.item = item
|
||||||
|
self.tree = None
|
||||||
|
self.closed = False
|
||||||
|
|
||||||
|
# opening our root node
|
||||||
|
if self.item is None:
|
||||||
|
self.open()
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
if self.tree is None:
|
||||||
|
self.tree = []
|
||||||
|
elif self.closed:
|
||||||
|
raise Exception("cannot re-open group for item '%s'" % (self.item))
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.tree is None:
|
||||||
|
raise Exception("close on unopened bracket")
|
||||||
|
elif len(self.tree) == 0:
|
||||||
|
raise Exception("item '%s' has a group without sub options" % (self.item))
|
||||||
|
else:
|
||||||
|
self.closed = True
|
||||||
|
|
||||||
|
def last(self):
|
||||||
|
return self.tree[-1]
|
||||||
|
|
||||||
|
def choose(self):
|
||||||
|
if self.item:
|
||||||
|
yield self.item
|
||||||
|
|
||||||
|
if self.tree:
|
||||||
|
sel = random.choice(self.tree)
|
||||||
|
for sub in sel.choose():
|
||||||
|
yield sub
|
||||||
|
|
||||||
|
def add(self, item):
|
||||||
|
self.tree.append( ChooseTree(item) )
|
||||||
|
|
||||||
|
# because of error handling we're nesting this function here
|
||||||
|
def xchoose(line):
|
||||||
|
item = ''
|
||||||
|
quote = None
|
||||||
|
choose_tree = ChooseTree()
|
||||||
|
choose_stack = [ choose_tree ]
|
||||||
|
bracket_stack = []
|
||||||
|
|
||||||
|
for pos, c in enumerate(line, 1):
|
||||||
|
try:
|
||||||
|
if quote:
|
||||||
|
if c == quote:
|
||||||
|
quote = None
|
||||||
|
else:
|
||||||
|
item += c
|
||||||
|
|
||||||
|
elif c == ' ':
|
||||||
|
if item:
|
||||||
|
choose_stack[-1].add(item)
|
||||||
|
item = ''
|
||||||
|
|
||||||
|
elif c in ('(', '[', '{', '<'):
|
||||||
|
if item:
|
||||||
|
choose_stack[-1].add(item)
|
||||||
|
item = ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
last = choose_stack[-1].last()
|
||||||
|
last.open()
|
||||||
|
choose_stack.append(last)
|
||||||
|
bracket_stack.append(c)
|
||||||
|
except IndexError:
|
||||||
|
raise Exception("cannot open group without preceding option")
|
||||||
|
|
||||||
|
elif c in (')', ']', '}', '>'):
|
||||||
|
if not bracket_stack:
|
||||||
|
raise Exception("missing leading bracket for '%s'" % (c))
|
||||||
|
|
||||||
|
opening_bracket = bracket_stack.pop(-1)
|
||||||
|
wanted_closing_bracket = { '(':')', '[':']', '{':'}', '<':'>' }[opening_bracket]
|
||||||
|
if c != wanted_closing_bracket:
|
||||||
|
raise Exception("bracket mismatch, wanted bracket '%s' but got '%s'" % (
|
||||||
|
wanted_closing_bracket, c))
|
||||||
|
|
||||||
|
if item:
|
||||||
|
choose_stack[-1].add(item)
|
||||||
|
item = ''
|
||||||
|
|
||||||
|
choose_stack[-1].close()
|
||||||
|
choose_stack.pop(-1)
|
||||||
|
|
||||||
|
elif c in ('"', "'"):
|
||||||
|
quote = c
|
||||||
|
|
||||||
|
else:
|
||||||
|
item += c
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception("%s (at pos %d)" % (e, pos))
|
||||||
|
|
||||||
|
if bracket_stack:
|
||||||
|
raise Exception("missing closing bracket for '%s'" % (bracket_stack[-1]))
|
||||||
|
|
||||||
|
if quote:
|
||||||
|
raise Exception("missing closing quote (%s)" % (quote))
|
||||||
|
|
||||||
|
if item:
|
||||||
|
choose_stack[-1].add(item)
|
||||||
|
|
||||||
|
return ' '.join(choose_tree.choose())
|
||||||
|
|
||||||
|
|
||||||
|
# start of command_xchoose
|
||||||
|
line = re.sub('.*xchoose *', '', args['data'])
|
||||||
|
if not line:
|
||||||
|
return {
|
||||||
|
'msg': '%s: %s' % (args['reply_user'], 'missing options')
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return {
|
||||||
|
'msg': '%s: %s' % (args['reply_user'], xchoose(line))
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {
|
||||||
|
'msg': '%s: %s' % (args['reply_user'], str(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction('choose', 'chooses randomly between arguments', ptypes.COMMAND, ratelimit_class=RATE_INTERACTIVE)
|
@pluginfunction('choose', 'chooses randomly between arguments', ptypes.COMMAND, ratelimit_class=RATE_INTERACTIVE)
|
||||||
def command_choose(argv, **args):
|
def command_choose(argv, **args):
|
||||||
alternatives = argv
|
alternatives = argv
|
||||||
|
binary = (
|
||||||
|
(('Yes.', 'Yeah!', 'Ok!', 'Aye!', 'Great!'), 4),
|
||||||
|
(('No.', 'Naah..', 'Meh.', 'Nay.', 'You stupid?'), 4),
|
||||||
|
(('Maybe.', 'Dunno.', 'I don\'t care.'), 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
def weighted_choice(choices):
|
||||||
|
total = sum(w for c, w in choices)
|
||||||
|
r = random.uniform(0, total)
|
||||||
|
upto = 0
|
||||||
|
for c, w in choices:
|
||||||
|
if upto + w >= r:
|
||||||
|
return c
|
||||||
|
upto += w
|
||||||
|
|
||||||
|
# single or no choice
|
||||||
if len(alternatives) < 2:
|
if len(alternatives) < 2:
|
||||||
return {
|
return {
|
||||||
'msg': '{}: {}.'.format(args['reply_user'], random.choice(['Yes', 'No']))
|
'msg': '{}: {}'.format(args['reply_user'], random.choice(weighted_choice(binary)))
|
||||||
}
|
}
|
||||||
|
elif 'choose' not in alternatives:
|
||||||
choice = random.choice(alternatives)
|
choice = random.choice(alternatives)
|
||||||
log.info('sent random choice')
|
|
||||||
return {
|
return {
|
||||||
'msg': '%s: I prefer %s!' % (args['reply_user'], choice)
|
'msg': '%s: I prefer %s!' % (args['reply_user'], choice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def choose_between(options):
|
||||||
|
responses = []
|
||||||
|
current_choices = []
|
||||||
|
|
||||||
|
for item in options:
|
||||||
|
if item == 'choose':
|
||||||
|
if len(current_choices) < 2:
|
||||||
|
responses.append(random.choice(weighted_choice(binary)))
|
||||||
|
else:
|
||||||
|
responses.append(random.choice(current_choices))
|
||||||
|
current_choices = []
|
||||||
|
else:
|
||||||
|
current_choices.append(item)
|
||||||
|
if len(current_choices) < 2:
|
||||||
|
responses.append(random.choice(weighted_choice(binary)))
|
||||||
|
else:
|
||||||
|
responses.append(random.choice(current_choices))
|
||||||
|
return responses
|
||||||
|
|
||||||
|
log.info('sent multiple random choices')
|
||||||
|
return {
|
||||||
|
'msg': '%s: My choices are: %s!' % (args['reply_user'], ', '.join(choose_between(alternatives)))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction('teatimer', 'sets a tea timer to $1 or currently %d seconds' % config.conf_get('tea_steep_time'),
|
@pluginfunction('teatimer', 'sets a tea timer to $1 or currently %d seconds' % config.conf_get('tea_steep_time'),
|
||||||
ptypes.COMMAND)
|
ptypes.COMMAND)
|
||||||
@@ -324,7 +494,8 @@ def command_teatimer(argv, **args):
|
|||||||
),
|
),
|
||||||
'event': {
|
'event': {
|
||||||
'time': ready,
|
'time': ready,
|
||||||
'msg': (args['reply_user'] + ': Your tea is ready!')
|
'msg': (args['reply_user'] + ': Your tea is ready!'),
|
||||||
|
'mutex': 'teatimer_{}'.format(args['reply_user'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,9 +761,11 @@ def command_dsa_watcher(argv=None, **_):
|
|||||||
msg = 'next crawl set to %s' % time.strftime('%Y-%m-%d %H:%M', time.localtime(crawl_at))
|
msg = 'next crawl set to %s' % time.strftime('%Y-%m-%d %H:%M', time.localtime(crawl_at))
|
||||||
out.append(msg)
|
out.append(msg)
|
||||||
return {
|
return {
|
||||||
|
# 'msg': out,
|
||||||
'event': {
|
'event': {
|
||||||
'time': crawl_at,
|
'time': crawl_at,
|
||||||
'command': (command_dsa_watcher, ([],))
|
'command': (command_dsa_watcher, ([],)),
|
||||||
|
'mutex': 'dsa'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,8 +794,9 @@ def remove_from_botlist(argv, **args):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction("add-to-botlist", "add a user to the botlist", ptypes.COMMAND)
|
@pluginfunction("add-to-botlist", "add a user to the botlist", ptypes.COMMAND, enabled=False)
|
||||||
def add_to_botlist(argv, **args):
|
def add_to_botlist(argv, **args):
|
||||||
|
return {'msg': 'feature disabled until channel separation'}
|
||||||
if not argv:
|
if not argv:
|
||||||
return {'msg': "wrong number of arguments!"}
|
return {'msg': "wrong number of arguments!"}
|
||||||
suspect = argv[0]
|
suspect = argv[0]
|
||||||
@@ -707,35 +881,6 @@ def reload_runtimeconfig(argv, **args):
|
|||||||
return {'msg': 'done'}
|
return {'msg': 'done'}
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction('snitch', "tell on a spammy user", ptypes.COMMAND)
|
|
||||||
def ignore_user(argv, **args):
|
|
||||||
if not argv:
|
|
||||||
return {'msg': 'syntax: "{}: snitch username"'.format(config.conf_get("bot_nickname"))}
|
|
||||||
|
|
||||||
then = time.time() + 15 * 60
|
|
||||||
spammer = argv[0]
|
|
||||||
|
|
||||||
if spammer == config.conf_get("bot_owner"):
|
|
||||||
return {
|
|
||||||
'msg': 'My owner does not spam, he is just very informative.'
|
|
||||||
}
|
|
||||||
|
|
||||||
if spammer not in config.runtime_config_store['spammers']:
|
|
||||||
config.runtime_config_store['spammers'].append(spammer)
|
|
||||||
|
|
||||||
def unblock_user(user):
|
|
||||||
if user not in config.runtime_config_store['spammers']:
|
|
||||||
config.runtime_config_store['spammers'].append(user)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'msg': 'user reported and ignored till {}'.format(time.strftime('%H:%M', time.localtime(then))),
|
|
||||||
'event': {
|
|
||||||
'time': then,
|
|
||||||
'command': (unblock_user, ([spammer],))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction('search', 'search the web (using duckduckgo)', ptypes.COMMAND)
|
@pluginfunction('search', 'search the web (using duckduckgo)', ptypes.COMMAND)
|
||||||
def search_the_web(argv, **args):
|
def search_the_web(argv, **args):
|
||||||
url = 'http://api.duckduckgo.com/'
|
url = 'http://api.duckduckgo.com/'
|
||||||
@@ -776,6 +921,7 @@ def raise_an_error(argv, **args):
|
|||||||
|
|
||||||
@pluginfunction('repeat', 'repeat the last message', ptypes.COMMAND)
|
@pluginfunction('repeat', 'repeat the last message', ptypes.COMMAND)
|
||||||
def repeat_message(argv, **args):
|
def repeat_message(argv, **args):
|
||||||
|
if args['stack']:
|
||||||
return {
|
return {
|
||||||
'msg': args['stack'][-1]['body']
|
'msg': args['stack'][-1]['body']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import config
|
import config
|
||||||
from plugin_system import pluginfunction, ptypes
|
from plugin_system import pluginfunction, ptypes
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
comment_joins_strings = [
|
comment_joins_strings = [
|
||||||
|
|||||||
176
plugins/morse.py
Normal file
176
plugins/morse.py
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
from plugin_system import pluginfunction, ptypes
|
||||||
|
from rate_limit import RATE_FUN, RATE_GLOBAL
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# copy from https://de.wikipedia.org/wiki/Morsezeichen
|
||||||
|
raw_wiki_copy = """
|
||||||
|
A· −
|
||||||
|
B− · · ·
|
||||||
|
C− · − ·
|
||||||
|
D− · ·
|
||||||
|
E·
|
||||||
|
F· · − ·
|
||||||
|
G− − ·
|
||||||
|
H· · · ·
|
||||||
|
I· ·
|
||||||
|
J· − − −
|
||||||
|
K− · −
|
||||||
|
L· − · ·
|
||||||
|
M− −
|
||||||
|
N− ·
|
||||||
|
O− − −
|
||||||
|
P· − − ·
|
||||||
|
Q− − · −
|
||||||
|
R· − ·
|
||||||
|
S· · ·
|
||||||
|
T−
|
||||||
|
U· · −
|
||||||
|
V· · · −
|
||||||
|
W· − −
|
||||||
|
X− · · −
|
||||||
|
Y− · − −
|
||||||
|
Z− − · ·
|
||||||
|
1· − − − −
|
||||||
|
2· · − − −
|
||||||
|
3· · · − −
|
||||||
|
4· · · · −
|
||||||
|
5· · · · ·
|
||||||
|
6− · · · ·
|
||||||
|
7− − · · ·
|
||||||
|
8− − − · ·
|
||||||
|
9− − − − ·
|
||||||
|
0− − − − −
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# machen dictionary aus wikipaste
|
||||||
|
def wiki_paste_to_morse_dict(wikicopy):
|
||||||
|
wikicopy = wikicopy.replace(' ', '')
|
||||||
|
morse_dict = {l[0]: l[1:] for l in wikicopy.splitlines() if l}
|
||||||
|
return morse_dict
|
||||||
|
|
||||||
|
|
||||||
|
ascii_morse = wiki_paste_to_morse_dict(raw_wiki_copy)
|
||||||
|
morse_ascii = {v: k for k, v in ascii_morse.items()}
|
||||||
|
|
||||||
|
|
||||||
|
# return a dictionary of possible morse-chars as key
|
||||||
|
# and their count as value
|
||||||
|
def possible_morse_chars(string):
|
||||||
|
"""
|
||||||
|
returns dit,dah or None
|
||||||
|
"""
|
||||||
|
stats = {}
|
||||||
|
|
||||||
|
for c in re.sub("[\w\d ]", '', string):
|
||||||
|
try:
|
||||||
|
stats[c] += 1
|
||||||
|
except KeyError:
|
||||||
|
stats[c] = 1
|
||||||
|
|
||||||
|
return stats
|
||||||
|
|
||||||
|
|
||||||
|
# return morse-encoded string
|
||||||
|
def morse_encode(string, dot='·', dash='−', sep=' ', ignore_unknown=False):
|
||||||
|
morse_codes = []
|
||||||
|
|
||||||
|
for char in string.upper():
|
||||||
|
try:
|
||||||
|
morse_codes.append(ascii_morse[char].replace('·', dot).replace('−', dash))
|
||||||
|
except KeyError:
|
||||||
|
if not ignore_unknown:
|
||||||
|
morse_codes.append(char)
|
||||||
|
|
||||||
|
return sep.join(morse_codes)
|
||||||
|
|
||||||
|
|
||||||
|
# return morse-decoded string with number of errors as tuple
|
||||||
|
# -> (decoded string, num errors)
|
||||||
|
def morse_decode(string, dot=None, dash=None):
|
||||||
|
"""
|
||||||
|
decode a "morse string" to ascii text
|
||||||
|
uses \s{2,} as word separator
|
||||||
|
"""
|
||||||
|
# dot and dash given, just decode
|
||||||
|
if dot and dash:
|
||||||
|
errors = 0
|
||||||
|
|
||||||
|
words = []
|
||||||
|
# drawback: does not allow single characters.
|
||||||
|
for match in re.finditer('([{dit}{dah}]+((?:\\s)[{dit}{dah}]+)+|\w+)'.format(dit=dot, dah=dash), string):
|
||||||
|
word = match.group()
|
||||||
|
log.debug("morse word: ", word)
|
||||||
|
if any([dot in word, dash in word]):
|
||||||
|
w = []
|
||||||
|
for morse_character in word.split():
|
||||||
|
try:
|
||||||
|
character = morse_ascii[morse_character.replace(dot, '·').replace(dash, '−')]
|
||||||
|
print("Converted \t{} \tto {}".format(morse_character, character))
|
||||||
|
except KeyError:
|
||||||
|
character = morse_character
|
||||||
|
errors += 1
|
||||||
|
w.append(character)
|
||||||
|
words.append(''.join(w))
|
||||||
|
# words.append(''.join([morse_ascii[x.replace(dot, '·').replace(dash, '−')] for x in word.split()]))
|
||||||
|
else:
|
||||||
|
words.append(word)
|
||||||
|
return ' '.join(words), errors
|
||||||
|
|
||||||
|
# dot/dash given, search for dash/dot
|
||||||
|
else:
|
||||||
|
if not dash:
|
||||||
|
dash_stats = {x: string.count(x) for x in '-−_'}
|
||||||
|
dash = max(dash_stats, key=dash_stats.get)
|
||||||
|
if not dot:
|
||||||
|
dot_stats = {x: string.count(x) for x in '.·*'}
|
||||||
|
dot = max(dot_stats, key=dot_stats.get)
|
||||||
|
|
||||||
|
return morse_decode(string, dot=dot, dash=dash)
|
||||||
|
|
||||||
|
|
||||||
|
@pluginfunction('morse-encode', 'encode string to morse', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
||||||
|
def command_morse_encode(argv, **args):
|
||||||
|
if not argv:
|
||||||
|
return {
|
||||||
|
'msg': args['reply_user'] + "usage: morse-encode <string>"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(argv) == 1 and argv[0] == 'that':
|
||||||
|
message_stack = args['stack']
|
||||||
|
if not message_stack[-1]:
|
||||||
|
return
|
||||||
|
message = message_stack[-1]['body']
|
||||||
|
else:
|
||||||
|
message = ' '.join(argv)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'msg': args['reply_user'] + ': %s' % morse_encode(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pluginfunction('morse-decode', 'decode morse encoded string', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
||||||
|
def command_morse_decode(argv, **args):
|
||||||
|
if not argv:
|
||||||
|
return {
|
||||||
|
'msg': args['reply_user'] + "usage: morse-decode <string>"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(argv) == 1 and argv[0] == 'that':
|
||||||
|
message_stack = args['stack']
|
||||||
|
if not message_stack[-1]:
|
||||||
|
return
|
||||||
|
message = message_stack[-1]['body']
|
||||||
|
else:
|
||||||
|
message = ' '.join(argv)
|
||||||
|
|
||||||
|
decoded, errors = morse_decode(message, dot='·', dash='-')
|
||||||
|
|
||||||
|
return {
|
||||||
|
'msg': args['reply_user'] + ': %s (%d errors)' % (decoded, errors)
|
||||||
|
}
|
||||||
@@ -39,6 +39,14 @@ def parse_mental_ill(**args):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pluginfunction('woof', '*puts sunglasses on*', ptypes.PARSE, ratelimit_class=RATE_NO_SILENCE | RATE_GLOBAL)
|
||||||
|
def command_woof(**args):
|
||||||
|
if 'who let the bots out' in args['data']:
|
||||||
|
return {
|
||||||
|
'msg': 'beeep! beep! beep! beep! beep!'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction('debbug', 'parse Debian bug numbers', ptypes.PARSE, ratelimit_class=RATE_NO_SILENCE | RATE_GLOBAL)
|
@pluginfunction('debbug', 'parse Debian bug numbers', ptypes.PARSE, ratelimit_class=RATE_NO_SILENCE | RATE_GLOBAL)
|
||||||
def parse_debbug(**args):
|
def parse_debbug(**args):
|
||||||
bugs = re.findall(r'#(\d{4,})', args['data'])
|
bugs = re.findall(r'#(\d{4,})', args['data'])
|
||||||
@@ -50,14 +58,11 @@ def parse_debbug(**args):
|
|||||||
log.info('detected Debian bug #%s' % b)
|
log.info('detected Debian bug #%s' % b)
|
||||||
|
|
||||||
url = 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s' % b
|
url = 'https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s' % b
|
||||||
status, title = extract_title(url)
|
|
||||||
|
|
||||||
if 0 == status:
|
title = extract_title(url)
|
||||||
|
|
||||||
|
if title:
|
||||||
out.append('Debian Bug: %s: %s' % (title, url))
|
out.append('Debian Bug: %s: %s' % (title, url))
|
||||||
elif 3 == status:
|
|
||||||
out.append('error for #%s: %s' % (b, title))
|
|
||||||
else:
|
|
||||||
log.info('unknown status %d' % status)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'msg': out
|
'msg': out
|
||||||
@@ -122,32 +127,6 @@ def parse_slash_me(**args):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction("recognize_bots", "got ya", ptypes.PARSE)
|
|
||||||
def recognize_bots(**args):
|
|
||||||
unique_standard_phrases = (
|
|
||||||
'independent bot and have nothing to do with other artificial intelligence systems',
|
|
||||||
'new Debian Security Announce',
|
|
||||||
'I\'m a bot (highlight me',
|
|
||||||
)
|
|
||||||
|
|
||||||
def _add_to_list(username, message):
|
|
||||||
if username not in config.runtime_config_store['other_bots']:
|
|
||||||
config.runtime_config_store['other_bots'].append(username)
|
|
||||||
config.runtimeconf_persist()
|
|
||||||
log.info("Adding {} to the list of bots (now {})".format(username, config.runtime_config_store['other_bots']))
|
|
||||||
return {
|
|
||||||
'event': {
|
|
||||||
'time': time.time() + 3,
|
|
||||||
'msg': message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if any([phrase in args['data'] for phrase in unique_standard_phrases]):
|
|
||||||
return _add_to_list(args['reply_user'], 'Making notes...')
|
|
||||||
elif 'I\'ll be back' in args['data']:
|
|
||||||
return _add_to_list(args['reply_user'], 'Hey there, buddy!')
|
|
||||||
|
|
||||||
|
|
||||||
@pluginfunction('resolve-url-title', 'extract titles from urls', ptypes.PARSE, ratelimit_class=RATE_URL)
|
@pluginfunction('resolve-url-title', 'extract titles from urls', ptypes.PARSE, ratelimit_class=RATE_URL)
|
||||||
def resolve_url_title(**args):
|
def resolve_url_title(**args):
|
||||||
user = args['reply_user']
|
user = args['reply_user']
|
||||||
@@ -163,7 +142,7 @@ def resolve_url_title(**args):
|
|||||||
url_blacklist = config.runtime_config_store['url_blacklist'].values()
|
url_blacklist = config.runtime_config_store['url_blacklist'].values()
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
for url in result:
|
for url in result[:10]:
|
||||||
if any([re.match(b, url) for b in url_blacklist]):
|
if any([re.match(b, url) for b in url_blacklist]):
|
||||||
log.info('url blacklist match for ' + url)
|
log.info('url blacklist match for ' + url)
|
||||||
break
|
break
|
||||||
@@ -184,3 +163,10 @@ def resolve_url_title(**args):
|
|||||||
'msg': out
|
'msg': out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pluginfunction('doctor', 'parse doctor', ptypes.PARSE, ratelimit_class=RATE_FUN | RATE_GLOBAL)
|
||||||
|
def parse_doctor(**args):
|
||||||
|
if 'doctor' in args['data'].lower() or 'doktor' in args['data'].lower():
|
||||||
|
return {
|
||||||
|
'msg': 'ELIMINIEREN! ELIMINIEREN!'
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ def translate(argv, **args):
|
|||||||
if not api_key:
|
if not api_key:
|
||||||
return
|
return
|
||||||
message_stack = args['stack']
|
message_stack = args['stack']
|
||||||
|
if not message_stack[-1]:
|
||||||
|
return
|
||||||
last_message = message_stack[-1]['body']
|
last_message = message_stack[-1]['body']
|
||||||
data = {
|
data = {
|
||||||
'q': last_message,
|
'q': last_message,
|
||||||
|
|||||||
26
urlbot.py
26
urlbot.py
@@ -7,10 +7,14 @@ import re
|
|||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from sleekxmpp.plugins import PluginNotFound
|
||||||
|
|
||||||
|
import plugins # force initialization
|
||||||
from plugin_system import plugin_storage, ptypes, plugin_enabled_get
|
from plugin_system import plugin_storage, ptypes, plugin_enabled_get
|
||||||
from rate_limit import rate_limit_classes, RATE_GLOBAL, RATE_CHAT, RATE_EVENT, rate_limit
|
from rate_limit import rate_limit_classes, RATE_GLOBAL, RATE_CHAT, RATE_EVENT, rate_limit
|
||||||
|
|
||||||
@@ -34,7 +38,7 @@ class UrlBot(IdleBot):
|
|||||||
|
|
||||||
self.hist_ts = {p: [] for p in rate_limit_classes}
|
self.hist_ts = {p: [] for p in rate_limit_classes}
|
||||||
self.hist_flag = {p: True for p in rate_limit_classes}
|
self.hist_flag = {p: True for p in rate_limit_classes}
|
||||||
self.message_stack = []
|
self.message_stack = {str(room): deque(maxlen=5) for room in self.rooms}
|
||||||
|
|
||||||
self.add_event_handler('message', self.message)
|
self.add_event_handler('message', self.message)
|
||||||
self.priority = 100
|
self.priority = 100
|
||||||
@@ -42,6 +46,9 @@ class UrlBot(IdleBot):
|
|||||||
for room in self.rooms:
|
for room in self.rooms:
|
||||||
self.add_event_handler('muc::%s::got_online' % room, self.muc_online)
|
self.add_event_handler('muc::%s::got_online' % room, self.muc_online)
|
||||||
|
|
||||||
|
dsa_plugin = list(filter(lambda x: x.plugin_name == 'dsa-watcher', plugin_storage[ptypes.COMMAND]))[0]
|
||||||
|
self._run_action(dsa_plugin(), dsa_plugin, None)
|
||||||
|
|
||||||
def muc_message(self, msg_obj):
|
def muc_message(self, msg_obj):
|
||||||
"""
|
"""
|
||||||
Handle muc messages, return if irrelevant content or die by hangup.
|
Handle muc messages, return if irrelevant content or die by hangup.
|
||||||
@@ -81,7 +88,7 @@ class UrlBot(IdleBot):
|
|||||||
request_counter = int(config.runtimeconf_get('request_counter'))
|
request_counter = int(config.runtimeconf_get('request_counter'))
|
||||||
config.runtimeconf_set('request_counter', request_counter + 1)
|
config.runtimeconf_set('request_counter', request_counter + 1)
|
||||||
|
|
||||||
if str is not type(message):
|
if not isinstance(message, str):
|
||||||
message = '\n'.join(message)
|
message = '\n'.join(message)
|
||||||
|
|
||||||
def cached(function, ttl=60):
|
def cached(function, ttl=60):
|
||||||
@@ -107,7 +114,10 @@ class UrlBot(IdleBot):
|
|||||||
other_bots = config.runtimeconf_get("other_bots")
|
other_bots = config.runtimeconf_get("other_bots")
|
||||||
if not other_bots:
|
if not other_bots:
|
||||||
return False
|
return False
|
||||||
|
try:
|
||||||
users = self.plugin['xep_0045'].getRoster(room)
|
users = self.plugin['xep_0045'].getRoster(room)
|
||||||
|
except PluginNotFound:
|
||||||
|
users = []
|
||||||
return set(users).intersection(set(other_bots))
|
return set(users).intersection(set(other_bots))
|
||||||
|
|
||||||
def _prevent_panic(message, room):
|
def _prevent_panic(message, room):
|
||||||
@@ -196,9 +206,8 @@ class UrlBot(IdleBot):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.exception(e)
|
self.logger.exception(e)
|
||||||
finally:
|
finally:
|
||||||
if len(self.message_stack) > 4:
|
if msg_obj['from'].bare in self.rooms:
|
||||||
self.message_stack.pop(0)
|
self.message_stack[msg_obj['from'].bare].append(msg_obj)
|
||||||
self.message_stack.append(msg_obj)
|
|
||||||
|
|
||||||
def handle_muc_online(self, msg_obj):
|
def handle_muc_online(self, msg_obj):
|
||||||
"""
|
"""
|
||||||
@@ -268,7 +277,7 @@ class UrlBot(IdleBot):
|
|||||||
reply_user=reply_user,
|
reply_user=reply_user,
|
||||||
msg_obj=msg_obj,
|
msg_obj=msg_obj,
|
||||||
argv=words[2:] if len(words) > 1 else [],
|
argv=words[2:] if len(words) > 1 else [],
|
||||||
stack=self.message_stack
|
stack=self.message_stack.get(msg_obj['from'].bare, [])
|
||||||
)
|
)
|
||||||
|
|
||||||
if ret:
|
if ret:
|
||||||
@@ -291,7 +300,7 @@ class UrlBot(IdleBot):
|
|||||||
if not plugin_enabled_get(plugin):
|
if not plugin_enabled_get(plugin):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ret = plugin(reply_user=reply_user, data=data)
|
ret = plugin(reply_user=reply_user, data=data, sender=msg_obj['from'])
|
||||||
|
|
||||||
if ret:
|
if ret:
|
||||||
self._run_action(ret, plugin, msg_obj)
|
self._run_action(ret, plugin, msg_obj)
|
||||||
@@ -348,7 +357,8 @@ class UrlBot(IdleBot):
|
|||||||
args=command[1],
|
args=command[1],
|
||||||
action_runner=self._run_action,
|
action_runner=self._run_action,
|
||||||
plugin=plugin,
|
plugin=plugin,
|
||||||
msg_obj=msg_obj
|
msg_obj=msg_obj,
|
||||||
|
mutex=event.get('mutex')
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'msg' in action and rate_limit(RATE_CHAT | plugin.ratelimit_class):
|
if 'msg' in action and rate_limit(RATE_CHAT | plugin.ratelimit_class):
|
||||||
|
|||||||
Reference in New Issue
Block a user