Add browse logic

This commit is contained in:
ABelliqueux 2024-03-24 17:34:48 +01:00
parent 6dc317a1a7
commit 16db9c6309
1 changed files with 142 additions and 32 deletions

View File

@ -55,32 +55,37 @@ ui_vol_y = 4
ui_vol_x = device.width - ui_vol_width - 8
ui_vol_icon_coords = (ui_vol_x - 10, 4)
ui_vol_icon_polygon = [0,3,3,3,8,0,8,8,3,5,0,5]
play_icon = [0,0,8,4,0,8]
# ~ play_icon_ = [0,0,8,4,0,8]
pause_icon = [0,0,3,0,3,8,5,8,5,0,8,0,8,8,0,8]
stop_icon = [0,0,8,0,8,8,0,8]
next_icon = [0,0,3,3,3,0,8,4,3,8,3,5,0,8]
prev_icon = [0,4,3,0,3,3,8,0,8,8,3,5,3,8]
menu_icon = [0,0, 5,0, 4,1, 8,4, 6,6, 2,4, 0,6]
menu_icon = [0,0, 5,0, 4,2, 8,5, 10,10, 7,7, 2,4, 0,6]
menu_icon_ = [0,0, 5,0, 4,2, 8,5, 10,10, 7,7, 2,4, 0,6]
down_icon = [0,0, 8,0, 4,8]
up_icon = [0,8, 4,0, 8,8]
add_icon = [0,3, 3,3, 3,0, 6,0, 6,3, 8,3, 8,6, 6,6, 6,8, 3,8, 3,6, 0,6]
ui_state = {'cursor_pos': 0, 'prev_cursor_pos': 0, 'current_selection': [], 'current_selection_level': 0, 'current_artist': None, 'current_album': None }
MODES_ORDER = ['playback', 'browse']
MODES = { 'playback' : dict(BTN_1=dict(FUNCTION='prev', ICON=prev_icon, XY=(((btn_width+1)*0.5), (menu_bar_y + 2)) ),
BTN_2=dict(FUNCTION='stop', ICON=stop_icon, XY=(((btn_width+1)*1.5), (menu_bar_y + 2))),
BTN_3=dict(FUNCTION='toggle', ICON=play_icon, XY=(((btn_width+1)*2.5), (menu_bar_y + 2))),
BTN_4=dict(FUNCTION='next', ICON=next_icon, XY=(((btn_width+1)*3.5), (menu_bar_y + 2))),
BTN_5=dict(FUNCTION='menu', ICON=prev_icon, XY=(((btn_width+1)*4.5), (menu_bar_y + 2))),
BTN_5=dict(FUNCTION='menu', ICON=menu_icon, XY=(((btn_width+1)*4.5), (menu_bar_y + 2))),
),
'browse' : dict(BTN_1=dict(FUNCTION='none', ICON=down_icon, XY=(((btn_width+1)*0.5), (menu_bar_y + 2)) ),
BTN_2=dict(FUNCTION='none', ICON=up_icon, XY=(((btn_width+1)*1.5), (menu_bar_y + 2))),
BTN_3=dict(FUNCTION='none', ICON=add_icon, XY=(((btn_width+1)*2.5), (menu_bar_y + 2))),
BTN_4=dict(FUNCTION='none', ICON=play_icon, XY=(((btn_width+1)*3.5), (menu_bar_y + 2))),
'browse' : dict(BTN_1=dict(FUNCTION='down', ICON=down_icon, XY=(((btn_width+1)*0.5), (menu_bar_y + 2)) ),
BTN_2=dict(FUNCTION='up', ICON=up_icon, XY=(((btn_width+1)*1.5), (menu_bar_y + 2))),
BTN_3=dict(FUNCTION='select', ICON=play_icon, XY=(((btn_width+1)*2.5), (menu_bar_y + 2))),
BTN_4=dict(FUNCTION='add', ICON=add_icon, XY=(((btn_width+1)*3.5), (menu_bar_y + 2))),
BTN_5=dict(FUNCTION='menu', ICON=menu_icon, XY=(((btn_width+1)*4.5), (menu_bar_y + 2))),
),
}
# Becomes true when receiving SIGINT
# Becomes true when receiving SIGINT
ctrlc_pressed = False
mpd_client_status = {'volume': 'N/A',
@ -142,12 +147,13 @@ def sectomin(sec:str):
def apply_xy_offset(polygon:list, offset:tuple):
polygon_copy = []
i=0
while i < len(polygon):
polygon[i] += offset[0]
polygon[i+1] += offset[1]
polygon_copy.append(polygon[i] + offset[0])
polygon_copy.append(polygon[i+1] + offset[1])
i+=2
return polygon
return polygon_copy
def offset_polygons(modes:dict):
@ -174,7 +180,7 @@ def generate_static_ui(mode:str):
return im
def update_display(device, currentsong, status):
def update_display(device, currentsong:dict, status:dict, mode:str, cursor_pos:int):
# We want to display 4 buttons at the bottom of the screen
btn_width = floor((device.width-3) / 4)
btn_height = 8
@ -184,17 +190,47 @@ def update_display(device, currentsong, status):
ui = static_ui.copy()
draw = ImageDraw.Draw(ui)
draw.text((ui_vol_x, ui_vol_y), status['volume'], fill="white")
if current_mode == 'playback':
draw.text((ui_text_x, 2), currentsong['artist'], fill="white")
draw.text((ui_text_x, 14), currentsong['title'], fill="white")
draw.text((ui_text_x, 26), currentsong['album'], fill="white")
if 'elapsed' in status:
draw.text((ui_text_x, 38), "{}/{}".format(sectomin(status['elapsed']), sectomin(status['duration'])), fill="white")
if mode == 'playback':
if len(currentsong):
draw.text((ui_text_x, 2), currentsong['artist'], fill="white")
draw.text((ui_text_x, 14), currentsong['title'], fill="white")
draw.text((ui_text_x, 26), currentsong['album'], fill="white")
if 'elapsed' in status:
draw.text((ui_text_x, 38), "{}/{}".format(sectomin(status['elapsed']), sectomin(status['duration'])), fill="white")
elif mode == 'browse':
draw.regular_polygon(bounding_circle=(ui_text_x + 2, 6, 4), n_sides=3, rotation=270, outline="white", fill="black")
if (type(ui_state['current_selection']) is list) and (len(ui_state['current_selection'])):
draw.text((ui_text_x + 10, 1), ui_state['current_selection'][cursor_pos], fill="white")
if (len(ui_state['current_selection']) > 1) and (cursor_pos < len(ui_state['current_selection'])-1):
draw.text((ui_text_x, 14), ui_state['current_selection'][cursor_pos+1], fill="white")
if len(ui_state['current_selection']) > 2 and (cursor_pos < len(ui_state['current_selection'])-2):
draw.text((ui_text_x, 26), ui_state['current_selection'][cursor_pos+2], fill="white")
else:
draw.text((ui_text_x + 10, 1), ui_state['current_selection'], fill="white")
device.contrast(0)
device.display(ui)
def send_mpd_cmd(client, cmd:str):
def populate_empty_tags(current_selection:list, selection_level:int):
if '' in current_selection:
if selection_level == 0:
# Empty artist
current_selection[current_selection.index('')] = '(No artist)'
if selection_level == 1:
# Empty album
current_selection[current_selection.index('')] = '(No album)'
if selection_level == 2:
# Empty title
current_selection[current_selection.index('')] = '(No title)'
def send_mpd_cmd(client, cmd:str, ui_state:dict):
cursor_pos = ui_state['cursor_pos']
prev_cursor_pos = ui_state['prev_cursor_pos']
current_selection = ui_state['current_selection']
current_artist = ui_state['current_artist']
current_album = ui_state['current_album']
current_selection_level = ui_state['current_selection_level']
idle_states = ['stop', 'pause']
if cmd == 'menu':
global current_mode
@ -203,11 +239,18 @@ def send_mpd_cmd(client, cmd:str):
if current_mode_index >= len(MODES_ORDER)-1:
current_mode_index = 0
else:
current_mode_index += 1
current_mode_index += 1
current_mode = MODES_ORDER[current_mode_index]
# TODO : use menu button as return
# prev_cursor_pos
global static_ui
static_ui = generate_static_ui(current_mode)
if cmd == 'prev':
current_selection = client.list('artist')
current_selection_level = 0
populate_empty_tags(current_selection, current_selection_level)
cursor_pos = 0
elif cmd == 'prev':
if client.status()['state'] != 'stop':
client.previous()
elif cmd == 'next':
@ -220,13 +263,71 @@ def send_mpd_cmd(client, cmd:str):
client.pause()
elif cmd == 'stop':
client.stop()
else:
return 0
return 1
elif cmd == 'down':
if cursor_pos in range(0, len(current_selection)-1):
cursor_pos += 1
else:
cursor_pos = 0
elif cmd == 'up':
if cursor_pos in range(1, len(current_selection)):
cursor_pos -= 1
else:
cursor_pos = len(current_selection)-1
elif cmd == 'select':
if current_selection_level == 0:
# Select artist
# ~ current_selection = current_selection[cursor_pos]
# ~ current_selection = client.list('artist')
if len(current_selection):
current_artist = current_selection[cursor_pos]
current_selection = client.list('album', 'artist', current_selection[cursor_pos])
print("Artist:")
print(current_artist)
current_selection_level += 1
populate_empty_tags(current_selection, current_selection_level)
prev_cursor_pos = cursor_pos
cursor_pos = 0
elif current_selection_level == 1:
if len(current_selection):
current_album = current_selection[cursor_pos]
# List albums by selected artist
# ~ current_selection = client.list('album', 'artist', current_selection[cursor_pos])
current_selection = client.list('title', 'album', current_selection[cursor_pos])
print("Album:")
print(current_album)
current_selection_level += 1
populate_empty_tags(current_selection, current_selection_level)
cursor_pos = 0
elif current_selection_level == 2:
# List songs by selected album
# ~ current_selection = client.list('title', 'album', current_selection[cursor_pos])
current_selection = client.list('artist')
cursor_pos = prev_cursor_pos
print("Return to menu")
print(current_selection)
# TODO : change icon to a X and return to artist list if used
current_selection_level = 0
elif cmd == 'add':
if current_selection_level == 0:
print(current_selection[cursor_pos])
selected_song_files = client.find('artist', current_selection[cursor_pos])
if current_selection_level == 1:
print(current_artist)
selected_song_files = client.find('artist', current_artist, 'album', current_selection[cursor_pos])
if current_selection_level == 2:
print(current_album)
selected_song_files = client.find('title', current_selection[cursor_pos], 'artist', current_artist,'album', current_album )
# ~ selected_song_file = client.find('title', current_selection[cursor_pos])
# ~ selected_song_files = selected_song_file[0]
for file in selected_song_files:
client.add(file['file'])
state = {'cursor_pos': cursor_pos, 'prev_cursor_pos': prev_cursor_pos, 'current_selection': current_selection, 'current_selection_level': current_selection_level, 'current_artist': current_artist, 'current_album':current_album}
return state
def main(args):
previous_sond_id = None
previous_song_id = None
previous_state = None
paused_since_seconds = 0
# MPDclient setup
@ -245,6 +346,14 @@ def main(args):
print("Check host and port are correct.")
# ~ print(client.status()) # duration, elapsed, volume, repeat, random, single
# ~ print(client.currentsong()) # artist, title, album
# Cache MPD's artist list
global ui_state
ui_state['current_selection'] = client.list('artist')
# List albums by artist
# ~ album_by = client.list('album', 'artist', artist_list[x])
# List song by album
# ~ songs_from_album = client.list('title', 'album', album_by_x[x])
offset_polygons(MODES)
global ui_vol_icon_polygon
ui_vol_icon_polygon = apply_xy_offset(ui_vol_icon_polygon, ui_vol_icon_coords)
@ -256,12 +365,14 @@ def main(args):
if len(mpd_status):
mpd_client_status = mpd_status
mpd_client_currentsong = client.currentsong()
play_state = mpd_client_status['state']
current_song_id = mpd_client_status['songid']
if 'state' in mpd_client_status:
play_state = mpd_client_status['state']
if 'songid' in mpd_client_status:
current_song_id = mpd_client_status['songid']
if play_state in mpd_states:
if play_state == 'play':
paused_since_seconds = 0
if (current_song_id != previous_sond_id) and (previous_state != play_state):
if (current_song_id != previous_song_id) and (previous_state != play_state):
print("Play")
# Relay on
GPIO.output(RELAIS_1_GPIO, GPIO.HIGH)
@ -274,7 +385,7 @@ def main(args):
# Relay off
GPIO.output(RELAIS_1_GPIO, GPIO.LOW)
if play_state == 'stop' or play_state == 'unknown':
previous_sond_id = None
previous_song_id = None
paused_since_seconds = 0
if previous_state != play_state:
print("Stopped")
@ -282,18 +393,18 @@ def main(args):
GPIO.output(RELAIS_1_GPIO, GPIO.LOW)
previous_state = play_state
sleep(.2)
update_display(device, mpd_client_currentsong, mpd_client_status)
# Handle buttons
for BTN in BTNS:
# Avoid double trigger by saving the previous state of the button and commpare it to current state
if (GPIO.input(BTNS[BTN]['GPIO']) == 0) and (GPIO.input(BTNS[BTN]['GPIO']) != BTNS[BTN]['state']):
send_mpd_cmd(client, MODES[current_mode][BTN]['FUNCTION'])
ui_state = send_mpd_cmd(client, MODES[current_mode][BTN]['FUNCTION'], ui_state)
print("{} pressed".format(MODES[current_mode][BTN]['FUNCTION']))
# Save previous state
BTNS[BTN]['state'] = GPIO.input(BTNS[BTN]['GPIO'])
if (GPIO.input(BTNS[BTN]['GPIO']) == 1) and (GPIO.input(BTNS[BTN]['GPIO']) != BTNS[BTN]['state']):
# Save previous state
BTNS[BTN]['state'] = GPIO.input(BTNS[BTN]['GPIO'])
update_display(device, mpd_client_currentsong, mpd_client_status, current_mode, ui_state['cursor_pos'])
device.cleanup()
client.disconnect()
return 0
@ -303,7 +414,6 @@ def signal_handler(sig, frame):
global ctrlc_pressed
print('You pressed Ctrl+C!')
ctrlc_pressed = True
# ~ sys.exit(0)
if __name__ == '__main__':