From 7163122e1bb36ccf446e09a6720db89908a27130 Mon Sep 17 00:00:00 2001 From: David Wahlstrom Date: Wed, 16 Mar 2016 16:27:02 -0700 Subject: [PATCH 1/3] last.fm: initial commit of last.fm module This last.fm module will report to the status bar the current track that is being played. Last.fm requires an API key for access to their APIs, so the user must provide their own API key which can be easily obtained for free from http://www.last.fm/api/. --- i3pystatus/lastfm.py | 56 ++++++++++++++++++++++++++++++++++++++++++++ tests/test_lastfm.py | 40 +++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 i3pystatus/lastfm.py create mode 100644 tests/test_lastfm.py diff --git a/i3pystatus/lastfm.py b/i3pystatus/lastfm.py new file mode 100644 index 0000000..3ac37d7 --- /dev/null +++ b/i3pystatus/lastfm.py @@ -0,0 +1,56 @@ +from urllib.request import urlopen +import json +from i3pystatus import IntervalModule + + +class LastFM(IntervalModule): + """ + Displays currently playing song as reported by last.fm. Get your API key + from http://www.last.fm/api. + """ + + settings = ( + ("apikey", "API key used to make calls to last.fm."), + ("user", "Name of last.fm user to track."), + ("playing_format", "Output format when a song is playing"), + ("stopped_format", "Output format when nothing is playing"), + "playing_color", + "stopped_color", + "interval", + ) + required = ("apikey", "user") + playing_color = 'FFFFFF' + stopped_color = '000000' + interval = 5 + playing_format = "{artist} - {track}" + stopped_format = "" + + def run(self): + apiurl = 'http://ws.audioscrobbler.com/2.0/' + uri = '?method=user.getrecenttracks'\ + '&user=%s&api_key=%s' \ + '&format=json&'\ + 'limit=1' % (self.user, self.apikey) + content = urlopen(apiurl + uri).read() + responsestr = content.decode('utf-8') + response = json.loads(responsestr) + + try: + track = response['recenttracks']['track'][0] + if track['@attr']['nowplaying'] == 'true': + cdict = { + "artist": track['artist']['#text'], + "track": track['name'], + "album": track['album']['#text'], + } + + self.data = cdict + self.output = { + "full_text": self.playing_format.format(**cdict), + "color": self.playing_color + } + except KeyError: + self.output = { + "full_text": self.stopped_format, + "color": self.stopped_color + } diff --git a/tests/test_lastfm.py b/tests/test_lastfm.py new file mode 100644 index 0000000..ae75f94 --- /dev/null +++ b/tests/test_lastfm.py @@ -0,0 +1,40 @@ +""" +Basic test for the plexstatus module +""" + +import unittest +from mock import patch +from unittest.mock import MagicMock +from urllib.request import urlopen +from i3pystatus import lastfm + +# inline json of stream info from last.fm APIs +ACTIVE_CONTENT = b'''{"recenttracks":{"track":[{"artist":{"#text":"Tuomas Holopainen","mbid":"ae4c7a2c-fb0f-4bfd-a9be-c815d00030b8"},"name":"The Last Sled","streamable":"0","mbid":"61739f28-42ab-4f5c-88ca-69715fb9f96b","album":{"#text":"Music Inspired by the Life and Times of Scrooge","mbid":"da39ccaf-10af-40c1-a49c-c8ebb95adb2c"},"url":"http://www.last.fm/music/Tuomas+Holopainen/_/The+Last+Sled","image":[{"#text":"http://img2-ak.lst.fm/i/u/34s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"small"},{"#text":"http://img2-ak.lst.fm/i/u/64s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"medium"},{"#text":"http://img2-ak.lst.fm/i/u/174s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"large"},{"#text":"http://img2-ak.lst.fm/i/u/300x300/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"extralarge"}],"@attr":{"nowplaying":"true"}},{"artist":{"#text":"Gungor","mbid":"f68ad842-13b9-4302-8eeb-ade8af70ce96"},"name":"Beautiful Things","streamable":"0","mbid":"f8f52d8f-f934-41ed-92dc-2ea81e708393","album":{"#text":"Beautiful Things","mbid":"f054aca4-b472-42d2-984b-9c52f75da83a"},"url":"http://www.last.fm/music/Gungor/_/Beautiful+Things","image":[{"#text":"http://img2-ak.lst.fm/i/u/34s/e8ba0f40c87040599f1680f04a002d31.png","size":"small"},{"#text":"http://img2-ak.lst.fm/i/u/64s/e8ba0f40c87040599f1680f04a002d31.png","size":"medium"},{"#text":"http://img2-ak.lst.fm/i/u/174s/e8ba0f40c87040599f1680f04a002d31.png","size":"large"},{"#text":"http://img2-ak.lst.fm/i/u/300x300/e8ba0f40c87040599f1680f04a002d31.png","size":"extralarge"}],"date":{"uts":"1458168739","#text":"16 Mar 2016, 22:52"}}],"@attr":{"user":"drwahl","page":"1","perPage":"1","totalPages":"15018","total":"15018"}}}''' + +INACTIVE_CONTENT = b'''{"recenttracks":{"track":[{"artist":{"#text":"Tuomas Holopainen","mbid":"ae4c7a2c-fb0f-4bfd-a9be-c815d00030b8"},"name":"The Last Sled","streamable":"0","mbid":"61739f28-42ab-4f5c-88ca-69715fb9f96b","album":{"#text":"Music Inspired by the Life and Times of Scrooge","mbid":"da39ccaf-10af-40c1-a49c-c8ebb95adb2c"},"url":"http://www.last.fm/music/Tuomas+Holopainen/_/The+Last+Sled","image":[{"#text":"http://img2-ak.lst.fm/i/u/34s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"small"},{"#text":"http://img2-ak.lst.fm/i/u/64s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"medium"},{"#text":"http://img2-ak.lst.fm/i/u/174s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"large"},{"#text":"http://img2-ak.lst.fm/i/u/300x300/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"extralarge"}],"date":{"uts":"1458169072","#text":"16 Mar 2016, 22:57"}}],"@attr":{"user":"drwahl","page":"1","perPage":"1","totalPages":"15019","total":"15019"}}}''' + +class LastFMTest(unittest.TestCase): + + @patch('i3pystatus.lastfm.urlopen', autospec=True) + def test_not_stream(self, urlopen): + """ + Test output when no song is being played + """ + lastfm.urlopen.return_value.read.return_value = INACTIVE_CONTENT + i3lastfm = lastfm.LastFM(apikey='111111', user='drwahl') + i3lastfm.run() + self.assertTrue(i3lastfm.output['full_text'] == i3lastfm.stopped_format) + + @patch('i3pystatus.lastfm.urlopen', autospec=True) + def test_streaming(self, urlopen): + """ + Test output when a song is being played + """ + lastfm.urlopen.return_value.read.return_value = ACTIVE_CONTENT + i3lastfm = lastfm.LastFM(apikey='111111', user='drwahl') + i3lastfm.run() + self.assertTrue(i3lastfm.output['full_text'] == 'Tuomas Holopainen - The Last Sled') + + +if __name__ == '__main__': + unittest.main() From e27c0421b7f3e002a2c15dfe5ed0eec724d22fda Mon Sep 17 00:00:00 2001 From: David Wahlstrom Date: Thu, 17 Mar 2016 19:59:02 -0700 Subject: [PATCH 2/3] test_lastfm: pep8 compliance --- tests/test_lastfm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_lastfm.py b/tests/test_lastfm.py index ae75f94..7225669 100644 --- a/tests/test_lastfm.py +++ b/tests/test_lastfm.py @@ -13,6 +13,7 @@ ACTIVE_CONTENT = b'''{"recenttracks":{"track":[{"artist":{"#text":"Tuomas Holopa INACTIVE_CONTENT = b'''{"recenttracks":{"track":[{"artist":{"#text":"Tuomas Holopainen","mbid":"ae4c7a2c-fb0f-4bfd-a9be-c815d00030b8"},"name":"The Last Sled","streamable":"0","mbid":"61739f28-42ab-4f5c-88ca-69715fb9f96b","album":{"#text":"Music Inspired by the Life and Times of Scrooge","mbid":"da39ccaf-10af-40c1-a49c-c8ebb95adb2c"},"url":"http://www.last.fm/music/Tuomas+Holopainen/_/The+Last+Sled","image":[{"#text":"http://img2-ak.lst.fm/i/u/34s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"small"},{"#text":"http://img2-ak.lst.fm/i/u/64s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"medium"},{"#text":"http://img2-ak.lst.fm/i/u/174s/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"large"},{"#text":"http://img2-ak.lst.fm/i/u/300x300/b3efb95e128e427cc25bbf9d97e9f57c.png","size":"extralarge"}],"date":{"uts":"1458169072","#text":"16 Mar 2016, 22:57"}}],"@attr":{"user":"drwahl","page":"1","perPage":"1","totalPages":"15019","total":"15019"}}}''' + class LastFMTest(unittest.TestCase): @patch('i3pystatus.lastfm.urlopen', autospec=True) From e529fa8c95b58d8d2a2e05efeeb68ed7f6a3debc Mon Sep 17 00:00:00 2001 From: David Wahlstrom Date: Fri, 16 Oct 2015 20:49:27 -0700 Subject: [PATCH 3/3] dota2wins: truncate win percentage Use only 2 decimals for win percentage so we don't fill all of the status bar with decimal places. --- i3pystatus/dota2wins.py | 1 + 1 file changed, 1 insertion(+) diff --git a/i3pystatus/dota2wins.py b/i3pystatus/dota2wins.py index db85bae..2c50520 100644 --- a/i3pystatus/dota2wins.py +++ b/i3pystatus/dota2wins.py @@ -101,6 +101,7 @@ class Dota2wins(IntervalModule): "screenname": screenname, "wins": wins, "losses": losses, + "win_percent": win_percent, "win_percent": "%.2f" % win_percent, }