ui.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import urwid
  2. songs = ['one', 'another on bites the dust', 'enter sandman', 'piano man', 'dance of death']
  3. artists = ['metallica', 'iron maiden', 'judas priest', 'haken']
  4. albums = ['some kind of bird egg', 'electric boogaloo', 'another time', '13']
  5. log = []
  6. class Song:
  7. def __init__(self, title, artist, album):
  8. self.title = title
  9. self.album = album
  10. self.artist = artist
  11. def __repr__(self):
  12. return f'<Song title:{self.title}, album:{self.album}, artist:{self.artist}>'
  13. class Album:
  14. def __init__(self, title, artist):
  15. self.title = title
  16. self.artist = artist
  17. def __repr__(self):
  18. return f'<Album title:{self.title}, artist:{self.artist}>'
  19. class Artist:
  20. def __init__(self, name):
  21. self.name = name
  22. def __repr__(self):
  23. return f'<Artist name:{self.name}>'
  24. def build_search_collection(N):
  25. from random import choice
  26. types = (Song, Artist, Album)
  27. collection = []
  28. for _ in range(N):
  29. type_ = choice(types)
  30. if type_ == Song:
  31. collection.append(Song(choice(songs), choice(artists), choice(albums)))
  32. elif type_ == Artist:
  33. collection.append(Artist(choice(artists)))
  34. else:
  35. collection.append(Album(choice(albums), choice(artists)))
  36. return (list(filter(lambda o: type(o) == Song, collection)),
  37. list(filter(lambda o: type(o) == Album, collection)),
  38. list(filter(lambda o: type(o) == Artist, collection)))
  39. class UI(urwid.Pile):
  40. palette = [
  41. ('header', 'white,underline', 'black'),
  42. ('header_bg', 'white', 'black'),
  43. ('line', 'white', ''),
  44. ('search normal', 'white', ''),
  45. ('search select', 'white', 'dark red'),
  46. ('region_bg normal', '', ''),
  47. ('region_bg select', '', 'black'),
  48. ]
  49. def click(self, *args, **kwargs):
  50. print(args, kwargs)
  51. def __init__(self):
  52. self.search_results = urwid.SimpleFocusListWalker([])
  53. search_results_box = urwid.ListBox(self.search_results)
  54. search_results_box = urwid.LineBox(search_results_box, title='Search Results')
  55. search_results_box = urwid.AttrMap(search_results_box, 'region_bg normal', 'region_bg select')
  56. self.now_playing = urwid.Text('Now Playing')
  57. # urwid.connect_signal(search_results_box.base_widget, 'click', self.click)
  58. self.queue = urwid.SimpleFocusListWalker([])
  59. queue_box = urwid.ListBox(self.queue)
  60. queue_box = urwid.LineBox(queue_box, title='Queue')
  61. queue_box = urwid.AttrMap(queue_box, 'region_bg normal', 'region_bg select')
  62. self.command_input = urwid.Edit('> ', multiline=False, allow_tab=False)
  63. urwid.Pile.__init__(self, [('weight', 12, search_results_box),
  64. ('pack', self.now_playing),
  65. ('weight', 7, queue_box),
  66. ('pack', self.command_input)
  67. ])
  68. def header(self, txts):
  69. header = urwid.Columns([('weight', 1, urwid.Text(('header', txt)))
  70. for txt in txts])
  71. return urwid.AttrMap(header, 'header_bg')
  72. def line(self, txts):
  73. first, *rest = txts
  74. items = [urwid.SelectableIcon(first, 0)]
  75. for line in rest:
  76. items.append(urwid.Text(line))
  77. line = urwid.Columns(items)
  78. line = urwid.AttrMap(line, 'search normal', 'search select')
  79. return line
  80. def selected_search_obj(self):
  81. focus_id = self.search_results.get_focus()[1]
  82. songs, albums, artists = self.search_list
  83. focus_id -= 1
  84. if focus_id < len(songs):
  85. return songs[focus_id]
  86. focus_id -= (1 + len(songs))
  87. if focus_id < len(albums):
  88. return albums[focus_id]
  89. focus_id -= (1 + len(albums))
  90. return artists[focus_id]
  91. def enqueue(self, obj):
  92. pass
  93. def expand(self, obj):
  94. pass
  95. def radio(self, obj):
  96. pass
  97. def keypress(self, size, key):
  98. if key in ('q', 'e', 'r'):
  99. focus_obj = self.selected_search_obj()
  100. self.now_playing.set_text(repr(focus_obj))
  101. if key == 'q' and type(focus_obj) in (Song, Album):
  102. self.enqueue(focus_obj)
  103. elif key == 'e':
  104. self.expand(focus_obj)
  105. else:
  106. self.radio(focus_obj)
  107. else:
  108. return self.focus.keypress(size, key)
  109. def display_search_results(self, search_list=None):
  110. if search_list is None:
  111. self.search_list = build_search_collection(40)
  112. songs, albums, artists = self.search_list
  113. self.search_results.clear()
  114. if songs:
  115. self.search_results.append(self.header(['Title', 'Album', 'Artist']))
  116. for song in songs:
  117. self.search_results.append(self.line([song.title, song.album, song.artist]))
  118. if albums:
  119. self.search_results.append(self.header(['Album', 'Artist']))
  120. for album in albums:
  121. self.search_results.append(self.line([album.title, album.artist]))
  122. if artists:
  123. self.search_results.append(self.header(['Artist']))
  124. for artist in artists:
  125. self.search_results.append(self.line([artist.name]))
  126. ui = UI()
  127. def show_or_exit(key):
  128. if key == 'esc':
  129. raise urwid.ExitMainLoop()
  130. elif key == 'enter':
  131. ui.display_search_results()
  132. else:
  133. # ui.now_playing.set_text(repr(key))
  134. # try:
  135. # ui.now_playing.set_text(repr(ui.search_results.get_focus()[0].base_widget))
  136. # except AttributeError:
  137. ui.now_playing.set_text(repr(ui.search_results.get_focus()))
  138. # current = ui.search_results.get_focus()[1]
  139. # try:
  140. # ui.search_results.set_focus(current+1)
  141. # except IndexError:
  142. # pass
  143. loop = urwid.MainLoop(ui, ui.palette, unhandled_input=show_or_exit)
  144. loop.screen.set_terminal_properties(colors=256)
  145. try:
  146. loop.run()
  147. except Exception as e:
  148. print(log)
  149. raise e