Difference between revisions of "User:WindPower/RCNotify.py"
m (New release, fixes blog checking I think, and uses non-Template: refresh rate page) |
m (poosh: now check for TF2 patches) |
||
Line 7: | Line 7: | ||
* First way: Download Python and run the script as is. | * First way: Download Python and run the script as is. | ||
** [http://python.org/download/releases/2.6.6/ Download Python] and install it if you haven't got it yet. | ** [http://python.org/download/releases/2.6.6/ Download Python] and install it if you haven't got it yet. | ||
− | ** [http://upload.gaiatools.com/files/ | + | ** [http://upload.gaiatools.com/files/rcNotify.tar_1.bz Download the archive file] and extract it somewhere. You should have a file named <code>rcNotify.py</code> (the Python script), a file named <code>rcConfig.py</code> (configuration file) and a folder called <code>wikitools</code> (Wiki API library). |
** Edit <code>rcConfig.py</code> to your liking. Read the comments next to each line. Do not use Notepad to edit the file, because it cannot read Unix-style linebreaks (<code>\n</code>). Use WordPad or whatever code editor you have. | ** Edit <code>rcConfig.py</code> to your liking. Read the comments next to each line. Do not use Notepad to edit the file, because it cannot read Unix-style linebreaks (<code>\n</code>). Use WordPad or whatever code editor you have. | ||
** Open a command prompt or terminal window, and run Python with the script's path as argument. | ** Open a command prompt or terminal window, and run Python with the script's path as argument. | ||
Line 36: | Line 36: | ||
import time #, Dr. Freeman? | import time #, Dr. Freeman? | ||
import urllib, urllib2 # Series of tubes | import urllib, urllib2 # Series of tubes | ||
+ | import re # Dem regexes | ||
import hashlib # Yummy | import hashlib # Yummy | ||
import pprint # prettyPrint | import pprint # prettyPrint | ||
Line 47: | Line 48: | ||
# Constants: | # Constants: | ||
wiki = wikitools.wiki.Wiki('http://wiki.teamfortress.com/w/api.php') | wiki = wikitools.wiki.Wiki('http://wiki.teamfortress.com/w/api.php') | ||
− | refreshRatePage = 'User:WindPower/ | + | refreshRatePage = 'User:WindPower/RCNotifyRefreshRate' |
notifyUrl = 'http://irc.biringa.com/tfwikirc.php?shapass=04d39797d3b879c26612bbbccd546c8717fd9b8e' | notifyUrl = 'http://irc.biringa.com/tfwikirc.php?shapass=04d39797d3b879c26612bbbccd546c8717fd9b8e' | ||
tf2Blog = 'http://www.teamfortress.com/' | tf2Blog = 'http://www.teamfortress.com/' | ||
+ | tf2UpdatesFeed = 'http://store.steampowered.com/news/posts/?feed=steam_updates&appids=440' | ||
# Globals: | # Globals: | ||
refreshRate = config['refreshRate'] # 3 minutes by default | refreshRate = config['refreshRate'] # 3 minutes by default | ||
tf2BlogHash = None # Will be populated later | tf2BlogHash = None # Will be populated later | ||
+ | tf2UpdateID = None # Will be populated later | ||
lastRC = -1 # Will be populated later | lastRC = -1 # Will be populated later | ||
Line 119: | Line 122: | ||
tf2BlogHash = newHash | tf2BlogHash = newHash | ||
print 'TF2 hash response:', getNotifyResponse('newblog=' + tf2BlogHash) | print 'TF2 hash response:', getNotifyResponse('newblog=' + tf2BlogHash) | ||
− | + | def checkTf2Update(): | |
+ | global tf2UpdatesFeed, tf2UpdateID | ||
+ | idRegex = re.compile(r'<div[^<>]*class="posttitle"[^<>]*><a[^<>]*href="http://store.steampowered.com/news/(\d+)', re.IGNORECASE) | ||
+ | try: | ||
+ | webfeed = urllib2.urlopen(tf2UpdatesFeed).read() | ||
+ | idResult = int(idRegex.search(webfeed).group(1)) | ||
+ | except: | ||
+ | print 'Couldn\'t grab latest news ID' | ||
+ | return | ||
+ | if idResult != tf2UpdateID: | ||
+ | tf2UpdateID = idResult | ||
+ | getNotifyResponse('newnews=' + str(idResult)) | ||
def reviewRC(rc): | def reviewRC(rc): | ||
global lastRC | global lastRC | ||
Line 200: | Line 214: | ||
try: | try: | ||
tf2BlogCountdown -= 1 | tf2BlogCountdown -= 1 | ||
− | if | + | if tf2BlogCountdown <= 0: |
− | + | tf2BlogCountdown = config['blogRefresh'] | |
print 'Checking for updates to TF2\'s blog.' | print 'Checking for updates to TF2\'s blog.' | ||
updateTf2Blog() | updateTf2Blog() | ||
+ | print 'Checking for news updates' | ||
+ | checkTf2Update() | ||
except KeyboardInterrupt: | except KeyboardInterrupt: | ||
raise KeyboardInterrupt | raise KeyboardInterrupt |
Revision as of 23:41, 16 March 2011
About this script
This is a Python script that:
- Fetches the recent changes log every 30 seconds
- Fetches the TF2 blog to look for updates
- Sends the results back to the IRC bot (#tfwiki on irc.freenode.net), and the bot notifies everyone in the channel about it.
Running this script
- First way: Download Python and run the script as is.
- Download Python and install it if you haven't got it yet.
- Download the archive file and extract it somewhere. You should have a file named
rcNotify.py
(the Python script), a file namedrcConfig.py
(configuration file) and a folder calledwikitools
(Wiki API library). - Edit
rcConfig.py
to your liking. Read the comments next to each line. Do not use Notepad to edit the file, because it cannot read Unix-style linebreaks (\n
). Use WordPad or whatever code editor you have. - Open a command prompt or terminal window, and run Python with the script's path as argument.
- On Windows:
C:\Python26\python.exe C:\path\to\script.py
- On Windows: Double-click the file
- You can also rename it to .pyw and double-click it if you don't want the command prompt window to appear.
- On Unix (Mac/Linux):
python /path/to/script.py
- On Unix (Mac/Linux), you can also type simply
/path/to/script.py
if you set the executable bit on the script file beforehand (chmod +x /path/to/script.py
).
- On Windows:
- Second way (Windows only): Download the exe.
- Coming soon if there is demand.
Source
#!/usr/bin/env python # -*- coding: utf-8 -*- # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import time #, Dr. Freeman? import urllib, urllib2 # Series of tubes import re # Dem regexes import hashlib # Yummy import pprint # prettyPrint import wikitools # Wiki bindings import sys # Command-line arguments parsing import traceback # Print error stack traces # Config: from rcConfig import * # Constants: wiki = wikitools.wiki.Wiki('http://wiki.teamfortress.com/w/api.php') refreshRatePage = 'User:WindPower/RCNotifyRefreshRate' notifyUrl = 'http://irc.biringa.com/tfwikirc.php?shapass=04d39797d3b879c26612bbbccd546c8717fd9b8e' tf2Blog = 'http://www.teamfortress.com/' tf2UpdatesFeed = 'http://store.steampowered.com/news/posts/?feed=steam_updates&appids=440' # Globals: refreshRate = config['refreshRate'] # 3 minutes by default tf2BlogHash = None # Will be populated later tf2UpdateID = None # Will be populated later lastRC = -1 # Will be populated later def u(s): if type(s) is type(u''): return s if type(s) is type(''): try: return unicode(s) except: try: return unicode(s.decode('utf8')) except: try: return unicode(s.decode('windows-1252')) except: return unicode(s, errors='ignore') try: return unicode(s) except: try: return u(str(s)) except: return s def urlEncode(s): return urllib2.quote(urllib2.unquote(eval(u(s).encode('utf8').__repr__().replace('\\x', '%')))) def getNotifyResponse(params): global notifyUrl, config if type(params) in (type(''), type(u'')): params = u(params) else: params = u(urllib.urlencode(params)) if config['via'] is not None: params += '&via=' + u(urlEncode(config['via'])) response = urllib2.urlopen(notifyUrl, params).read(-1) print 'Response:', response return response def updateRefreshRate(): global wiki, refreshRate, refreshRatePage, config if type(config['refreshRate']) is type(0): return try: refreshRate = int(wikitools.page.Page(wiki, refreshRatePage).getWikiText()) except: refreshRate = config['refreshRate'] if type(refreshRate) is not type(0): print 'Error while grabbing refresh rate; defaulting to 180s.' refreshRate = 180 def updateLastRC(last=None): global lastRC try: if last is None: lastRC = int(getNotifyResponse('requestrcid=1')) else: lastRC = int(last) except: lastRC = -1 def updateTf2Blog(): global tf2Blog, tf2BlogHash newHash = hashlib.md5() for i in urllib2.urlopen(tf2Blog): newHash.update(i) newHash = newHash.hexdigest().lower() print 'Old hash is', tf2BlogHash, '; New one is', newHash if tf2BlogHash is None or tf2BlogHash != newHash: tf2BlogHash = newHash print 'TF2 hash response:', getNotifyResponse('newblog=' + tf2BlogHash) def checkTf2Update(): global tf2UpdatesFeed, tf2UpdateID idRegex = re.compile(r'<div[^<>]*class="posttitle"[^<>]*><a[^<>]*href="http://store.steampowered.com/news/(\d+)', re.IGNORECASE) try: webfeed = urllib2.urlopen(tf2UpdatesFeed).read() idResult = int(idRegex.search(webfeed).group(1)) except: print 'Couldn\'t grab latest news ID' return if idResult != tf2UpdateID: tf2UpdateID = idResult getNotifyResponse('newnews=' + str(idResult)) def reviewRC(rc): global lastRC if rc['rcid'] <= lastRC: return None pprint.PrettyPrinter(indent=4).pprint(rc) flag = '' if 'redirect' in rc: flag += 'R' if rc['type'] == u'new': flag += 'N' elif rc['type'] == u'log': flag += 'L' if 'minor' in rc: flag += 'm' if 'bot' in rc: flag += 'b' if not flag: flag = '-' params = { 'rcid': rc['rcid'], 'user': rc['user'], 'title': rc['title'], 'pageid': rc['pageid'], 'namespace': rc['ns'], 'newrevid': rc['revid'], 'oldrevid': rc['old_revid'], 'newsize': rc['newlen'], 'oldsize': rc['oldlen'], 'flags': flag, 'comment': rc['comment'], 'timestamp': rc['timestamp'] } optionalstuff = ('logtype', 'logid', 'logaction') for o in optionalstuff: if o in rc: params[o] = rc[o] return params def multiUrlEncode(allParams): s = [] c = 0 for p in allParams: for k in p.keys(): s.append(urlEncode(k) + u'_' + u(c) + u'=' + urlEncode(p[k])) c += 1 return u'&'.join(s) def checkForRCs(): rcs = wikitools.api.APIRequest(wiki, { 'action': 'query', 'list': 'recentchanges', 'rclimit': str(config['rcLimit']), 'rcprop': 'user|comment|title|ids|timestamp|sizes|redirect|flags|loginfo' }).query(querycontinue=False)['query']['recentchanges'] rcs.reverse() # Chronological order allParams = [] for rc in rcs: rc = reviewRC(rc) if rc is not None: allParams.append(rc) response = getNotifyResponse(multiUrlEncode(allParams)) updateLastRC(response) def main(once=False): global refreshRate, config updateRefreshRate() updateLastRC() updateTf2Blog() print 'Started with last RCID =', lastRC print 'TF2 blog hash =', tf2BlogHash print 'Refresh rate =', refreshRate tf2BlogCountdown = 1 # Start at 1 to ensure the blog gets refreshed on the first run once = once or '--once' in sys.argv[1:] while True: try: try: print 'Checking for RCs.' checkForRCs() except: print 'Error while checking for RCs.' traceback.print_exc() try: tf2BlogCountdown -= 1 if tf2BlogCountdown <= 0: tf2BlogCountdown = config['blogRefresh'] print 'Checking for updates to TF2\'s blog.' updateTf2Blog() print 'Checking for news updates' checkTf2Update() except KeyboardInterrupt: raise KeyboardInterrupt except: print 'Error while checking for updates to TF2\'s blog.' traceback.print_exc() if once: print 'Exitting after only one run.' break print 'Sleeping for', refreshRate, 'seconds.' time.sleep(refreshRate) except KeyboardInterrupt: print 'End.' break if __name__ == '__main__': main()