1
from xl import main as ex, track, common, event, xdg, settings, providers
1
from xl import main as ex, trax, common, event, xdg, settings, providers
2
2
from xl.nls import gettext as _
3
3
from xlgui import panel, guiutil, playlist, menu
5
from StringIO import StringIO
15
17
from inspector import Inspector
17
LFM_API_KEY = '3b954460f7b207e5414ffdf8c5710592'
19
# Last.fm API Key for Exaile
20
# if you reuse this code in a different application, please
21
# register your own key with last.fm
22
LFM_API_KEY = "3599c79a97fd61ce518b75922688bc38"
19
25
CURPATH = os.path.realpath(__file__)
20
26
BASEDIR = os.path.dirname(CURPATH)+os.path.sep
41
47
selected = self.widget.get_selected_tracks()
42
48
pl = xlgui.controller().main.get_selected_playlist()
43
ex.exaile().queue.add_tracks(selected, add_duplicates=False)
49
ex.exaile().queue.add_tracks(selected)
45
pl.playlist.add_tracks(selected, add_duplicates=False)
51
pl.playlist.add_tracks(selected)
46
52
pl.list.queue_draw()
48
54
class BrowserPage(webkit.WebView, providers.ProviderHandler):
291
297
selected = self.get_selected_tracks()
292
298
pl = xlgui.controller().main.get_selected_playlist()
294
pl.playlist.add_tracks(selected, add_duplicates=False)
300
pl.playlist.add_tracks(selected)
296
302
def _navigation_requested_cb(self, view, frame, networkRequest):
297
303
link = self.un_url(networkRequest.get_uri()).split('://', 1)
403
def get_image_data(filename, size):
399
class ImageBuffer(object):
403
def write(self, str):
406
def get_base64(self):
407
return base64.b64encode(self.buffer)
409
def get_image_data(data, size):
404
410
imbuff = ImageBuffer()
405
im = Image.open(filename)
412
im = Image.open(StringIO(data))
414
im = Image.open(xdg.get_data_path('images/nocover.png'))
406
415
im = im.resize(size, Image.ANTIALIAS)
407
416
im.save(imbuff, "PNG")
408
417
return 'data:image/png;base64,%s' % imbuff.get_base64()
653
663
class DefaultPage(ContextPage):
655
665
def __init__(self, theme, base='default://', template='default.html', async=[]):
657
self.username = settings.get_option('plugin/ascrobbler/user')
668
self.username = settings.get_option('plugin/lastfm/user')
669
self.password_hash = pylast.md5(settings.get_option('plugin/lastfm/password'))
659
671
self.username = None
672
self.password_hash = None
660
674
ContextPage.__init__(self, theme, base, template, async+['last-played-tracks', 'last-played-artists', 'last-added-tracks', 'last-added-artists', 'most-played-tracks', 'most-played-artists', 'lfm-last-played', 'lfm-top-tracks', 'lfm-top-albums', 'lfm-top-artists'])
662
676
def _last_played_tracks_title(self):
663
return "Rencently Played Tracks"
677
return "Recently Played Tracks"
665
679
def _last_played_tracks(self, limit=10):
666
680
tracks = get_top_tracks('__last_played', int(limit))
667
681
return "<br/>".join(self.get_track_anchor_from_track(track, img=True) for track in tracks)
669
683
def _last_played_albums_title(self):
670
return "Rencently Played Albums"
684
return "Recently Played Albums"
672
686
def _last_played_albums(self, limit=5):
673
687
cds = get_top_albums('last_played', int(limit))
728
742
artists = get_top_artists('__playcount', int(limit))
729
743
return ', '.join(self.get_artist_anchor(artist) for artist in artists)
745
def get_lfm_user(self):
747
self.user = pylast.User(self.username, self.password_hash, pylast.network)
731
750
def _lfm_last_played_title(self):
732
751
return "Last Scrobbled Tracks"
734
753
def _lfm_last_played(self, limit=10):
736
tracks = pylast.User(self.username, LFM_API_KEY, None, None).get_recent_tracks(int(limit))
737
return '<br/>'.join(self.get_track_anchor_from_artist_title(tr.get_track().get_artist(), tr.get_track().get_title()) for tr in tracks)
755
tracks = self.get_lfm_user().get_recent_tracks(int(limit))
756
return '<br/>'.join(self.get_track_anchor_from_artist_title(tr.track.get_artist(), tr.track.get_title()) for tr in tracks)
738
757
return "Enter your username in the settings"
740
759
def _lfm_top_tracks_title(self):
741
760
return "Your Top Tracks on Last.fm"
743
762
def _lfm_top_tracks(self, period='overall', limit=15):
745
tracks = pylast.User(self.username, LFM_API_KEY, None, None).get_top_tracks(period)[:int(limit)]
746
return '<br/>'.join(self.get_track_anchor_from_artist_title(tr.get_item().get_artist(), tr.get_item().get_title()) for tr in tracks)
763
if self.get_lfm_user():
764
tracks = self.get_lfm_user().get_top_tracks(period, int(limit))
765
return '<br/>'.join(self.get_track_anchor_from_artist_title(tr.track.get_artist(), tr.track.get_title()) for tr in tracks)
747
766
return "Enter your username in the settings"
749
768
def _lfm_top_artists_title(self):
750
769
return "Your Top Artists on Last.fm"
752
771
def _lfm_top_artists(self, period='overall', limit=20):
754
artists = pylast.User(self.username, LFM_API_KEY, None, None).get_top_artists(period)[:int(limit)]
755
return ', '.join(self.get_artist_anchor(artist.get_item().get_name()) for artist in artists)
772
if self.get_lfm_user():
773
artists = self.get_lfm_user().get_top_artists(period,int(limit))
774
return ', '.join(self.get_artist_anchor(artist.item.get_name()) for artist in artists)
756
775
return "Enter your username in the settings"
758
777
def _lfm_top_albums_title(self):
759
778
return "Your Top Albums on Last.fm"
761
780
def _lfm_top_albums(self, period='overall', limit=10):
763
cds = [album.get_item().get_title() for album in pylast.User(self.username, LFM_API_KEY, None, None).get_top_albums(period)[:int(limit)]]
781
if self.get_lfm_user():
782
cds = [album.get_item().get_title() for album in self.get_lfm_user().get_top_albums(period,int(limit))]
772
791
class ArtistPage(DefaultPage):
773
792
def __init__(self, theme, artist, base = 'artist://', template ='artist.html', async=[]):
774
793
self.artist = artist
775
self.artist_tracks = get_artist_tracks(artist)
794
self.lfm_artist = None
776
796
DefaultPage.__init__(self, theme, base, template, async+['compils', 'albums', 'artist-info', 'artist-img', 'artist-tags', 'similar-artists', 'top-tracks'])
798
def get_lfm_artist(self):
799
if not self.lfm_artist:
800
self.lfm_artist = pylast.Artist(self.artist, pylast.network)
801
return self.lfm_artist
778
803
def get_template_fields(self):
779
804
fields = ContextPage.get_template_fields(self)
780
805
for field in fields:
805
830
def _artist(self):
806
831
return self.artist
808
def _artist_img(self, size=pylast.IMAGE_LARGE):
833
def _artist_img(self, size=pylast.COVER_LARGE):
810
url = pylast.search_for_artist(self.artist, LFM_API_KEY, None, None).get_next_page()[0].get_image_url(size)
835
url = self.get_lfm_artist().get_cover_image(size)
811
836
return '<img id="artist-info-img" src="%s"/>' % url
815
840
def _artist_info(self):
816
bio = pylast.search_for_artist(self.artist, LFM_API_KEY, None, None).get_next_page()[0].get_bio_summary()
817
return self.LFMInfoParser(self, str(bio), self['artist']).data
841
if self.get_lfm_artist():
842
bio = self.get_lfm_artist().get_bio_summary()
843
return self.LFMInfoParser(self, str(bio), self['artist']).data
819
846
def _top_tracks_title(self):
820
847
return 'Top tracks by %s' % self['artist']
822
849
def _top_tracks(self, limit=10):
823
doc = pylast.search_for_artist(self['artist'],LFM_API_KEY, None, None).get_next_page()[0].get_top_tracks()[:int(limit)]
824
return '<br/>'.join(self.get_track_anchor_from_artist_title(self['artist'], tr.get_item().get_title(), img=True) for tr in doc)
850
if self.get_lfm_artist():
851
doc = self.get_lfm_artist().get_top_tracks(int(limit))
852
return '<br/>'.join(self.get_track_anchor_from_artist_title(self['artist'], tr.get_item().get_title(), img=True) for tr in doc)
826
855
def _artist_tags_title(self):
827
856
return "Tags for %s" % self['artist']
829
858
def _artist_tags(self, limit=10):
830
doc = pylast.search_for_artist(self['artist'],LFM_API_KEY, None, None).get_next_page()[0].get_top_tags()[:int(limit)]
831
return ', '.join(self.get_tag_anchor(tag) for tag in doc)
859
if self.get_lfm_artist():
860
doc = self.get_lfm_artist().get_top_tags(int(limit))
861
return ', '.join(self.get_tag_anchor(tag.item) for tag in doc)
833
864
def _compils_title(self):
834
865
return "Compilations with %s"%self['artist']
842
873
def _similar_artists_title(self):
843
874
return "Artists related to %s" % self['artist']
845
def _similar_artists_images(self):
846
doc = pylast.search_for_artist(self['artist'], LFM_API_KEY, None, None)
847
temp = doc.get_next_page()[0].get_similar(10)
850
data.append('<img title ="%s" src="%s"/>' % (art, pylast.Artist.get_square_image(art)))
853
876
def _similar_artists(self, limit=10):
854
sim_artists = pylast.search_for_artist(self['artist'], LFM_API_KEY, None, None).get_next_page()[0].get_similar(int(limit))
855
return ', '.join(self.get_artist_anchor(sim_artist) for sim_artist in sim_artists)
877
if self.get_lfm_artist():
878
sim_artists = self.get_lfm_artist().get_similar(int(limit))
879
return ', '.join(self.get_artist_anchor(sim_artist.item) for sim_artist in sim_artists)
857
882
def _albums_title(self):
858
883
return "Albums by %s" % self['artist']
909
934
def __init__(self, theme, tag, base='tag://', template='tag.html', async=[]):
911
938
DefaultPage.__init__(self, theme, base, template, async+['similar-tags', 'top-artists', 'tag-top-tracks', 'tag-top-albums'])
940
def get_lfm_tag(self):
942
self.lfm_tag = pylast.Tag(self.tag, pylast.network)
917
949
return "Tags similar to %s" % self['tag']
919
951
def _similar_tags(self):
920
tags = pylast.search_for_tag(self.tag, LFM_API_KEY, None, None).get_next_page()[0].get_similar()
921
return ', '.join(self.get_tag_anchor(tag) for tag in tags[:20])
952
if self.get_lfm_tag():
953
tags = self.get_lfm_tag().get_similar()
954
return ', '.join(self.get_tag_anchor(tag) for tag in tags[:20])
923
957
def _top_artists_title(self):
924
958
return "Top %s artists" % self.tag
926
960
def _top_artists(self):
927
artists = pylast.search_for_tag(self.tag, LFM_API_KEY, None, None).get_next_page()[0].get_top_artists()
928
return ', '.join(self.get_artist_anchor(artist.get_item().get_name()) for artist in artists[:20])
961
if self.get_lfm_tag():
962
artists = self.get_lfm_tag().get_top_artists()
963
return ', '.join(self.get_artist_anchor(artist.item) for artist in artists[:20])
930
966
def _tag_top_tracks_title(self):
931
967
return "Top %s tracks" % self.tag
933
969
def _tag_top_tracks(self):
934
tracks = pylast.search_for_tag(self.tag, LFM_API_KEY, None, None).get_next_page()[0].get_top_tracks()
935
return '<br/>'.join(self.get_track_anchor_from_artist_title(track.get_item().get_artist(), track.get_item().get_title()) for track in tracks[:15])
970
if self.get_lfm_tag():
971
tracks = self.get_lfm_tag().get_top_tracks()
972
return '<br/>'.join(self.get_track_anchor_from_artist_title(track.item.get_artist(), track.item.get_title()) for track in tracks[:15])
937
975
def _tag_top_albums_title(self):
938
976
return "Top %s albums" % self.tag
940
978
def _tag_top_albums(self):
941
albums = pylast.search_for_tag(self.tag, LFM_API_KEY, None, None).get_next_page()[0].get_top_albums()
942
return '<br/>'.join("%s %s"%(self['album-ico'],self.get_album_anchor_from_artist_title(album.get_item().get_artist(), album.get_item().get_title())) for album in albums[:15])
979
if self.get_lfm_tag():
980
albums = self.get_lfm_tag().get_top_albums()
981
return '<br/>'.join("%s %s"%(self['album-ico'],self.get_album_anchor_from_artist_title(album.item.get_artist(), album.item.get_name())) for album in albums[:15])
944
984
class PlayingPage(ArtistPage):
946
986
def __init__(self, theme, track, base='playing://', template='playing.html', async=[]):
947
987
self.track = track
988
self.lfm_track = None
948
989
ArtistPage.__init__(self, theme, get_track_tag(self.track, 'artist', 'unknown'),base, template, async+['track-tags', 'suggested-tracks', 'similar-tracks', 'lyrics'])
949
990
event.add_callback(self.refresh_rating, 'rating_changed')
992
def get_lfm_track(self):
993
if not self.lfm_track:
994
self.lfm_track = pylast.Track(get_track_tag(self.track, 'artist', 'unknown'), get_track_tag(self.track, 'title', 'unknown'), pylast.network)
995
return self.lfm_track
951
997
def link_clicked(self, link):
952
998
if link[0] == 'rate':
953
999
self.track.set_rating(int(link[1]))
964
1010
return get_track_tag(self.track, 'album', 'unknown')
966
1012
def _track_cover(self):
967
coverpath = get_track_cover(self.track)
968
cover = get_image_data(coverpath, (100, 100))
969
return "<a id='cover-image' href='%s'><img src='%s'></a>" % (self.get_album_href(self['album']), cover)
1013
cover = get_track_cover(self.track)
1014
cover_data = get_image_data(cover, (100, 100))
1015
return "<a id='cover-image' href='%s'><img src='%s'></a>" % (self.get_album_href(self['album']), cover_data)
971
1017
def _playcount(self):
973
self['playcount'] = self.track['__playcount']
1019
self['playcount'] = self.track.get_tag_display('__playcount')
974
1020
if self['playcount'] == None:
975
1021
self['playcount'] = 0
1003
1049
def _track_tags_title(self):
1004
1050
return "Tags for %s" % self['title']
1006
def _track_tags(self):
1007
tags = pylast.search_for_track(self['artist'], self['title'], LFM_API_KEY, None, None).get_next_page()[0].get_top_tags()
1008
return ', '.join(self.get_tag_anchor(tag) for tag in tags)
1052
def _track_tags(self, limit=10):
1053
if self.get_lfm_track():
1054
tags = self.get_lfm_track().get_top_tags(limit)
1055
return ', '.join(self.get_tag_anchor(tag.item) for tag in tags)
1010
1058
def _suggested_tracks_title(self):
1011
1059
return "Suggested tracks for %s" % self['title']
1018
1066
return 'Tracks similar to %s' % self['title']
1020
1068
def _similar_tracks(self, limit=10):
1021
doc = pylast.search_for_track(self['artist'], self['title'],LFM_API_KEY, None, None).get_next_page()[0].get_similar()[:int(limit)]
1022
return '<br/>'.join(self.get_track_anchor_from_artist_title(str(tr.get_artist()), str(tr.get_title()), img=True) for tr in doc)
1069
if self.get_lfm_track():
1070
doc = self.get_lfm_track().get_similar(int(limit))
1071
return '<br/>'.join(self.get_track_anchor_from_artist_title(str(tr.get_artist()), str(tr.get_title()), img=True) for tr in doc)
1024
1074
def _lyrics_title(self):
1025
1075
return "Lyrics of %s by %s" % (self['title'],self['artist'])