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()
|