Remove FFmpeg Linux download which wouldnt work and add messageboxes, add a yes/no messagebox for yt-dlp, add acoustid music recognition, only support MP3, split online_metadata to multiple files, add missing metadata to files automatically, add synchronized lyrics pane

This commit is contained in:
csd4ni3l
2025-07-10 20:29:49 +02:00
parent b086a6b921
commit c7aad868db
16 changed files with 575 additions and 257 deletions

View File

@@ -49,20 +49,27 @@ class Downloader(arcade.gui.UIView):
self.anchor.detect_focusable_widgets()
def on_update(self, delta_time: float) -> bool | None:
self.status_label.text = self.yt_dl_buffer
if not self.yt_dl_buffer == "download_yt_dlp":
self.status_label.text = self.yt_dl_buffer
if "WARNING" in self.yt_dl_buffer:
self.status_label.update_font(font_color=arcade.color.YELLOW)
elif "ERROR" in self.yt_dl_buffer:
self.status_label.update_font(font_color=arcade.color.RED)
if "WARNING" in self.yt_dl_buffer:
self.status_label.update_font(font_color=arcade.color.YELLOW)
elif "ERROR" in self.yt_dl_buffer:
self.status_label.update_font(font_color=arcade.color.RED)
else:
self.status_label.update_font(font_color=arcade.color.LIGHT_GREEN)
else:
self.status_label.update_font(font_color=arcade.color.LIGHT_GREEN)
msgbox = self.ui.add(arcade.gui.UIMessageBox(width=self.window.width / 2, height=self.window.height / 2, title="This app needs to download third-party software.", message_text="This app needs to download yt-dlp (a third-party tool) to enable video/audio downloading.\n Do you want to continue?", buttons=("Yes", "No")))
msgbox.on_action = lambda event: self.install_and_run_yt_dlp() if event.action == "Yes" else None
self.yt_dl_buffer = ''
def run_yt_dlp(self, url):
yt_dlp_path = self.ensure_yt_dlp()
if not self.check_for_yt_dlp():
self.yt_dl_buffer = "download_yt_dlp"
return None
command = [
yt_dlp_path, f"{url}",
self.get_yt_dlp_path(), f"{url}",
"--write-info-json",
"-x", "--audio-format", "mp3",
"-o", "downloaded_music.mp3",
@@ -101,6 +108,8 @@ class Downloader(arcade.gui.UIView):
path = os.path.expanduser(self.tab_selector.value)
info = self.run_yt_dlp(url)
if not info:
return # download will get re-executed.
os.remove("downloaded_music.mp3.info.json")
os.remove("downloaded_music.info.json")
@@ -155,33 +164,41 @@ class Downloader(arcade.gui.UIView):
self.yt_dl_buffer = f"Successfully downloaded {title} to {path}"
def ensure_yt_dlp(self):
def get_yt_dlp_path(self):
system = platform.system()
if system == "Windows":
path = os.path.join("bin", "yt-dlp.exe")
return os.path.join("bin", "yt-dlp.exe")
elif system == "Darwin":
path = os.path.join("bin", "yt-dlp_macos")
return os.path.join("bin", "yt-dlp_macos")
elif system == "Linux":
path = os.path.join("bin", "yt-dlp_linux")
return os.path.join("bin", "yt-dlp_linux")
def check_for_yt_dlp(self):
path = self.get_yt_dlp_path()
if not os.path.exists("bin"):
os.makedirs("bin")
if not os.path.exists(path):
if system == "Windows":
url = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe"
elif system == "Darwin":
url = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos"
elif system == "Linux":
url = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux"
else:
raise RuntimeError("Unsupported OS")
return os.path.exists(path)
urllib.request.urlretrieve(url, path)
os.chmod(path, 0o755)
def install_and_run_yt_dlp(self):
system = platform.system()
path = self.get_yt_dlp_path()
return path
if system == "Windows":
url = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe"
elif system == "Darwin":
url = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos"
elif system == "Linux":
url = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux"
else:
raise RuntimeError("Unsupported OS")
urllib.request.urlretrieve(url, path)
os.chmod(path, 0o755)
threading.Thread(target=self.download, daemon=True).start()
def main_exit(self):
from menus.main import Main

View File

@@ -1,6 +1,6 @@
import arcade, arcade.gui
import os, sys, subprocess, platform, urllib.request, zipfile, logging
import os, sys, subprocess, platform, logging
class FFmpegMissing(arcade.gui.UIView):
def __init__(self):
@@ -15,11 +15,11 @@ class FFmpegMissing(arcade.gui.UIView):
height=self.window.height / 2,
title="FFmpeg Missing",
message_text="FFmpeg has not been found but is required for this application.",
buttons=("Exit", "Auto Install")
buttons=("Exit", "Install")
)
)
msgbox.on_action = lambda event: self.install_ffmpeg() if event.action == "Auto Install" else sys.exit()
msgbox.on_action = lambda event: self.install_ffmpeg() if event.action == "Install" else sys.exit()
def install_ffmpeg(self):
bin_dir = os.path.join(os.getcwd(), "bin")
@@ -28,22 +28,9 @@ class FFmpegMissing(arcade.gui.UIView):
system = platform.system()
if system == "Linux" or system == "Darwin":
url = "https://evermeet.cx/ffmpeg/ffmpeg-7.1.1.zip"
filename = "ffmpeg.zip"
logging.debug(f"Downloading FFmpeg from {url}...")
file_path = os.path.join(bin_dir, filename)
urllib.request.urlretrieve(url, file_path)
logging.debug("Extracting FFmpeg...")
with zipfile.ZipFile(file_path, 'r') as zip_ref:
zip_ref.extractall(bin_dir)
ffmpeg_path = os.path.join(bin_dir, "ffmpeg")
os.chmod(ffmpeg_path, 0o755)
os.remove(file_path)
logging.debug("FFmpeg installed in ./bin")
msgbox = self.add_widget(arcade.gui.UIMessageBox(message_text="You are on a Linux or Darwin based OS. You need to install FFmpeg, and libavcodec shared libraries from your package manager so it is in PATH.", width=self.window.width / 2, height=self.window.height / 2))
msgbox.on_action = lambda: sys.exit()
return
elif system == "Windows":
try:
@@ -52,11 +39,12 @@ class FFmpegMissing(arcade.gui.UIView):
"--accept-source-agreements", "--accept-package-agreements"
], check=True)
logging.debug("FFmpeg installed via winget.")
msgbox = self.add_widget(arcade.gui.UIMessageBox(message_text="You are on a Linux or Darwin based OS. You need to install FFmpeg, and libavcodec shared libraries from your package manager so it is in PATH.", width=self.window.width / 2, height=self.window.height / 2))
msgbox.on_action = lambda: sys.exit()
return
except subprocess.CalledProcessError as e:
logging.debug("Failed to install FFmpeg via winget:", e)
else:
logging.error(f"Unsupported OS: {system}")
from menus.main import Main
self.window.show_view(Main())
self.add_widget(arcade.gui.UIMessageBox(message_text="Your OS is unsupported by this script. You are probably on some kind of BSD system. Please install FFmpeg and libavcodec shared libraries from your package manager so it is in PATH.", width=self.window.width / 2, height=self.window.height / 2))

View File

@@ -3,7 +3,7 @@ import arcade, arcade.gui
from utils.preload import music_icon, person_icon, button_texture, button_hovered_texture
from utils.constants import button_style
from utils.utils import Card, MouseAwareScrollArea, get_wordwrapped_text
from utils.online_metadata import search_recordings, search_artists, search_albums, get_artists_metadata, get_album_metadata
from utils.musicbrainz_metadata import search_recordings, search_artists, search_albums, get_artists_metadata, get_album_metadata
from arcade.gui.experimental.focus import UIFocusGroup
from arcade.gui.experimental.scroll_area import UIScrollBar

View File

@@ -6,6 +6,7 @@ from utils.constants import button_style, slider_style, audio_extensions, discor
from utils.utils import FakePyPresence, UIFocusTextureButton, Card, MouseAwareScrollArea, get_wordwrapped_text
from utils.music_handling import update_last_play_statistics, extract_metadata_and_thumbnail, adjust_volume, truncate_end
from utils.file_watching import watch_directories, watch_files
from utils.lyrics_metadata import get_lyrics, get_closest_time, parse_synchronized_lyrics
from thefuzz import process, fuzz
@@ -15,7 +16,7 @@ from arcade.gui.experimental.focus import UIFocusGroup
class Main(arcade.gui.UIView):
def __init__(self, pypresence_client: None | FakePyPresence | pypresence.Presence=None, current_tab: str | None=None, current_mode: str | None=None, current_music_artist: str | None=None,
current_music_title: str | None=None, current_music_path: str | None=None, current_length: int | None=None,
current_music_player: pyglet.media.Player | None=None, queue: list | None=None, loaded_sounds: dict | None=None, shuffle: bool=False):
current_music_player: pyglet.media.Player | None=None, current_synchronized_lyrics: str | None=None, queue: list | None=None, loaded_sounds: dict | None=None, shuffle: bool=False):
super().__init__()
self.pypresence_client = pypresence_client
@@ -61,16 +62,19 @@ class Main(arcade.gui.UIView):
self.file_metadata = {}
self.tab_buttons = {}
self.music_buttons = {}
self.queue = []
self.queue = queue or []
self.current_music_artist = current_music_artist
self.current_music_title = current_music_title
self.current_music_player = current_music_player
self.current_music_path = current_music_path
self.current_length = current_length if current_length else 0
self.current_synchronized_lyrics = current_synchronized_lyrics if current_synchronized_lyrics else None
self.shuffle = shuffle
self.volume = self.settings_dict.get("default_volume", 100)
self.lyrics_times, self.parsed_lyrics = parse_synchronized_lyrics(self.current_synchronized_lyrics) if self.current_synchronized_lyrics else (None, None)
self.current_mode = current_mode if current_mode else "files"
self.current_tab = current_tab if current_tab else self.tab_options[0]
self.search_term = ""
@@ -112,10 +116,10 @@ class Main(arcade.gui.UIView):
if self.current_mode == "playlist" and not self.current_tab:
self.current_tab = list(self.playlist_content.keys())[0] if self.playlist_content else None
# Scrollable Sounds
# Scrollable Sounds and Lyrics
self.scroll_box = self.content_box.add(arcade.gui.UIBoxLayout(size_hint=(1, 0.90), space_between=15, vertical=False))
self.scroll_area = MouseAwareScrollArea(size_hint=(1, 1)) # center on screen
self.scroll_area = MouseAwareScrollArea(size_hint=(0.8, 1)) # center on screen
self.scroll_area.scroll_speed = -50
self.scroll_box.add(self.scroll_area)
@@ -123,9 +127,17 @@ class Main(arcade.gui.UIView):
self.scrollbar.size_hint = (0.02, 1)
self.scroll_box.add(self.scrollbar)
self.music_grid = arcade.gui.UIGridLayout(horizontal_spacing=10, vertical_spacing=10, row_count=99, column_count=8)
self.music_grid = arcade.gui.UIGridLayout(horizontal_spacing=10, vertical_spacing=10, row_count=99, column_count=6)
self.scroll_area.add(self.music_grid)
self.lyrics_box = self.scroll_box.add(arcade.gui.UIBoxLayout(space_between=5, size_hint=(0.25, 1), align="left"))
self.current_lyrics_label = arcade.gui.UILabel(size_hint=(0.2, 0.05), width=self.window.width * 0.2, multiline=True, font_size=16, font_name="Roboto", text_color=arcade.color.WHITE, text=self.current_synchronized_lyrics if self.current_synchronized_lyrics else "Play a song to get lyrics.")
self.lyrics_box.add(self.current_lyrics_label)
self.next_lyrics_label = arcade.gui.UILabel(size_hint=(0.2, 0.95), width=self.window.width * 0.2, multiline=True, font_size=16, font_name="Roboto", text_color=arcade.color.GRAY, text=self.current_synchronized_lyrics if self.current_synchronized_lyrics else "Play a song to get lyrics.")
self.lyrics_box.add(self.next_lyrics_label)
# Controls
self.now_playing_box = self.content_box.add(arcade.gui.UIBoxLayout(size_hint=(0.99, 0.075), space_between=10, vertical=False))
@@ -270,6 +282,9 @@ class Main(arcade.gui.UIView):
self.current_music_player = None
self.current_music_path = None
self.progressbar.value = 0
self.current_synchronized_lyrics = None
self.lyrics_times = None
self.parsed_lyrics = None
self.current_music_thumbnail_image.texture = music_icon
self.current_music_title_label.text = "No songs playing"
self.full_length_label.text = "00:00"
@@ -294,7 +309,7 @@ class Main(arcade.gui.UIView):
def view_metadata(self, file_path):
from menus.metadata_viewer import MetadataViewer
self.window.show_view(MetadataViewer(self.pypresence_client, "file", self.file_metadata[file_path], file_path, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.queue, self.loaded_sounds, self.shuffle))
self.window.show_view(MetadataViewer(self.pypresence_client, "file", self.file_metadata[file_path], file_path, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.current_synchronized_lyrics, self.queue, self.loaded_sounds, self.shuffle))
def show_content(self, tab, content_type):
for music_button in self.music_buttons.values():
@@ -328,8 +343,8 @@ class Main(arcade.gui.UIView):
row, col = 0, 0
for n, music_filename in enumerate(content_to_show):
row = n // 8
col = n % 8
row = n // self.music_grid.column_count
col = n % self.music_grid.column_count
if self.current_mode == "files":
music_path = f"{tab}/{music_filename}"
@@ -338,17 +353,17 @@ class Main(arcade.gui.UIView):
metadata = self.file_metadata[music_path]
self.music_buttons[music_path] = self.music_grid.add(Card(metadata["thumbnail"], get_wordwrapped_text(metadata["title"]), get_wordwrapped_text(metadata["artist"]), width=self.window.width / 9, height=self.window.width / 9), row=row, column=col)
self.music_buttons[music_path] = self.music_grid.add(Card(metadata["thumbnail"], get_wordwrapped_text(metadata["title"]), get_wordwrapped_text(metadata["artist"]), width=self.window.width / (self.music_grid.column_count + 1), height=self.window.width / (self.music_grid.column_count + 1)), row=row, column=col)
self.music_buttons[music_path].button.on_click = lambda event, music_path=music_path: self.music_button_click(event, music_path)
row = (n + 1) // 8
col = (n + 1) % 8
row = (n + 1) // self.music_grid.column_count
col = (n + 1) % self.music_grid.column_count
self.music_grid.row_count = row + 1
self.music_grid._update_size_hints()
if self.current_mode == "playlist":
self.music_buttons["add_music"] = self.music_grid.add(Card(music_icon, "Add Music", None, width=self.window.width / 9, height=self.window.width / 9), row=row, column=col)
self.music_buttons["add_music"] = self.music_grid.add(Card(music_icon, "Add Music", None, width=self.window.width / (self.music_grid.column_count + 1), height=self.window.width / (self.music_grid.column_count + 1)), row=row, column=col)
self.music_buttons["add_music"].button.on_click = lambda event: self.add_music()
self.anchor.detect_focusable_widgets()
@@ -365,7 +380,7 @@ class Main(arcade.gui.UIView):
with open("settings.json", "w") as file:
file.write(json.dumps(self.settings_dict, indent=4))
self.window.show_view(Main(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.queue, self.loaded_sounds, self.shuffle))
self.window.show_view(Main(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.current_synchronized_lyrics, self.queue, self.loaded_sounds, self.shuffle))
def load_content(self):
self.tab_content.clear()
@@ -436,6 +451,17 @@ class Main(arcade.gui.UIView):
self.current_music_player.volume = self.volume / 100
def on_update(self, delta_time):
if self.current_synchronized_lyrics:
closest_lyrics_time = get_closest_time(self.current_music_player.time, self.lyrics_times)
self.current_lyrics_label.text = self.parsed_lyrics.get(closest_lyrics_time, '[Music]') or '[Music]'
self.current_lyrics_label.fit_content()
if closest_lyrics_time in self.lyrics_times:
next_lyrics_times = self.lyrics_times[self.lyrics_times.index(closest_lyrics_time) + 1:self.lyrics_times.index(closest_lyrics_time) + 11]
self.next_lyrics_label.text = '\n'.join([self.parsed_lyrics[next_lyrics_time] for next_lyrics_time in next_lyrics_times])
else:
self.next_lyrics_label.text = '\n'.join(list(self.parsed_lyrics.values())[0:10])
if self.should_reload:
self.should_reload = False
self.reload()
@@ -476,6 +502,8 @@ class Main(arcade.gui.UIView):
self.full_length_label.text = "00:00"
self.progressbar.max_value = self.current_length
self.progressbar.value = 0
self.current_synchronized_lyrics = get_lyrics(self.current_music_artist, self.current_music_title)[1]
self.lyrics_times, self.parsed_lyrics = parse_synchronized_lyrics(self.current_synchronized_lyrics) if self.current_synchronized_lyrics else (None, None)
else:
if self.current_music_player is not None:
@@ -541,31 +569,31 @@ class Main(arcade.gui.UIView):
from menus.global_search import GlobalSearch
arcade.unschedule(self.update_presence)
self.ui.clear()
self.window.show_view(GlobalSearch(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.queue, self.loaded_sounds, self.shuffle))
self.window.show_view(GlobalSearch(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.current_synchronized_lyrics, self.queue, self.loaded_sounds, self.shuffle))
def settings(self):
from menus.settings import Settings
arcade.unschedule(self.update_presence)
self.ui.clear()
self.window.show_view(Settings(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.queue, self.loaded_sounds, self.shuffle))
self.window.show_view(Settings(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.current_synchronized_lyrics, self.queue, self.loaded_sounds, self.shuffle))
def new_tab(self):
from menus.new_tab import NewTab
arcade.unschedule(self.update_presence)
self.ui.clear()
self.window.show_view(NewTab(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.queue, self.loaded_sounds, self.shuffle))
self.window.show_view(NewTab(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.current_synchronized_lyrics, self.queue, self.loaded_sounds, self.shuffle))
def add_music(self):
from menus.add_music import AddMusic
arcade.unschedule(self.update_presence)
self.ui.clear()
self.window.show_view(AddMusic(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.queue, self.loaded_sounds, self.shuffle))
self.window.show_view(AddMusic(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.current_synchronized_lyrics, self.queue, self.loaded_sounds, self.shuffle))
def downloader(self):
from menus.downloader import Downloader
arcade.unschedule(self.update_presence)
self.ui.clear()
self.window.show_view(Downloader(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.queue, self.loaded_sounds, self.shuffle))
self.window.show_view(Downloader(self.pypresence_client, self.current_tab, self.current_mode, self.current_music_artist, self.current_music_title, self.current_music_path, self.current_length, self.current_music_player, self.current_synchronized_lyrics, self.queue, self.loaded_sounds, self.shuffle))
def reload(self):
self.load_content()

View File

@@ -1,26 +1,54 @@
import arcade, arcade.gui, webbrowser
import arcade, arcade.gui, webbrowser, os
from arcade.gui.experimental.focus import UIFocusGroup
from arcade.gui.experimental.scroll_area import UIScrollArea, UIScrollBar
from utils.online_metadata import get_music_metadata, download_albums_cover_art
from utils.musicbrainz_metadata import get_music_metadata
from utils.cover_art import download_albums_cover_art
from utils.constants import button_style
from utils.preload import button_texture, button_hovered_texture
from utils.utils import convert_seconds_to_date
from utils.music_handling import convert_timestamp_to_time_ago, truncate_end
from utils.music_handling import convert_timestamp_to_time_ago, truncate_end, add_metadata_to_file
from utils.acoustid_metadata import get_recording_id_from_acoustic, get_fpcalc_path, download_fpcalc
class MetadataViewer(arcade.gui.UIView):
def __init__(self, pypresence_client, metadata_type="file", metadata=None, file_path=None, *args):
super().__init__()
self.metadata_type = metadata_type
self.pypresence_client = pypresence_client
self.args = args
self.more_metadata_buttons = []
self.metadata_labels = []
self.msgbox = None
if metadata_type == "file":
self.file_metadata = metadata
self.file_path = file_path
self.artist = self.file_metadata["artist"] if not self.file_metadata["artist"] == "Unknown" else None
self.title = self.file_metadata["title"]
if metadata.get("confirm_download") is None:
if not os.path.exists(get_fpcalc_path()):
self.msgbox = self.add_widget(arcade.gui.UIMessageBox(width=self.window.width / 2, height=self.window.height / 2, title="Third-party fpcalc download", message_text="We need to download fpcalc from AcoustID to recognize the song for you for better results.\nIf you say no, we will use a searching algorithm instead which might give wrong results.\nEven if fpcalc is downloaded, it might not find the music since its a community-based project.\nIf so, we will fallback to the searching algorithm.\nDo you want to continue?", buttons=("Yes", "No")))
self.msgbox.on_action = lambda event: self.window.show_view(MetadataViewer(pypresence_client, metadata_type, metadata | {"confirm_download": event.action == "Yes"}, file_path, *args))
return
else:
self.acoustid_id, musicbrainz_id = get_recording_id_from_acoustic(self.file_path)
else:
if metadata["confirm_download"]:
download_fpcalc()
self.acoustid_id, musicbrainz_id = get_recording_id_from_acoustic(self.file_path)
self.music_metadata, self.artist_metadata, self.album_metadata, self.lyrics_metadata = get_music_metadata(self.artist, self.title)
else:
self.acoustid_id = None
if self.acoustid_id and musicbrainz_id:
self.music_metadata, self.artist_metadata, self.album_metadata, self.lyrics_metadata = get_music_metadata(musicbrainz_id=musicbrainz_id)
return
self.music_metadata, self.artist_metadata, self.album_metadata, self.lyrics_metadata = get_music_metadata(artist=self.artist, title=self.title)
elif metadata_type == "music":
self.artist = metadata["artist"]
self.title = metadata["title"]
@@ -31,14 +59,15 @@ class MetadataViewer(arcade.gui.UIView):
elif metadata_type == "album":
self.album_metadata = metadata
self.pypresence_client = pypresence_client
self.args = args
self.more_metadata_buttons = []
self.metadata_labels = []
def on_show_view(self):
super().on_show_view()
if self.msgbox:
return
if self.metadata_type == "file":
add_metadata_to_file(self.file_path, [artist['musicbrainz_id'] for artist in self.artist_metadata.values()], self.artist, self.title, self.lyrics_metadata[1], self.music_metadata["isrc-list"], self.acoustid_id)
self.anchor = self.add_widget(UIFocusGroup(size_hint=(1, 1)))
self.back_button = self.anchor.add(arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='<--', style=button_style, width=100, height=50), anchor_x="left", anchor_y="top", align_x=5, align_y=-5)
@@ -98,7 +127,7 @@ Sample rate: {self.file_metadata['sample_rate']}KHz'''
else:
metadata_text = musicbrainz_metadata_text
metadata_text += f"\n\nLyrics:\n{self.lyrics_metadata}"
metadata_text += f"\n\nLyrics:\n{self.lyrics_metadata[0]}"
self.more_metadata_buttons.append(self.more_metadata_box.add(arcade.gui.UITextureButton(text="Artist Metadata", style=button_style, texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 4.5 if self.metadata_type == "file" else self.window.width / 2.5, height=self.window.height / 15)))
self.more_metadata_buttons[-1].on_click = lambda event: self.show_artist_metadata()