Merge pull request #299 from pylast/deprecate-User.get_artist_tracks
Deprecate User.get_artist_tracks, add user.getTrackScrobbles
This commit is contained in:
commit
c95e39b624
|
@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
* Extract username from session via new
|
* Extract username from session via new
|
||||||
`SessionKeyGenerator.get_web_auth_session_key_username` ([#290])
|
`SessionKeyGenerator.get_web_auth_session_key_username` ([#290])
|
||||||
|
* `User.get_track_scrobbles` ([#298])
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
* `User.get_artist_tracks`. Use `User.get_track_scrobbles` as a partial replacement.
|
||||||
|
([#298])
|
||||||
|
|
||||||
## [3.0.0] - 2019-01-01
|
## [3.0.0] - 2019-01-01
|
||||||
### Added
|
### Added
|
||||||
|
@ -31,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
[Unreleased]: https://github.com/pylast/pylast/compare/v3.0.0...HEAD
|
[Unreleased]: https://github.com/pylast/pylast/compare/v3.0.0...HEAD
|
||||||
[3.0.0]: https://github.com/pylast/pylast/compare/2.4.0...3.0.0
|
[3.0.0]: https://github.com/pylast/pylast/compare/2.4.0...3.0.0
|
||||||
[2.4.0]: https://github.com/pylast/pylast/compare/2.3.0...2.4.0
|
[2.4.0]: https://github.com/pylast/pylast/compare/2.3.0...2.4.0
|
||||||
|
[#298]: https://github.com/pylast/pylast/issues/298
|
||||||
[#290]: https://github.com/pylast/pylast/pull/290
|
[#290]: https://github.com/pylast/pylast/pull/290
|
||||||
[#265]: https://github.com/pylast/pylast/issues/265
|
[#265]: https://github.com/pylast/pylast/issues/265
|
||||||
[#273]: https://github.com/pylast/pylast/issues/273
|
[#273]: https://github.com/pylast/pylast/issues/273
|
||||||
|
|
|
@ -20,18 +20,19 @@
|
||||||
#
|
#
|
||||||
# https://github.com/pylast/pylast
|
# https://github.com/pylast/pylast
|
||||||
|
|
||||||
from xml.dom import minidom, Node
|
|
||||||
import collections
|
import collections
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import html.entities
|
||||||
import logging
|
import logging
|
||||||
import shelve
|
import shelve
|
||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
import warnings
|
||||||
import xml.dom
|
import xml.dom
|
||||||
import html.entities
|
|
||||||
from http.client import HTTPSConnection
|
from http.client import HTTPSConnection
|
||||||
|
from xml.dom import Node, minidom
|
||||||
|
|
||||||
from . import version
|
from . import version
|
||||||
|
|
||||||
|
@ -2236,6 +2237,14 @@ class User(_BaseObject, _Chartable):
|
||||||
# Not implemented:
|
# Not implemented:
|
||||||
# "Can be limited to specific timeranges, defaults to all time."
|
# "Can be limited to specific timeranges, defaults to all time."
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"User.get_artist_tracks is deprecated and will be removed in a future "
|
||||||
|
"version. User.get_track_scrobbles is a partial replacement. "
|
||||||
|
"See https://github.com/pylast/pylast/issues/298",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
params = self._get_params()
|
params = self._get_params()
|
||||||
params["artist"] = artist
|
params["artist"] = artist
|
||||||
|
|
||||||
|
@ -2525,6 +2534,32 @@ class User(_BaseObject, _Chartable):
|
||||||
|
|
||||||
return self._get_things("getTopTracks", "track", Track, params, cacheable)
|
return self._get_things("getTopTracks", "track", Track, params, cacheable)
|
||||||
|
|
||||||
|
def get_track_scrobbles(self, artist, track, cacheable=False):
|
||||||
|
"""
|
||||||
|
Get a list of this user's scrobbles of this artist's track,
|
||||||
|
including scrobble time.
|
||||||
|
"""
|
||||||
|
|
||||||
|
params = self._get_params()
|
||||||
|
params["artist"] = artist
|
||||||
|
params["track"] = track
|
||||||
|
|
||||||
|
seq = []
|
||||||
|
for track in _collect_nodes(
|
||||||
|
None, self, self.ws_prefix + ".getTrackScrobbles", cacheable, params
|
||||||
|
):
|
||||||
|
title = _extract(track, "name")
|
||||||
|
artist = _extract(track, "artist")
|
||||||
|
date = _extract(track, "date")
|
||||||
|
album = _extract(track, "album")
|
||||||
|
timestamp = track.getElementsByTagName("date")[0].getAttribute("uts")
|
||||||
|
|
||||||
|
seq.append(
|
||||||
|
PlayedTrack(Track(artist, title, self.network), album, date, timestamp)
|
||||||
|
)
|
||||||
|
|
||||||
|
return seq
|
||||||
|
|
||||||
def get_image(self, size=SIZE_EXTRA_LARGE):
|
def get_image(self, size=SIZE_EXTRA_LARGE):
|
||||||
"""
|
"""
|
||||||
Returns the user's avatar
|
Returns the user's avatar
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
Integration (not unit) tests for pylast.py
|
Integration (not unit) tests for pylast.py
|
||||||
"""
|
"""
|
||||||
import unittest
|
import unittest
|
||||||
|
import warnings
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
|
@ -12,10 +13,10 @@ from .test_pylast import TestPyLastWithLastFm
|
||||||
class TestPyLastAlbum(TestPyLastWithLastFm):
|
class TestPyLastAlbum(TestPyLastWithLastFm):
|
||||||
def test_album_tags_are_topitems(self):
|
def test_album_tags_are_topitems(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
albums = self.network.get_user("RJ").get_top_albums()
|
album = self.network.get_album("Test Artist", "Test Album")
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
tags = albums[0].item.get_top_tags(limit=1)
|
tags = album.get_top_tags(limit=1)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertGreater(len(tags), 0)
|
self.assertGreater(len(tags), 0)
|
||||||
|
@ -44,6 +45,8 @@ class TestPyLastAlbum(TestPyLastWithLastFm):
|
||||||
lastfm_user = self.network.get_user(self.username)
|
lastfm_user = self.network.get_user(self.username)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||||
track = lastfm_user.get_artist_tracks(artist="Test Artist")[0]
|
track = lastfm_user.get_artist_tracks(artist="Test Artist")[0]
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
|
|
|
@ -20,15 +20,14 @@ class TestPyLastNetwork(TestPyLastWithLastFm):
|
||||||
lastfm_user = self.network.get_user(self.username)
|
lastfm_user = self.network.get_user(self.username)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
|
self.network.scrobble(artist=artist, title="test title 2", timestamp=timestamp)
|
||||||
self.network.scrobble(artist=artist, title=title, timestamp=timestamp)
|
self.network.scrobble(artist=artist, title=title, timestamp=timestamp)
|
||||||
time.sleep(1) # Delay, for Last.fm latency. TODO Can this be removed later?
|
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
# limit=2 to ignore now-playing:
|
# limit=2 to ignore now-playing:
|
||||||
last_scrobble = lastfm_user.get_recent_tracks(limit=2)[0]
|
last_scrobble = lastfm_user.get_recent_tracks(limit=2)[0]
|
||||||
self.assertEqual(str(last_scrobble.track.artist).lower(), artist)
|
self.assertEqual(str(last_scrobble.track.artist).lower(), artist)
|
||||||
self.assertEqual(str(last_scrobble.track.title).lower(), title)
|
self.assertEqual(str(last_scrobble.track.title).lower(), title)
|
||||||
self.assertEqual(str(last_scrobble.timestamp), str(timestamp))
|
|
||||||
|
|
||||||
def test_update_now_playing(self):
|
def test_update_now_playing(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -4,6 +4,7 @@ Integration (not unit) tests for pylast.py
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
import warnings
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
|
@ -186,6 +187,8 @@ class TestPyLastUser(TestPyLastWithLastFm):
|
||||||
lastfm_user = self.network.get_authenticated_user()
|
lastfm_user = self.network.get_authenticated_user()
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||||
result1 = lastfm_user.get_artist_tracks("Test Artist", cacheable=False)
|
result1 = lastfm_user.get_artist_tracks("Test Artist", cacheable=False)
|
||||||
result2 = lastfm_user.get_artist_tracks("Test Artist", cacheable=True)
|
result2 = lastfm_user.get_artist_tracks("Test Artist", cacheable=True)
|
||||||
result3 = lastfm_user.get_artist_tracks("Test Artist")
|
result3 = lastfm_user.get_artist_tracks("Test Artist")
|
||||||
|
@ -430,6 +433,34 @@ class TestPyLastUser(TestPyLastWithLastFm):
|
||||||
self.assertIsNotNone(track)
|
self.assertIsNotNone(track)
|
||||||
self.assertIsInstance(track.network, pylast.LastFMNetwork)
|
self.assertIsInstance(track.network, pylast.LastFMNetwork)
|
||||||
|
|
||||||
|
def test_user_get_track_scrobbles(self):
|
||||||
|
# Arrange
|
||||||
|
artist = "France Gall"
|
||||||
|
title = "Laisse Tomber Les Filles"
|
||||||
|
user = self.network.get_user("bbc6music")
|
||||||
|
|
||||||
|
# Act
|
||||||
|
scrobbles = user.get_track_scrobbles(artist, title)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertGreater(len(scrobbles), 0)
|
||||||
|
self.assertEqual(str(scrobbles[0].track.artist), "France Gall")
|
||||||
|
self.assertEqual(scrobbles[0].track.title, "Laisse Tomber Les Filles")
|
||||||
|
|
||||||
|
def test_cacheable_user_get_track_scrobbles(self):
|
||||||
|
# Arrange
|
||||||
|
artist = "France Gall"
|
||||||
|
title = "Laisse Tomber Les Filles"
|
||||||
|
user = self.network.get_user("bbc6music")
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result1 = user.get_track_scrobbles(artist, title, cacheable=False)
|
||||||
|
result2 = user.get_track_scrobbles(artist, title, cacheable=True)
|
||||||
|
result3 = user.get_track_scrobbles(artist, title)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.helper_validate_results(result1, result2, result3)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main(failfast=True)
|
unittest.main(failfast=True)
|
||||||
|
|
Loading…
Reference in a new issue