Example #1
0
 def __init__(self, irc):
     self.__parent = super(LastFM, self)
     self.__parent.__init__(irc)
     self.db = LastFMDB(dbfilename)
     world.flushers.append(self.db.flush)
     self.APIKEY = self.registryValue("apiKey")
     self.APIURL = "http://ws.audioscrobbler.com/2.0/?api_key=%s&" % self.APIKEY
Example #2
0
 def __init__(self, irc):
     self.__parent = super(LastFM, self)
     self.__parent.__init__(irc)
     self.db = LastFMDB(dbfilename)
     world.flushers.append(self.db.flush)
Example #3
0
class LastFM(callbacks.Plugin):
    # 1.0 API (deprecated)
    APIURL_1_0 = "http://ws.audioscrobbler.com/1.0/user"

    # 2.0 API (see http://www.lastfm.de/api/intro)
    APIKEY = "b7638a70725eea60737f9ad9f56f3099"
    APIURL_2_0 = "http://ws.audioscrobbler.com/2.0/?api_key=%s&" % APIKEY

    def __init__(self, irc):
        self.__parent = super(LastFM, self)
        self.__parent.__init__(irc)
        self.db = LastFMDB(dbfilename)
        world.flushers.append(self.db.flush)

    def die(self):
        if self.db.flush in world.flushers:
            world.flushers.remove(self.db.flush)
        self.db.close()
        self.__parent.die()

    def lastfm(self, irc, msg, args, method, optionalId):
        """<method> [<id>]

        Lists LastFM info where <method> is in
        [friends, neighbours, profile, recenttracks, tags, topalbums,
        topartists, toptracks].
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (optionalId or self.db.getId(msg.nick) or msg.nick)
        channel = msg.args[0]
        maxResults = self.registryValue("maxResults", channel)
        method = method.lower()

        url = "%s/%s/%s.txt" % (self.APIURL_1_0, id, method)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown ID (%s) or unknown method (%s)"
                    % (msg.nick, method))
            return


        lines = f.read().split("\n")
        content = map(lambda s: s.split(",")[-1], lines)

        irc.reply("%s's %s: %s (with a total number of %i entries)"
                % (id, method, ", ".join(content[0:maxResults]),
                    len(content)))

    lastfm = wrap(lastfm, ["something", optional("something")])

    def nowPlaying(self, irc, msg, args, optionalId):
        """[<id>]

        Announces the now playing track of the specified LastFM ID.
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (optionalId or self.db.getId(msg.nick) or msg.nick)

        # see http://www.lastfm.de/api/show/user.getrecenttracks
        url = "%s&method=user.getrecenttracks&user=%s" % (self.APIURL_2_0, id)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown ID (%s)" % id)
            return

        xml = minidom.parse(f).getElementsByTagName("recenttracks")[0]
        user = xml.getAttribute("user")
        t = xml.getElementsByTagName("track")[0] # most recent track
        isNowplaying = (t.getAttribute("nowplaying") == "true")
        artist = t.getElementsByTagName("artist")[0].firstChild.data
        track = t.getElementsByTagName("name")[0].firstChild.data
        try:
            album = "["+t.getElementsByTagName("album")[0].firstChild.data+"]"
        except IndexError:
            album = ""

        if isNowplaying:
            irc.reply(('%s is listening to "%s" by %s %s'
                    % (user, track, artist, album)).encode("utf8"))
        else:
            time = int(t.getElementsByTagName("date")[0].getAttribute("uts"))
            irc.reply(('%s listened to "%s" by %s %s more than %s'
                    % (user, track, artist, album,
                        self._formatTimeago(time))).encode("utf-8"))

    np = wrap(nowPlaying, [optional("something")])

    def setUserId(self, irc, msg, args, newId):
        """<id>

        Sets the LastFM ID for the caller and saves it in a database.
        """

        self.db.set(msg.nick, newId)

        irc.reply("LastFM ID changed.")
        self.profile(irc, msg, args)

    set = wrap(setUserId, ["something"])

    def profile(self, irc, msg, args, optionalId):
        """[<id>]

        Prints the profile info for the specified LastFM ID.
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (optionalId or self.db.getId(msg.nick) or msg.nick)

        url = "%s/%s/profile.xml" % (self.APIURL_1_0, id)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown user (%s)" % id)
            return

        xml = minidom.parse(f).getElementsByTagName("profile")[0]
        keys = "realname registered age gender country playcount".split()
        profile = tuple([self._parse(xml, node) for node in keys])

        irc.reply(("%s (realname: %s) registered on %s; age: %s / %s; \
Country: %s; Tracks played: %s" % ((id,) + profile)).encode("utf8"))

    profile = wrap(profile, [optional("something")])

    def compareUsers(self, irc, msg, args, user1, optionalUser2):
        """user1 [<user2>]

        Compares the taste from two users
        If <user2> is ommitted, the taste is compared against the ID of the calling user.
        """

        user2 = (optionalUser2 or self.db.getId(msg.nick) or msg.nick)

        channel = msg.args[0]
        maxResults = self.registryValue("maxResults", channel)
        # see http://www.lastfm.de/api/show/tasteometer.compare
        url = "%s&method=tasteometer.compare&type1=user&type2=user&value1=%s&value2=%s&limit=%s" % (
            self.APIURL_2_0, user1, user2, maxResults
        )
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError, e:
            irc.error("Failure: %s" % (e))
            return

        xml = minidom.parse(f)
        resultNode = xml.getElementsByTagName("result")[0]
        score = float(self._parse(resultNode, "score"))
        scoreStr = "%s (%s)" % (round(score, 2), self._formatRating(score))
        # Note: XPath would be really cool here...
        artists = [el for el in resultNode.getElementsByTagName("artist")]
        artistNames = [el.getElementsByTagName("name")[0].firstChild.data for el in artists]
        irc.reply(("Result of comparison between %s and %s: score: %s, common artists: %s" \
                % (user1, user2, scoreStr, ", ".join(artistNames))
            ).encode("utf-8")
        )
Example #4
0
class LastFM(callbacks.Plugin):
    # {{{ vars
    BASEURL = "http://ws.audioscrobbler.com/1.0/user"
    APIKEY = "" # FIXME: Get own key
    APIURL = ""
    # }}}

    # {{{ system functions
    def __init__(self, irc):
        self.__parent = super(LastFM, self)
        self.__parent.__init__(irc)
        self.db = LastFMDB(dbfilename)
        world.flushers.append(self.db.flush)
        self.APIKEY = self.registryValue("apiKey")
        self.APIURL = "http://ws.audioscrobbler.com/2.0/?api_key=%s&" % self.APIKEY

    def die(self):
        if self.db.flush in world.flushers:
            world.flushers.remove(self.db.flush)
        self.db.close()
        self.__parent.die()
    # }}}

    # {{{ lastfm
    def lastfm(self, irc, msg, args, method, optionalId):
        """<method> [<id>]

        Lists LastFM info where <method> is in
        [friends, neighbours, profile, recenttracks, tags, topalbums,
        topartists, toptracks].
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (optionalId or self.db.getId(msg.nick) or msg.nick)
        channel = msg.args[0]
        maxResults = self.registryValue("maxResults", channel)
        method = method.lower()

        try:
            f = urlopen("%s/%s/%s.txt" % (self.BASEURL, id, method))
        except HTTPError:
            irc.error("Unknown ID (%s) or unknown method (%s)"
                    % (msg.nick, method))
            return


        lines = f.read().split("\n")
        content = map(lambda s: s.split(",")[-1], lines)

        irc.reply("%s's %s: %s (with a total number of %i entries)"
                % (id, method, ", ".join(content[0:maxResults]),
                    len(content)))

    lastfm = wrap(lastfm, ["something", optional("something")])
    # }}}

    # {{{ np
    def np(self, irc, msg, args, optionalId):
        """[<id>]

        Announces the now playing track of the specified LastFM ID.
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (self.db.getId(optionalId) or optionalId or self.db.getId(msg.nick) or msg.nick)
        channel = msg.args[0]
        showColours = self.registryValue("showColours", channel)
        trackInfo = self.registryValue("showTrackInfo", channel)
        showTags = self.registryValue("showTags", channel)

        getYear = True

        try:
            f = urlopen("%s&method=user.getrecenttracks&user=%s"
                    % (self.APIURL, id))
        except (HTTPError) as e:
            irc.error("Unknown ID (%s)! Also, \"%s\"" % (id,e))
            return

        try:
            xml = minidom.parse(f).getElementsByTagName("recenttracks")[0]
        except IndexError:
            irc.error("Something broke, or you ain't listened to any tracks lol.")
            return
        user = xml.getAttribute("user")
        try:
            t = xml.getElementsByTagName("track")[0] # most recent track
        except IndexError,e:
            irc.error("No tracks or something for %s lol or maybe it's \"%s\"" % (id,e))
            return
        isNowplaying = (t.getAttribute("nowplaying") == "true")
        artist = t.getElementsByTagName("artist")[0].firstChild.data
        track = t.getElementsByTagName("name")[0].firstChild.data
        try:
            theAlbum = t.getElementsByTagName("album")[0].firstChild.data
            album = u" [{0}]".format(theAlbum)
        except AttributeError:
            album = ""
            getYear = False

        artist2 = quote_plus(artist.encode("utf8"))
        track2 = quote_plus(track.encode("utf8"))

        # Play count and shit
        try:
            herp = urlopen("%s&method=track.getInfo&username=%s&artist=%s&track=%s"
                    % (self.APIURL, id, artist2, track2))
            playinfo = minidom.parse(herp).getElementsByTagName("track")[0]
            playcount = playinfo.getElementsByTagName("playcount")[0].firstChild.data
            listenercount = playinfo.getElementsByTagName("listeners")[0].firstChild.data
            userloved = playinfo.getElementsByTagName("userloved")[0].firstChild.data
        except (IndexError, HTTPError,AttributeError):
            trackInfo = False

        try:
            userplaycount = playinfo.getElementsByTagName("userplaycount")[0].firstChild.data
        except IndexError:
            userplaycount = 0

        if getYear:
            try:
                albuminfox = urlopen(u"{0}&method=album.getinfo&artist={1}&album={2}".format(self.APIURL, artist2, theAlbum))
                albuminfo = minidom.parse(albuminfox).getElementsByTagName("album")[0]
                releasedate = albuminfo.getElementsByTagName("releasedate")[0].firstChild.data
                releasedate = releasedate.split(' ')[6].split(',')[0]
                album = " [{0} ~{1}~]".format(theAlbum,releasedate)
            except (IndexError, HTTPError,BadStatusLine,UnicodeEncodeError):
                releasedate = ""

        # tags
        tags = []
        #if album != "":
            #thetags = urlopen("%s&method=album.getTopTags&artist=%s&album=%s&autocorrect=1"
                    #% ( self.APIURL,artist2,quote_plus(t.getElementsByTagName("album")[0].firstChild.data)))
        #else:
        if True:
            try:
                thetags = urlopen("{0}&method=artist.getTopTags&artist={1}".format(self.APIURL,artist2))
                toptags = minidom.parse(thetags).getElementsByTagName("toptags")[0]
            except IndexError: 
                toptags = []
        for item in range(3):
            try:
                tags.append(toptags.getElementsByTagName("tag")[item].getElementsByTagName("name")[0].firstChild.data)
            except IndexError:
                break
        if len(tags) == 0:
            isTagged = False
        else:
            isTagged = True

        if showColours:
            if isNowplaying:
                output = ('\x038%s\x03 is listening to "\x0310%s\x03" by \x0312%s\x0313%s\x03' % (user, track, artist, album)).encode("utf8")
            else:
                time = int(t.getElementsByTagName("date")[0].getAttribute("uts"))
                output = ('\x038%s\x03 listened to "\x0310%s\x03" by \x0312%s\x0313%s\x03 about \x0315%s\x03' % (user, track, artist, album, self._formatTimeago(time))).encode("utf8")
            if trackInfo == True:
                if userloved == "1":
                    output += (' \x035%s\x03. %s plays by \x038%s\x03, %s plays by %s listeners.' % (u'♥', userplaycount, user, playcount, listenercount)).encode("utf8")
                else:
                    output += ('. %s plays by \x038%s\x03, %s plays by %s listeners.' % (userplaycount, user, playcount, listenercount)).encode("utf8")
            if showTags == True:
                if isTagged == True:
                    output += " ("
                    for i,item in enumerate(tags):
                        output += ("\x0307%s\x03" % item).encode("utf8")
                        if i != (len(tags)-1):
                            output += ", "
                    output += ")"
                else:
                    output += (' (\x037%s\x03)' % ("no tags")).encode("utf8")
        else:
            if isNowplaying:
                output = ('%s is listening to "%s" by %s%s' % (user, track, artist, album)).encode("utf8")
            else:
                time = int(t.getElementsByTagName("date")[0].getAttribute("uts"))
                output = ('%s listened to "%s" by %s%s about %s' % (user, track, artist, album, self._formatTimeago(time))).encode("utf8")
            if trackInfo == True:
                if userloved == "1":
                    output += (' %s. %s plays by %s, %s plays by %s listeners.' % (u'♥', userplaycount, user, playcount, listenercount)).encode("utf8")
                else:
                    output += ('. %s plays by %s, %s plays by %s listeners.' % (userplaycount, user, playcount, listenercount)).encode("utf8")
            if showTags == True:
                if isTagged == True:
                    output += " ("
                    for i,item in enumerate(tags):
                        output += ("%s" % item).encode("utf8")
                        if i != (len(tags)-1):
                            output += ", "
                    output += ")"
                else:
                    output += (' (%s)' % ("no tags")).encode("utf8")

        irc.reply(output)
Example #5
0
 def __init__(self, irc):
     self.__parent = super(LastFM, self)
     self.__parent.__init__(irc)
     self.db = LastFMDB(dbfilename)
     world.flushers.append(self.db.flush)
Example #6
0
class LastFM(callbacks.Plugin):
    # 1.0 API (deprecated)
    APIURL_1_0 = "http://ws.audioscrobbler.com/1.0/user"

    # 2.0 API (see http://www.lastfm.de/api/intro)
    APIKEY = "b7638a70725eea60737f9ad9f56f3099"
    APIURL_2_0 = "http://ws.audioscrobbler.com/2.0/?api_key=%s&" % APIKEY

    def __init__(self, irc):
        self.__parent = super(LastFM, self)
        self.__parent.__init__(irc)
        self.db = LastFMDB(dbfilename)
        world.flushers.append(self.db.flush)

    def die(self):
        if self.db.flush in world.flushers:
            world.flushers.remove(self.db.flush)
        self.db.close()
        self.__parent.die()

    def lastfm(self, irc, msg, args, method, optionalId):
        """<method> [<id>]

        Lists LastFM info where <method> is in
        [friends, neighbours, profile, recenttracks, tags, topalbums,
        topartists, toptracks].
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (optionalId or self.db.getId(msg.nick) or msg.nick)
        channel = msg.args[0]
        maxResults = self.registryValue("maxResults", channel)
        method = method.lower()

        url = "%s/%s/%s.txt" % (self.APIURL_1_0, id, method)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown ID (%s) or unknown method (%s)" %
                      (msg.nick, method))
            return

        lines = f.read().split("\n")
        content = map(lambda s: s.split(",")[-1], lines)

        irc.reply("%s's %s: %s (with a total number of %i entries)" %
                  (id, method, ", ".join(content[0:maxResults]), len(content)))

    lastfm = wrap(lastfm, ["something", optional("something")])

    def nowPlaying(self, irc, msg, args, optionalId):
        """[<id>]

        Announces the now playing track of the specified LastFM ID.
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (optionalId or self.db.getId(msg.nick) or msg.nick)

        # see http://www.lastfm.de/api/show/user.getrecenttracks
        url = "%s&method=user.getrecenttracks&user=%s" % (self.APIURL_2_0, id)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown ID (%s)" % id)
            return

        parser = LastFMParser()
        (user, isNowPlaying, artist, track, album,
         time) = parser.parseRecentTracks(f)
        albumStr = "[" + album + "]" if album else ""
        if isNowPlaying:
            irc.reply(('%s is listening to "%s" by %s %s' %
                       (user, track, artist, albumStr)).encode("utf8"))
        else:
            irc.reply(('%s listened to "%s" by %s %s more than %s' %
                       (user, track, artist, albumStr,
                        self._formatTimeago(time))).encode("utf-8"))

    np = wrap(nowPlaying, [optional("something")])

    def setUserId(self, irc, msg, args, newId):
        """<id>

        Sets the LastFM ID for the caller and saves it in a database.
        """

        self.db.set(msg.nick, newId)

        irc.reply("LastFM ID changed.")
        self.profile(irc, msg, args)

    set = wrap(setUserId, ["something"])

    def profile(self, irc, msg, args, optionalId):
        """[<id>]

        Prints the profile info for the specified LastFM ID.
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (optionalId or self.db.getId(msg.nick) or msg.nick)

        url = "%s/%s/profile.xml" % (self.APIURL_1_0, id)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown user (%s)" % id)
            return

        xml = minidom.parse(f).getElementsByTagName("profile")[0]
        keys = "realname registered age gender country playcount".split()
        profile = tuple([self._parse(xml, node) for node in keys])

        irc.reply(("%s (realname: %s) registered on %s; age: %s / %s; \
Country: %s; Tracks played: %s" % ((id, ) + profile)).encode("utf8"))

    profile = wrap(profile, [optional("something")])

    def compareUsers(self, irc, msg, args, user1, optionalUser2):
        """user1 [<user2>]

        Compares the taste from two users
        If <user2> is ommitted, the taste is compared against the ID of the calling user.
        """

        user2 = (optionalUser2 or self.db.getId(msg.nick) or msg.nick)

        channel = msg.args[0]
        maxResults = self.registryValue("maxResults", channel)
        # see http://www.lastfm.de/api/show/tasteometer.compare
        url = "%s&method=tasteometer.compare&type1=user&type2=user&value1=%s&value2=%s&limit=%s" % (
            self.APIURL_2_0, user1, user2, maxResults)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError, e:
            irc.error("Failure: %s" % (e))
            return

        xml = minidom.parse(f)
        resultNode = xml.getElementsByTagName("result")[0]
        score = float(self._parse(resultNode, "score"))
        scoreStr = "%s (%s)" % (round(score, 2), self._formatRating(score))
        # Note: XPath would be really cool here...
        artists = [el for el in resultNode.getElementsByTagName("artist")]
        artistNames = [
            el.getElementsByTagName("name")[0].firstChild.data
            for el in artists
        ]
        irc.reply(("Result of comparison between %s and %s: score: %s, common artists: %s" \
                % (user1, user2, scoreStr, ", ".join(artistNames))
            ).encode("utf-8")
        )
Example #7
0
class LastFM(callbacks.Plugin):
    # 1.0 API (deprecated)
    APIURL_1_0 = "http://ws.audioscrobbler.com/1.0/user"

    # 2.0 API (see http://www.lastfm.de/api/intro)
    APIKEY = "fe777aa8d75991a017c59a6ec7ad5bdf"
    APIURL_2_0 = "http://ws.audioscrobbler.com/2.0/?api_key=%s&" % APIKEY

    def __init__(self, irc):
        self.__parent = super(LastFM, self)
        self.__parent.__init__(irc)
        self.db = LastFMDB(dbfilename)
        world.flushers.append(self.db.flush)

    def die(self):
        if self.db.flush in world.flushers:
            world.flushers.remove(self.db.flush)
        self.db.close()
        self.__parent.die()

    def lastfm(self, irc, msg, args, method, optionalId):
        """<method> [<id>]

        Lists LastFM info where <method> is in
        [friends, neighbours, profile, recenttracks, tags, topalbums,
        topartists, toptracks].
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (self.db.getId(msg.nick) or msg.nick)
        if optionalId:
            id = (self.db.getId(optionalId) or optionalId)

        channel = msg.args[0]
        maxResults = self.registryValue("maxResults", channel)
        method = method.lower()

        url = "%s/%s/%s.txt" % (self.APIURL_1_0, id, method)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown ID (%s) or unknown method (%s)"
                    % (msg.nick, method))
            return


        lines = f.read().split("\n")
        content = map(lambda s: s.split(",")[-1], lines)

        irc.reply("%s's %s: %s (with a total number of %i entries)"
                % (id, method, ", ".join(content[0:maxResults]),
                    len(content)))

    lastfm = wrap(lastfm, ["something", optional("something")])

    def nowPlaying(self, irc, msg, args, optionalId):
        """[<id>]

        Announces the now playing track of the specified LastFM ID.
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """
        nick = msg.nick
        id = (self.db.getId(nick) or nick)
        user = nick
        channel = None

        if optionalId:
            if optionalId[0] == "#":
                channel = optionalId
            else:
                id = (self.db.getId(optionalId) or optionalId)
                user = optionalId

        # see http://www.lastfm.de/api/show/user.getrecenttracks
        url = "%s&method=user.getrecenttracks&user=%s" % (self.APIURL_2_0, id)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown ID (%s)" % id)
            return

        parser = LastFMParser()
        (username, isNowPlaying, artist, track, album, time) = parser.parseRecentTracks(f)

        # extra API call to get: listeners, playcount, user playcount, user loved (0/1 toggle), track tags
        # doc: http://www.last.fm/api/show/track.getInfo
        try:
    	    params = urllib.urlencode({'username': id.encode("utf8"), 'track': track.encode("utf8"), 'artist': artist.encode("utf8")})
            urlTwo = "%smethod=track.getInfo&%s" % (self.APIURL_2_0, params)
            fTwo = urllib2.urlopen(urlTwo)
        except urllib2.HTTPError:
            irc.error("Error getting now playing track infomation for %s" % id)

        (listeners, playcount, usercount, userloved, tags) = parser.parseTrackInformation(fTwo)

        replyStr = self._formatNowPlaying(user, id, track.encode("utf8"), artist.encode("utf8"), album, usercount, playcount, listeners, userloved, isNowPlaying)
        tagStr = self._formatTags(tags).encode("utf8")

        if channel == None:
            irc.reply(replyStr + tagStr)
        else:
            irc.queueMsg(ircmsgs.privmsg(channel, replyStr + tagStr))
            irc.noReply()

    np = wrap(nowPlaying, [optional("something")])

    def setUserId(self, irc, msg, args, newId):
        """<id>

        Sets the LastFM ID for the caller and saves it in a database.
        """

        self.db.set(msg.nick, newId)

        irc.reply("LastFM ID changed.")
        self.profile(irc, msg, args)

    set = wrap(setUserId, ["something"])

    def profile(self, irc, msg, args, optionalId):
        """[<id>]

        Prints the profile info for the specified LastFM ID.
        Set your LastFM ID with the set method (default is your current nick)
        or specify <id> to switch for one call.
        """

        id = (self.db.getId(msg.nick) or msg.nick)
        user = msg.nick

        if optionalId:
            id = (self.db.getId(optionalId) or optionalId)
            user = optionalId

        url = "%s/%s/profile.xml" % (self.APIURL_1_0, id)
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError:
            irc.error("Unknown user (%s)" % id)
            return

        xml = minidom.parse(f).getElementsByTagName("profile")[0]
        keys = "realname registered playcount".split()
        profile = tuple([self._parse(xml, node) for node in keys])

        irc.reply(("%s (realname: %s) joined Last.FM on %s. Total tracks played: %s. [http://last.fm/user/%s]" % ((user,) + profile + (id,))).encode("utf8"))

    profile = wrap(profile, [optional("something")])

    def compareUsers(self, irc, msg, args, user1, optionalUser2):
        """user1 [<user2>]

        Compares the taste from two users
        If <user2> is ommitted, the taste is compared against the ID of the calling user.
        """

	name1 = user1
        name2 = msg.nick
        user2 = (self.db.getId(msg.nick) or msg.nick)

	if optionalUser2:
            name2 = optionalUser2
            user2 = (self.db.getId(optionalUser2) or optionalUser2)

	if self.db.getId(user1): user1 = self.db.getId(user1)


        channel = msg.args[0]
        maxResults = self.registryValue("maxResults", channel)
        # see http://www.lastfm.de/api/show/tasteometer.compare
        url = "%s&method=tasteometer.compare&type1=user&type2=user&value1=%s&value2=%s&limit=%s" % (
            self.APIURL_2_0, user1, user2, maxResults
        )
        try:
            f = urllib2.urlopen(url)
        except urllib2.HTTPError, e:
            irc.error("Failure: %s" % (e))
            return

        xml = minidom.parse(f)
        resultNode = xml.getElementsByTagName("result")[0]
        score = float(self._parse(resultNode, "score"))
        scoreStr = "%s (%s)" % (int(round(score, 2) * 100), self._formatRating(score))
        # Note: XPath would be really cool here...
        artists = [el for el in resultNode.getElementsByTagName("artist")]
        artistNames = [el.getElementsByTagName("name")[0].firstChild.data for el in artists]
        irc.reply(("Result of comparison between %s (%s) and %s (%s): score: %s, common artists: %s" \
                % (name1, user1, name2, user2, scoreStr, ", ".join(artistNames))
            ).encode("utf-8")
        )