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'
|