git.fiddlerwoaroof.com
urwid_playlist.py
5475dee4
 # Copyright (c) 2011 Edward Langley
 # All rights reserved.
 
0fdce423
 import mpdprotocol
 import responsedict
 import urwid
 import itertools
 from twisted.internet import defer
 
 class SelectableText(urwid.Text):
     def keypress(self, __, key): return key
     def selectable(self): return True
 
 class Playlist(urwid.WidgetWrap):
cadb4011
     def __init__(self, columns, col_display, plylst=None):
         if plylst == None:
             plylst = responsedict.ResponseDict()
0fdce423
         self.columns = columns
cadb4011
         self.display_pref = col_display
         self.texts = self.get_texts(plylst.as_list())
         self.body = urwid.SimpleFocusListWalker([])
         self.make_playlist()
0fdce423
 
cadb4011
         self.titles = self.make_columns()
0fdce423
         self.header = urwid.Pile([self.titles, urwid.Divider('-')])
cadb4011
         widget = urwid.ListBox(self.body)
0fdce423
         widget = urwid.Frame(widget, self.header)
         urwid.WidgetWrap.__init__(self, widget)
 
cadb4011
     def make_columns(self):
         return urwid.Columns([
                 ('weight',self.display_pref[c].weight,SelectableText(self.display_pref[c].dispname))
                     for c in self.columns
             ],1)
 
     def get_texts(self, choices):
         #TODO: re-work column info to separate data from presentation info
0fdce423
         texts = []
cadb4011
         for x in choices:
             texts.append([])
             for col in self.columns:
                 display = self.display_pref[col]
                 texts[-1].append((display.weight,display.transform(x.get(col,[""])[0])))
0fdce423
         return texts
 
cadb4011
     def update_texts(self, choices):
         self.texts = self.get_texts(choices.as_list())
         self.update_playlist()
 
     def make_body(self):
         for x in self.texts:
0fdce423
             new_widg = [('weight',wgt,SelectableText(it,wrap='clip')) for wgt,it in x]
             new_widg = urwid.Columns(new_widg, 1)
             new_widg = urwid.AttrMap(new_widg, 'unselected', 'selected')
cadb4011
             self.body.append(new_widg)
 
     def update_playlist(self):
         del self.body[:]
         self.make_body()
 
     def make_playlist(self):
         self.make_body()
0fdce423
 
 def exit_on_q(key):
     if key in ('q', 'Q'):
         try: raise urwid.ExitMainLoop()
         finally: reactor.stop()
 
 cols = [
cadb4011
     'Pos',
     'Date',
     'Album',
     'Artist',
     'AlbumArtist',
     'Title',
0fdce423
 ]
 
cadb4011
 import collections
 class DisplayDict(collections.Mapping):
     def __init__(self, data):
         self.row_class=collections.namedtuple('displaytuple', ['dispname','weight','transform'])
         self.data = self.normalize(data)
     def normalize(self, data):
         out = {}
         for key,val in data.iteritems():
             dispname,weight,transform = None,1,lambda x:x
             if hasattr(val, '__iter__'):
                 if len(val) == 3: dispname,weight,transform = val
                 if len(val) == 2: dispname,weight = val
             if dispname is None:
                 dispname = key
             out[key] = self.row_class(dispname, weight, transform)
         return out
     def __getitem__(self, key):
         head, _, tail = key.partition('.')
         if tail:
             try:
                 return getattr(self.data[head], tail)
             except AttributeError, e:
                 raise KeyError('Key not found: %s' % key)
         else:
             return self.data[head]
     def __iter__(self):
         return iter(self.data)
     def __len__(self):
         return len(self.data)
 
 
 col_display = DisplayDict(
     dict(
         Pos=('#',1,lambda x: x and str(int(x) + 1)),
         Date=('Year', 4),
         Album=(None,8),
         Artist=(None,8),
         AlbumArtist=('Album Artist',5),
         Title=(None,13),
 ))
 
0fdce423
 @defer.inlineCallbacks
 def get_playlist():
     client = yield mpdprotocol.get_client()
cadb4011
     method, data = yield client.sendCommand('playlistinfo')
     loop.widget.update_texts(data)
0fdce423
     loop.draw_screen()
cadb4011
     while True:
         idle = yield client.idle(['playlist'])
         method, data = yield client.sendCommand('playlistinfo')
         loop.widget.update_texts(data)
         loop.draw_screen()
0fdce423
 
 from twisted.internet import reactor
 palette = [
     ('selected', 'white', 'black'),
     ('selected', 'black', 'white'),
 ]
cadb4011
 loop = urwid.MainLoop(Playlist(cols, col_display), palette, event_loop=urwid.TwistedEventLoop(), unhandled_input=exit_on_q)
0fdce423
 reactor.callWhenRunning(get_playlist)
 loop.run()