User:Jyotirmoyb/Watchlistfeed

A Python script to fetch the RSS/ATOM feed for you watchlist using the new MediaWiki API. The API is still in alpha, and so is this program, hence there are no guarantees.

The program takes two compulsory parameters--your username and password--and an optional third parameter specifying the feed format which must either be "rss" or "atom".

#!/usr/bin/python
"""Get Wikipedia watchlist as an RSS/ATOM feed

(c) Jyotirmoy Bhattacharya, 2007

Usage: wikiwatch <username> <password> [format]
[format] is either 'rss' or 'atom'
"""

import sys
import xml.sax,xml.sax.handler
import urllib,urllib2,cookielib,httplib

#Constants
version="0.1alpha"
user_agent="wikiwatch.py (jmoy.matecon@gmail.com)/"+version
usage="Usage: wikiwatch <Username> <Password> [rss/atom]"
apiURL="http://en.wikipedia.org/w/api.php"

class LoginFailedException(Exception):
    """Login to Wikipedia failed
    """
    def __init__(self,status):
        self.message=status

class RunTimeError(Exception):
    """Run-time error
    """
    def __init__(self,what):
        self.message=what

class BadCmdException(Exception):
    """Bad command-line arguments to program
    """
    def __init__(self):
        self.message="Bad command-line argument"
        


def callapi(data,cookie_jar):
    """Make an API call
    data: list of tuples containing data to be sent in the PUT request
    cookie_jar: cookielib.CookieJar used for the request

    Returns a file-like object containing the response
    """

    opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar))
    req=urllib2.Request(apiURL,urllib.urlencode(data))
    req.add_header("User-Agent",user_agent)
    return opener.open(req)

        
def wikiauth(uname,passwd,cookie_jar):
    """Authenticate to Wikipedia and return authentication tokens as cookies

    uname: Wikipedia username
    passwd: Wikipedia password
    cookie_jar: cookielib.CookieJar to store authentication cookies

    Returns nothing
    Raises LoginFailedException in case of failure
    """
    
    class LoginResp(xml.sax.ContentHandler):
        def __init__(self):
            self.result=""

        def startElement(self,name,attrs):
            if name=="login":
                self.result=attrs["result"]
    try:
        #Create SAX parser
        parser=xml.sax.make_parser()
        parser.setFeature(xml.sax.handler.feature_namespaces,0)
        lr=LoginResp()
        parser.setContentHandler(lr)

        #Get login response
        r=callapi([("action","login"),
                   ("format","xml"),
                   ("lgname",uname),
                   ("lgpassword",passwd)],
                  cookie_jar)
        #Parse login response to get tokens and see if login succeeded
        parser.parse(r)
        if lr.result!="Success":
            raise LoginFailedException("Authentication denied: "+lr.result)
        pass
    except xml.sax.SAXException,inst:
        raise LoginFailedException("Parse error in login response: "
                                   +inst.getMessage())

        
    
def getfeed(uname,passwd,feedformat):
    """Get Wikipedia watchlist feed

    uname: Wikipedia username
    passwd: Wikipedia password
    feedformat: format of the feed, must be 'rss' or 'atom'

    Returns a file-like object containing the feed
    """

    jar=cookielib.CookieJar()
    wikiauth(uname,passwd,jar)
    return callapi([("action","feedwatchlist"),
                    ("feedformat",feedformat)],
                   jar)


def do_fetch(argv):
    """Parse command-line arguments and fetch feed

    argv: list of command-line arguments

    Returns feed as a string
    Raises BadCmdException if arguments are not proper
    """

    format="atom"
    if len(argv)==3:
        pass
    elif len(argv)==4:
        if (argv[3]=="rss" or argv[3]=="atom"):
            format=argv[3]
        else:
            raise BadCmdException()
    else:
        raise BadCmdException()

    try:
        r=getfeed(argv[1],argv[2],format)
        return r.read()
    except httplib.HTTPException,inst:
        raise RunTimeError("httplib Exception: "+str(inst))
    except urllib2.URLError, inst:
        raise RunTimeError("urllib Exception: "+str(inst.reason))


#Main program
if __name__=="__main__":
    try:
        print do_fetch(sys.argv)
    except BadCmdException:
        sys.stderr.write("%s\n"%usage)
        sys.exit(1)
    except LoginFailedException,inst:
        sys.stderr.write("Login failed: %s\n"%inst.message)
        sys.exit(2)
    except RunTimeError, inst:
        sys.stderr.write("Runtime error: %s\n"%inst.message)
        sys.exit(2)