From cfd83089c989cba863928cde4eed6a2d35cbac09 Mon Sep 17 00:00:00 2001 From: William Bell <62452284+Ugric@users.noreply.github.com> Date: Fri, 26 Dec 2025 21:30:06 +0000 Subject: [PATCH] disable graphics (the raspberry pi doesnt support drm, only a direct frame buffer) --- app.py | 597 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 302 insertions(+), 295 deletions(-) diff --git a/app.py b/app.py index 5e6d18e..661b905 100644 --- a/app.py +++ b/app.py @@ -9,68 +9,68 @@ import time import os from jelly import server, client -# --- Configuration Constants --- -INITIAL_SCREEN_WIDTH = 240 -INITIAL_SCREEN_HEIGHT = 240 -TARGET_FPS =60 +# # --- Configuration Constants --- +# INITIAL_SCREEN_WIDTH = 240 +# INITIAL_SCREEN_HEIGHT = 240 +# TARGET_FPS =60 -# --- State Variables --- -state = { - "screen_width": INITIAL_SCREEN_WIDTH, - "screen_height": INITIAL_SCREEN_HEIGHT, -} +# # --- State Variables --- +# state = { +# "screen_width": INITIAL_SCREEN_WIDTH, +# "screen_height": INITIAL_SCREEN_HEIGHT, +# } -# --- Utility Functions --- +# # --- Utility Functions --- -def format_time_mm_ss(seconds): - """Converts a time in seconds to an 'MM:SS' string format.""" - seconds = int(seconds) - minutes = seconds // 60 - seconds_remainder = seconds % 60 - return f"{minutes:02d}:{seconds_remainder:02d}" +# def format_time_mm_ss(seconds): +# """Converts a time in seconds to an 'MM:SS' string format.""" +# seconds = int(seconds) +# minutes = seconds // 60 +# seconds_remainder = seconds % 60 +# return f"{minutes:02d}:{seconds_remainder:02d}" -def get_progress_bar_rect(screen_width, screen_height): - width = screen_width - height = screen_height*0.021 - x = (screen_width - width) / 2 - y = screen_height - height - return pr.Rectangle(x, y, width, height) +# def get_progress_bar_rect(screen_width, screen_height): +# width = screen_width +# height = screen_height*0.021 +# x = (screen_width - width) / 2 +# y = screen_height - height +# return pr.Rectangle(x, y, width, height) -def draw_progress_bar(rect, current_time, total_time): - if total_time > 0: - progress_ratio = current_time / total_time - else: - progress_ratio = 0.0 +# def draw_progress_bar(rect, current_time, total_time): +# if total_time > 0: +# progress_ratio = current_time / total_time +# else: +# progress_ratio = 0.0 - pr.draw_rectangle_rec(rect, pr.Color(100, 100, 100, 255)) - progress_width = rect.width * progress_ratio - pr.draw_rectangle( - int(rect.x), - int(rect.y)+1, - int(progress_width), - int(rect.height), - pr.Color(200, 50, 50, 255), - ) - # pr.draw_rectangle_lines_ex(rect, 2, pr.Color(50, 50, 50, 255)) +# pr.draw_rectangle_rec(rect, pr.Color(100, 100, 100, 255)) +# progress_width = rect.width * progress_ratio +# pr.draw_rectangle( +# int(rect.x), +# int(rect.y)+1, +# int(progress_width), +# int(rect.height), +# pr.Color(200, 50, 50, 255), +# ) +# # pr.draw_rectangle_lines_ex(rect, 2, pr.Color(50, 50, 50, 255)) - time_text = f"{format_time_mm_ss(current_time)} / {format_time_mm_ss(total_time)}" - text_width = pr.measure_text(time_text, int(rect.height * 0.7)) - # pr.draw_text( - # time_text, - # int(rect.x + rect.width / 2 - text_width / 2), - # int(rect.y + rect.height * 0.15), - # int(rect.height * 0.7), - # pr.WHITE, - # ) +# time_text = f"{format_time_mm_ss(current_time)} / {format_time_mm_ss(total_time)}" +# text_width = pr.measure_text(time_text, int(rect.height * 0.7)) +# # pr.draw_text( +# # time_text, +# # int(rect.x + rect.width / 2 - text_width / 2), +# # int(rect.y + rect.height * 0.15), +# # int(rect.height * 0.7), +# # pr.WHITE, +# # ) -pr.set_config_flags(pr.ConfigFlags.FLAG_WINDOW_RESIZABLE) -# pr.set_config_flags(pr.FLAG_MSAA_4X_HINT) -#pr.set_config_flags(pr.FLAG_FULLSCREEN_MODE) -pr.init_window(state["screen_width"], state["screen_height"], "UgPod") -pr.set_target_fps(TARGET_FPS) +# pr.set_config_flags(pr.ConfigFlags.FLAG_WINDOW_RESIZABLE) +# # pr.set_config_flags(pr.FLAG_MSAA_4X_HINT) +# #pr.set_config_flags(pr.FLAG_FULLSCREEN_MODE) +# pr.init_window(state["screen_width"], state["screen_height"], "UgPod") +# pr.set_target_fps(TARGET_FPS) player = GaplessPlayer() @@ -116,316 +116,323 @@ for track in tracks["Items"]: ) print("add queue done") -player.load_state("data/player.json") -close_event = threading.Event() -def save_state_loop(): - while not close_event.wait(10): - player.save_state("data/player.lock.json") - os.rename("data/player.lock.json", "data/player.json") -# save_state_thread = threading.Thread(target=save_state_loop) -# save_state_thread.start() +# player.load_state("data/player.json") +# close_event = threading.Event() +# def save_state_loop(): +# while not close_event.wait(10): +# player.save_state("data/player.lock.json") +# os.rename("data/player.lock.json", "data/player.json") +# # save_state_thread = threading.Thread(target=save_state_loop) +# # save_state_thread.start() -current_path = None -texture = None +# current_path = None +# texture = None -def load_texture(path): - global texture, current_path +# def load_texture(path): +# global texture, current_path - if not path: - return +# if not path: +# return - if path == current_path: - return +# if path == current_path: +# return - if texture is not None: - pr.unload_texture(texture) +# if texture is not None: +# pr.unload_texture(texture) - texture = pr.load_texture(path) - current_path = path +# texture = pr.load_texture(path) +# current_path = path -def draw_play_pause_button(pos: pr.Vector2, size: pr.Vector2, is_playing: bool) -> bool: - clicked = False +# def draw_play_pause_button(pos: pr.Vector2, size: pr.Vector2, is_playing: bool) -> bool: +# clicked = False - rect = pr.Rectangle(pos.x, pos.y, size.x, size.y) +# rect = pr.Rectangle(pos.x, pos.y, size.x, size.y) - # Optional hover background - if pr.check_collision_point_rec(pr.get_mouse_position(), rect): - pr.draw_rectangle_rec(rect, pr.fade(pr.BLACK, 0.4)) - if pr.is_mouse_button_pressed(pr.MOUSE_LEFT_BUTTON): - clicked = True - cx = pos.x + size.x / 2 - cy = pos.y + size.y / 2 +# # Optional hover background +# if pr.check_collision_point_rec(pr.get_mouse_position(), rect): +# pr.draw_rectangle_rec(rect, pr.fade(pr.BLACK, 0.4)) +# if pr.is_mouse_button_pressed(pr.MOUSE_LEFT_BUTTON): +# clicked = True +# cx = pos.x + size.x / 2 +# cy = pos.y + size.y / 2 - icon_padding = size.x * 0.25 - icon_size = size.x - icon_padding * 2 +# icon_padding = size.x * 0.25 +# icon_size = size.x - icon_padding * 2 - if is_playing: - # PAUSE (two bars centered, same visual weight as play) - bar_width = icon_size * 0.25 - bar_height = icon_size +# if is_playing: +# # PAUSE (two bars centered, same visual weight as play) +# bar_width = icon_size * 0.25 +# bar_height = icon_size - left_x = cx - bar_width - bar_width * 0.4 - right_x = cx + bar_width * 0.4 - top_y = 1+cy - bar_height / 2 +# left_x = cx - bar_width - bar_width * 0.4 +# right_x = cx + bar_width * 0.4 +# top_y = 1+cy - bar_height / 2 - pr.draw_rectangle( - int(left_x), - int(top_y), - int(bar_width), - int(bar_height), - pr.WHITE, - ) - pr.draw_rectangle( - int(right_x), - int(top_y), - int(bar_width), - int(bar_height), - pr.WHITE, - ) - else: - # PLAY (centered triangle) - p1 = pr.Vector2(cx - icon_size / 2, cy - icon_size / 2) - p2 = pr.Vector2(cx - icon_size / 2, cy + icon_size / 2) - p3 = pr.Vector2(cx + icon_size / 2, cy) +# pr.draw_rectangle( +# int(left_x), +# int(top_y), +# int(bar_width), +# int(bar_height), +# pr.WHITE, +# ) +# pr.draw_rectangle( +# int(right_x), +# int(top_y), +# int(bar_width), +# int(bar_height), +# pr.WHITE, +# ) +# else: +# # PLAY (centered triangle) +# p1 = pr.Vector2(cx - icon_size / 2, cy - icon_size / 2) +# p2 = pr.Vector2(cx - icon_size / 2, cy + icon_size / 2) +# p3 = pr.Vector2(cx + icon_size / 2, cy) - pr.draw_triangle(p1, p2, p3, pr.WHITE) +# pr.draw_triangle(p1, p2, p3, pr.WHITE) - return clicked +# return clicked -title = ScrollingText( - "", - 15 -) +# title = ScrollingText( +# "", +# 15 +# ) -# --- Main Game Loop --- -while not pr.window_should_close(): - # 1. Update - current_width = pr.get_screen_width() - current_height = pr.get_screen_height() +# # --- Main Game Loop --- +# while not pr.window_should_close(): +# # 1. Update +# current_width = pr.get_screen_width() +# current_height = pr.get_screen_height() - if pr.is_key_pressed(pr.KEY_F11): - pr.toggle_fullscreen() - if pr.is_key_pressed(pr.KeyboardKey.KEY_SPACE): - if player.playing: - player.pause() - else: - player.play() - if pr.is_key_pressed(pr.KeyboardKey.KEY_LEFT): - player.seek(player.position - 5) - if pr.is_key_pressed(pr.KeyboardKey.KEY_RIGHT): - player.seek(player.position + 5) +# if pr.is_key_pressed(pr.KEY_F11): +# pr.toggle_fullscreen() +# if pr.is_key_pressed(pr.KeyboardKey.KEY_SPACE): +# if player.playing: +# player.pause() +# else: +# player.play() +# if pr.is_key_pressed(pr.KeyboardKey.KEY_LEFT): +# player.seek(player.position - 5) +# if pr.is_key_pressed(pr.KeyboardKey.KEY_RIGHT): +# player.seek(player.position + 5) - pr.begin_drawing() - pr.clear_background(pr.Color(40, 40, 40, 255)) - dt = pr.get_frame_time() +# pr.begin_drawing() +# pr.clear_background(pr.Color(40, 40, 40, 255)) +# dt = pr.get_frame_time() - progress_rect = get_progress_bar_rect(current_width, current_height) +# progress_rect = get_progress_bar_rect(current_width, current_height) - # pr.draw_text( - # "UgPod", - # int(current_width * 0.05), - # int(current_height * 0.05), - # int(current_height * 0.05), - # pr.SKYBLUE, - # ) +# # pr.draw_text( +# # "UgPod", +# # int(current_width * 0.05), +# # int(current_height * 0.05), +# # int(current_height * 0.05), +# # pr.SKYBLUE, +# # ) - current_song = player.get_current_song() +# current_song = player.get_current_song() - draw_progress_bar( - progress_rect, - player.position, - (current_song and current_song.duration) or 0.0, - ) - if current_song: - load_texture(current_song.album_cover_path) - title_font_size = int(current_height*0.05) - album_cover_size = int(min(current_width, current_height*0.7)) - title.speed = title_font_size*2.5 - title_size = pr.Vector2(current_width-int(current_height * 0.01)*2, title_font_size) - title.update(dt,title_size) - title.set_text(f"{current_song.name} - {current_song.artist_name}", title_font_size) - title.draw(pr.Vector2(int(current_height * 0.01),int(current_height * 0.8)),title_size) - # pr.draw_text( - # , - # , - # int(current_height * 0.03), - # pr.WHITE, - # ) - points = player.oscilloscope_data_points - if texture is not None: - scale = min(album_cover_size / texture.width, album_cover_size / texture.height) +# draw_progress_bar( +# progress_rect, +# player.position, +# (current_song and current_song.duration) or 0.0, +# ) +# if current_song: +# load_texture(current_song.album_cover_path) +# title_font_size = int(current_height*0.05) +# album_cover_size = int(min(current_width, current_height*0.7)) +# title.speed = title_font_size*2.5 +# title_size = pr.Vector2(current_width-int(current_height * 0.01)*2, title_font_size) +# title.update(dt,title_size) +# title.set_text(f"{current_song.name} - {current_song.artist_name}", title_font_size) +# title.draw(pr.Vector2(int(current_height * 0.01),int(current_height * 0.8)),title_size) +# # pr.draw_text( +# # , +# # , +# # int(current_height * 0.03), +# # pr.WHITE, +# # ) +# points = player.oscilloscope_data_points +# if texture is not None: +# scale = min(album_cover_size / texture.width, album_cover_size / texture.height) - dest_rect = pr.Rectangle( - current_width//2 - album_cover_size//2, - (current_height*0.8)//2 - album_cover_size//2, - texture.width * scale, - texture.height * scale, - ) +# dest_rect = pr.Rectangle( +# current_width//2 - album_cover_size//2, +# (current_height*0.8)//2 - album_cover_size//2, +# texture.width * scale, +# texture.height * scale, +# ) - src_rect = pr.Rectangle(0, 0, texture.width, texture.height) +# src_rect = pr.Rectangle(0, 0, texture.width, texture.height) - pr.draw_texture_pro( - texture, src_rect, dest_rect, pr.Vector2(0, 0), 0.0, pr.WHITE - ) - else: - clip = pr.Rectangle(int(current_width//2 - album_cover_size//2), - int((current_height*0.8)//2 - album_cover_size//2), - int(album_cover_size), - int(album_cover_size)) - pr.begin_scissor_mode( - int(clip.x), - int(clip.y), - int(clip.width), - int(clip.height), - ) - pr.draw_rectangle( - int(clip.x), - int(clip.y), - int(clip.width), - int(clip.height), pr.BLACK) +# pr.draw_texture_pro( +# texture, src_rect, dest_rect, pr.Vector2(0, 0), 0.0, pr.WHITE +# ) +# else: +# clip = pr.Rectangle(int(current_width//2 - album_cover_size//2), +# int((current_height*0.8)//2 - album_cover_size//2), +# int(album_cover_size), +# int(album_cover_size)) +# pr.begin_scissor_mode( +# int(clip.x), +# int(clip.y), +# int(clip.width), +# int(clip.height), +# ) +# pr.draw_rectangle( +# int(clip.x), +# int(clip.y), +# int(clip.width), +# int(clip.height), pr.BLACK) - # cx = current_width * 0.5+1 - # cy = current_height * 0.4+1 +# # cx = current_width * 0.5+1 +# # cy = current_height * 0.4+1 - # MAX_LEN = album_cover_size * 0.25 # tune this - # MIN_ALPHA = 10 - # MAX_ALPHA = 255 +# # MAX_LEN = album_cover_size * 0.25 # tune this +# # MIN_ALPHA = 10 +# # MAX_ALPHA = 255 - # for i in range(len(points) - 1): - # x1 = cx + points[i][0] * album_cover_size * 0.5 - # y1 = cy + -points[i][1] * album_cover_size * 0.5 - # x2 = cx + points[i+1][0] * album_cover_size * 0.5 - # y2 = cy + -points[i+1][1] * album_cover_size * 0.5 +# # for i in range(len(points) - 1): +# # x1 = cx + points[i][0] * album_cover_size * 0.5 +# # y1 = cy + -points[i][1] * album_cover_size * 0.5 +# # x2 = cx + points[i+1][0] * album_cover_size * 0.5 +# # y2 = cy + -points[i+1][1] * album_cover_size * 0.5 - # dx = x2 - x1 - # dy = y2 - y1 - # length = (dx * dx + dy * dy) ** 0.5 +# # dx = x2 - x1 +# # dy = y2 - y1 +# # length = (dx * dx + dy * dy) ** 0.5 - # # 1.0 = short line, 0.0 = long line - # t = max(0.0, min(1.0, 1.0 - (length / MAX_LEN)))*math.pow(i/len(points), 2) +# # # 1.0 = short line, 0.0 = long line +# # t = max(0.0, min(1.0, 1.0 - (length / MAX_LEN)))*math.pow(i/len(points), 2) - # alpha = int(MIN_ALPHA + t * (MAX_ALPHA - MIN_ALPHA)) +# # alpha = int(MIN_ALPHA + t * (MAX_ALPHA - MIN_ALPHA)) - # color = pr.Color(255, 255, 255, alpha) +# # color = pr.Color(255, 255, 255, alpha) - # pr.draw_line(int(x1), int(y1), int(x2), int(y2), color) - # draw background square - if len(points) >= 2: - samples = np.fromiter( - ((p[0] + p[1]) * 0.5 for p in points), - dtype=np.float32 - ) +# # pr.draw_line(int(x1), int(y1), int(x2), int(y2), color) +# # draw background square +# if len(points) >= 2: +# samples = np.fromiter( +# ((p[0] + p[1]) * 0.5 for p in points), +# dtype=np.float32 +# ) - # Guard: FFT must have meaningful size - if samples.size > 128: +# # Guard: FFT must have meaningful size +# if samples.size > 128: - rect_x = int(current_width // 2 - album_cover_size // 2) - rect_y = int((current_height * 0.8) // 2 - album_cover_size // 2) +# rect_x = int(current_width // 2 - album_cover_size // 2) +# rect_y = int((current_height * 0.8) // 2 - album_cover_size // 2) - # ---- FFT ---- +# # ---- FFT ---- - FFT_SIZE = min(samples.size, 2048) - window = np.hanning(FFT_SIZE) +# FFT_SIZE = min(samples.size, 2048) +# window = np.hanning(FFT_SIZE) - fft = np.fft.rfft(samples[:FFT_SIZE] * window) - magnitudes = np.abs(fft) +# fft = np.fft.rfft(samples[:FFT_SIZE] * window) +# magnitudes = np.abs(fft) - # remove DC component (important for visuals) - magnitudes[0] = 0.0 +# # remove DC component (important for visuals) +# magnitudes[0] = 0.0 - # ---- LOG BINNING ---- +# # ---- LOG BINNING ---- - num_bars = album_cover_size//10 - num_bins = magnitudes.size +# num_bars = album_cover_size//10 +# num_bins = magnitudes.size - # logarithmic bin edges (low end stretched) - log_min = 1 - log_max = math.log10(num_bins) +# # logarithmic bin edges (low end stretched) +# log_min = 1 +# log_max = math.log10(num_bins) - log_edges = np.logspace( - math.log10(log_min), - log_max, - num_bars + 1 - ).astype(int) +# log_edges = np.logspace( +# math.log10(log_min), +# log_max, +# num_bars + 1 +# ).astype(int) - bar_values = np.zeros(num_bars, dtype=np.float32) +# bar_values = np.zeros(num_bars, dtype=np.float32) - for i in range(num_bars): - start = log_edges[i] - end = log_edges[i + 1] +# for i in range(num_bars): +# start = log_edges[i] +# end = log_edges[i + 1] - if end <= start: - continue +# if end <= start: +# continue - bar_values[i] = np.mean(magnitudes[start:end]) +# bar_values[i] = np.mean(magnitudes[start:end]) -# ---- STATIC SCALING ---- +# # ---- STATIC SCALING ---- - # Instead of normalizing to the max of the frame, we scale by the FFT size. - # For a Hanning windowed FFT, dividing by (FFT_SIZE / 4) maps - # maximum possible volume roughly to 1.0. - bar_values = bar_values / (FFT_SIZE / 4.0) +# # Instead of normalizing to the max of the frame, we scale by the FFT size. +# # For a Hanning windowed FFT, dividing by (FFT_SIZE / 4) maps +# # maximum possible volume roughly to 1.0. +# bar_values = bar_values / (FFT_SIZE / 4.0) - # ---- DRAW ---- +# # ---- DRAW ---- - def map_to_screen(val): - return rect_x + (math.log10(max(1, val)) / log_max) * album_cover_size +# def map_to_screen(val): +# return rect_x + (math.log10(max(1, val)) / log_max) * album_cover_size - spacing = 0 +# spacing = 0 - for i in range(num_bars): - # 1. Calculate integer pixel boundaries first - # This ensures the right edge of one bar is exactly the left edge of the next - x_start_int = int(map_to_screen(log_edges[i])) - x_end_int = int(map_to_screen(log_edges[i+1])) +# for i in range(num_bars): +# # 1. Calculate integer pixel boundaries first +# # This ensures the right edge of one bar is exactly the left edge of the next +# x_start_int = int(map_to_screen(log_edges[i])) +# x_end_int = int(map_to_screen(log_edges[i+1])) - # 2. Width is the difference between these fixed integer points - w = (x_end_int - x_start_int) - spacing +# # 2. Width is the difference between these fixed integer points +# w = (x_end_int - x_start_int) - spacing - value = bar_values[i] - h = int(min(1.0, value) * album_cover_size) +# value = bar_values[i] +# h = int(min(1.0, value) * album_cover_size) - # 3. Anchor to bottom - y = (rect_y + album_cover_size) - h +# # 3. Anchor to bottom +# y = (rect_y + album_cover_size) - h - alpha = min(1.0, ((value+1)**2)-1) - r = 255 - g = 0 - b = 0 +# alpha = min(1.0, ((value+1)**2)-1) +# r = 255 +# g = 0 +# b = 0 - # Keep alpha at 255 (fully opaque) - color = pr.Color(r, g, b, int(255 * alpha)) +# # Keep alpha at 255 (fully opaque) +# color = pr.Color(r, g, b, int(255 * alpha)) - # 4. Draw the bar - # Use max(1, w) to ensure high-frequency bars don't disappear on small screens - pr.draw_rectangle( - x_start_int, - int(y), - max(1, int(w)), - h, - color - ) - pr.end_scissor_mode() +# # 4. Draw the bar +# # Use max(1, w) to ensure high-frequency bars don't disappear on small screens +# pr.draw_rectangle( +# x_start_int, +# int(y), +# max(1, int(w)), +# h, +# color +# ) +# pr.end_scissor_mode() - pos = pr.Vector2(current_width * 0.5 - current_height * 0.05, current_height * 0.9-progress_rect.height) - size = pr.Vector2(current_height * 0.1, current_height * 0.1) +# pos = pr.Vector2(current_width * 0.5 - current_height * 0.05, current_height * 0.9-progress_rect.height) +# size = pr.Vector2(current_height * 0.1, current_height * 0.1) - if draw_play_pause_button(pos, size, player.playing): - if player.playing: - player.pause() - else: - player.play() - pr.end_drawing() +# if draw_play_pause_button(pos, size, player.playing): +# if player.playing: +# player.pause() +# else: +# player.play() +# pr.end_drawing() -# Cleanup -if texture is not None: - pr.unload_texture(texture) +# # Cleanup +# if texture is not None: +# pr.unload_texture(texture) -pr.close_window() -close_event.set() -# save_state_thread.join() \ No newline at end of file +# pr.close_window() +# close_event.set() +# # save_state_thread.join() + + + + +player.play() +while True: + time.sleep(1) \ No newline at end of file