From 44b759cfcfb80d94ddac5ea11302a6f94cb307b4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristoffer=20Gr=C3=B6nlund?= Date: Fri, 1 Jan 2010 17:30:14 +0100 Subject: [PATCH 1/1] Download links --- jamaendo/api.py | 15 +++++++--- jamaui/albumlist.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++ jamaui/favorites.py | 39 ++++++++++---------------- jamaui/player.py | 8 ++++++ jamaui/playerwindow.py | 36 ++++++++---------------- jamaui/postoffice.py | 55 +++++++++++++++++++----------------- jamaui/search.py | 6 ++-- jamaui/settings.py | 7 +++++ jamaui/showalbum.py | 72 +++++++++++++++++++----------------------------- jamaui/showartist.py | 28 ++++++------------- jamaui/ui.py | 10 +++++++ 11 files changed, 200 insertions(+), 146 deletions(-) create mode 100644 jamaui/albumlist.py diff --git a/jamaendo/api.py b/jamaendo/api.py index d026770..74c96f7 100644 --- a/jamaendo/api.py +++ b/jamaendo/api.py @@ -35,7 +35,7 @@ _COVERDIR = None _GET2 = '''http://api.jamendo.com/get2/''' _MP3URL = _GET2+'stream/track/redirect/?id=%d&streamencoding=mp31' _OGGURL = _GET2+'stream/track/redirect/?id=%d&streamencoding=ogg2' - +_TORRENTURL = _GET2+'bittorrent/file/redirect/?album_id=%d&type=archive&class=mp32' def set_cache_dir(cachedir): global _CACHEDIR @@ -137,6 +137,10 @@ class Album(LazyQuery): if json: self.set_from_json(json) + def torrent_url(self): + return _TORRENTURL%(self.ID) + + def _needs_load(self): return self._needs_load_impl('name', 'image', 'artist_name', 'artist_id', 'license_url', 'tracks') @@ -261,9 +265,12 @@ class CoverFetcher(threading.Thread): self.cond.wait() self.cond.release() + multi = len(work) > 1 for albumid, size, cb in work: cover = self._fetch_cover(albumid, size) cb(albumid, size, cover) + if multi: + time.sleep(1.0) class CoverCache(object): """ @@ -303,16 +310,16 @@ class CoverCache(object): def get_async(self, albumid, size, cb): cover = self._covers.get((albumid, size), None) if cover: - cb(cover) + cb(albumid, size, cover) else: self._fetcher.request_cover(albumid, size, cb) _cover_cache = CoverCache() -def get_album_cover(albumid, size=200): +def get_album_cover(albumid, size=100): return _cover_cache.get_cover(albumid, size) -def get_album_cover_async(cb, albumid, size=200): +def get_album_cover_async(cb, albumid, size=100): _cover_cache.get_async(albumid, size, cb) class CustomQuery(Query): diff --git a/jamaui/albumlist.py b/jamaui/albumlist.py new file mode 100644 index 0000000..e851cdb --- /dev/null +++ b/jamaui/albumlist.py @@ -0,0 +1,70 @@ +import gtk +import hildon +import jamaendo +from settings import settings +from postoffice import postoffice +import logging + +log = logging.getLogger(__name__) + +class AlbumList(gtk.TreeView): + def __init__(self): + gtk.TreeView.__init__(self) + self.__store = gtk.ListStore(str, int) + self.set_model(self.__store) + + col = gtk.TreeViewColumn('Name') + self.append_column(col) + cell = gtk.CellRendererText() + col.pack_start(cell, True) + col.add_attribute(cell, 'text', 0) + self.set_search_column(0) + col.set_sort_column_id(0) + + self.__show_artist = True + + def add_album(self, album): + if self.__show_artist: + txt = "%s - %s" % (album.artist_name, album.name) + else: + txt = album.name + self.__store.append([txt, album.ID]) + + def get_album_id(self, path): + treeiter = self.__store.get_iter(path) + _, _id = self.__store.get(treeiter, 0, 1) + return _id + + def show_artist(self, show): + self.__show_artist = show + +class TrackList(gtk.TreeView): + def __init__(self, numbers = True): + gtk.TreeView.__init__(self) + self.track_numbers = numbers + self.__store = gtk.ListStore(int, str, int) + self.set_model(self.__store) + + if numbers: + col0 = gtk.TreeViewColumn('Num') + self.append_column(col0) + cell0 = gtk.CellRendererText() + col0.pack_start(cell0, True) + col0.add_attribute(cell0, 'text', 0) + + col = gtk.TreeViewColumn('Name') + self.append_column(col) + cell = gtk.CellRendererText() + col.pack_start(cell, True) + col.add_attribute(cell, 'text', 1) + + self.set_search_column(1 if numbers else 0) + col.set_sort_column_id(0) + + def add_track(self, track): + self.__store.append([track.numalbum, track.name, track.ID]) + + def get_track_id(self, path): + treeiter = self.__store.get_iter(path) + _, _id = self.__store.get(treeiter, 0, 1) + return _id diff --git a/jamaui/favorites.py b/jamaui/favorites.py index 9c37393..d607a8b 100644 --- a/jamaui/favorites.py +++ b/jamaui/favorites.py @@ -30,6 +30,8 @@ from showalbum import ShowAlbum from settings import settings import logging +from albumlist import AlbumList + log = logging.getLogger(__name__) def _alist(l, match): @@ -46,43 +48,33 @@ class FavoritesWindow(hildon.StackableWindow): if settings.user: # Results list self.panarea = hildon.PannableArea() - self.result_store = gtk.ListStore(str, int) - #self.result_store.append(['red']) - self.result_view = gtk.TreeView(self.result_store) - col = gtk.TreeViewColumn('Name') - self.result_view.append_column(col) - cell = gtk.CellRendererText() - col.pack_start(cell, True) - col.add_attribute(cell, 'text', 0) - self.result_view.set_search_column(0) - col.set_sort_column_id(0) - self.result_view.connect('row-activated', self.row_activated) - - self.panarea.add(self.result_view) + self.results = AlbumList() + self.results.connect('row-activated', self.row_activated) + self.panarea.add(self.results) self.idmap = {} + + def add_album(ID, album_factory): + if ID not in self.idmap: + album = album_factory() + self.idmap[ID] = album + self.results.add_album(album) + try: for item in jamaendo.favorite_albums(settings.user): - self.idmap[item.ID] = item - self.result_store.append([self.get_item_text(item), item.ID]) + add_album(item.ID, lambda: item) except jamaendo.JamendoAPIException, e: msg = "Query failed, is the user name '%s' correct?" % (settings.user) banner = hildon.hildon_banner_show_information(self, '', msg) banner.set_timeout(3000) - - def add_album(albumid): - album = jamaendo.get_album(albumid) - self.idmap[albumid] = album - self.result_store.append([self.get_item_text(album), albumid]) - for item in settings.favorites: try: if isinstance(item, tuple) and len(item) == 2: ftype, fid = item if ftype == 'album': - add_album(fid) + add_album(fid, lambda: jamaendo.get_album(fid)) except jamaendo.JamendoAPIException, e: log.exception("jamaendo.get_album(%s)"%(fid)) @@ -123,8 +115,7 @@ enter your username return button def row_activated(self, treeview, path, view_column): - treeiter = self.result_store.get_iter(path) - title, _id = self.result_store.get(treeiter, 0, 1) + _id = self.results.get_album_id(path) item = self.idmap[_id] print _id, item self.open_item(item) diff --git a/jamaui/player.py b/jamaui/player.py index d860ccb..ec3c75b 100644 --- a/jamaui/player.py +++ b/jamaui/player.py @@ -27,6 +27,7 @@ import dbus import jamaendo from settings import settings +from postoffice import postoffice log = logging.getLogger(__name__) @@ -65,6 +66,13 @@ class GStreamer(_Player): self.volume_multiplier = 1. self.volume_property = None self.eos_callback = lambda: self.stop() + postoffice.connect('settings-changed', self.on_settings_changed) + + def on_settings_changed(self, key, value): + if key == 'volume': + self._set_volume_level(value) + #postoffice.disconnect(self.on_settings_changed) + def play_url(self, filetype, uri): if None in (filetype, uri): diff --git a/jamaui/playerwindow.py b/jamaui/playerwindow.py index 65fe075..57ea13f 100644 --- a/jamaui/playerwindow.py +++ b/jamaui/playerwindow.py @@ -23,27 +23,15 @@ # import gtk import hildon -import jamaendo from settings import settings +from postoffice import postoffice from player import Playlist, the_player -_player_window = None - -def album_cover_receiver(albumid, size, cover): - if _player_window: - playing = _player_window.get_album_id() - if int(playing) == int(albumid): - _player_window.set_album_cover(cover) - class PlayerWindow(hildon.StackableWindow): def __init__(self, playlist=None): hildon.StackableWindow.__init__(self) self.set_title("jamaendo") - global _player_window - _player_window = self - - self.connect('hide', self.on_hide) self.connect('destroy', self.on_destroy) self.playlist = Playlist(playlist) @@ -54,7 +42,6 @@ class PlayerWindow(hildon.StackableWindow): hbox = gtk.HBox() self.cover = gtk.Image() - self.cover.set_size_request(200, 200) self.cover.set_from_stock(gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG) vbox2 = gtk.VBox() @@ -103,6 +90,8 @@ class PlayerWindow(hildon.StackableWindow): hbox.pack_start(self.volume, False) self.add(vbox) + postoffice.connect('album-cover', self.set_album_cover) + print "Created player window, playlist: %s" % (self.playlist) def get_album_id(self): @@ -110,15 +99,8 @@ class PlayerWindow(hildon.StackableWindow): return self.playlist.current().album_id return None - def on_hide(self, wnd): - print "Hiding player window" - def on_destroy(self, wnd): - print "Destroying player window" - global _player_window - _player_window = None - if self.player: - self.player.stop() + postoffice.disconnect('album-cover', self.set_album_cover) def add_stock_button(self, btns, stock, cb): btn = hildon.GtkButton(gtk.HILDON_SIZE_FINGER_HEIGHT) @@ -151,13 +133,17 @@ class PlayerWindow(hildon.StackableWindow): print "current:", item self.set_labels(item.name, item.artist_name, item.album_name, self.playlist.current_index(), self.playlist.size()) - jamaendo.get_album_cover_async(album_cover_receiver, int(item.album_id), size=200) + postoffice.notify('request-album-cover', int(item.album_id), 300) + #jamaendo.get_album_cover_async(album_cover_receiver, int(item.album_id), size=200) #coverfile = jamaendo.get_album_cover(int(item.album_id), size=200) #print "coverfile:", coverfile #self.cover.set_from_file(coverfile) - def set_album_cover(self, cover): - self.cover.set_from_file(cover) + def set_album_cover(self, albumid, size, cover): + if size == 300: + playing = self.get_album_id() + if int(playing) == int(albumid): + self.cover.set_from_file(cover) def play_tracks(self, tracks): self.playlist = Playlist(tracks) diff --git a/jamaui/postoffice.py b/jamaui/postoffice.py index 009c884..675f9bf 100644 --- a/jamaui/postoffice.py +++ b/jamaui/postoffice.py @@ -23,35 +23,38 @@ # # message central +import logging + +log = logging.getLogger(__name__) + class PostOffice(object): - class Client(object): - def __init__(self): - self.tags = {} - def has_tag(self, tag): - return tag in self.tags - def notify(self, tags, data): - for tag in tags: - cb = self.tags.get(tag) - if cb: - cb(data) - def register(self, tag, callback): - self.tags[tag] = callback def __init__(self): - self.clients = {} - - def notify(self, tags, data): - if not isinstance(tags, list): - tags = [tags] - for client in clients: - client.notify(tags, data) - - def register(self, client_id, tag, callback): - client = self.clients.get(client_id) - if not client: - client = Client() - self.clients[client_id] = client - client.register(tag, callback) + self.tags = {} # tag -> [callback] + + def notify(self, tag, *data): + clients = self.tags.get(tag) + if clients: + log.debug("(%s %s) -> [%s]", + tag, + " ".join(str(x) for x in data), + " ".join(str(x) for x in clients)) + for client in clients: + client(*data) + + def connect(self, tag, callback): + if tag not in self.tags: + self.tags[tag] = [] + clients = self.tags[tag] + if callback not in clients: + clients.append(callback) + + def disconnect(self, tag, callback): + if tag not in self.tags: + self.tags[tag] = [] + clients = self.tags[tag] + if callback in clients: + clients.remove(callback) postoffice = PostOffice() diff --git a/jamaui/search.py b/jamaui/search.py index 40779f7..f7e27fb 100644 --- a/jamaui/search.py +++ b/jamaui/search.py @@ -88,8 +88,8 @@ class SearchWindow(hildon.StackableWindow): self.idmap = {} def mode_changed(self, selector, user_data): - current_selection = selector.get_current_text() - print current_selection + pass + #current_selection = selector.get_current_text() def on_search(self, w): mode = self.mode.get_active() @@ -115,7 +115,7 @@ class SearchWindow(hildon.StackableWindow): treeiter = self.result_store.get_iter(path) title, _id = self.result_store.get(treeiter, 0, 1) item = self.idmap[_id] - print _id, item + #print _id, item self.open_item(item) def open_item(self, item): diff --git a/jamaui/settings.py b/jamaui/settings.py index c1dcc61..f141c69 100644 --- a/jamaui/settings.py +++ b/jamaui/settings.py @@ -24,6 +24,8 @@ import cPickle, os import logging +from postoffice import postoffice + VERSION = 1 log = logging.getLogger(__name__) @@ -39,6 +41,11 @@ class Settings(object): for k,v in self.defaults.iteritems(): setattr(self, k, v) + def __setattr__(self, key, value): + object.__setattr__(self, key, value) + if key in self.defaults.keys(): + postoffice.notify('settings-changed', key, value) + def set_filename(self, savename): self.__savename = savename diff --git a/jamaui/showalbum.py b/jamaui/showalbum.py index c95974e..773db8c 100644 --- a/jamaui/showalbum.py +++ b/jamaui/showalbum.py @@ -26,27 +26,22 @@ import hildon import jamaendo from playerwindow import open_playerwindow from settings import settings +from postoffice import postoffice import util +import logging +from albumlist import TrackList +import webbrowser -_instance = None - -def album_cover_receiver(albumid, size, cover): - if _instance: - playing = _instance.get_album_id() - if int(playing) == int(albumid): - _instance.set_album_cover(cover) +log = logging.getLogger(__name__) class ShowAlbum(hildon.StackableWindow): def __init__(self, album): hildon.StackableWindow.__init__(self) - self.set_title("Album") + self.set_title(album.artist_name) self.album = album - global _instance - _instance = self self.connect('destroy', self.on_destroy) - top_vbox = gtk.VBox() top_hbox = gtk.HBox() vbox1 = gtk.VBox() self.cover = gtk.Image() @@ -62,33 +57,16 @@ class ShowAlbum(hildon.StackableWindow): self.playbtn.connect('clicked', self.on_play) vbox2 = gtk.VBox() - self.albumtitle = gtk.Label() - self.albumtitle.set_markup('%s' % (album.name)) - self.artist = gtk.Label() - self.artist.set_markup('%s'%(album.artist_name)) + self.albumname = gtk.Label() + self.albumname.set_markup('%s'%(album.name)) self.trackarea = hildon.PannableArea() - self.album_store = gtk.ListStore(int, str, int) - self.album_view = gtk.TreeView(self.album_store) - col0 = gtk.TreeViewColumn('Num') - col = gtk.TreeViewColumn('Name') - self.album_view.append_column(col0) - self.album_view.append_column(col) - cell0 = gtk.CellRendererText() - col0.pack_start(cell0, True) - col0.add_attribute(cell0, 'text', 0) - cell = gtk.CellRendererText() - col.pack_start(cell, True) - col.add_attribute(cell, 'text', 1) - self.album_view.set_search_column(1) - col.set_sort_column_id(0) - self.album_view.connect('row-activated', self.row_activated) + self.tracks = TrackList(numbers=True) + self.tracks.connect('row-activated', self.row_activated) for track in jamaendo.get_tracks(album.ID): - self.album_store.append([track.numalbum, track.name, track.ID]) + self.tracks.add_track(track) - top_vbox.pack_start(self.albumtitle, False) - top_vbox.pack_start(top_hbox) top_hbox.pack_start(vbox1, False) top_hbox.pack_start(vbox2, True) vbox1.pack_start(self.cover, True) @@ -98,21 +76,23 @@ class ShowAlbum(hildon.StackableWindow): self.bbox.add(self.download) self.bbox.add(self.favorite) self.bbox.add(self.license) - vbox2.pack_start(self.artist, False) + vbox2.pack_start(self.albumname, False) vbox2.pack_start(self.trackarea, True) - self.trackarea.add(self.album_view) + self.trackarea.add(self.tracks) - self.add(top_vbox) + self.add(top_hbox) - # here it's probably ok to get the cover synchronously.. - coverfile = jamaendo.get_album_cover(self.album.ID, size=200) - self.cover.set_from_file(coverfile) + postoffice.connect('album-cover', self.on_album_cover) + postoffice.notify('request-album-cover', self.album.ID, 300) self.show_all() def on_destroy(self, wnd): - global _instance - _instance = None + postoffice.disconnect('album-cover', self.on_album_cover) + + def on_album_cover(self, albumid, size, cover): + if albumid == self.album.ID and size == 300: + self.cover.set_from_file(cover) def make_imagebutton(self, name, cb): btn = hildon.GtkButton(gtk.HILDON_SIZE_AUTO) @@ -131,8 +111,10 @@ class ShowAlbum(hildon.StackableWindow): self.open_item(artist) def on_download(self, btn): - banner = hildon.hildon_banner_show_information(self, '', "Downloads disabled in this version") + banner = hildon.hildon_banner_show_information(self, '', "Opening in web browser") banner.set_timeout(2000) + url = self.album.torrent_url() + webbrowser.open_new(url) def on_favorite(self, btn): settings.favorite(self.album) @@ -141,15 +123,17 @@ class ShowAlbum(hildon.StackableWindow): def on_license(self, btn): + banner = hildon.hildon_banner_show_information(self, '', "Opening in web browser") + banner.set_timeout(2000) url = self.album.license_url - import webbrowser webbrowser.open_new(url) def on_play(self, btn): self.open_item(self.album) def row_activated(self, treeview, path, view_column): - pass + _id = self.tracks.get_track_id(path) + log.debug("clicked %s", _id) def open_item(self, item): if isinstance(item, jamaendo.Album): diff --git a/jamaui/showartist.py b/jamaui/showartist.py index ecc857b..9cae975 100644 --- a/jamaui/showartist.py +++ b/jamaui/showartist.py @@ -25,42 +25,30 @@ import gtk import hildon import jamaendo from playerwindow import open_playerwindow +from albumlist import AlbumList class ShowArtist(hildon.StackableWindow): def __init__(self, artist): hildon.StackableWindow.__init__(self) - self.set_title("Artist") + self.set_title(artist.name) self.artist = artist self.panarea = hildon.PannableArea() vbox = gtk.VBox(False, 0) - name = gtk.Label() - name.set_markup('%s'%(artist.name)) - vbox.pack_start(name, False) + self.albums = AlbumList() + self.albums.show_artist(False) + self.albums.connect('row-activated', self.row_activated) - self.album_store = gtk.ListStore(str, int) - self.album_view = gtk.TreeView(self.album_store) - col = gtk.TreeViewColumn('Name') - self.album_view.append_column(col) - cell = gtk.CellRendererText() - col.pack_start(cell, True) - col.add_attribute(cell, 'text', 0) - self.album_view.set_search_column(0) - col.set_sort_column_id(0) - self.album_view.connect('row-activated', self.row_activated) - - - self.panarea.add(self.album_view) + self.panarea.add(self.albums) vbox.pack_start(self.panarea, True, True, 0) self.add(vbox) for album in jamaendo.get_albums(artist.ID): - self.album_store.append([album.name, album.ID]) + self.albums.add_album(album) def row_activated(self, treeview, path, view_column): - treeiter = self.album_store.get_iter(path) - title, _id = self.album_store.get(treeiter, 0, 1) + _id = self.albums.get_album_id(path) album = jamaendo.get_album(_id) if isinstance(album, list): album = album[0] diff --git a/jamaui/ui.py b/jamaui/ui.py index 2ba4597..7a8fc6d 100644 --- a/jamaui/ui.py +++ b/jamaui/ui.py @@ -56,6 +56,7 @@ DBusGMainLoop(set_as_default=True) import jamaendo +from postoffice import postoffice from playerwindow import open_playerwindow from search import SearchWindow from featured import FeaturedWindow @@ -91,6 +92,8 @@ class Jamaui(object): settings.set_filename(os.path.join(self.CONFDIR, 'ui_settings')) settings.load() + postoffice.connect('request-album-cover', self.on_request_cover) + def save_settings(self): settings.save() @@ -167,6 +170,12 @@ class Jamaui(object): btn.connect('clicked', callback) self.bbox.add(btn) + def on_request_cover(self, albumid, size): + jamaendo.get_album_cover_async(self.got_album_cover, int(albumid), size) + + def got_album_cover(self, albumid, size, cover): + postoffice.notify('album-cover', albumid, size, cover) + #def add_featured_button(self): # self.featured_sel = hildon.TouchSelector(text=True) # self.featured_sel.append_text("Albums of the week") @@ -181,6 +190,7 @@ class Jamaui(object): # self.bbox.add(btn) def destroy(self, widget): + postoffice.disconnect('request-album-cover', self.on_request_cover) gtk.main_quit() def show_about(self, w, win): -- 1.7.9.5