Tons of fixes/tweaks/changes in general
authorKristoffer Grönlund <kristoffer.gronlund@purplescout.se>
Sat, 2 Jan 2010 01:26:23 +0000 (02:26 +0100)
committerKristoffer Grönlund <kristoffer.gronlund@purplescout.se>
Sat, 2 Jan 2010 23:37:45 +0000 (00:37 +0100)
13 files changed:
jamaendo/api.py
jamaui/__init__.py
jamaui/albumlist.py
jamaui/favorites.py
jamaui/featured.py
jamaui/player.py
jamaui/playerwindow.py
jamaui/postoffice.py
jamaui/radios.py
jamaui/search.py
jamaui/settings.py
jamaui/showalbum.py
jamaui/songposition.py [new file with mode: 0644]

index 44a47e1..4c94cac 100644 (file)
@@ -59,7 +59,7 @@ def set_cache_dir(cachedir):
 
 _ARTIST_FIELDS = ['id', 'name', 'image']
 _ALBUM_FIELDS = ['id', 'name', 'image', 'artist_name', 'artist_id', 'license_url']
 
 _ARTIST_FIELDS = ['id', 'name', 'image']
 _ALBUM_FIELDS = ['id', 'name', 'image', 'artist_name', 'artist_id', 'license_url']
-_TRACK_FIELDS = ['id', 'name', 'image', 'artist_name', 'album_name', 'album_id', 'numalbum', 'duration']
+_TRACK_FIELDS = ['id', 'name', 'image', 'artist_id', 'artist_name', 'album_name', 'album_id', 'numalbum', 'duration']
 _RADIO_FIELDS = ['id', 'name', 'idstr', 'image']
 
 class LazyQuery(object):
 _RADIO_FIELDS = ['id', 'name', 'idstr', 'image']
 
 class LazyQuery(object):
@@ -152,6 +152,7 @@ class Track(LazyQuery):
         self.ID = int(ID)
         self.name = None
         self.image = None
         self.ID = int(ID)
         self.name = None
         self.image = None
+        self.artist_id = None
         self.artist_name = None
         self.album_name = None
         self.album_id = None
         self.artist_name = None
         self.album_name = None
         self.album_id = None
@@ -167,10 +168,10 @@ class Track(LazyQuery):
        return _OGGURL%(self.ID)
 
     def _needs_load(self):
        return _OGGURL%(self.ID)
 
     def _needs_load(self):
-        return self._needs_load_impl('name', 'artist_name', 'album_name', 'album_id', 'numalbum', 'duration')
+        return self._needs_load_impl('name', 'artist_name', 'artist_id', 'album_name', 'album_id', 'numalbum', 'duration')
 
     def _set_from(self, other):
 
     def _set_from(self, other):
-        return self._set_from_impl(other, 'name', 'image', 'artist_name', 'album_name', 'album_id', 'numalbum', 'duration')
+        return self._set_from_impl(other, 'name', 'image', 'artist_name', 'artist_id', 'album_name', 'album_id', 'numalbum', 'duration')
 
 class Radio(LazyQuery):
     def __init__(self, ID, json=None):
 
 class Radio(LazyQuery):
     def __init__(self, ID, json=None):
@@ -217,7 +218,7 @@ class Query(object):
         pass
 
     def _geturl(self, url):
         pass
 
     def _geturl(self, url):
-        #print "*** %s" % (url)
+        print "*** %s" % (url)
         Query._ratelimit()
         try:
             f = urllib.urlopen(url)
         Query._ratelimit()
         try:
             f = urllib.urlopen(url)
@@ -347,11 +348,21 @@ class GetQuery(Query):
             'params' : 'artist_id=%d',
             'constructor' : Artist
             },
             'params' : 'artist_id=%d',
             'constructor' : Artist
             },
+        'artist_list' : {
+            'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/artist/json/?',
+            'params' : 'artist_id=%s',
+            'constructor' : Album
+            },
         'album' : {
             'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/album/json/?',
             'params' : 'album_id=%d',
             'constructor' : Album
             },
         'album' : {
             'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/album/json/?',
             'params' : 'album_id=%d',
             'constructor' : Album
             },
+        'album_list' : {
+            'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/album/json/?',
+            'params' : 'album_id=%s',
+            'constructor' : Album
+            },
         'albums' : {
             'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/album/json/?',
             'params' : 'artist_id=%d',
         'albums' : {
             'url' : _GET2+'+'.join(_ALBUM_FIELDS)+'/album/json/?',
             'params' : 'artist_id=%d',
@@ -362,6 +373,11 @@ class GetQuery(Query):
             'params' : 'id=%d',
             'constructor' : Track
             },
             'params' : 'id=%d',
             'constructor' : Track
             },
+        'track_list' : {
+            'url' : _GET2+'+'.join(_TRACK_FIELDS)+'/track/json/track_album+album_artist?',
+            'params' : 'id=%s',
+            'constructor' : Track
+            },
         'tracks' : {
             'url' : _GET2+'+'.join(_TRACK_FIELDS)+'/track/json/track_album+album_artist?',
             'params' : 'order=numalbum_asc&album_id=%d',
         'tracks' : {
             'url' : _GET2+'+'.join(_TRACK_FIELDS)+'/track/json/track_album+album_artist?',
             'params' : 'order=numalbum_asc&album_id=%d',
@@ -449,6 +465,12 @@ def _update_cache(cache, new_items):
             old._set_from(item)
         else:
             cache[item.ID] = item
             old._set_from(item)
         else:
             cache[item.ID] = item
+        if isinstance(item, Artist) and item.albums:
+            for album in item.albums:
+                _update_cache(_albums, album)
+        elif isinstance(item, Album) and item.tracks:
+            for track in item.tracks:
+                _update_cache(_tracks, track)
 
 def get_artist(artist_id):
     """Returns: Artist"""
 
 def get_artist(artist_id):
     """Returns: Artist"""
@@ -463,8 +485,56 @@ def get_artist(artist_id):
             a = a[0]
     return a
 
             a = a[0]
     return a
 
-def get_albums(artist_id):
+def get_artists(artist_ids):
+    """Returns: [Artist]"""
+    assert(isinstance(artist_ids, list))
+    found = []
+    lookup = []
+    for artist_id in artist_ids:
+        a = _artists.get(artist_id, None)
+        if not a:
+            lookup.append(artist_id)
+        else:
+            found.append(a)
+    if lookup:
+        q = GetQuery('artist_list', '+'.join(str(x) for x in lookup))
+        a = q.execute()
+        if not a:
+            raise JamendoAPIException(str(q))
+        _update_cache(_artists, a)
+        lookup = a
+    return found + lookup
+
+def get_album_list(album_ids):
     """Returns: [Album]"""
     """Returns: [Album]"""
+    assert(isinstance(album_ids, list))
+    found = []
+    lookup = []
+    for album_id in album_ids:
+        a = _albums.get(album_id, None)
+        if not a:
+            lookup.append(album_id)
+        else:
+            found.append(a)
+    if lookup:
+        q = GetQuery('album_list', '+'.join(str(x) for x in lookup))
+        a = q.execute()
+        if not a:
+            raise JamendoAPIException(str(q))
+        _update_cache(_albums, a)
+        lookup = a
+    return found + lookup
+
+def get_albums(artist_id):
+    """Returns: [Album]
+    Parameter can either be an artist_id or a list of album ids.
+    """
+    if isinstance(artist_id, list):
+        return get_album_list(artist_id)
+    a = _artists.get(artist_id, None)
+    if a and a.albums:
+        return a.albums
+
     q = GetQuery('albums', artist_id)
     a = q.execute()
     if not a:
     q = GetQuery('albums', artist_id)
     a = q.execute()
     if not a:
@@ -485,8 +555,36 @@ def get_album(album_id):
             a = a[0]
     return a
 
             a = a[0]
     return a
 
-def get_tracks(album_id):
+def get_track_list(track_ids):
     """Returns: [Track]"""
     """Returns: [Track]"""
+    assert(isinstance(track_ids, list))
+    found = []
+    lookup = []
+    for track_id in track_ids:
+        a = _tracks.get(track_id, None)
+        if not a:
+            lookup.append(track_id)
+        else:
+            found.append(a)
+    if lookup:
+        q = GetQuery('track_list', '+'.join(str(x) for x in lookup))
+        a = q.execute()
+        if not a:
+            raise JamendoAPIException(str(q))
+        _update_cache(_tracks, a)
+        lookup = a
+    return found + lookup
+
+def get_tracks(album_id):
+    """Returns: [Track]
+    Parameter can either be an album_id or a list of track ids.
+    """
+    if isinstance(album_id, list):
+        return get_track_list(album_id)
+    a = _albums.get(album_id, None)
+    if a and a.tracks:
+        return a.tracks
+
     q = GetQuery('tracks', album_id)
     a = q.execute()
     if not a:
     q = GetQuery('tracks', album_id)
     a = q.execute()
     if not a:
@@ -602,6 +700,7 @@ def favorite_albums(user):
 def _artist_loader(self):
     if self._needs_load():
         artist = get_artist(self.ID)
 def _artist_loader(self):
     if self._needs_load():
         artist = get_artist(self.ID)
+        artist.albums = get_albums(self.ID)
         self._set_from(artist)
 Artist.load = _artist_loader
 
         self._set_from(artist)
 Artist.load = _artist_loader
 
index 7e847ff..505bc11 100644 (file)
@@ -26,6 +26,8 @@ import logging
 import sys
 
 LOG_FILENAME = '/tmp/jamaendo.log'
 import sys
 
 LOG_FILENAME = '/tmp/jamaendo.log'
-LOG_LEVEL = logging.INFO
+LOG_LEVEL = logging.DEBUG
+
+# 
+logging.basicConfig(filename=LOG_FILENAME, level=LOG_LEVEL, format="%(name)-15s: [%(lineno)4d] %(levelname)-8s %(message)s")
 
 
-logging.basicConfig(filename=LOG_FILENAME,level=LOG_LEVEL, format="%(name)-15s: [%(lineno)4d] %(levelname)-8s %(message)s")
index e851cdb..ce1671a 100644 (file)
@@ -66,5 +66,36 @@ class TrackList(gtk.TreeView):
 
     def get_track_id(self, path):
         treeiter = self.__store.get_iter(path)
 
     def get_track_id(self, path):
         treeiter = self.__store.get_iter(path)
+        _, _, _id = self.__store.get(treeiter, 0, 1, 2)
+        return _id
+
+class RadioList(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)
+
+    def add_radio(self, radio):
+        self.__store.append([self.radio_name(radio), radio.ID])
+
+    def get_radio_id(self, path):
+        treeiter = self.__store.get_iter(path)
         _, _id = self.__store.get(treeiter, 0, 1)
         return _id
         _, _id = self.__store.get(treeiter, 0, 1)
         return _id
+
+    def radio_name(self, radio):
+        if radio.idstr:
+            return radio.idstr.capitalize()
+        elif radio.name:
+            return radio.name
+        else:
+            return "Radio #%s" % (radio.ID)
index 6eb07b6..5a0474c 100644 (file)
@@ -69,15 +69,13 @@ class FavoritesWindow(hildon.StackableWindow):
                                                                msg)
                 banner.set_timeout(3000)
 
                                                                msg)
                 banner.set_timeout(3000)
 
-            for item in settings.favorites:
-                try:
-                    if isinstance(item, tuple) and len(item) == 2:
-                        ftype, fid = item
-                        if ftype == 'album':
-                            add_album(fid, lambda: jamaendo.get_album(fid))
-
-                except jamaendo.JamendoAPIException, e:
-                    log.exception("jamaendo.get_album(%s)"%(fid))
+            favorite_albums = [f[1] for f in settings.favorites if isinstance(f, tuple) and len(f) == 2 and f[0] == 'album' and f[1] not in self.idmap]
+            try:
+                for album in jamaendo.get_albums(favorite_albums):
+                    add_album(album.ID, lambda: album)
+
+            except jamaendo.JamendoAPIException, e:
+                log.exception("jamaendo.get_albums(%s)"%(favorite_albums))
 
             self.add(self.panarea)
 
 
             self.add(self.panarea)
 
index b7b14fd..010ce23 100644 (file)
@@ -72,7 +72,7 @@ class FeaturedWindow(hildon.StackableWindow):
         self.create_menu()
 
     def create_menu(self):
         self.create_menu()
 
     def create_menu(self):
-        def on_player():
+        def on_player(*args):
             from playerwindow import open_playerwindow
             open_playerwindow()
         self.menu = hildon.AppMenu()
             from playerwindow import open_playerwindow
             open_playerwindow()
         self.menu = hildon.AppMenu()
index 24ec4f2..65cc549 100644 (file)
@@ -359,12 +359,15 @@ class Player(object):
                 entry = self.playlist.next()
                 self.backend.play_url('mp3', entry.mp3_url())
                 log.debug("playing %s", entry)
                 entry = self.playlist.next()
                 self.backend.play_url('mp3', entry.mp3_url())
                 log.debug("playing %s", entry)
+            postoffice.notify('play', entry)
 
     def pause(self):
         self.backend.pause()
 
     def pause(self):
         self.backend.pause()
+        postoffice.notify('pause', self.playlist.current())
 
     def stop(self):
         self.backend.stop()
 
     def stop(self):
         self.backend.stop()
+        postoffice.notify('stop', self.playlist.current())
 
     def playing(self):
         return self.backend.playing()
 
     def playing(self):
         return self.backend.playing()
@@ -375,6 +378,7 @@ class Player(object):
             entry = self.playlist.next()
             self.backend.play_url('mp3', entry.mp3_url())
             log.debug("playing %s", entry)
             entry = self.playlist.next()
             self.backend.play_url('mp3', entry.mp3_url())
             log.debug("playing %s", entry)
+            postoffice.notify('next', entry)
         else:
             self.stop()
 
         else:
             self.stop()
 
@@ -384,6 +388,7 @@ class Player(object):
             entry = self.playlist.prev()
             self.backend.play_url('mp3', entry.mp3_url())
             log.debug("playing %s", entry)
             entry = self.playlist.prev()
             self.backend.play_url('mp3', entry.mp3_url())
             log.debug("playing %s", entry)
+            postoffice.notify('prev', entry)
 
     def _on_eos(self):
         log.debug("EOS!")
 
     def _on_eos(self):
         log.debug("EOS!")
index 01df496..ce13494 100644 (file)
 import gtk
 import gobject
 import hildon
 import gtk
 import gobject
 import hildon
+import util
+import pango
 from settings import settings
 from postoffice import postoffice
 from player import Playlist, the_player
 import logging
 from settings import settings
 from postoffice import postoffice
 from player import Playlist, the_player
 import logging
+import cgi
+
+from songposition import SongPosition
 
 log = logging.getLogger(__name__)
 
 
 log = logging.getLogger(__name__)
 
@@ -43,32 +48,38 @@ class PlayerWindow(hildon.StackableWindow):
 
         vbox = gtk.VBox()
 
 
         vbox = gtk.VBox()
 
-        hbox = gtk.HBox()
+        hbox = gtk.HBox(False, 8)
 
         self.cover = gtk.Image()
 
         self.cover = gtk.Image()
-        self.cover.set_from_stock(gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
+        tmp = util.find_resource('album.png')
+        if tmp:
+            self.cover.set_from_file(tmp)
 
         vbox2 = gtk.VBox()
 
         self.playlist_pos = gtk.Label()
 
         vbox2 = gtk.VBox()
 
         self.playlist_pos = gtk.Label()
+        self.playlist_pos.set_alignment(1.0,0)
         self.track = gtk.Label()
         self.track = gtk.Label()
-        self.progress = hildon.GtkHScale()
-        self.progress.set_draw_value(False)
-        self.progress.set_range(0.0, 1.0)
+        self.track.set_alignment(0,0)
+        self.track.set_ellipsize(pango.ELLIPSIZE_END)
         self.artist = gtk.Label()
         self.artist = gtk.Label()
+        self.artist.set_alignment(0,0)
+        self.artist.set_ellipsize(pango.ELLIPSIZE_END)
         self.album = gtk.Label()
         self.album = gtk.Label()
+        self.album.set_alignment(0,0)
+        self.album.set_ellipsize(pango.ELLIPSIZE_END)
+        self.progress = SongPosition()
 
         self.set_labels('', '', '', 0, 0)
 
         self._position_timer = None
 
 
         self.set_labels('', '', '', 0, 0)
 
         self._position_timer = None
 
-        vbox2.pack_start(self.track, True)
-        vbox2.pack_start(self.artist, False)
-        vbox2.pack_start(self.album, False)
         vbox2.pack_start(self.playlist_pos, False)
         vbox2.pack_start(self.playlist_pos, False)
-        vbox2.pack_start(self.progress, False)
+        vbox2.pack_start(self.track, True)
+        vbox2.pack_start(self.artist, True)
+        vbox2.pack_start(self.album, True)
 
 
-        hbox.pack_start(self.cover, True, True, 0)
+        hbox.pack_start(self.cover, False, True, 0)
         hbox.pack_start(vbox2, True, True, 0)
 
         vbox.pack_start(hbox, True, True, 0)
         hbox.pack_start(vbox2, True, True, 0)
 
         vbox.pack_start(hbox, True, True, 0)
@@ -76,37 +87,84 @@ class PlayerWindow(hildon.StackableWindow):
         btns = gtk.HButtonBox()
         btns.set_property('layout-style', gtk.BUTTONBOX_SPREAD)
 
         btns = gtk.HButtonBox()
         btns.set_property('layout-style', gtk.BUTTONBOX_SPREAD)
 
-        vbox.pack_end(btns, False, True, 0)
+        vbox.pack_start(btns, False, True, 0)
+
+        vbox.pack_start(self.progress, False)
 
         self.add_stock_button(btns, gtk.STOCK_MEDIA_PREVIOUS, self.on_prev)
         self.add_play_button(btns)
         self.add_stock_button(btns, gtk.STOCK_MEDIA_STOP, self.on_stop)
         self.add_stock_button(btns, gtk.STOCK_MEDIA_NEXT, self.on_next)
 
 
         self.add_stock_button(btns, gtk.STOCK_MEDIA_PREVIOUS, self.on_prev)
         self.add_play_button(btns)
         self.add_stock_button(btns, gtk.STOCK_MEDIA_STOP, self.on_stop)
         self.add_stock_button(btns, gtk.STOCK_MEDIA_NEXT, self.on_next)
 
-        self.volume = hildon.VVolumebar()
-        self.volume.set_property('can-focus', False)
-        self.volume.connect('level_changed', self.volume_changed_hildon)
-        self.volume.connect('mute_toggled', self.mute_toggled)
-        #self.__gui_root.main_window.connect( 'key-press-event',
-        #                                     self.on_key_press )
-        hbox.pack_start(self.volume, False)
+        #self.volume = hildon.VVolumebar()
+        #self.volume.set_property('can-focus', False)
+        #self.volume.connect('level_changed', self.volume_changed_hildon)
+        #self.volume.connect('mute_toggled', self.mute_toggled)
+        #hbox.pack_start(self.volume, False)
         self.add(vbox)
 
         postoffice.connect('album-cover', self, self.set_album_cover)
         self.add(vbox)
 
         postoffice.connect('album-cover', self, self.set_album_cover)
+        postoffice.connect(['next', 'prev', 'play', 'pause', 'stop'], self, self.on_state_changed)
 
         #print "Created player window, playlist: %s" % (self.playlist)
 
 
         #print "Created player window, playlist: %s" % (self.playlist)
 
+        self.on_state_changed()
+
+        self.create_menu()
+
+    def create_menu(self):
+        self.menu = hildon.AppMenu()
+
+        def to_artist(*args):
+            import jamaendo
+            from showartist import ShowArtist
+            track = self.playlist.current()
+            artist = jamaendo.get_artist(int(track.artist_id))
+            wnd = ShowArtist(artist)
+            wnd.show_all()
+        def to_album(*args):
+            import jamaendo
+            from showalbum import ShowAlbum
+            track = self.playlist.current()
+            album = jamaendo.get_album(int(track.album_id))
+            wnd = ShowAlbum(album)
+            wnd.show_all()
+
+        b = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+        b.set_label("Artist")
+        b.connect("clicked", to_artist)
+        self.menu.append(b)
+
+        b = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+        b.set_label("Album")
+        b.connect("clicked", to_album)
+        self.menu.append(b)
+
+        self.menu.show_all()
+        self.set_app_menu(self.menu)
+
+    def on_state_changed(self, *args):
         self.update_state()
         self.update_play_button()
 
         self.update_state()
         self.update_play_button()
 
+        if self.player.playing():
+            self.start_position_timer()
+        else:
+            self.stop_position_timer()
+
+
     def get_album_id(self):
     def get_album_id(self):
-        if self.playlist and self.playlist.current_index() > -1:
-            return self.playlist.current().album_id
+        if self.player.playlist and self.player.playlist.current():
+            c = self.player.playlist.current()
+            if not c.album_id:
+                c.load()
+            if c.album_id:
+                return c.album_id
         return None
 
     def on_destroy(self, wnd):
         self.stop_position_timer()
         return None
 
     def on_destroy(self, wnd):
         self.stop_position_timer()
-        postoffice.disconnect('album-cover', self)
+        postoffice.disconnect(['album-cover', 'next', 'prev', 'play', 'stop'], self)
 
     def add_stock_button(self, btns, stock, cb):
         btn = hildon.GtkButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
 
     def add_stock_button(self, btns, stock, cb):
         btn = hildon.GtkButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
@@ -141,10 +199,10 @@ class PlayerWindow(hildon.StackableWindow):
             self.playbtn.set_data('state', 'play')
 
     def set_labels(self, track, artist, album, playlist_pos, playlist_size):
             self.playbtn.set_data('state', 'play')
 
     def set_labels(self, track, artist, album, playlist_pos, playlist_size):
-        self.playlist_pos.set_markup('<span size="small">%s/%s songs</span>'%(playlist_pos, playlist_size))
-        self.track.set_markup('<span size="x-large">%s</span>'%(track))
-        self.artist.set_markup('<span size="large">%s</span>'%(artist))
-        self.album.set_markup('<span foreground="#aaaaaa">%s</span>'%(album))
+        self.playlist_pos.set_markup('<span size="small">Track %s of %s</span>'%(int(playlist_pos)+1, playlist_size))
+        self.track.set_markup('<span size="x-large">%s</span>'%(cgi.escape(track)))
+        self.artist.set_markup('<span size="large">%s</span>'%(cgi.escape(artist)))
+        self.album.set_markup('<span foreground="#aaaaaa">%s</span>'%(cgi.escape(album)))
 
 
     def volume_changed_hildon(self, widget):
 
 
     def volume_changed_hildon(self, widget):
@@ -174,63 +232,52 @@ class PlayerWindow(hildon.StackableWindow):
             self._position_timer = None
 
     def clear_position(self):
             self._position_timer = None
 
     def clear_position(self):
-        self.progress.set_value(0)
+        self.progress.set_position(0)
 
     def set_song_position(self, time_elapsed, total_time):
         value = (float(time_elapsed) / float(total_time)) if total_time else 0
 
     def set_song_position(self, time_elapsed, total_time):
         value = (float(time_elapsed) / float(total_time)) if total_time else 0
-        self.progress.set_value( value )
+        self.progress.set_position(value)
 
     def update_state(self):
         item = self.playlist.current()
         if item:
             if not item.name:
                 item.load()
 
     def update_state(self):
         item = self.playlist.current()
         if item:
             if not item.name:
                 item.load()
-            #print "current:", item
             self.set_labels(item.name, item.artist_name, item.album_name,
                             self.playlist.current_index(), self.playlist.size())
             postoffice.notify('request-album-cover', int(item.album_id), 300)
             self.set_labels(item.name, item.artist_name, item.album_name,
                             self.playlist.current_index(), self.playlist.size())
             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)
+        else:
+            self.set_labels('', '', '', 0, 0)
+            tmp = util.find_resource('album.png')
+            if tmp:
+                self.cover.set_from_file(tmp)
 
     def set_album_cover(self, albumid, size, cover):
         if size == 300:
             playing = self.get_album_id()
 
     def set_album_cover(self, albumid, size, cover):
         if size == 300:
             playing = self.get_album_id()
-            if int(playing) == int(albumid):
+            if playing and albumid and (int(playing) == int(albumid)):
                 self.cover.set_from_file(cover)
 
     def play_tracks(self, tracks):
                 self.cover.set_from_file(cover)
 
     def play_tracks(self, tracks):
-        self.stop_position_timer()
         self.clear_position()
         self.playlist = Playlist(tracks)
         self.player.stop()
         self.player.play(self.playlist)
         self.clear_position()
         self.playlist = Playlist(tracks)
         self.player.stop()
         self.player.play(self.playlist)
-        self.update_state()
-        self.update_play_button()
 
     def on_play(self, button):
         if not self.player.playing():
             self.player.play(self.playlist)
 
     def on_play(self, button):
         if not self.player.playing():
             self.player.play(self.playlist)
-            self.start_position_timer()
-            self.update_state()
-            self.update_play_button()
         else:
         else:
-            self.stop_position_timer()
             self.player.pause()
             self.player.pause()
-            self.update_state()
-            self.update_play_button()
     def on_prev(self, button):
         self.player.prev()
     def on_prev(self, button):
         self.player.prev()
-        self.update_state()
+
     def on_next(self, button):
         self.player.next()
     def on_next(self, button):
         self.player.next()
-        self.update_state()
+
     def on_stop(self, button):
     def on_stop(self, button):
-        self.stop_position_timer()
         self.clear_position()
         self.player.stop()
         self.clear_position()
         self.player.stop()
-        self.update_play_button()
 
 def open_playerwindow():
     player = PlayerWindow()
 
 def open_playerwindow():
     player = PlayerWindow()
index 9453176..078316c 100644 (file)
@@ -35,24 +35,26 @@ class PostOffice(object):
     def notify(self, tag, *data):
         clients = self.tags.get(tag)
         if clients:
     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(repr(x) for x,_ in clients))
             for ref, client in clients:
                 client(*data)
 
     def connect(self, tag, ref, callback):
             for ref, client in clients:
                 client(*data)
 
     def connect(self, tag, ref, callback):
-        if tag not in self.tags:
-            self.tags[tag] = []
-        clients = self.tags[tag]
-        if callback not in clients:
-            clients.append((ref, callback))
+        if not isinstance(tag, list):
+            tag = [tag]
+        for t in tag:
+            if t not in self.tags:
+                self.tags[t] = []
+            clients = self.tags[t]
+            if callback not in clients:
+                clients.append((ref, callback))
 
     def disconnect(self, tag, ref):
 
     def disconnect(self, tag, ref):
-        if tag not in self.tags:
-            self.tags[tag] = []
-        self.tags[tag] = [(_ref, cb) for _ref, cb in self.tags[tag] if _ref != ref]
+        if not isinstance(tag, list):
+            tag = [tag]
+        for t in tag:
+            if t not in self.tags:
+                self.tags[t] = []
+            self.tags[t] = [(_ref, cb) for _ref, cb in self.tags[t] if _ref != ref]
 
 postoffice = PostOffice()
 
 
 postoffice = PostOffice()
 
index 11c6a07..2068b82 100644 (file)
@@ -25,6 +25,7 @@ import gtk
 import hildon
 import jamaendo
 from playerwindow import open_playerwindow
 import hildon
 import jamaendo
 from playerwindow import open_playerwindow
+from albumlist import RadioList
 
 class RadiosWindow(hildon.StackableWindow):
     def __init__(self):
 
 class RadiosWindow(hildon.StackableWindow):
     def __init__(self):
@@ -33,39 +34,20 @@ class RadiosWindow(hildon.StackableWindow):
 
         # Results list
         self.panarea = hildon.PannableArea()
 
         # 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.radiolist = RadioList()
+        self.radiolist.connect('row-activated', self.row_activated)
 
 
-        self.panarea.add(self.result_view)
+        self.panarea.add(self.radiolist)
 
         self.radios = {}
         hildon.hildon_gtk_window_set_progress_indicator(self, 1)
         for item in jamaendo.starred_radios():
             self.radios[item.ID] = item
 
         self.radios = {}
         hildon.hildon_gtk_window_set_progress_indicator(self, 1)
         for item in jamaendo.starred_radios():
             self.radios[item.ID] = item
-            self.result_store.append([self.radio_text(item), item.ID])
+            self.radiolist.add_radio(item)
         hildon.hildon_gtk_window_set_progress_indicator(self, 0)
 
         self.add(self.panarea)
 
         hildon.hildon_gtk_window_set_progress_indicator(self, 0)
 
         self.add(self.panarea)
 
-    def radio_text(self, radio):
-        if radio.name and radio.idstr:
-            return "%s (%s)" % (radio.name, radio.idstr)
-        elif radio.name:
-            return radio.name
-        elif radio.idstr:
-            return radio.idstr
-        else:
-            return "Radio #%s" % (radio.ID)
-
     def make_button(self, text, subtext, callback):
         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT,
                                hildon.BUTTON_ARRANGEMENT_VERTICAL)
     def make_button(self, text, subtext, callback):
         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT,
                                hildon.BUTTON_ARRANGEMENT_VERTICAL)
@@ -74,17 +56,11 @@ class RadiosWindow(hildon.StackableWindow):
         if callback:
             button.connect('clicked', callback)
 
         if callback:
             button.connect('clicked', callback)
 
-        #image = gtk.image_new_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON)
-        #button.set_image(image)
-        #button.set_image_position(gtk.POS_RIGHT)
-
         return button
 
     def row_activated(self, treeview, path, view_column):
         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.radiolist.get_radio_id(path)
         item = self.radios[_id]
         item = self.radios[_id]
-        #print _id, item
         self.open_item(item)
 
     def open_item(self, item):
         self.open_item(item)
 
     def open_item(self, item):
index dd33b94..e487765 100644 (file)
@@ -87,7 +87,7 @@ class SearchWindow(hildon.StackableWindow):
         self.create_menu()
 
     def create_menu(self):
         self.create_menu()
 
     def create_menu(self):
-        def on_player():
+        def on_player(*args):
             from playerwindow import open_playerwindow
             open_playerwindow()
         self.menu = hildon.AppMenu()
             from playerwindow import open_playerwindow
             open_playerwindow()
         self.menu = hildon.AppMenu()
index f141c69..04dce11 100644 (file)
@@ -31,7 +31,7 @@ log = logging.getLogger(__name__)
 
 class Settings(object):
     defaults = {
 
 class Settings(object):
     defaults = {
-        'volume':0.5,
+        'volume':0.1,
         'user':None,
         'favorites':set([]) # local favorites - until we can sync back
         }
         'user':None,
         'favorites':set([]) # local favorites - until we can sync back
         }
index bfe6e8f..4325622 100644 (file)
@@ -22,6 +22,7 @@
 #  (based on http://pygstdocs.berlios.de/pygst-tutorial/seeking.html)
 #
 import gtk
 #  (based on http://pygstdocs.berlios.de/pygst-tutorial/seeking.html)
 #
 import gtk
+import cgi
 import hildon
 import jamaendo
 from playerwindow import open_playerwindow
 import hildon
 import jamaendo
 from playerwindow import open_playerwindow
@@ -61,7 +62,7 @@ class ShowAlbum(hildon.StackableWindow):
 
         vbox2 = gtk.VBox()
         self.albumname = gtk.Label()
 
         vbox2 = gtk.VBox()
         self.albumname = gtk.Label()
-        self.albumname.set_markup('<big>%s</big>'%(album.name))
+        self.albumname.set_markup('<big>%s</big>'%(cgi.escape(album.name)))
         self.trackarea = hildon.PannableArea()
 
         self.tracks = TrackList(numbers=True)
         self.trackarea = hildon.PannableArea()
 
         self.tracks = TrackList(numbers=True)
@@ -90,10 +91,8 @@ class ShowAlbum(hildon.StackableWindow):
 
         self.create_menu()
 
 
         self.create_menu()
 
-        self.show_all()
-
     def create_menu(self):
     def create_menu(self):
-        def on_player():
+        def on_player(*args):
             from playerwindow import open_playerwindow
             open_playerwindow()
         self.menu = hildon.AppMenu()
             from playerwindow import open_playerwindow
             open_playerwindow()
         self.menu = hildon.AppMenu()
@@ -150,7 +149,8 @@ class ShowAlbum(hildon.StackableWindow):
 
     def row_activated(self, treeview, path, view_column):
         _id = self.tracks.get_track_id(path)
 
     def row_activated(self, treeview, path, view_column):
         _id = self.tracks.get_track_id(path)
-        log.debug("clicked %s", _id)
+        track = jamaendo.get_track(_id)
+        self.open_item(track)
 
     def open_item(self, item):
         if isinstance(item, jamaendo.Album):
 
     def open_item(self, item):
         if isinstance(item, jamaendo.Album):
diff --git a/jamaui/songposition.py b/jamaui/songposition.py
new file mode 100644 (file)
index 0000000..705962c
--- /dev/null
@@ -0,0 +1,92 @@
+import logging
+import gtk
+import cairo
+
+log = logging.getLogger(__name__)
+
+# shows the current song position (looking a bit nicer than a default widget, hopefully)
+class SongPosition(gtk.DrawingArea):
+    WIDTH = 8.0
+    HEIGHT = 8.0
+
+    def __init__(self):
+        gtk.DrawingArea.__init__(self)
+        self.connect('expose-event', self.on_expose)
+        self.set_size_request(24, 8)
+        self.pos = 0.0
+
+        orange0 = self.hex_to_flt(0xec, 0xac, 0x1f)
+        orange1 = self.hex_to_flt(0xea, 0x86, 0x1d, 0.25)
+        purple0 = self.hex_to_flt(0x81, 0x3e, 0x82)
+        purple1 = self.hex_to_flt(0x56, 0x2d, 0x5a, 0.25)
+
+        lightclr = cairo.LinearGradient(0.0, 0.0, 0.0, self.HEIGHT)
+        lightclr.add_color_stop_rgba(0.0, *purple1)
+        lightclr.add_color_stop_rgba(1.0, *purple0)
+
+        darkclr = cairo.LinearGradient(0.0, 0.0, 0.0, self.HEIGHT)
+        darkclr.add_color_stop_rgba(0.0, 0.0, 0.0, 0.0, 0.0)
+        darkclr.add_color_stop_rgba(1.0, 0.25, 0.25, 0.25, 1.0)
+
+        markerclr = cairo.LinearGradient(0.0, 0.0, 0.0, self.HEIGHT)
+        markerclr.add_color_stop_rgba(0.0, *orange1)
+        markerclr.add_color_stop_rgba(0.5, *orange0)
+        markerclr.add_color_stop_rgba(1.0, *orange0)
+
+        self.lightclr = lightclr
+        self.darkclr = darkclr
+        self.markerclr = markerclr
+
+    def on_expose(self, widget, event):
+        context = self.window.cairo_create()
+        context.rectangle(event.area.x, event.area.y,
+            event.area.width, event.area.height)
+        context.clip()
+        self.draw(context)
+        return True
+
+    #ecac1f - light orange
+    #ea861d - dark orange
+
+    #813e82 - light purple
+    #562d5a - dark purple
+
+    def hex_to_flt(self, r, g, b, a = 255.0):
+        return float(r)/255.0, float(g)/255.0, float(b)/255.0, float(a)/255.0
+
+    def draw(self, context):
+        rect = self.get_allocation()
+
+
+        #context.set_source_rgb(1.0, 0.5, 0.0)
+        lowx = rect.width*self.pos - self.WIDTH*0.5
+        hix = rect.width*self.pos + self.WIDTH*0.5
+
+        if lowx < 0.0:
+            lowx = 0.0
+            hix = self.WIDTH
+        elif hix > rect.width:
+            lowx = rect.width - self.WIDTH
+            hix = rect.width
+
+        if lowx > 0.01:
+            context.rectangle(0, 0, lowx, rect.height)
+            context.set_source(self.lightclr)
+            context.fill()
+
+        if hix < rect.width-0.01:
+            context.rectangle(hix, 0, rect.width-hix, rect.height)
+            context.set_source(self.darkclr)
+            context.fill()
+
+        context.rectangle(lowx, 0, self.WIDTH, rect.height)
+        context.set_source(self.markerclr)
+        context.fill()
+
+    def set_position(self, pos):
+        assert 0 <= pos <= 1
+        self.pos = pos
+        self.invalidate()
+
+    def invalidate(self):
+        self.queue_draw()