summaryrefslogtreecommitdiffstats
path: root/update_topic.py
blob: e88c80aaa69a38aa064ae8c3980b3dc5cce6d356 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python
"""
update_topic.py - Keep topic in #spline up-to-date
Copyright 2015-2016, Alexander Sulfrian <alex@spline.inf.fu-berlin.de>
Licensed under the Eiffel Forum License 2.

http://inamidst.com/phenny/
"""

import asyncore
import re
import socket
import threading
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from calendar import TUESDAY


DEFAULT_CONFIG = {
    'channel': '#spline',
    'format': 'https://padlite.spline.de/p/treffen%y%m%d',
    'regex': r'.*(https://padlite\.spline\.de/p/treffen[0-9]{6}).*',
}


def setup(phenny):
    config = dict()
    config.update(DEFAULT_CONFIG)
    config.update(getattr(phenny.config, 'update_topic', dict()))
    config['regex'] = re.compile(config['regex'])
    phenny.data['update_topic.config'] = config

    Scheduler(config, phenny)


class Timer(object):
    def __init__(self, sock):
        self.sock = sock
        self.start()

    def start(self):
        sleep = seconds_until(get_next_meeting() + timedelta(days=1))
        self.timer = threading.Timer(sleep, self.run)
        self.timer.start()

    def run(self):
        self.sock.send('.')
        self.start()

    def cancel(self):
        self.timer.cancel()


class Scheduler(asyncore.dispatcher):
    def __init__(self, config, phenny):
        self.config = config
        self.phenny = phenny
        self.phenny._orig_close = self.phenny.close
        self.phenny.close = (lambda: self._phenny_close())

	recv_timer, send_timer = socket.socketpair()
        self.timer = Timer(send_timer)
        asyncore.dispatcher.__init__(self, recv_timer)

    def _phenny_close(self):
        self.close()
        self.phenny._orig_close()

    def close(self):
        self.timer.cancel()
        asyncore.dispatcher.close(self)

    def writable(self):
        return False

    def handle_read(self):
       data = self.recv(8192)
       if data:
           self._exec()
       else:
           self.close()

    def _exec(self):
        # get topic, topic update is handled if a topic is received
        self.phenny.write(['TOPIC'], self.config['channel'])


def seconds_until(when):
    today = datetime.today().date()
    return (when - today).total_seconds()


def get_next_meeting():
    today = datetime.today()
    delta = relativedelta(day=1, weekday=TUESDAY)
    if today >= (today + delta):
        delta.months = 1
    return (today + delta).date()


def update_topic(phenny, channel, topic):
    if phenny.data.get('update_topic.config') is None:
        return

    config = phenny.data['update_topic.config']
    if channel != config['channel']:
        return

    match = config['regex'].match(topic)
    if match is None:
        return

    new_topic = topic.replace(
        match.groups()[0],
        get_next_meeting().strftime(config['format']),
        1)

    if new_topic != topic:
        print('Updating topic')
        phenny.msg('ChanServ', 'TOPIC %s %s' % (channel, new_topic))


def topic_change(phenny, input):
    update_topic(phenny, input.sender, input)
topic_change.event = 'TOPIC'
topic_change.rule = r'.*'


def topic_reply(phenny, input):
    update_topic(phenny, input.args[1], input)
topic_reply.event = '332'
topic_reply.rule = r'.*'


def request_topic(phenny, input):
    parts = input.split(None, 1)
    if len(parts) < 2:
        phenny.notice(input.nick, 'Usage: %s #channel' % parts[0])
    else:
        phenny.write(['TOPIC'], parts[1])
        phenny.notice(input.nick, 'Done.')
request_topic.rule = r'^!(update|topic|update-topic)(?: +(.*))?$'
request_topic.event = 'NOTICE'