commit
2fca8c66b2
|
@ -1,7 +1,7 @@
|
||||||
pyLast
|
pyLast
|
||||||
======
|
======
|
||||||
|
|
||||||
[](https://travis-ci.org/pylast/pylast) [](https://pypi.python.org/pypi/pylast/) [](https://pypi.python.org/pypi/pylast/) [](https://coveralls.io/r/pylast/pylast?branch=develop) [](https://scrutinizer-ci.com/g/pylast/pylast/?branch=develop) [](https://landscape.io/github/hugovk/pylast/develop)
|
[](https://travis-ci.org/pylast/pylast) [](https://pypi.python.org/pypi/pylast/) [](https://pypi.python.org/pypi/pylast/) [](https://coveralls.io/r/pylast/pylast?branch=develop) [](https://landscape.io/github/hugovk/pylast/develop)
|
||||||
|
|
||||||
|
|
||||||
A Python interface to [Last.fm](http://www.last.fm/) and other api-compatible websites such as [Libre.fm](http://libre.fm/).
|
A Python interface to [Last.fm](http://www.last.fm/) and other api-compatible websites such as [Libre.fm](http://libre.fm/).
|
||||||
|
|
|
@ -32,7 +32,7 @@ import warnings
|
||||||
import re
|
import re
|
||||||
import six
|
import six
|
||||||
|
|
||||||
__version__ = '1.2.1'
|
__version__ = '1.2.2'
|
||||||
__author__ = 'Amr Hassan, hugovk'
|
__author__ = 'Amr Hassan, hugovk'
|
||||||
__copyright__ = "Copyright (C) 2008-2010 Amr Hassan, 2013-2015 hugovk"
|
__copyright__ = "Copyright (C) 2008-2010 Amr Hassan, 2013-2015 hugovk"
|
||||||
__license__ = "apache2"
|
__license__ = "apache2"
|
||||||
|
@ -1928,6 +1928,12 @@ class Artist(_BaseObject, _Taggable):
|
||||||
|
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def get_correction(self):
|
||||||
|
"""Returns the corrected artist name."""
|
||||||
|
|
||||||
|
return _extract(
|
||||||
|
self._request(self.ws_prefix + ".getCorrection"), "name")
|
||||||
|
|
||||||
def get_cover_image(self, size=COVER_MEGA):
|
def get_cover_image(self, size=COVER_MEGA):
|
||||||
"""
|
"""
|
||||||
Returns a uri to the cover image
|
Returns a uri to the cover image
|
||||||
|
@ -2947,6 +2953,12 @@ class Track(_Opus):
|
||||||
def __init__(self, artist, title, network, username=None):
|
def __init__(self, artist, title, network, username=None):
|
||||||
super(Track, self).__init__(artist, title, network, "track", username)
|
super(Track, self).__init__(artist, title, network, "track", username)
|
||||||
|
|
||||||
|
def get_correction(self):
|
||||||
|
"""Returns the corrected track name."""
|
||||||
|
|
||||||
|
return _extract(
|
||||||
|
self._request(self.ws_prefix + ".getCorrection"), "name")
|
||||||
|
|
||||||
def get_duration(self):
|
def get_duration(self):
|
||||||
"""Returns the track duration."""
|
"""Returns the track duration."""
|
||||||
|
|
||||||
|
@ -3505,6 +3517,41 @@ class User(_BaseObject, _Chartable):
|
||||||
return doc.getElementsByTagName(
|
return doc.getElementsByTagName(
|
||||||
"registered")[0].getAttribute("unixtime")
|
"registered")[0].getAttribute("unixtime")
|
||||||
|
|
||||||
|
def get_tagged_albums(self, tag, limit=None, cacheable=True):
|
||||||
|
"""Returns the albums tagged by a user."""
|
||||||
|
|
||||||
|
params = self._get_params()
|
||||||
|
params['tag'] = tag
|
||||||
|
params['taggingtype'] = 'album'
|
||||||
|
if limit:
|
||||||
|
params['limit'] = limit
|
||||||
|
doc = self._request(self.ws_prefix + '.getpersonaltags', cacheable,
|
||||||
|
params)
|
||||||
|
return _extract_albums(doc, self.network)
|
||||||
|
|
||||||
|
def get_tagged_artists(self, tag, limit=None):
|
||||||
|
"""Returns the artists tagged by a user."""
|
||||||
|
|
||||||
|
params = self._get_params()
|
||||||
|
params['tag'] = tag
|
||||||
|
params['taggingtype'] = 'artist'
|
||||||
|
if limit:
|
||||||
|
params["limit"] = limit
|
||||||
|
doc = self._request(self.ws_prefix + '.getpersonaltags', True, params)
|
||||||
|
return _extract_artists(doc, self.network)
|
||||||
|
|
||||||
|
def get_tagged_tracks(self, tag, limit=None, cacheable=True):
|
||||||
|
"""Returns the tracks tagged by a user."""
|
||||||
|
|
||||||
|
params = self._get_params()
|
||||||
|
params['tag'] = tag
|
||||||
|
params['taggingtype'] = 'track'
|
||||||
|
if limit:
|
||||||
|
params['limit'] = limit
|
||||||
|
doc = self._request(self.ws_prefix + '.getpersonaltags', cacheable,
|
||||||
|
params)
|
||||||
|
return _extract_tracks(doc, self.network)
|
||||||
|
|
||||||
def get_top_albums(
|
def get_top_albums(
|
||||||
self, period=PERIOD_OVERALL, limit=None, cacheable=True):
|
self, period=PERIOD_OVERALL, limit=None, cacheable=True):
|
||||||
"""Returns the top albums played by a user.
|
"""Returns the top albums played by a user.
|
||||||
|
@ -3693,7 +3740,7 @@ class AuthenticatedUser(User):
|
||||||
|
|
||||||
def get_recommended_artists(self, limit=50, cacheable=False):
|
def get_recommended_artists(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequence of Event objects
|
Returns a sequence of Artist objects
|
||||||
if limit==None it will return all
|
if limit==None it will return all
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -4087,6 +4134,31 @@ def _extract_top_albums(doc, network):
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_artists(doc, network):
|
||||||
|
seq = []
|
||||||
|
for node in doc.getElementsByTagName("artist"):
|
||||||
|
seq.append(Artist(_extract(node, "name"), network))
|
||||||
|
return seq
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_albums(doc, network):
|
||||||
|
seq = []
|
||||||
|
for node in doc.getElementsByTagName("album"):
|
||||||
|
name = _extract(node, "name")
|
||||||
|
artist = _extract(node, "name", 1)
|
||||||
|
seq.append(Album(artist, name, network))
|
||||||
|
return seq
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_tracks(doc, network):
|
||||||
|
seq = []
|
||||||
|
for node in doc.getElementsByTagName("track"):
|
||||||
|
name = _extract(node, "name")
|
||||||
|
artist = _extract(node, "name", 1)
|
||||||
|
seq.append(Track(artist, name, network))
|
||||||
|
return seq
|
||||||
|
|
||||||
|
|
||||||
def _extract_events_from_doc(doc, network):
|
def _extract_events_from_doc(doc, network):
|
||||||
events = []
|
events = []
|
||||||
for node in doc.getElementsByTagName("event"):
|
for node in doc.getElementsByTagName("event"):
|
||||||
|
|
|
@ -1041,6 +1041,12 @@ class TestPyLast(unittest.TestCase):
|
||||||
self.assertIsInstance(things[0], pylast.TopItem)
|
self.assertIsInstance(things[0], pylast.TopItem)
|
||||||
self.assertIsInstance(things[0].item, expected_type)
|
self.assertIsInstance(things[0].item, expected_type)
|
||||||
|
|
||||||
|
def helper_only_one_thing_in_list(self, things, expected_type):
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(len(things), 1)
|
||||||
|
self.assertIsInstance(things, list)
|
||||||
|
self.assertIsInstance(things[0], expected_type)
|
||||||
|
|
||||||
def helper_two_different_things_in_top_list(self, things, expected_type):
|
def helper_two_different_things_in_top_list(self, things, expected_type):
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(len(things), 2)
|
self.assertEqual(len(things), 2)
|
||||||
|
@ -1400,6 +1406,44 @@ class TestPyLast(unittest.TestCase):
|
||||||
# Assert
|
# Assert
|
||||||
self.helper_only_one_thing_in_top_list(albums, pylast.Album)
|
self.helper_only_one_thing_in_top_list(albums, pylast.Album)
|
||||||
|
|
||||||
|
def test_user_tagged_artists(self):
|
||||||
|
# Arrange
|
||||||
|
lastfm_user = self.network.get_user(self.username)
|
||||||
|
tags = ["artisttagola"]
|
||||||
|
artist = self.network.get_artist("Test Artist")
|
||||||
|
artist.add_tags(tags)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
artists = lastfm_user.get_tagged_artists('artisttagola', limit=1)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.helper_only_one_thing_in_list(artists, pylast.Artist)
|
||||||
|
|
||||||
|
def test_user_tagged_albums(self):
|
||||||
|
# Arrange
|
||||||
|
lastfm_user = self.network.get_user(self.username)
|
||||||
|
tags = ["albumtagola"]
|
||||||
|
album = self.network.get_album("Test Artist", "Test Album")
|
||||||
|
album.add_tags(tags)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
albums = lastfm_user.get_tagged_albums('albumtagola', limit=1)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.helper_only_one_thing_in_list(albums, pylast.Album)
|
||||||
|
|
||||||
|
def test_user_tagged_tracks(self):
|
||||||
|
# Arrange
|
||||||
|
lastfm_user = self.network.get_user(self.username)
|
||||||
|
tags = ["tracktagola"]
|
||||||
|
track = self.network.get_track("Test Artist", "Test Title")
|
||||||
|
track.add_tags(tags)
|
||||||
|
# Act
|
||||||
|
tracks = lastfm_user.get_tagged_tracks('tracktagola', limit=1)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.helper_only_one_thing_in_list(tracks, pylast.Track)
|
||||||
|
|
||||||
def test_caching(self):
|
def test_caching(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
user = self.network.get_user("RJ")
|
user = self.network.get_user("RJ")
|
||||||
|
@ -1908,6 +1952,25 @@ class TestPyLast(unittest.TestCase):
|
||||||
self.assertEqual(str(tracks[0].track.artist), "Johnny Cash")
|
self.assertEqual(str(tracks[0].track.artist), "Johnny Cash")
|
||||||
self.assertEqual(str(tracks[0].track.title), "Ring of Fire")
|
self.assertEqual(str(tracks[0].track.title), "Ring of Fire")
|
||||||
|
|
||||||
|
def test_artist_get_correction(self):
|
||||||
|
# Arrange
|
||||||
|
artist = pylast.Artist("guns and roses", self.network)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
corrected_artist_name = artist.get_correction()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(corrected_artist_name, "Guns N' Roses")
|
||||||
|
|
||||||
|
def test_track_get_correction(self):
|
||||||
|
# Arrange
|
||||||
|
track = pylast.Track("Guns N' Roses", "mrbrownstone", self.network)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
corrected_track_name = track.get_correction()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(corrected_track_name, "Mr. Brownstone")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(failfast=True)
|
unittest.main(failfast=True)
|
||||||
|
|
5
tox.ini
5
tox.ini
|
@ -4,6 +4,11 @@ recreate = False
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
downloadcache = {homedir}/.pipcache
|
downloadcache = {homedir}/.pipcache
|
||||||
|
setenv =
|
||||||
|
PYLAST_USERNAME={env:PYLAST_USERNAME:}
|
||||||
|
PYLAST_PASSWORD_HASH={env:PYLAST_PASSWORD_HASH:}
|
||||||
|
PYLAST_API_KEY={env:PYLAST_API_KEY:}
|
||||||
|
PYLAST_API_SECRET={env:PYLAST_API_SECRET:}
|
||||||
deps =
|
deps =
|
||||||
pyyaml
|
pyyaml
|
||||||
pytest
|
pytest
|
||||||
|
|
Loading…
Reference in a new issue