~ubuntu-branches/ubuntu/precise/gozerbot/precise

« back to all changes in this revision

Viewing changes to debian/gozerbot/usr/lib/python2.5/site-packages/gozerplugs/plugs/rss.py

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Malcolm
  • Date: 2008-06-02 19:26:39 UTC
  • mfrom: (1.1.3 upstream) (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080602192639-3rn65nx4q1sgd6sy
Tags: 0.8.1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
#
3
3
#
4
4
 
5
 
""" manage rss feeds """
 
5
"""the rss mantra is of the following:
 
6
 
 
7
as OPER:
 
8
 
 
9
. add a url with rss-add
 
10
. start the watcher with rss-watch
 
11
 
 
12
now the user can start the bot sending messages of the feed to him with
 
13
rss-start. if an OPER gives a rss-start command in a channel data will be
 
14
send to the channel.
 
15
 """
6
16
 
7
17
__copyright__ = 'this file is in the public domain'
 
18
__gendocfirst__ = ['rss-add', 'rss-watch', 'rss-start']
 
19
__gendocskip__ = ['rss-dump', ]
8
20
 
9
21
from gozerbot.persist import Persist
10
22
from gozerbot.generic import geturl2, handle_exception, rlog, lockdec, \
11
 
strippedtxt, fromenc
 
23
strippedtxt, fromenc, striphtml, useragent
12
24
from gozerbot.rsslist import rsslist
13
25
from gozerbot.statdict import Statdict
14
26
from gozerbot.fleet import fleet
16
28
from gozerbot.examples import examples
17
29
from gozerbot.datadir import datadir
18
30
from gozerbot.dol import Dol
 
31
from gozerbot.pdod import Pdod
 
32
from gozerbot.pdol import Pdol
19
33
from gozerbot.plughelp import plughelp
20
34
from gozerbot.periodical import periodical
21
35
from gozerbot.aliases import aliasset
 
36
from gozerbot.users import users
 
37
from gozerbot.contrib import feedparser
22
38
import gozerbot.thr as thr
23
39
import time, os, types, thread, socket, xml
24
40
 
25
 
__gendocfirst__ = ['rss-add', ]
26
 
 
27
41
plughelp.add('rss', 'manage rss feeds')
28
42
 
29
43
savelist = []
36
50
        else:
37
51
            result.append(j)
38
52
 
 
53
def checkfordate(data, date):
 
54
    for item in data:
 
55
        try:
 
56
            d = item['updated']
 
57
        except KeyError:
 
58
            continue
 
59
        if date == d:
 
60
            return True
 
61
    return False
 
62
 
39
63
rsslock = thread.allocate_lock()
40
64
locked = lockdec(rsslock)
41
65
 
 
66
class RssException(Exception):
 
67
    pass
 
68
 
 
69
class Rss301(RssException):
 
70
    pass
 
71
 
 
72
class RssStatus(RssException):
 
73
    pass
 
74
 
 
75
class RssBozoException(RssException):
 
76
    pass
 
77
 
 
78
class RssNoSuchItem(RssException):
 
79
    pass
 
80
 
42
81
class Rssitem(object):
43
82
 
44
83
    """ item that contains rss data """
67
106
        Persist.__init__(self, filename)
68
107
        if not self.data:
69
108
            self.data = {}
 
109
        if self.data.has_key('itemslists'):
 
110
            del self.data['itemslists']
 
111
        self.itemslists = Pdol(filename + '.itemslists')
70
112
        self.handlers = {}
71
 
        for i in self.data.values():
72
 
            self.results = Dol()
 
113
        self.results = {}
 
114
        self.jobids = {}
 
115
        self.rawresults = {}
 
116
        self.results = Dol()
 
117
        self.modified = {}
 
118
        self.etag = {}
 
119
        self.markup = Pdod(filename + '.markup')
73
120
 
74
121
    def size(self):
75
122
        """ return number of rss entries """
76
123
        return len(self.data)
77
124
 
 
125
    @locked
78
126
    def add(self, name, url):
79
127
        """ add rss item """
80
128
        rlog(10, 'rss', 'adding %s %s' % (name, url))
81
129
        self.data[name] = Rssitem(name, url, ['title', ])
82
130
        self.save()
83
131
 
 
132
    @locked
84
133
    def delete(self, name):
85
134
        """ delete rss item by name """
86
 
        for i in self.data.values():
87
 
            if i.name == name:
88
 
                i.running = 0
 
135
        target = None
 
136
        for j, i in self.data.iteritems():
 
137
           if i.name == name:
 
138
               target = i
 
139
        if target:
 
140
            try:
 
141
                target.running = 0
89
142
                del self.data[name]
90
143
                self.save()
91
 
 
 
144
            except:
 
145
                pass
 
146
 
92
147
    def byname(self, name):
93
148
        """ return rss item by name """
94
149
        try:
100
155
        """ get data of rss feed """
101
156
        rssitem = self.byname(name)
102
157
        if rssitem == None:
103
 
            return []
104
 
        # fetch data from url
105
 
        urlresult = fromenc(geturl2(rssitem.url, True), what=name)
106
 
        if not urlresult:
107
 
            return []
108
 
        try:
109
 
            result = rsslist(urlresult)
110
 
        except xml.parsers.expat.ExpatError, ex:
111
 
            rlog(10, 'rss', '%s: %s' % (name, str(ex)))
112
 
            return []
113
 
        resultlist = []
114
 
        for i in result:
115
 
            temp = {}
116
 
            for z, zz in i.iteritems():
117
 
                if z in rssitem.itemslist:
118
 
                    if type(zz) == types.DictType:
119
 
                        res = []
120
 
                        txtindicts(res, zz)
121
 
                        if len(res) == 1:
122
 
                            temp[z] = res[0]
123
 
                        else:
124
 
                            temp[z] = res
125
 
                    else:
126
 
                        temp[z] = zz
127
 
            if temp:
128
 
                resultlist.append(temp)
129
 
        return resultlist
 
158
            raise RssNoSuchItem("no %s rss item found" % name)
 
159
        try:
 
160
            modified = self.modified[name]
 
161
        except KeyError:
 
162
            modified = None
 
163
        try:
 
164
            etag = self.etag[name]
 
165
        except KeyError:
 
166
            etag = None
 
167
        result = feedparser.parse(rssitem.url, modified=modified, etag=etag, \
 
168
agent=useragent())
 
169
        if result and result.has_key('bozo_exception'):
 
170
            rlog(10, 'rss', '%s bozo_exception: %s' % (name, \
 
171
result['bozo_exception']))
 
172
            #raise RssStatus(result['bozo_exception'])
 
173
        try:
 
174
            status = result.status
 
175
        except AttributeError:
 
176
            status = 200
 
177
        if status != 200 and status != 301 and status != 302 and status != 304:
 
178
            raise RssStatus(status)
 
179
        try:
 
180
            self.modified[name] = result.modified
 
181
        except AttributeError:
 
182
            pass
 
183
        try:
 
184
            self.etag[name] = result.etag
 
185
        except AttributeError:
 
186
            pass
 
187
        if status == 304:
 
188
            return self.rawresults[name]
 
189
        else:
 
190
            self.rawresults[name] = result.entries
 
191
        return result.entries
130
192
 
131
193
class Rsswatcher(Rssdict):
132
194
 
134
196
 
135
197
    def __init__(self, filename):
136
198
        Rssdict.__init__(self, filename)
137
 
        self.results = {}
138
 
        self.jobids = {}
 
199
        
 
200
    def sync(self, name):
 
201
        result = self.getdata(name)
 
202
        if result:
 
203
            self.results[name] = result
139
204
 
140
205
    def changeinterval(self, name, interval):
141
206
        periodical.changeinterval(self.jobids[name], interval)
142
207
 
 
208
    @locked
143
209
    def startwatchers(self):
144
210
        """ start watcher threads """
145
 
        for i in self.data.values():
 
211
        for j, i in self.data.iteritems():
146
212
            if i.running:
147
 
                try:
148
 
                    self.watch(i.name)
149
 
                except Exception, ex:
150
 
                    rlog(100, 'rss', '%s feed error: %s' % (i.name, str(ex)))
151
 
                    continue
152
 
                rlog(10, 'rss', 'started %s rss watch' % i.name)
 
213
                thr.start_new_thread(self.watch, (i.name, ))
153
214
 
 
215
    @locked
154
216
    def stopwatchers(self):
155
217
        """ stop all watcher threads """
156
 
        for i in self.data.values():
 
218
        for j, i in self.data.iteritems():
157
219
            if i.running:
158
220
                i.stoprunning = 1
159
221
        periodical.killgroup('rss')
160
 
        
 
222
 
 
223
    def dowatch(self, name, sleeptime=1800):
 
224
        rssitem = self.byname(name)
 
225
        if not rssitem:
 
226
            rlog(10, 'rss', "no %s rss item available" % name)
 
227
            return
 
228
        while 1:
 
229
            try:
 
230
                self.watch(name)
 
231
            except Exception, ex:
 
232
                rlog(100, 'rss', '%s feed error: %s' % (name, str(ex)))
 
233
                rlog(100, 'rss', '%s sleeping %s seconds for retry' % \
 
234
(name, sleeptime))
 
235
                time.sleep(sleeptime)
 
236
                if not rssitem.running:
 
237
                    break
 
238
            else:
 
239
                break
 
240
 
 
241
    def makeresult(self, name, target, data):
 
242
        res = []
 
243
        for j in data:
 
244
            tmp = {}
 
245
            if not self.itemslists[(name, target)]:
 
246
                return []
 
247
            for i in self.itemslists[(name, target)]:
 
248
                try:
 
249
                    tmp[i] = unicode(j[i])
 
250
                except KeyError:
 
251
                    continue
 
252
            res.append(tmp)
 
253
        return res
 
254
 
161
255
    def watch(self, name):
162
256
        """ start a watcher thread """
163
257
        # get basic data
164
 
        result = self.getdata(name)
 
258
        rlog(10, 'rss', 'trying %s rss feed watcher' % name)
 
259
        try:
 
260
            result = self.getdata(name)
 
261
        except RssException, ex:
 
262
            rlog(10, 'rss', "%s error: %s" % (name, str(ex)))
 
263
            result = []
 
264
        rssitem = self.byname(name)
 
265
        if not rssitem:
 
266
            raise RssNoItem()
 
267
        # poll every sleeptime seconds
165
268
        self.results[name] = result
166
 
        rssitem = self.byname(name)
167
 
        # poll every sleeptime seconds
168
269
        pid = periodical.addjob(rssitem.sleeptime, 0, self.peek, name, name)
169
270
        self.jobids[name] = pid
170
 
 
171
 
    def peek(self, name):
 
271
        rlog(10, 'rss', 'started %s rss watch' % name)
 
272
 
 
273
    def makeresponse(self, name, res, channel, sep="\002||\002"):
 
274
        # loop over result to make a response
 
275
        result = ""
 
276
        itemslist = self.itemslists[(name, channel)]
 
277
        if not itemslist:
 
278
            rssitem = self.byname(name)
 
279
            if not rssitem:
 
280
                return "no %s rss item" % name
 
281
            else:
 
282
                self.itemslists.extend((name, channel), rssitem.itemslist)
 
283
                self.itemslists.save()
 
284
        for j in res:
 
285
            resultstr = ""
 
286
            for i in self.itemslists[(name, channel)]:
 
287
                try:
 
288
                    item = unicode(j[i])
 
289
                    if not item:
 
290
                        continue
 
291
                    if item.startswith('http://'):
 
292
                        resultstr += "<%s> - " % item
 
293
                    else:
 
294
                        resultstr += "%s - " % striphtml(item)
 
295
                except KeyError:
 
296
                    continue
 
297
            resultstr = resultstr[:-3]
 
298
            if resultstr:
 
299
                result += "%s %s " % (resultstr, sep)
 
300
        return result[:-6]
 
301
 
 
302
    def peek(self, name, *args):
172
303
        rssitem = self.byname(name)
173
304
        if not rssitem or not rssitem.running or rssitem.stoprunning:
174
305
            return
178
309
            except socket.timeout:
179
310
                rlog(10, 'rss', 'socket timeout of %s' % name)
180
311
                return
 
312
            except RssException, ex:
 
313
                rlog(10, 'rss', '%s error: %s' % (name, str(ex)))
 
314
                return
181
315
            if not res:
182
 
                rlog(10, 'rss', "can't match %s data" % name)
183
 
            # loop over result to see if we already seen item
184
 
            teller = 0
185
 
            res2 = ""
186
 
            for j in res[::-1]:
187
 
                if j not in self.results[name]:
188
 
                    self.results[name].append(j)
 
316
                return
 
317
            res2 = []
 
318
            for j in res:
 
319
                try:
 
320
                    d = j['date']
 
321
                except KeyError:
 
322
                    if j not in self.results[name]:
 
323
                        self.results[name].append(j)
 
324
                        res2.append(j)
189
325
                else:
 
326
                    if not checkfordate(self.results[name], d):
 
327
                        self.results[name].append(j)
 
328
                        res2.append(j)
 
329
            if not res2:
 
330
                return
 
331
            for item in rssitem.watchchannels:
 
332
                try:
 
333
                    (botname, channel) = item
 
334
                except:
 
335
                    rlog(10, 'rss', '%s is not in the format \
 
336
(botname,channel)' % str(item))
 
337
                bot = fleet.byname(botname)
 
338
                if not bot:
190
339
                    continue
191
 
                teller += 1
192
 
                resultstr = ""
193
 
                for i in rssitem.itemslist:
194
 
                    try:
195
 
                        if j[i].startswith('http://'):
196
 
                            resultstr += "<%s> - " % j[i]
197
 
                        else:
198
 
                            resultstr += "%s - " % j[i]
199
 
                    except KeyError:
200
 
                            continue
201
 
                resultstr = resultstr[:-3]
202
 
                res2 += "%s \002||\002 " % resultstr
203
 
            if res2:
204
 
                for item in rssitem.watchchannels:
205
 
                    try:
206
 
                        (botname, channel) = item
207
 
                        bot = fleet.byname(botname)
208
 
                        if not bot:
209
 
                            rlog(10, 'rss', "can't find bot %s in fleet" \
210
 
% botname)
211
 
                            return
212
 
                        bot.say(channel, "%s: %s" % (rssitem.name, res2[:-4]))
213
 
                    except:
214
 
                        rlog(10, 'rss', '%s is not in the format \
215
 
(botname,channel)' % item)
 
340
                if self.markup.get((name, channel), 'all-lines'):
 
341
                    for i in res2:
 
342
                        response = self.makeresponse(name, [i, ], channel)
 
343
                        bot.say(channel, "\002%s\002: %s" % \
 
344
(rssitem.name, response), fromm=rssitem.name)
 
345
                else:
 
346
                    sep =  self.markup.get((name, channel), 'seperator')
 
347
                    if sep:
 
348
                        response = self.makeresponse(name, res2, channel, \
 
349
sep=sep)
 
350
                    else:
 
351
                        response = self.makeresponse(name, res2, channel)
 
352
                    bot.say(channel, "\002%s\002: %s" % (rssitem.name, \
 
353
response), fromm=rssitem.name)
216
354
        except Exception, ex:
217
355
            handle_exception(txt=name)
218
356
 
 
357
    @locked
219
358
    def stopwatch(self, name):
220
359
        """ stop watcher thread """
221
360
        for i, j in self.data.iteritems():
232
371
                    pass
233
372
                return 1
234
373
 
 
374
    @locked
235
375
    def list(self):
236
376
        """ return of rss names """
237
 
        return self.data.keys()
 
377
        feeds = self.data.keys()
 
378
        return feeds
238
379
 
 
380
    @locked
239
381
    def runners(self):  
240
382
        """ show names/channels of running watchers """
241
383
        result = []
242
 
        for i in self.data.values():
 
384
        for j, i in self.data.iteritems():
243
385
            if i.running == 1 and not i.stoprunning: 
244
386
                result.append((i.name, i.watchchannels))
245
387
        return result
246
388
 
 
389
    @locked
247
390
    def feeds(self, botname, channel):
248
391
        """ show names/channels of running watcher """
249
392
        result = []
250
 
        for i in self.data.values():
 
393
        for j, i in self.data.iteritems():
251
394
            if (botname, channel) in i.watchchannels:
252
395
                result.append(i.name)
253
396
        return result
254
397
 
 
398
    @locked
255
399
    def url(self, name):
256
400
        """ return url of rssitem """
257
 
        for i in self.data.values():
 
401
        for j, i in self.data.iteritems():
258
402
            if i.name == name:
259
403
                return i.url
260
404
 
261
405
    def scan(self, name):
262
406
        """ scan a rss url for used xml items """
263
407
        try:
264
 
            result = fromenc(geturl2(self.url(name), True))
265
 
        except Exception, ex:
266
 
            rlog(10, 'rss', str(ex))
267
 
            return None
268
 
        reslist = rsslist(result)
 
408
            result = self.getdata(name)
 
409
        except RssException, ex:
 
410
            rlog(10, 'rss', '%s error: %s' % (name, str(ex)))
 
411
            return
 
412
        if not result:
 
413
            return
 
414
        keys = []
 
415
        for item in self.rawresults[name]:
 
416
             for key in item.keys():
 
417
                 keys.append(key)            
269
418
        statdict = Statdict()
270
 
        for i in reslist:
271
 
            for j, z in i.iteritems():
272
 
                if z:
273
 
                    statdict.upitem(j)
274
 
        return statdict.top(start=2)
 
419
        for key in keys:
 
420
            statdict.upitem(key)
 
421
        return statdict.top()  
 
422
 
 
423
    def search(self, name, item, search):
 
424
        res = []
 
425
        for result in self.rawresults[name]:
 
426
            try:
 
427
                title = result['title']
 
428
                txt = result[item]
 
429
            except KeyError:
 
430
                continue
 
431
            if search in title.lower():
 
432
                if txt:
 
433
                   res.append(txt)
 
434
        return res
 
435
 
 
436
    def searchall(self, item, search):
 
437
        res = []
 
438
        for name, results in self.rawresults.iteritems():
 
439
            for result in results:
 
440
                try:
 
441
                    title = result['title']
 
442
                    txt = result[item]
 
443
                except KeyError:
 
444
                    continue
 
445
                if search in title.lower():
 
446
                    if txt:
 
447
                        res.append("%s: %s" % (name, txt))
 
448
        return res
 
449
 
 
450
    def all(self, name, item):
 
451
        res = []
 
452
        for result in self.rawresults[name]:
 
453
            try:
 
454
                txt = result[item]
 
455
            except KeyError:
 
456
                continue
 
457
            if txt:
 
458
                res.append(txt)
 
459
        return res
275
460
 
276
461
watcher = Rsswatcher(datadir + os.sep + 'rss')
277
462
 
299
484
    watcher.add(name, url)
300
485
    ievent.reply('rss item added')
301
486
 
302
 
cmnds.add('rss-add', handle_rssadd, ['RSS', 'OPER', 'USER'])
 
487
cmnds.add('rss-add', handle_rssadd, 'OPER')
303
488
examples.add('rss-add', 'rss-add <name> <url> to the rsswatcher', 'rss-add \
304
489
gozerbot http://gozerbot.org/hg/gozerbot/?cmd=changelog;style=rss')
305
490
 
317
502
    else:
318
503
        ievent.reply('there is no %s rss item' % name)
319
504
 
320
 
cmnds.add('rss-del', handle_rssdel, ['RSS', 'OPER'])
 
505
cmnds.add('rss-del', handle_rssdel, 'OPER')
321
506
examples.add('rss-del', 'rss-del <name> .. remove <name> from the \
322
507
rsswatcher', 'rss-del mekker')
323
508
 
343
528
    if rssitem == None:
344
529
        ievent.reply("we don't have a %s rss object" % name)
345
530
        return
346
 
    if (bot.name, ievent.channel) not in rssitem.watchchannels:
347
 
        rssitem.watchchannels.append((bot.name, ievent.channel))
 
531
    got = None
 
532
    if not rssitem.running:
348
533
        rssitem.sleeptime = sleepsec
349
534
        rssitem.running = 1
350
535
        rssitem.stoprunning = 0
 
536
        got = True
351
537
        watcher.save()
352
538
        try:
353
539
            watcher.watch(name)
354
540
        except Exception, ex:
355
541
            ievent.reply(str(ex))
356
542
            return
 
543
    if got:
 
544
        watcher.save()
357
545
        ievent.reply('watcher started')
358
546
    else:
359
547
        ievent.reply('already watching %s' % name)
360
548
 
361
 
cmnds.add('rss-watch', handle_rsswatch, ['RSS', 'OPER'])
 
549
cmnds.add('rss-watch', handle_rsswatch, 'OPER')
362
550
examples.add('rss-watch', 'rss-watch <name> [seconds to sleep] .. go \
363
551
watching <name>', '1) rss-watch gozerbot 2) rss-watch gozerbot 600')
364
552
 
 
553
def handle_rssstart(bot, ievent):
 
554
    """ rss-start <name> .. start a rss feed to a user """
 
555
    if not ievent.rest:
 
556
       ievent.missing('<feed name>')
 
557
       return
 
558
    name = ievent.rest
 
559
    rssitem = watcher.byname(name)
 
560
    if bot.jabber:
 
561
        target = ievent.userhost
 
562
    else:
 
563
        if users.allowed(ievent.userhost, ['OPER', ]) and not ievent.msg:
 
564
            target = ievent.channel
 
565
        else:
 
566
            target = ievent.nick
 
567
    if rssitem == None:
 
568
        ievent.reply("we don't have a %s rss object" % name)
 
569
        return
 
570
    if not rssitem.running:
 
571
        ievent.reply('%s watcher is not running' % name)
 
572
        return
 
573
    if (bot.name, target) in rssitem.watchchannels:
 
574
        ievent.reply('we are already monitoring %s on (%s,%s)' % \
 
575
(name, bot.name, target))
 
576
        return
 
577
    rssitem.watchchannels.append((bot.name, target))
 
578
    for item in rssitem.itemslist:
 
579
        watcher.itemslists.adduniq((name, target), item)
 
580
    watcher.save()
 
581
    ievent.reply('%s started' % name)
 
582
 
 
583
cmnds.add('rss-start', handle_rssstart, ['RSS', 'USER'])
 
584
examples.add('rss-start', 'rss-start <name> .. start a rss feed \
 
585
(per user/channel) ', 'rss-start gozerbot')
 
586
 
 
587
def handle_rssstop(bot, ievent):
 
588
    """ rss-start <name> .. start a rss feed to a user """
 
589
    if not ievent.rest:
 
590
       ievent.missing('<feed name>')
 
591
       return
 
592
    name = ievent.rest
 
593
    rssitem = watcher.byname(name)
 
594
    if bot.jabber:
 
595
        target = ievent.userhost
 
596
    else:
 
597
        if users.allowed(ievent.userhost, ['OPER', ]) and not ievent.msg:
 
598
            target = ievent.channel
 
599
        else:
 
600
            target = ievent.nick
 
601
    if rssitem == None:
 
602
        ievent.reply("we don't have a %s rss feed" % name)
 
603
        return
 
604
    if not rssitem.running:
 
605
        ievent.reply('%s watcher is not running' % name)
 
606
        return
 
607
    if not (bot.name, target) in rssitem.watchchannels:
 
608
        ievent.reply('we are not monitoring %s on (%s,%s)' % \
 
609
(name, bot.name, target))
 
610
        return
 
611
    rssitem.watchchannels.remove((bot.name, target))
 
612
    watcher.save()
 
613
    ievent.reply('%s stopped' % name)
 
614
 
 
615
cmnds.add('rss-stop', handle_rssstop, ['RSS', 'USER'])
 
616
examples.add('rss-stop', 'rss-stop <name> .. stop a rss feed \
 
617
(per user/channel) ', 'rss-stop gozerbot')
 
618
 
365
619
def handle_rsschannels(bot, ievent):
366
620
    """ rss-channels <name> .. show channels of rss feed """
367
621
    try:
381
635
        result.append(str(i))
382
636
    ievent.reply("channels of %s: " % name, result, dot=True)
383
637
 
384
 
cmnds.add('rss-channels', handle_rsschannels, ['RSS', 'OPER'])
 
638
cmnds.add('rss-channels', handle_rsschannels, 'OPER')
385
639
examples.add('rss-channels', 'rss-channels <name> .. show channels', \
386
640
'rss-channels gozerbot')
387
641
 
417
671
    watcher.save()
418
672
    ievent.reply('%s added to %s rss item' % (channel, name))
419
673
 
420
 
cmnds.add('rss-addchannel', handle_rssaddchannel, ['RSS', 'OPER'])
 
674
cmnds.add('rss-addchannel', handle_rssaddchannel, 'OPER')
421
675
examples.add('rss-addchannel', 'rss-addchannel <name> [<botname>] <channel> \
422
676
..add <channel> or <botname> <channel> to watchchannels of <name>', \
423
677
'1) rss-addchannel gozerbot #dunkbots 2) rss-addchannel gozerbot main \
424
678
#dunkbots')
425
679
 
426
 
def handle_rssstart(bot, ievent):
427
 
    """ rss-start <name> .. start a rss feed to a user """
428
 
    if not ievent.rest:
429
 
       ievent.missing('<feed name>')
430
 
       return
431
 
    name = ievent.rest
432
 
    rssitem = watcher.byname(name)
433
 
    if bot.jabber:
434
 
        target = ievent.userhost
435
 
    else:
436
 
        target = ievent.nick
437
 
    if rssitem == None:
438
 
        ievent.reply("we don't have a %s rss object" % name)
439
 
        return
440
 
    if not rssitem.running:
441
 
        ievent.reply('%s watcher is not running' % name)
442
 
        return
443
 
    if (bot.name, target) in rssitem.watchchannels:
444
 
        ievent.reply('we are already monitoring %s on (%s,%s)' % \
445
 
(name, bot.name, target))
446
 
        return
447
 
    rssitem.watchchannels.append((bot.name, target))
448
 
    watcher.save()
449
 
    ievent.reply('%s started' % name)
450
 
 
451
 
cmnds.add('rss-start', handle_rssstart, ['USER'])
452
 
examples.add('rss-start', 'rss-start <name> .. start a rss watcher ',\
453
 
'rss-start gozerbot')
454
 
 
455
 
def handle_rssstop(bot, ievent):
456
 
    """ rss-start <name> .. start a rss feed to a user """
457
 
    if not ievnt.rest:
458
 
       ievent.missing('<feed name>')
459
 
       return
460
 
    name = ievent.rest
461
 
    rssitem = watcher.byname(name)
462
 
    if bot.jabber:
463
 
        target = ievent.userhost
464
 
    else:
465
 
        target = ievent.nick
466
 
    if rssitem == None:
 
680
def handle_rssadditem(bot, ievent):
 
681
    try:
 
682
        (name, item) = ievent.args
 
683
    except ValueError:
 
684
        ievent.missing('<name> <item>')
 
685
        return
 
686
    if bot.jabber or users.allowed(ievent.userhost, ['OPER', ]):
 
687
        target = ievent.channel.lower()
 
688
    else:
 
689
        target = ievent.nick.lower()
 
690
    if not watcher.byname(name):
 
691
        ievent.reply("we don't have a %s feed" % name)
 
692
        return
 
693
    watcher.itemslists.adduniq((name, target), item)
 
694
    watcher.itemslists.save()
 
695
    #watcher.sync(name)
 
696
    ievent.reply('%s added to (%s,%s) itemslist' % (item, name, target))
 
697
 
 
698
cmnds.add('rss-additem', handle_rssadditem, ['RSS', 'USER'])
 
699
examples.add('rss-additem', 'add a token to the itemslist (per user/channel)',\
 
700
 'rss-additem gozerbot link')
 
701
 
 
702
def handle_rssdelitem(bot, ievent):
 
703
    try:
 
704
        (name, item) = ievent.args
 
705
    except ValueError:
 
706
        ievent.missing('<name> <item>')
 
707
        return
 
708
    if users.allowed(ievent.userhost, ['OPER', 'RSS']):
 
709
        target = ievent.channel.lower()
 
710
    else:
 
711
        target = ievent.nick.lower()
 
712
    if not watcher.byname(name):
 
713
        ievent.reply("we don't have a %s feed" % name)
 
714
        return
 
715
    try:
 
716
        watcher.itemslists.remove((name, target), item)
 
717
        watcher.itemslists.save()
 
718
    except RssNoSuchItem:
467
719
        ievent.reply("we don't have a %s rss feed" % name)
468
720
        return
469
 
    if not rssitem.running:
470
 
        ievent.reply('%s watcher is not running' % name)
471
 
        return
472
 
    if not (bot.name, channel) in rssitem.watchchannels:
473
 
        ievent.reply('we are not monitoring %s on (%s,%s)' % \
474
 
(name, bot.name, channel))
475
 
        return
476
 
    rssitem.watchchannels.remove((bot.name, ievent.target))
477
 
    watcher.save()
478
 
    ievent.reply('%s stopped' % name)
479
 
 
480
 
cmnds.add('rss-stop', handle_rssstop, ['USER'])
481
 
examples.add('rss-stop', 'rss-stop <name> .. stop a rss watcher ',\
482
 
'rss-stop gozerbot')
 
721
    ievent.reply('%s removed from (%s,%s) itemslist' % (item, name, target))
 
722
 
 
723
cmnds.add('rss-delitem', handle_rssdelitem, ['RSS', 'USER'])
 
724
examples.add('rss-delitem', 'remove a token from the itemslist \
 
725
(per user/channel)', 'rss-delitem gozerbot link')
 
726
 
 
727
def handle_rssmarkup(bot, ievent):
 
728
    try:
 
729
        name = ievent.args[0]
 
730
    except IndexError:
 
731
        ievent.missing('<name>')
 
732
        return
 
733
    if users.allowed(ievent.userhost, ['OPER', ]):
 
734
        target = ievent.channel.lower()
 
735
    else:
 
736
        target = ievent.nick.lower()
 
737
    try:
 
738
        ievent.reply(str(watcher.markup[(name, target)]))
 
739
    except KeyError:
 
740
        pass
 
741
 
 
742
cmnds.add('rss-markup', handle_rssmarkup, ['RSS', 'USER'])
 
743
examples.add('rss-markup', 'show markup list for a feed (per user/channel)', \
 
744
'rss-markup gozerbot')
 
745
 
 
746
def handle_rssaddmarkup(bot, ievent):
 
747
    try:
 
748
        (name, item, value) = ievent.args
 
749
    except ValueError:
 
750
        ievent.missing('<name> <item> <value>')
 
751
        return
 
752
    if users.allowed(ievent.userhost, ['OPER', ]):
 
753
        target = ievent.channel.lower()
 
754
    else:
 
755
        target = ievent.nick.lower()
 
756
    try:
 
757
        watcher.markup.set((name, target), item, value)
 
758
        watcher.markup.save()
 
759
        ievent.reply('%s added to (%s,%s) markuplist' % (item, name, target))
 
760
    except KeyError:
 
761
        ievent.reply("no (%s,%s) feed available" % (name, target))
 
762
 
 
763
cmnds.add('rss-addmarkup', handle_rssaddmarkup, ['RSS', 'USER'])
 
764
examples.add('rss-addmarkup', 'add a markup option to the markuplist \
 
765
(per user/channel)', 'rss-addmarkup gozerbot noseperator 1')
 
766
 
 
767
def handle_rssdelmarkup(bot, ievent):
 
768
    try:
 
769
        (name, item) = ievent.args
 
770
    except ValueError:
 
771
        ievent.missing('<name> <item>')
 
772
        return
 
773
    if users.allowed(ievent.userhost, ['OPER', 'RSS']):
 
774
        target = ievent.channel.lower()
 
775
    else:
 
776
        target = ievent.nick.lower()
 
777
    try:
 
778
        del watcher.markup[(name, target)][item]
 
779
    except (KeyError, TypeError):
 
780
        ievent.reply("can't remove %s from %s feed's markup" %  (item, name))
 
781
        return
 
782
    watcher.markup.save()
 
783
    ievent.reply('%s removed from (%s,%s) markuplist' % (item, name, target))
 
784
 
 
785
cmnds.add('rss-delmarkup', handle_rssdelmarkup, ['RSS', 'USER'])
 
786
examples.add('rss-delmarkup', 'remove a markup option from the markuplist \
 
787
(per user/channel)', 'rss-delmarkup gozerbot noseperator')
483
788
 
484
789
def handle_rssdelchannel(bot, ievent):
485
790
    """ rss-delchannel <name> [<botname>] <channel> .. delete channel \
511
816
    ievent.reply('%s removed from %s rss item' % (channel, name))
512
817
    watcher.save()
513
818
 
514
 
cmnds.add('rss-delchannel', handle_rssdelchannel, ['RSS', 'OPER'])
 
819
cmnds.add('rss-delchannel', handle_rssdelchannel, 'OPER')
515
820
examples.add('rss-delchannel', 'rss-delchannel <name> [<botname>] \
516
821
[<channel>] .. delete <channel> or <botname> <channel> from watchchannels of \
517
822
<name>', '1) rss-delchannel gozerbot #dunkbots 2) rss-delchannel gozerbot \
518
823
main #dunkbots')
519
 
aliasset('rss-stop', 'rss-delchannel')
520
824
 
521
825
def handle_rssstopwatch(bot, ievent):
522
826
    """ rss-stopwatch <name> .. stop a watcher thread """
529
833
    if not rssitem:
530
834
        ievent.reply("there is no %s rssitem" % name)
531
835
        return
532
 
    if (bot.name, ievent.channel) not in rssitem.watchchannels:
533
 
        ievent.reply("we are not watching %s in %s" % (rssitem.name, \
534
 
ievent.channel))
535
 
        return
536
836
    if not watcher.stopwatch(name):
537
837
        ievent.reply("can't stop %s watcher" % name)
538
838
        return
539
 
    rssitem.watchchannels.remove((bot.name, ievent.channel))
540
839
    ievent.reply('stopped %s rss watch' % name)
541
840
 
542
 
cmnds.add('rss-stopwatch', handle_rssstopwatch, ['RSS', 'OPER'])
 
841
cmnds.add('rss-stopwatch', handle_rssstopwatch, 'OPER')
543
842
examples.add('rss-stopwatch', 'rss-stopwatch <name> .. stop polling <name>', \
544
843
'rss-stopwatch gozerbot')
545
844
 
560
859
    except AttributeError:
561
860
        ievent.reply("can't get sleeptime for %s" % name)
562
861
 
563
 
cmnds.add('rss-sleeptime', handle_rsssleeptime, ['RSS', 'OPER'])
 
862
cmnds.add('rss-sleeptime', handle_rsssleeptime, 'OPER')
564
863
examples.add('rss-sleeptime', 'rss-sleeptime <name> .. get sleeping time \
565
864
for <name>', 'rss-sleeptime gozerbot')
566
865
 
585
884
    watcher.save()
586
885
    ievent.reply('sleeptime set')
587
886
 
588
 
cmnds.add('rss-setsleeptime', handle_rsssetsleeptime, ['RSS', 'OPER'])
 
887
cmnds.add('rss-setsleeptime', handle_rsssetsleeptime, 'OPER')
589
888
examples.add('rss-setsleeptime', 'rss-setsleeptime <name> <seconds> .. set \
590
889
sleeping time for <name> .. min 60 sec', 'rss-setsleeptime gozerbot 600')
591
890
 
603
902
    try:
604
903
        result = watcher.getdata(name)
605
904
    except Exception, ex:
606
 
        ievent.reply(str(ex))
 
905
        ievent.reply('%s error: %s' % (name, str(ex)))
607
906
        return
608
 
    resultstr = ""
609
 
    res = []
610
 
    for i in result[::-1]:
611
 
        tempstr = ""
612
 
        for j in range(len(rssitem.itemslist)):
613
 
            try:
614
 
                item = rssitem.itemslist[j]
615
 
                if i[item].startswith('http://'):
616
 
                    tempstr += "<%s> - " % i[item]
617
 
                else:
618
 
                    tempstr += "%s - " % i[item]
619
 
            except KeyError:
620
 
                continue
621
 
        if tempstr:
622
 
            res.append(tempstr[:-3].strip())
623
 
    if res:
624
 
        ievent.reply("results of %s: " % name, res, dot=" \002||\002 ")
 
907
    response = watcher.makeresponse(name, result, ievent.channel)
 
908
    if response:
 
909
        ievent.reply("results of %s: %s" % (name, response))
625
910
    else:
626
911
        ievent.reply("can't match watcher data")
627
912
 
641
926
    else:
642
927
        ievent.reply('nothing running yet')
643
928
 
644
 
cmnds.add('rss-running', handle_rssrunning, ['RSS', 'OPER'])
 
929
cmnds.add('rss-running', handle_rssrunning, ['RSS', 'USER'])
645
930
examples.add('rss-running', 'rss-running .. get running rsswatchers', \
646
931
'rss-running')
647
932
 
671
956
examples.add('rss-url', 'rss-url <name> .. get url from rssitem with \
672
957
<name>', 'rss-url gozerbot')
673
958
 
674
 
def handle_rssadditemslist(bot, ievent):
675
 
    """ rss-additemslist <name> <item> .. add item to itemslist of rss item """
676
 
    try:
677
 
        (name, item) = ievent.args
678
 
    except ValueError:
679
 
        ievent.missing('<name> <item>')
680
 
        return
681
 
    rssitem = watcher.byname(name)
682
 
    if rssitem == None:
683
 
        ievent.reply("we don't have a %s rss item" % name)
684
 
        return
685
 
    if item not in rssitem.itemslist:
686
 
        rssitem.itemslist.append(item)
687
 
    else:
688
 
        ievent.reply('%s is already in %s rsslist' % (item, name))
689
 
        return
690
 
    watcher.save()
691
 
    ievent.reply('%s added to itemslist' % item)
692
 
 
693
 
cmnds.add('rss-additemslist', handle_rssadditemslist, ['RSS', 'OPER'])
694
 
examples.add('rss-additemslist', 'rss-additemslist <name> <item> .. add to \
695
 
itemslist of <name> ', 'rss-additemslist gozerbot url')
696
 
 
697
 
def handle_rssdelitemslist(bot, ievent):
698
 
    """ rss-delitemslist <name> <item> .. delete item from itemslist """
699
 
    try:
700
 
        (name, item) = ievent.args
701
 
    except ValueError:
702
 
        ievent.missing('<name> <item>')
703
 
        return
704
 
    rssitem = watcher.byname(name)
705
 
    if rssitem == None:
706
 
        ievent.reply("we don't have a %s rss item" % name)
707
 
        return
708
 
    if item in rssitem.itemslist:
709
 
        rssitem.itemslist.remove(item)
710
 
        watcher.save()
711
 
        ievent.reply('%s deleted from itemslist' % item)
712
 
    else:
713
 
        ievent.reply("%s doesn't have %s in itemslist" % (name, item))
714
 
 
715
 
cmnds.add('rss-delitemslist', handle_rssdelitemslist, ['RSS', 'OPER'])
716
 
examples.add('rss-delitemslist', 'rss-delitemslist <name> <item> .. \
717
 
delete from itemslist of <name> ', 'rss-delitemslist gozerbot url')
718
 
 
719
959
def handle_rssitemslist(bot, ievent):
720
960
    """ rss-itemslist <name> .. show itemslist of rss item """
721
961
    try:
723
963
    except IndexError:
724
964
        ievent.missing('<name>')
725
965
        return
726
 
    rssitem = watcher.byname(name)
727
 
    if rssitem == None:
728
 
        ievent.reply("we don't have a %s rss item" % name)
 
966
    try:
 
967
        itemslist = watcher.itemslists[(name, ievent.channel.lower())]
 
968
    except KeyError:
 
969
        ievent.reply("no itemslist set for (%s, %s)" % (name, \
 
970
ievent.channel.lower()))
729
971
        return
730
 
    if rssitem.itemslist:
731
 
        ievent.reply("itemslist of %s: " % name, rssitem.itemslist, dot=True)
732
 
    else:
733
 
        ievent.reply('%s had no itemslist set' % name)
 
972
    ievent.reply("itemslist of (%s, %s): " % (name, ievent.channel.lower()), \
 
973
itemslist, dot=True)
734
974
 
735
 
cmnds.add('rss-itemslist', handle_rssitemslist, ['RSS', 'OPER'])
 
975
cmnds.add('rss-itemslist', handle_rssitemslist, ['RSS', 'USER'])
736
976
examples.add('rss-itemslist', 'rss-itemslist <name> .. get itemslist of \
737
977
<name> ', 'rss-itemslist gozerbot')
738
978
 
742
982
        name = ievent.args[0]
743
983
    except IndexError:
744
984
        ievent.missing('<name>')
745
 
        return 
 
985
        return
 
986
    if not watcher.byname(name):
 
987
        ievent.reply('no %s feeds available' % name)
 
988
        return
746
989
    try:
747
990
        result = watcher.scan(name)
748
991
    except Exception, ex:
756
999
        res.append("%s=%s" % i)
757
1000
    ievent.reply("tokens of %s: " % name, res)
758
1001
 
759
 
cmnds.add('rss-scan', handle_rssscan, ['RSS', 'OPER'])
760
 
examples.add('rss-scan', 'rss-scan <name> .. get items of <name> ', \
 
1002
cmnds.add('rss-scan', handle_rssscan, 'OPER')
 
1003
examples.add('rss-scan', 'rss-scan <name> .. get possible items of <name> ', \
761
1004
'rss-scan gozerbot')
762
1005
 
763
1006
def handle_rsssync(bot, ievent):
768
1011
        ievent.missing('<name>')
769
1012
        return
770
1013
    try:
771
 
        result = watcher.getdata(name)
772
 
        watcher.results[name] = result
 
1014
        result = watcher.sync(name)
773
1015
        ievent.reply('%s synced' % name)
774
1016
    except Exception, ex:
775
 
        ievent.reply("ERROR: %s" % str(ex))
 
1017
        ievent.reply("%s error: %s" % (name, str(ex)))
776
1018
 
777
 
cmnds.add('rss-sync', handle_rsssync, ['RSS', 'OPER'])
 
1019
cmnds.add('rss-sync', handle_rsssync, 'OPER')
778
1020
examples.add('rss-sync', 'rss-sync <name> .. sync data of <name>', \
779
1021
'rss-sync gozerbot')
780
1022
 
783
1025
    try:
784
1026
        channel = ievent.args[0]
785
1027
    except IndexError:
786
 
        channel = ievent.channel
 
1028
        channel = ievent.printto
787
1029
    try:
788
1030
        result = watcher.feeds(bot.name, channel)
789
1031
        if result:
793
1035
    except Exception, ex:
794
1036
        ievent.reply("ERROR: %s" % str(ex))
795
1037
 
796
 
cmnds.add('rss-feeds', handle_rssfeeds, ['RSS', 'OPER'])
 
1038
cmnds.add('rss-feeds', handle_rssfeeds, ['USER', 'RSS'])
797
1039
examples.add('rss-feeds', 'rss-feeds <name> .. show what feeds are running \
798
1040
in a channel', '1) rss-feeds 2) rss-feeds #dunkbots')
 
1041
 
 
1042
def handle_rsslink(bot, ievent):
 
1043
    try:
 
1044
        feed, rest = ievent.rest.split(' ', 1)
 
1045
    except ValueError:
 
1046
        ievent.missing('<feed> <words to search>')
 
1047
        return
 
1048
    rest = rest.strip().lower()
 
1049
    try:
 
1050
        res = watcher.search(feed, 'link', rest)
 
1051
        if not res:
 
1052
            res = watcher.search(feed, 'feedburner:origLink', rest)
 
1053
        if res:
 
1054
            ievent.reply(res, dot=" \002||\002 ")
 
1055
    except KeyError:
 
1056
        ievent.reply('no %s feed data available' % feed)
 
1057
        return
 
1058
 
 
1059
cmnds.add('rss-link', handle_rsslink, ['RSS', 'USER'])
 
1060
examples.add('rss-link', 'give link of item which title matches search key', \
 
1061
'rss-link gozerbot gozer')
 
1062
 
 
1063
def handle_rssdescription(bot, ievent):
 
1064
    try:
 
1065
        feed, rest = ievent.rest.split(' ', 1)
 
1066
    except ValueError:
 
1067
        ievent.missing('<feed> <words to search>')
 
1068
        return
 
1069
    rest = rest.strip().lower()
 
1070
    res = ""
 
1071
    try:
 
1072
        ievent.reply(watcher.search(feed, 'description', rest), \
 
1073
dot=" \002||\002 ")
 
1074
    except KeyError:
 
1075
        ievent.reply('no %s feed data available' % feed)
 
1076
        return
 
1077
 
 
1078
cmnds.add('rss-description', handle_rssdescription, ['RSS', 'USER'])
 
1079
examples.add('rss-description', 'give description of item which title \
 
1080
matches search key', 'rss-description gozerbot gozer')
 
1081
 
 
1082
def handle_rssall(bot, ievent):
 
1083
    try:
 
1084
        feed = ievent.args[0]
 
1085
    except IndexError:
 
1086
        ievent.missing('<feed>')
 
1087
        return
 
1088
    try:
 
1089
        ievent.reply(watcher.all(feed, 'title'), dot=" \002||\002 ")
 
1090
    except KeyError:
 
1091
        ievent.reply('no %s feed data available' % feed)
 
1092
        return
 
1093
 
 
1094
cmnds.add('rss-all', handle_rssall, ['RSS', 'USER'])
 
1095
examples.add('rss-all', "give titles of a feed", 'rss-all gozerbot')
 
1096
 
 
1097
def handle_rsssearch(bot, ievent):
 
1098
    try:
 
1099
        txt = ievent.args[0]
 
1100
    except IndexError:
 
1101
        ievent.missing('<txt>')
 
1102
        return
 
1103
    try:        
 
1104
        ievent.reply(watcher.searchall('title', txt), dot=" \002||\002 ")
 
1105
    except KeyError:
 
1106
        ievent.reply('no %s feed data available' % feed)
 
1107
        return
 
1108
 
 
1109
cmnds.add('rss-search', handle_rsssearch, ['RSS', 'USER'])
 
1110
examples.add('rss-search', "search titles of all current feeds", \
 
1111
'rss-search goz')
 
1112
 
 
1113
def handle_rssdump(bot, ievent):
 
1114
    try:
 
1115
        ievent.reply(str(watcher.rawresults[ievent.rest]))
 
1116
    except Exception, ex:
 
1117
        ievent.reply(str(ex))
 
1118
 
 
1119
cmnds.add('rss-dump', handle_rssdump, 'OPER')
 
1120
examples.add('rss-dump', 'dump cached rss data', 'rss-dump')