mirror of
https://github.com/csd4ni3l/music-player.git
synced 2026-01-01 04:03:42 +01:00
Move from list to card grid view, only support popular file extensions,
Use Roboto Black as a font, dont recreate ui on refresh, update styles
This commit is contained in:
124
utils/utils.py
124
utils/utils.py
@@ -1,8 +1,9 @@
|
||||
import logging, arcade, arcade.gui, sys, traceback, os, re, platform, urllib.request, zipfile, subprocess
|
||||
import logging, sys, traceback, os, re, platform, urllib.request, zipfile, subprocess, textwrap, io, base64
|
||||
from mutagen.easyid3 import EasyID3
|
||||
|
||||
from mutagen import File
|
||||
from PIL import Image
|
||||
from utils.constants import menu_background_color
|
||||
import pyglet
|
||||
import pyglet, arcade, arcade.gui
|
||||
|
||||
def dump_platform():
|
||||
import platform
|
||||
@@ -58,25 +59,6 @@ class ErrorView(arcade.gui.UIView):
|
||||
msgbox.on_action = lambda event: self.exit()
|
||||
self.add_widget(msgbox)
|
||||
|
||||
def on_exception(*exc_info):
|
||||
logging.error(f"Unhandled exception:\n{''.join(traceback.format_exception(exc_info[1], limit=None))}")
|
||||
|
||||
def get_closest_resolution():
|
||||
allowed_resolutions = [(1366, 768), (1440, 900), (1600,900), (1920,1080), (2560,1440), (3840,2160)]
|
||||
screen_width, screen_height = arcade.get_screens()[0].width, arcade.get_screens()[0].height
|
||||
if (screen_width, screen_height) in allowed_resolutions:
|
||||
if not allowed_resolutions.index((screen_width, screen_height)) == 0:
|
||||
closest_resolution = allowed_resolutions[allowed_resolutions.index((screen_width, screen_height))-1]
|
||||
else:
|
||||
closest_resolution = (screen_width, screen_height)
|
||||
else:
|
||||
target_width, target_height = screen_width // 2, screen_height // 2
|
||||
|
||||
closest_resolution = min(
|
||||
allowed_resolutions,
|
||||
key=lambda res: abs(res[0] - target_width) + abs(res[1] - target_height)
|
||||
)
|
||||
return closest_resolution
|
||||
|
||||
class FakePyPresence():
|
||||
def __init__(self):
|
||||
@@ -97,16 +79,60 @@ class UIFocusTextureButton(arcade.gui.UITextureButton):
|
||||
else:
|
||||
self.resize(width=self.width / 1.1, height=self.height / 1.1)
|
||||
|
||||
class Card(arcade.gui.UIBoxLayout):
|
||||
def __init__(self, width: int, height: int, font_name: str, font_size: int, text: str, card_texture: arcade.Texture, padding=10):
|
||||
super().__init__(width=width, height=height, space_between=padding, align="bottom")
|
||||
|
||||
self.button = self.add(arcade.gui.UITextureButton(
|
||||
texture=card_texture,
|
||||
texture_hovered=card_texture,
|
||||
texture_pressed=card_texture,
|
||||
texture_disabled=card_texture,
|
||||
width=width / 2,
|
||||
height=height * 0.5,
|
||||
))
|
||||
|
||||
wrapped_lines = textwrap.wrap(text, width=int(width / (font_size * 0.6)))
|
||||
wrapped_text = "\n".join(wrapped_lines)
|
||||
|
||||
self.label = self.add(arcade.gui.UILabel(
|
||||
text=wrapped_text,
|
||||
font_name=font_name,
|
||||
font_size=font_size,
|
||||
width=width,
|
||||
height=height * 0.5,
|
||||
multiline=True
|
||||
))
|
||||
|
||||
def on_exception(*exc_info):
|
||||
logging.error(f"Unhandled exception:\n{''.join(traceback.format_exception(exc_info[1], limit=None))}")
|
||||
|
||||
def get_closest_resolution():
|
||||
allowed_resolutions = [(1366, 768), (1440, 900), (1600,900), (1920,1080), (2560,1440), (3840,2160)]
|
||||
screen_width, screen_height = arcade.get_screens()[0].width, arcade.get_screens()[0].height
|
||||
if (screen_width, screen_height) in allowed_resolutions:
|
||||
if not allowed_resolutions.index((screen_width, screen_height)) == 0:
|
||||
closest_resolution = allowed_resolutions[allowed_resolutions.index((screen_width, screen_height))-1]
|
||||
else:
|
||||
closest_resolution = (screen_width, screen_height)
|
||||
else:
|
||||
target_width, target_height = screen_width // 2, screen_height // 2
|
||||
|
||||
closest_resolution = min(
|
||||
allowed_resolutions,
|
||||
key=lambda res: abs(res[0] - target_width) + abs(res[1] - target_height)
|
||||
)
|
||||
return closest_resolution
|
||||
|
||||
def get_yt_dlp_binary_path():
|
||||
binary = "yt-dlp"
|
||||
system = platform.system()
|
||||
|
||||
if system == "Windows":
|
||||
binary += ".exe"
|
||||
binary = "yt-dlp.exe"
|
||||
elif system == "Darwin":
|
||||
binary += "_macos"
|
||||
binary = "yt-dlp_macos"
|
||||
elif system == "Linux":
|
||||
binary += "_linux"
|
||||
binary = "yt-dlp_linux"
|
||||
|
||||
return os.path.join("bin", binary)
|
||||
|
||||
@@ -150,10 +176,10 @@ def extract_metadata(filename):
|
||||
name_only = re.sub(r'\s*\[[a-zA-Z0-9\-_]{5,}\]$', '', name_only)
|
||||
|
||||
try:
|
||||
audio = EasyID3(filename)
|
||||
thumb_audio = EasyID3(filename)
|
||||
|
||||
artist = str(audio["artist"][0])
|
||||
title = str(audio["title"][0])
|
||||
artist = str(thumb_audio["artist"][0])
|
||||
title = str(thumb_audio["title"][0])
|
||||
|
||||
artist_title_match = re.search(r'^.+\s*-\s*.+$', title) # check for Artist - Title titles, so Artist doesnt appear twice
|
||||
|
||||
@@ -182,3 +208,43 @@ def extract_metadata(filename):
|
||||
title = name_only
|
||||
|
||||
return artist, title
|
||||
|
||||
def get_audio_thumbnail_texture(audio_path: str, window_resolution: tuple) -> arcade.Texture:
|
||||
ext = os.path.splitext(audio_path)[1].lower().lstrip('.')
|
||||
thumb_audio = File(audio_path)
|
||||
|
||||
thumb_image_data = None
|
||||
|
||||
try:
|
||||
if ext == 'mp3':
|
||||
for tag in thumb_audio.values():
|
||||
if tag.FrameID == "APIC":
|
||||
thumb_image_data = tag.data
|
||||
break
|
||||
|
||||
elif ext in ('m4a', 'mp4', 'aac'):
|
||||
if 'covr' in thumb_audio:
|
||||
thumb_image_data = thumb_audio['covr'][0]
|
||||
|
||||
elif ext == 'flac':
|
||||
if thumb_audio.pictures:
|
||||
thumb_image_data = thumb_audio.pictures[0].data
|
||||
|
||||
elif ext in ('ogg', 'opus'):
|
||||
if "metadata_block_picture" in thumb_audio:
|
||||
pic_data = base64.b64decode(thumb_audio["metadata_block_picture"][0])
|
||||
import struct
|
||||
header_len = struct.unpack(">I", pic_data[0:4])[0]
|
||||
thumb_image_data = pic_data[4 + header_len:]
|
||||
|
||||
if thumb_image_data:
|
||||
pil_image = Image.open(io.BytesIO(thumb_image_data)).convert("RGBA")
|
||||
pil_image = pil_image.resize((int(window_resolution[0] / 5), int(window_resolution[1] / 8)))
|
||||
thumb_texture = arcade.Texture(pil_image)
|
||||
return thumb_texture
|
||||
|
||||
except Exception as e:
|
||||
logging.debug(f"[Thumbnail Error] {audio_path}: {e}")
|
||||
|
||||
from utils.preload import music_icon
|
||||
return music_icon
|
||||
|
||||
Reference in New Issue
Block a user