mirror of
https://github.com/csd4ni3l/music-player.git
synced 2026-01-01 04:03:42 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user