Make rssnotify module suck significantly less

master
sfan5 2016-08-04 00:21:24 +02:00
parent 12d6c11e6b
commit dfe8fdc6c2
1 changed files with 111 additions and 115 deletions

View File

@ -1,15 +1,16 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
rssnotify.py - Phenny RssNotify Module rssnotify.py - Phenny RSSNotify Module
Copyright 2013, sfan5 Copyright 2016, sfan5
Licensed under GNU General Public License v2.0 Licensed under GNU General Public License v2.0
""" """
import time import time
import re import re
import web import web
import os import os
import threading
import feedparser # sudo pip install feedparser import feedparser # sudo pip install feedparser
rssnotify = {}
def to_unix_time(tstr): def to_unix_time(tstr):
if tstr.endswith("Z"): if tstr.endswith("Z"):
@ -31,125 +32,120 @@ def to_unix_time(tstr):
ts += int(g[3]) * 60 ts += int(g[3]) * 60
return ts return ts
def excepta(arr, exclude): class RssNotify():
o = [] def __init__(self, config):
for el in arr: self.config = config
if not el in exclude: self.last_updated = {}
o.append(el) self.last_check = 0
return o self.firstrun = True
for i in range(len(self.config["feeds"])):
rssnotify["last_updated_feeds"] = {} self.last_updated[i] = 0
rssnotify["logfilepath"] = os.getcwd() + "/rssnotify.log" def needs_check(self):
rssnotify["dont_print_first_message"] = True # prevents spam when restarting the bot/reloading the module return time.time() > self.last_check + self.config["check_interval"]
rssnotify["update_cooldown"] = 60 # in seconds def check(self, phenny):
rssnotify["show_commit_link"] = True start = self.last_check = time.time()
rssnotify["use_git.io"] = True print("[RssNotify]: Checking RSS feeds...")
rssnotify["last_update"] = time.time() - rssnotify["update_cooldown"] for fid, feedspec in enumerate(self.config["feeds"]):
feed = feedparser.parse(feedspec[0], agent="Mozilla/5.0 (compatible; MinetestBot)")
def rsscheck(phenny, input): updated = 0
t = time.time() for entry in feed.entries:
if rssnotify["last_update"] > t-rssnotify["update_cooldown"]: if self.last_updated[fid] >= to_unix_time(entry.updated):
return
rssnotify["last_update"] = t
print("[RssNotify]: Checking RSS Feeds...")
start = time.time()
allchans = excepta(phenny.bot.channels, ['##minebest'])
feeds = [
('https://github.com/minetest/minetest/commits/master.atom', allchans),
('https://github.com/minetest/minetest_game/commits/master.atom', allchans),
('https://github.com/minetest/minetestmapper/commits/master.atom', allchans),
('https://github.com/minetest/master-server/commits/master.atom', allchans),
('https://github.com/Uberi/Minetest-WorldEdit/commits/master.atom', allchans),
('https://github.com/Jeija/minetest-mod-mesecons/commits/master.atom', allchans),
('https://github.com/sfan5/phenny/commits/master.atom', ['##minetestbot']),
('https://github.com/sfan5/minetestbot-modules/commits/master.atom', ['##minetestbot']),
('https://github.com/BlockMen/minetest_next/commits/master.atom', allchans),
]
for v in range(0, len(feeds)):
url = feeds[v][0]
feednum = v
options = {
'agent': 'Mozilla/5.0 (MinetestBot)',
'referrer': 'http://minetest.net'
}
feed = feedparser.parse(url, **options)
updcnt = 0
for feed_entry in feed.entries:
if not feednum in rssnotify["last_updated_feeds"].keys():
rssnotify["last_updated_feeds"][feednum] = -1
if rssnotify["last_updated_feeds"][feednum] < to_unix_time(feed_entry.updated):
if rssnotify["dont_print_first_message"]:
continue continue
commiter_realname = feed_entry.authors[0].name if self.firstrun:
if commiter_realname == "": continue
try: message = self._format_msg(entry)
commiter_realname = feed_entry.authors[0].email self._announce(phenny, message, feedspec[1])
except AttributeError: if self.config["logfile"] is not None:
commiter_realname = "Unknown" with open(self.config["logfile"], "a") as f:
try: message = self._format_msg(entry, log_format=True)
commiter = feed_entry.authors[0].href.replace('https://github.com/',"") f.write(message)
except AttributeError: f.write("\n")
commiter = commiter_realname # This will only use the realname if the nickname couldn't be obtained updated += 1
reponame = url.replace("https://github.com/","").replace("/commits/master.atom","") self.last_updated[fid] = max((to_unix_time(e.updated) for e in feed.entries), default=0)
commit_hash = re.search(r"/([a-f0-9]{7})[a-f0-9]*$", feed_entry.links[0].href) if updated > 0:
if commit_hash: print("[RssNotify]: Found %d update(s) for '%s'" % (updated, feedspec[0]))
commit_hash = commit_hash.group(1) if self.firstrun:
else: self.firstrun = False
commit_hash = "?" * 7 print("[RssNotify]: Checked %d RSS feeds in %0.3f seconds" % (len(self.config["feeds"]), time.time()-start))
commit_time = feed_entry.updated def _shorten(self, link):
updcnt += 1 # We can utilitze git.io to shorten *.github.com links
if rssnotify["show_commit_link"]: l, code = web.post("https://git.io/create", {'url': link})
if rssnotify["use_git.io"]: if code != 200:
# Side note: git.io only works with *.github.com links return None
l, code = web.post("https://git.io/create", {'url': feed_entry.link})
if code == 200:
l = str(l, 'utf-8') l = str(l, 'utf-8')
if not ' ' in l: # If there are spaces it's an error if ' ' in l: # spaces means there was an error :(
commit_link = "https://git.io/" + l return None
else: return "https://git.io/" + l
commit_link = feed_entry.link def _format_msg(self, feed_entry, log_format=False):
else: if log_format:
commit_link = feed_entry.link f_cshort = "[color=#cc0000]%s[/color]"
f_clong = "[color=#cc0000]%s[/color] ([color=#cc0000]%s[/color])"
f_all = "[color=#3465a4][git][/color] %s -> [color=#73d216]%s[/color]: [b]%s[/b] [color=#a04265]%s[/color] %s ([color=#888a85]%s[/color])"
else: else:
f_cshort = "\x0304%s\x0f"
f_clong = "\x0304%s\x0f (\x0304%s\x0f)"
f_all = "\x0302[git]\x0f %s -> \x0303%s\x0f: \x02%s\x0f \x0313%s\x0f %s (\x0315%s\x0f)"
committer_realname = feed_entry.authors[0].name
if committer_realname == "":
try:
committer_realname = feed_entry.authors[0].email
except AttributeError:
committer_realname = ""
try:
committer = feed_entry.authors[0].href.replace('https://github.com/',"")
except AttributeError:
committer = committer_realname # This will only use the realname if the nickname couldn't be obtained
m = re.search(r'/([a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+)/commit/([a-f0-9]{7})', feed_entry.links[0].href)
repo_name = m.group(1) if m else "?"
commit_hash = m.group(2) if m else "???????"
commit_time = feed_entry.updated
commit_text = feed_entry.title
if self.config["show_link"]:
commit_link = feed_entry.link commit_link = feed_entry.link
if self.config["shorten_link"]:
commit_link = self._shorten(commit_link) or commit_link
else: else:
commit_link = "" commit_link = ""
if committer_realname == "" or committer_realname.lower() == committer.lower():
chans = [] committer_final = f_cshort % committer
if feeds[v][1] == '*': else:
committer_final = f_clong % (committer, committer_realname)
return f_all % (committer_final, repo_name, commit_text, commit_hash, commit_link, commit_time)
def _announce(self, phenny, message, chans):
if chans == "*":
chans = phenny.bot.channels chans = phenny.bot.channels
elif type(feeds[v][1]) == type([]): assert(type(chans) == list)
chans = feeds[v][1]
else:
print("[RssNotify]: Something went wrong!")
if rssnotify["logfilepath"] != "":
lf = open(rssnotify["logfilepath"], "a")
if commiter.lower() != commiter_realname.lower():
lf.write("[color=#3465a4][git][/color] [color=#cc0000]%s[/color] ([color=#cc0000]%s[/color]) -> [color=#73d216]%s[/color]: [b]%s[/b] [color=#a04265]%s[/color] %s ([color=#888a85]%s[/color])\n" % (commiter, commiter_realname, reponame, feed_entry.title, commit_hash, commit_link, commit_time))
else:
lf.write("[color=#3465a4][git][/color] [color=#cc0000]%s[/color] -> [color=#73d216]%s[/color]: [b]%s[/b] [color=#a04265]%s[/color] %s ([color=#888a85]%s[/color])\n" % (commiter, reponame, feed_entry.title, commit_hash, commit_link, commit_time))
lf.close()
for ch in chans: for ch in chans:
if commiter.lower() != commiter_realname.lower(): phenny.write(['PRIVMSG', ch], message)
phenny.write(['PRIVMSG', ch], "\x0302[git]\x0f \x0304%s\x0f (\x0304%s\x0f) -> \x0303%s\x0f: \x02%s\x0f \x0313%s\x0f %s (\x0315%s\x0f)" % (commiter, commiter_realname, reponame, feed_entry.title, commit_hash, commit_link, commit_time))
else:
phenny.write(['PRIVMSG', ch], "\x0302[git]\x0f \x0304%s\x0f -> \x0303%s\x0f: \x02%s\x0f \x0313%s\x0f %s (\x0315%s\x0f)" % (commiter, reponame, feed_entry.title, commit_hash, commit_link, commit_time))
if len(feed.entries) > 0:
m = -1
for i in range(0, len(feed.entries)):
if to_unix_time(feed.entries[i].updated) > m:
m = to_unix_time(feed.entries[i].updated)
rssnotify["last_updated_feeds"][feednum] = m
if updcnt > 0:
print("[RssNotify]: Found %i RSS Update(s) for URL '%s'" % (updcnt, url))
end = time.time()
if rssnotify["dont_print_first_message"]:
rssnotify["dont_print_first_message"] = False
print("[RssNotify]: Checked " + str(len(feeds)) + " RSS Feeds in %0.3f seconds" % (end-start))
rsscheck.priority = 'medium' rssn = RssNotify({
"check_interval": 120,
"show_link": True,
"shorten_link": True,
"logfile": os.getcwd() + "/rssnotify.log",
"feeds": [
('https://github.com/minetest/minetest/commits/master.atom', "*"),
('https://github.com/minetest/minetest_game/commits/master.atom', "*"),
('https://github.com/minetest/minetestmapper/commits/master.atom', "*"),
('https://github.com/minetest/master-server/commits/master.atom', "*"),
('https://github.com/Uberi/Minetest-WorldEdit/commits/master.atom', "*"),
('https://github.com/Jeija/minetest-mod-mesecons/commits/master.atom', "*"),
('https://github.com/sfan5/phenny/commits/master.atom', ['##minetestbot']),
('https://github.com/sfan5/minetestbot-modules/commits/master.atom', ['##minetestbot']),
('https://github.com/BlockMen/minetest_next/commits/master.atom', "*"),
],
})
def rsscheck(phenny, input):
if not rssn.needs_check():
return
t = threading.Thread(target=rssn.check, args=(phenny, ))
t.start()
rsscheck.priority = 'low'
rsscheck.rule = r'.*' rsscheck.rule = r'.*'
rsscheck.event = '*' rsscheck.event = '*'
rsscheck.thread = False
rsscheck.nohook = True rsscheck.nohook = True
if __name__ == '__main__': if __name__ == '__main__':