From e117a2b57c25c9b333cc8db4f930a69eea17204f Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 27 Aug 2014 00:16:59 +0300 Subject: [PATCH 1/2] Add artist.get_band_members() with tests --- pylast.py | 23 +++++++++++++++++------ test_pylast.py | 24 +++++++++++++++++++++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/pylast.py b/pylast.py index 49a2f1a..7b72178 100644 --- a/pylast.py +++ b/pylast.py @@ -121,10 +121,10 @@ RE_XML_ILLEGAL = (u'([\u0000-\u0008\u000b-\u000c\u000e-\u001f\ufffe-\uffff])' + u'|' + u'([%s-%s][^%s-%s])|([^%s-%s][%s-%s])|([%s-%s]$)|(^[%s-%s])' % - (unichr(0xd800), unichr(0xdbff), unichr(0xdc00), - unichr(0xdfff), unichr(0xd800), unichr(0xdbff), - unichr(0xdc00), unichr(0xdfff), unichr(0xd800), - unichr(0xdbff), unichr(0xdc00), unichr(0xdfff))) + (unichr(0xd800), unichr(0xdbff), unichr(0xdc00), + unichr(0xdfff), unichr(0xd800), unichr(0xdbff), + unichr(0xdc00), unichr(0xdfff), unichr(0xd800), + unichr(0xdbff), unichr(0xdc00), unichr(0xdfff))) XML_ILLEGAL = re.compile(RE_XML_ILLEGAL) @@ -1023,7 +1023,7 @@ class _Request(object): def sign_it(self): """Sign this request.""" - if not "api_sig" in self.params.keys(): + if "api_sig" not in self.params.keys(): self.params['api_sig'] = self._get_signature() def _get_signature(self): @@ -2093,6 +2093,17 @@ class Artist(_BaseObject, _Taggable): self._request("artist.Shout", False, params) + def get_band_members(self): + """Returns a list of band members or None if unknown.""" + + names = None + doc = self._request(self.ws_prefix + ".getInfo", True) + + for node in doc.getElementsByTagName("bandmembers"): + names = _extract_all(node, "name") + + return names + class Event(_BaseObject): """An event.""" @@ -4115,7 +4126,7 @@ def _number(string): def _unescape_htmlentity(string): - #string = _unicode(string) + # string = _unicode(string) mapping = htmlentitydefs.name2codepoint for key in mapping: diff --git a/test_pylast.py b/test_pylast.py index ed2bf9b..0f71c65 100755 --- a/test_pylast.py +++ b/test_pylast.py @@ -1251,7 +1251,7 @@ class TestPyLast(unittest.TestCase): # Assert # Check inbox for spam! - #album/artist/event/track/user + # album/artist/event/track/user def test_album_shouts(self): # Arrange @@ -1750,7 +1750,6 @@ class TestPyLast(unittest.TestCase): self.assertEqual(mbid, "a74b1b7f-71a5-4011-9441-d0b5e4122711") self.assertIsInstance(streamable, bool) - def test_events(self): # Arrange event_id_1 = 3162700 # Glasto 2013 @@ -1803,7 +1802,6 @@ class TestPyLast(unittest.TestCase): self.assertTrue(country1 != country2) self.assertEqual(url, "http://www.last.fm/place/italy") - def test_track_eq_none_is_false(self): # Arrange track1 = None @@ -1820,6 +1818,26 @@ class TestPyLast(unittest.TestCase): # Act / Assert self.assertTrue(track1 != track2) + def test_band_members(self): + # Arrange + artist = pylast.Artist("The Beatles", self.network) + + # Act + band_members = artist.get_band_members() + + # Assert + self.assertGreaterEqual(len(band_members), 4) + + def test_no_band_members(self): + # Arrange + artist = pylast.Artist("John Lennon", self.network) + + # Act + band_members = artist.get_band_members() + + # Assert + self.assertIsNone(band_members) + if __name__ == '__main__': parser = argparse.ArgumentParser( From bd9c351b21d18aedf32a7a4929959b29e326de2d Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 25 Oct 2014 15:52:01 +0300 Subject: [PATCH 2/2] Add from/to parameters to get_recent_tracks() --- pylast.py | 54 +++++++++++++++++++++++++++++++++++++------------- test_pylast.py | 20 +++++++++++++++++++ 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/pylast.py b/pylast.py index 7b72178..f2d7268 100644 --- a/pylast.py +++ b/pylast.py @@ -425,12 +425,18 @@ class _Network(object): params = {} - if long: params["long"] = long - if lat: params["lat"] = lat - if location: params["location"] = location - if limit: params["limit"] = limit - if distance: params["distance"] = distance - if tag: params["tag"] = tag + if long: + params["long"] = long + if lat: + params["lat"] = lat + if location: + params["location"] = location + if limit: + params["limit"] = limit + if distance: + params["distance"] = distance + if tag: + params["tag"] = tag if festivalsonly: params["festivalsonly"] = 1 elif not festivalsonly: @@ -671,12 +677,18 @@ class _Network(object): params = {"track": title, "artist": artist} - if album: params["album"] = album - if album_artist: params["albumArtist"] = album_artist - if context: params["context"] = context - if track_number: params["trackNumber"] = track_number - if mbid: params["mbid"] = mbid - if duration: params["duration"] = duration + if album: + params["album"] = album + if album_artist: + params["albumArtist"] = album_artist + if context: + params["context"] = context + if track_number: + params["trackNumber"] = track_number + if mbid: + params["mbid"] = mbid + if duration: + params["duration"] = duration _Request(self, "track.updateNowPlaying", params).execute() @@ -3377,12 +3389,22 @@ class User(_BaseObject, _Chartable): return Track(artist, title, self.network, self.name) - def get_recent_tracks(self, limit=10, cacheable=True): + def get_recent_tracks(self, limit=10, cacheable=True, + time_from=None, time_to=None): """ Returns this user's played track as a sequence of PlayedTrack objects in reverse order of playtime, all the way back to the first track. - If limit==None, it will try to pull all the available data. + Parameters: + limit : If None, it will try to pull all the available data. + from (Optional) : Beginning timestamp of a range - only display + scrobbles after this time, in UNIX timestamp format (integer + number of seconds since 00:00:00, January 1st 1970 UTC). This + must be in the UTC time zone. + to (Optional) : End timestamp of a range - only display scrobbles + before this time, in UNIX timestamp format (integer number of + seconds since 00:00:00, January 1st 1970 UTC). This must be in + the UTC time zone. This method uses caching. Enable caching only if you're pulling a large amount of data. @@ -3394,6 +3416,10 @@ class User(_BaseObject, _Chartable): params = self._get_params() if limit: params['limit'] = limit + if time_from: + params['from'] = time_from + if time_to: + params['to'] = time_to seq = [] for track in _collect_nodes( diff --git a/test_pylast.py b/test_pylast.py index 0f71c65..2216e00 100755 --- a/test_pylast.py +++ b/test_pylast.py @@ -1838,6 +1838,26 @@ class TestPyLast(unittest.TestCase): # Assert self.assertIsNone(band_members) + def test_get_recent_tracks_from_to(self): + # Arrange + lastfm_user = self.network.get_user("RJ") + + from datetime import datetime + start = datetime(2011, 7, 21, 15, 10) + end = datetime(2011, 7, 21, 15, 15) + import calendar + utc_start = calendar.timegm(start.utctimetuple()) + utc_end = calendar.timegm(end.utctimetuple()) + + # Act + tracks = lastfm_user.get_recent_tracks(time_from=utc_start, + time_to=utc_end) + + # Assert + self.assertEqual(len(tracks), 1) + self.assertEqual(str(tracks[0].track.artist), "Johnny Cash") + self.assertEqual(str(tracks[0].track.title), "Ring of Fire") + if __name__ == '__main__': parser = argparse.ArgumentParser(