From 5cd82ccddf41eed30478ce6a4c0b361da6c8a981 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Fri, 15 Nov 2024 17:58:23 +0100 Subject: [PATCH 01/63] t_main: Put all imports to the top of the file, remove ctypes and SDL star imports --- t_modules/t_main.py | 477 +++++++++++++++++++++++++++----------------- 1 file changed, 299 insertions(+), 178 deletions(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index 6c3ed2183..b0cdcc235 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -24,22 +24,307 @@ # along with this program. If not, see . from __future__ import annotations -from collections.abc import Callable -import sys -import socket +import base64 +import colorsys +import copy +import ctypes +import ctypes.util +import datetime +import gc as gbc +import gettext +import glob +import hashlib +import io +import json +import locale as py_locale +import logging +import math +import os +import pickle +import platform +import random +import re +import secrets +import shlex +import shutil +import socket +import stat +import subprocess +import sys +import threading +import time +import traceback +import urllib.parse +import urllib.request +import warnings +import webbrowser +import xml.etree.ElementTree as ET +import zipfile +from collections import OrderedDict +from collections.abc import Callable +from ctypes import c_char_p, pointer, Structure from dataclasses import dataclass -from t_modules import t_bootstrap -from t_modules.t_phazor import player4, phazor_exists +from pathlib import Path from typing import TYPE_CHECKING +from xml.sax.saxutils import escape, unescape + +import musicbrainzngs +import mutagen +import mutagen.flac +import mutagen.id3 +import mutagen.mp4 +import mutagen.oggvorbis +import requests +from PIL import Image, ImageDraw, ImageEnhance, ImageFilter +from sdl2 import ( + SDL_BLENDMODE_NONE, + SDL_BLENDMODE_BLEND, + SDL_BUTTON_LEFT, + SDL_BUTTON_MIDDLE, + SDL_BUTTON_RIGHT, + SDL_BUTTON_X1, + SDL_BUTTON_X2, + SDL_CONTROLLER_AXIS_LEFTY, + SDL_CONTROLLER_AXIS_RIGHTX, + SDL_CONTROLLER_AXIS_RIGHTY, + SDL_CONTROLLER_AXIS_TRIGGERLEFT, + SDL_CONTROLLER_BUTTON_A, + SDL_CONTROLLER_BUTTON_B, + SDL_CONTROLLER_BUTTON_DPAD_DOWN, + SDL_CONTROLLER_BUTTON_DPAD_LEFT, + SDL_CONTROLLER_BUTTON_DPAD_RIGHT, + SDL_CONTROLLER_BUTTON_DPAD_UP, + SDL_CONTROLLER_BUTTON_LEFTSHOULDER, + SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, + SDL_CONTROLLER_BUTTON_X, + SDL_CONTROLLER_BUTTON_Y, + SDL_CONTROLLERAXISMOTION, + SDL_CONTROLLERBUTTONDOWN, + SDL_CONTROLLERDEVICEADDED, + SDL_DROPFILE, + SDL_DROPTEXT, + SDL_HITTEST_DRAGGABLE, + SDL_HITTEST_NORMAL, + SDL_INIT_EVERYTHING, + SDL_INIT_GAMECONTROLLER, + SDL_KEYDOWN, + SDL_KEYUP, + SDL_MOUSEBUTTONDOWN, + SDL_MOUSEBUTTONUP, + SDL_MOUSEMOTION, + SDL_MOUSEWHEEL, + SDL_PIXELFORMAT_ARGB8888, + SDL_QUIT, + SDL_RENDER_TARGETS_RESET, + SDL_SCANCODE_A, + SDL_SCANCODE_C, + SDL_SCANCODE_V, + SDL_SCANCODE_X, + SDL_SCANCODE_Z, + SDL_SYSTEM_CURSOR_ARROW, + SDL_SYSTEM_CURSOR_HAND, + SDL_SYSTEM_CURSOR_IBEAM, + SDL_SYSTEM_CURSOR_SIZEWE, + SDL_SYSWM_COCOA, + SDL_SYSWM_UNKNOWN, + SDL_SYSWM_WAYLAND, + SDL_TEXTEDITING, + SDL_TEXTINPUT, + SDL_TEXTUREACCESS_TARGET, + SDL_WINDOW_INPUT_FOCUS, + SDL_WINDOWEVENT, + SDL_WINDOWEVENT_DISPLAY_CHANGED, + SDL_WINDOWEVENT_ENTER, + SDL_WINDOWEVENT_EXPOSED, + SDL_WINDOWEVENT_FOCUS_GAINED, + SDL_WINDOWEVENT_FOCUS_LOST, + SDL_WINDOWEVENT_LEAVE, + SDL_WINDOWEVENT_MAXIMIZED, + SDL_WINDOWEVENT_MINIMIZED, + SDL_WINDOWEVENT_RESIZED, + SDL_WINDOWEVENT_RESTORED, + SDL_WINDOWEVENT_SHOWN, + SDLK_BACKSPACE, + SDLK_DELETE, + SDLK_DOWN, + SDLK_END, + SDLK_HOME, + SDLK_KP_ENTER, + SDLK_LALT, + SDLK_LCTRL, + SDLK_LEFT, + SDLK_LGUI, + SDLK_LSHIFT, + SDLK_RALT, + SDLK_RCTRL, + SDLK_RETURN, + SDLK_RETURN2, + SDLK_RIGHT, + SDLK_RSHIFT, + SDLK_TAB, + SDLK_UP, + SDL_CreateRGBSurfaceWithFormatFrom, + SDL_CreateSystemCursor, + SDL_CreateTexture, + SDL_CreateTextureFromSurface, + SDL_Delay, + SDL_DestroyWindow, + SDL_Event, + SDL_FreeSurface, + SDL_GetClipboardText, + SDL_GetGlobalMouseState, + SDL_GetKeyFromName, + SDL_GetMouseState, + SDL_GetScancodeFromName, + SDL_GetVersion, + SDL_GetWindowFlags, + SDL_GetWindowPosition, + SDL_GetWindowWMInfo, + SDL_HasClipboardText, + SDL_HitTest, + SDL_InitSubSystem, + SDL_MinimizeWindow, + SDL_PollEvent, + SDL_PumpEvents, + SDL_PushEvent, + SDL_QueryTexture, + SDL_Quit, + SDL_QuitSubSystem, + SDL_RenderFillRect, + SDL_RestoreWindow, + SDL_SetClipboardText, + SDL_SetCursor, + SDL_SetRenderDrawBlendMode, + SDL_SetRenderTarget, + SDL_SetTextureAlphaMod, + SDL_SetTextureBlendMode, + SDL_SetTextureColorMod, + SDL_SetWindowAlwaysOnTop, + SDL_SetWindowBordered, + SDL_SetWindowFullscreen, + SDL_SetWindowHitTest, + SDL_SetWindowIcon, + SDL_SetWindowMinimumSize, + SDL_SetWindowPosition, + SDL_SetWindowResizable, + SDL_SetWindowSize, + SDL_StartTextInput, + SDL_SysWMinfo, + SDL_version, + SDL_WaitEventTimeout, + SDLK_a, + SDLK_c, + SDLK_v, + SDLK_x, + SDLK_z, + rw_from_object, +) + +from sdl2.sdlimage import IMG_Load_RW, IMG_Quit +from send2trash import send2trash +from unidecode import unidecode + +from t_modules import t_bootstrap +from t_modules.t_config import Config +from t_modules.t_extra import * +from t_modules.t_draw import TDraw, QuickThumbnail +from t_modules.t_jellyfin import Jellyfin +from t_modules.t_launch import * +from t_modules.t_lyrics import * +from t_modules.t_phazor import phazor_exists, player4 +from t_modules.t_search import * +from t_modules.t_spot import SpotCtl +from t_modules.t_stream import * +from t_modules.t_tagscan import Ape, Flac, M4a, Opus, Wav, parse_picture_block +from t_modules.t_themeload import * +from t_modules.t_tidal import Tidal +from t_modules.t_webserve import authserve, controller, stream_proxy, webserve, webserve2 + if TYPE_CHECKING: from t_modules.t_phazor import Cachement, LibreSpot -import os -import pickle -import shutil +try: + from jxlpy import JXLImagePlugin + print("Found jxlpy for JPEG XL support") +except Exception: + pass + +try: + import setproctitle + setproctitle.setproctitle("tauonmb") +except Exception: + print("Could not set process title.") + +# try: +# import rpc +# discord_allow = True +# except Exception: +# pass +try: + from pypresence import Presence + import asyncio + discord_allow = True +except Exception: + discord_allow = False +try: + import pylast + last_fm_enable = True + if pyinstaller_mode: + pylast.SSL_CONTEXT.load_verify_locations(os.path.join(install_directory, "certifi", "cacert.pem")) +except Exception: + last_fm_enable = False + print("PyLast moduel not found, last fm will be disabled.") + +use_cc = False +try: + import opencc + s2t = opencc.OpenCC("s2t") + t2s = opencc.OpenCC("t2s") + use_cc = True +except Exception: + print("OpenCC not found.") + +use_natsort = False +try: + import natsort + + use_natsort = True +except Exception: + print("Warning: Python module natsort not found") + +# Detect platform +windows_native = False +macos = False +msys = False +system = None +if sys.platform == "win32": + # system = 'windows' + # windows_native = False + system = "linux" + msys = True +else: + system = "linux" + import fcntl + +if sys.platform == "darwin": + macos = True + +if system == "windows": + import win32con + import win32api + import win32gui + import win32ui + import comtypes + import atexit + +if system == "linux": + from t_modules import t_topchart + +if system == "linux" and not macos and not msys: + from t_modules.t_dbus import Gnome h = t_bootstrap.holder t_window = h.w @@ -69,22 +354,6 @@ should_save_state = True -# Detect platform -windows_native = False -macos = False -msys = False -if sys.platform == "win32": - # system = 'windows' - # windows_native = False - system = "linux" - msys = True -else: - system = "linux" - import fcntl - -if sys.platform == "darwin": - macos = True - if not windows_native: import gi from gi.repository import GLib @@ -110,8 +379,6 @@ left_window_control = False xdpi = 0 -from t_modules.t_extra import * - detect_macstyle = False gtk_settings = None mac_close = (253, 70, 70, 255) @@ -320,15 +587,14 @@ old_backend = 2 # Things for detecting and launching programs outside of flatpak sandbox -def whicher(target): +def whicher(target) -> bool | str: try: if flatpak_mode: complete = subprocess.run(shlex.split("flatpak-spawn --host which " + target), stdout=subprocess.PIPE, stderr=subprocess.PIPE) r = complete.stdout.decode() return "bin/" + target in r - else: - return shutil.which(target) + return shutil.which(target) except Exception: return False @@ -339,10 +605,6 @@ def whicher(target): pid = os.getpid() -from sdl2 import * -from sdl2.sdlimage import * -from ctypes import pointer - if not macos: icon = IMG_Load(os.path.join(asset_directory, "icon-64.png").encode()) else: @@ -495,7 +757,6 @@ def asset_loader(name, mod=False): if maximized: i_x = pointer(c_int(0)) i_y = pointer(c_int(0)) - import time time.sleep(0.02) SDL_PumpEvents() @@ -519,98 +780,9 @@ def asset_loader(name, mod=False): last_fm_enable = False -try: - import setproctitle - - setproctitle.setproctitle("tauonmb") -except Exception: - print("Could not set process title.") - -# try: -# import rpc -# discord_allow = True -# except Exception: -# pass -try: - from pypresence import Presence - import asyncio - - discord_allow = True -except Exception: - discord_allow = False - if snap_mode: discord_allow = False -if system == "windows": - import win32con, win32api, win32gui, win32ui, comtypes - import atexit - -try: - import pylast - last_fm_enable = True - if pyinstaller_mode: - pylast.SSL_CONTEXT.load_verify_locations(os.path.join(install_directory, "certifi", "cacert.pem")) -except Exception: - last_fm_enable = False - print("PyLast moduel not found, last fm will be disabled.") - -use_cc = False -try: - import opencc - s2t = opencc.OpenCC('s2t') - t2s = opencc.OpenCC('t2s') - use_cc = True -except Exception: - print("OpenCC not found.") - -use_natsort = False -try: - import natsort - - use_natsort = True -except Exception: - print("Warning: Python module natsort not found") - -import platform as py_platform -import time -import ctypes -import ctypes.util -import random -import threading -import logging -import io -import copy -import subprocess -import urllib.parse -import urllib.request -import datetime -import shlex -import math -import locale as py_locale -import webbrowser -import base64 -import re -import zipfile -import warnings -import colorsys -import requests -import stat -import hashlib -import platform -import gettext -import secrets -import json -import glob -import xml.etree.ElementTree as ET -import musicbrainzngs -import traceback -from pathlib import Path -from xml.sax.saxutils import escape, unescape -from ctypes import * -from send2trash import send2trash -from unidecode import unidecode -from collections import OrderedDict musicbrainzngs.set_useragent("TauonMusicBox", n_version, "https://github.com/Taiko2k/Tauon") @@ -638,31 +810,16 @@ def _(message): # ------------------------------------------------ -if system == 'windows': +if system == "windows": os.environ["PYSDL2_DLL_PATH"] = install_directory + "\\lib" elif not msys and not macos: try: - gi.require_version('Notify', '0.7') + gi.require_version("Notify", "0.7") except Exception: - gi.require_version('Notify', '0.8') + gi.require_version("Notify", "0.8") from gi.repository import Notify -# Other imports -from PIL import Image, ImageDraw, ImageFilter, ImageEnhance - -try: - from jxlpy import JXLImagePlugin - - print("Found jxlpy for JPEG XL support") -except Exception: - pass - -import mutagen -import mutagen.id3 -import mutagen.flac -import mutagen.mp4 -import mutagen.oggvorbis def no_padding(info): @@ -674,25 +831,6 @@ def no_padding(info): wayland = False os.environ['GDK_BACKEND'] = "x11" -from t_modules.t_tagscan import Flac -from t_modules.t_tagscan import Opus -from t_modules.t_tagscan import Ape -from t_modules.t_tagscan import Wav -from t_modules.t_tagscan import M4a -from t_modules.t_tagscan import parse_picture_block - -from t_modules.t_stream import * -from t_modules.t_lyrics import * -from t_modules.t_themeload import * -from t_modules.t_spot import SpotCtl -from t_modules.t_tidal import Tidal -from t_modules.t_search import * - -if system == 'linux': - from t_modules import t_topchart - -if system == "linux" and not macos and not msys: - from t_modules.t_dbus import Gnome # Setting various timers @@ -2749,8 +2887,6 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" # ----------------------------------------------------- # STATE LOADING # Loading of program data from previous run -import gc as gbc - gbc.disable() ggc = 2 @@ -3766,8 +3902,6 @@ def get_theme_name(number): if music_directory is not None and os.path.isdir(music_directory): download_directories.append(music_directory) -from t_modules.t_config import Config - cf = Config() @@ -8247,9 +8381,6 @@ def scrob_full_track(self, track_object): lfm_scrobbler = LastScrob() -from t_modules.t_draw import TDraw -from t_modules.t_draw import QuickThumbnail - QuickThumbnail.renderer = renderer @@ -8312,12 +8443,6 @@ def __init__(self): self.clients = {} -from t_modules.t_webserve import webserve2 -from t_modules.t_webserve import webserve -from t_modules.t_webserve import authserve -from t_modules.t_webserve import controller -from t_modules.t_webserve import stream_proxy - class MenuIcon: def __init__(self, asset): @@ -8778,8 +8903,6 @@ def get_albums(self, return_list=False): plex = PlexService() tauon.plex = plex -from t_modules.t_jellyfin import Jellyfin - jellyfin = Jellyfin(tauon) tauon.jellyfin = jellyfin @@ -10328,8 +10451,6 @@ def coll(r): ddt.scale = gui.scale ddt.force_subpixel_text = prefs.force_subpixel_text -from t_modules.t_launch import * - launch = Launch(tauon, pctl, gui, ddt) @@ -43972,7 +44093,7 @@ def drop_file(target): elif event.window.event == SDL_WINDOWEVENT_RESIZED or event.window.event == SDL_WINDOWEVENT_DISPLAY_CHANGED: if event.window.data1 < 500: - print("Grrr why this happen, stupid bug") + print("Grrr why this happen, stupid bug - reproducible when moving window from one screen to another in Plasma") SDL_SetWindowSize(t_window, logical_size[0], logical_size[1]) elif restore_ignore_timer.get() > 1 or event.window.event == SDL_WINDOWEVENT_DISPLAY_CHANGED: # Hacky gui.update = 2 From 1600a59da095dd2889831fac0d76e3f02821018a Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Mon, 18 Nov 2024 16:15:44 +0100 Subject: [PATCH 02/63] t_main: Convert first 5Kloc from spaces to tabs --- t_modules/t_main.py | 6839 ++++++++++++++++++++++--------------------- 1 file changed, 3460 insertions(+), 3379 deletions(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index b0cdcc235..54abd4e39 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -355,20 +355,20 @@ should_save_state = True if not windows_native: - import gi - from gi.repository import GLib + import gi + from gi.repository import GLib - font_folder = os.path.join(install_directory, "fonts") - if os.path.isdir(font_folder): - import ctypes + font_folder = os.path.join(install_directory, "fonts") + if os.path.isdir(font_folder): + import ctypes - fc = ctypes.cdll.LoadLibrary("libfontconfig-1.dll") - fc.FcConfigReference.restype = ctypes.c_void_p - fc.FcConfigReference.argtypes = (ctypes.c_void_p,) - fc.FcConfigAppFontAddDir.argtypes = (ctypes.c_void_p, ctypes.c_char_p) - config = ctypes.c_void_p() - config.contents = fc.FcConfigGetCurrent() - fc.FcConfigAppFontAddDir(config.value, font_folder.encode()) + fc = ctypes.cdll.LoadLibrary("libfontconfig-1.dll") + fc.FcConfigReference.restype = ctypes.c_void_p + fc.FcConfigReference.argtypes = (ctypes.c_void_p,) + fc.FcConfigAppFontAddDir.argtypes = (ctypes.c_void_p, ctypes.c_char_p) + config = ctypes.c_void_p() + config.contents = fc.FcConfigGetCurrent() + fc.FcConfigAppFontAddDir(config.value, font_folder.encode()) # Detect what desktop environment we are in to enable specific features desktop = os.environ.get('XDG_CURRENT_DESKTOP') @@ -385,32 +385,32 @@ mac_maximize = (254, 176, 36, 255) mac_minimize = (42, 189, 49, 255) try: - gi.require_version("Gtk", "3.0") - from gi.repository import Gtk - - gtk_settings = Gtk.Settings().get_default() - xdpi = gtk_settings.get_property("gtk-xft-dpi") / 1024 - if "minimize" not in str(gtk_settings.get_property("gtk-decoration-layout")): - draw_min_button = False - if "maximize" not in str(gtk_settings.get_property("gtk-decoration-layout")): - draw_max_button = False - if "close" in str(gtk_settings.get_property("gtk-decoration-layout")).split(":")[0]: - left_window_control = True - gtk_theme = str(gtk_settings.get_property("gtk-theme-name")).lower() - #print(f"GTK theme is: {gtk_theme}") - for k, v in mac_styles.items(): - if k in gtk_theme: - detect_macstyle = True - if v is not None: - mac_close = v[0] - mac_maximize = v[1] - mac_minimize = v[2] + gi.require_version("Gtk", "3.0") + from gi.repository import Gtk + + gtk_settings = Gtk.Settings().get_default() + xdpi = gtk_settings.get_property("gtk-xft-dpi") / 1024 + if "minimize" not in str(gtk_settings.get_property("gtk-decoration-layout")): + draw_min_button = False + if "maximize" not in str(gtk_settings.get_property("gtk-decoration-layout")): + draw_max_button = False + if "close" in str(gtk_settings.get_property("gtk-decoration-layout")).split(":")[0]: + left_window_control = True + gtk_theme = str(gtk_settings.get_property("gtk-theme-name")).lower() + #print(f"GTK theme is: {gtk_theme}") + for k, v in mac_styles.items(): + if k in gtk_theme: + detect_macstyle = True + if v is not None: + mac_close = v[0] + mac_maximize = v[1] + mac_minimize = v[2] except Exception: print("Error accessing GTK settings") # if system == "windows" or msys: -# os.environ["PYSDL2_DLL_PATH"] = install_directory + "\\lib" +# os.environ["PYSDL2_DLL_PATH"] = install_directory + "\\lib" # Assume that it's a classic Linux install, use standard paths if install_directory.startswith("/usr/"): @@ -437,89 +437,90 @@ flatpak_mode = False snap_mode = False if install_directory.startswith("/opt/") \ - or install_directory.startswith("/usr/") \ - or install_directory.startswith("/app/") \ - or install_directory.startswith("/snap/"): - - install_mode = True - if install_directory[:6] == "/snap/": - snap_mode = True - if install_directory[:5] == "/app/": - # Flatpak mode - print("Detected running as Flatpak") - - # [old / no longer used] Symlink fontconfig from host system as workaround for poor font rendering - if os.path.exists(os.path.join(home_directory, ".var/app/com.github.taiko2k.tauonmb/config")): - - host_fcfg = os.path.join(home_directory, ".config/fontconfig/") - flatpak_fcfg = os.path.join(home_directory, ".var/app/com.github.taiko2k.tauonmb/config/fontconfig") - - if os.path.exists(host_fcfg): - - # if os.path.isdir(flatpak_fcfg) and not os.path.islink(flatpak_fcfg): - # shutil.rmtree(flatpak_fcfg) - if os.path.islink(flatpak_fcfg): - print("-- Symlink to fonconfig exists, removing") - os.unlink(flatpak_fcfg) - # else: - # print("-- Symlinking user fonconfig") - # #os.symlink(host_fcfg, flatpak_fcfg) + or install_directory.startswith("/usr/") \ + or install_directory.startswith("/app/") \ + or install_directory.startswith("/snap/"): + + install_mode = True + if install_directory[:6] == "/snap/": + snap_mode = True + if install_directory[:5] == "/app/": + # Flatpak mode + print("Detected running as Flatpak") + + # [old / no longer used] Symlink fontconfig from host system as workaround for poor font rendering + if os.path.exists(os.path.join(home_directory, ".var/app/com.github.taiko2k.tauonmb/config")): - flatpak_mode = True + host_fcfg = os.path.join(home_directory, ".config/fontconfig/") + flatpak_fcfg = os.path.join(home_directory, ".var/app/com.github.taiko2k.tauonmb/config/fontconfig") + + if os.path.exists(host_fcfg): + + # if os.path.isdir(flatpak_fcfg) and not os.path.islink(flatpak_fcfg): + # shutil.rmtree(flatpak_fcfg) + if os.path.islink(flatpak_fcfg): + print("-- Symlink to fonconfig exists, removing") + os.unlink(flatpak_fcfg) + # else: + # print("-- Symlinking user fonconfig") + # #os.symlink(host_fcfg, flatpak_fcfg) + + flatpak_mode = True # If we're installed, use home data locations if (install_mode and system == 'linux') or macos or msys: - cache_directory = os.path.join(GLib.get_user_cache_dir(), "TauonMusicBox") - user_directory = os.path.join(GLib.get_user_data_dir(), "TauonMusicBox") - config_directory = os.path.join(GLib.get_user_data_dir(), "TauonMusicBox") + cache_directory = os.path.join(GLib.get_user_cache_dir(), "TauonMusicBox") + user_directory = os.path.join(GLib.get_user_data_dir(), "TauonMusicBox") + config_directory = os.path.join(GLib.get_user_data_dir(), "TauonMusicBox") - if not os.path.isdir(user_directory): - os.makedirs(user_directory) + if not os.path.isdir(user_directory): + os.makedirs(user_directory) - if not os.path.isdir(config_directory): - os.makedirs(config_directory) + if not os.path.isdir(config_directory): + os.makedirs(config_directory) - if snap_mode: - print("Installed as Snap") - elif flatpak_mode: - print("Installed as Flatpak") - else: - print("Running from installed location") + if snap_mode: + print("Installed as Snap") + elif flatpak_mode: + print("Installed as Flatpak") + else: + print("Running from installed location") - print("User files location: " + user_directory) + print("User files location: " + user_directory) - if not os.path.isdir(os.path.join(user_directory, "encoder")): - os.makedirs(os.path.join(user_directory, "encoder")) + if not os.path.isdir(os.path.join(user_directory, "encoder")): + os.makedirs(os.path.join(user_directory, "encoder")) -# elif (system == 'windows' or msys) and ('Program Files' in install_directory or -# os.path.isfile(install_directory + '\\unins000.exe')): +# elif (system == 'windows' or msys) and ( +# 'Program Files' in install_directory or +# os.path.isfile(install_directory + '\\unins000.exe')): # -# user_directory = os.path.expanduser('~').replace("\\", '/') + "/Music/TauonMusicBox" -# config_directory = user_directory -# cache_directory = user_directory + "\\cache" -# print("User Directroy: ", end="") -# print(user_directory) -# install_mode = True -# if not os.path.isdir(user_directory): -# os.makedirs(user_directory) +# user_directory = os.path.expanduser('~').replace("\\", '/') + "/Music/TauonMusicBox" +# config_directory = user_directory +# cache_directory = user_directory + "\\cache" +# print("User Directroy: ", end="") +# print(user_directory) +# install_mode = True +# if not os.path.isdir(user_directory): +# os.makedirs(user_directory) else: - print("Running in portable mode") + print("Running in portable mode") - user_directory = os.path.join(install_directory, "user-data") - config_directory = user_directory + user_directory = os.path.join(install_directory, "user-data") + config_directory = user_directory - if not os.path.isdir(user_directory): - os.makedirs(user_directory) + if not os.path.isdir(user_directory): + os.makedirs(user_directory) if not os.path.isfile(os.path.join(user_directory, "state.p")): - if os.path.isdir(cache_directory): - print("Clearing old cache directory") - print(cache_directory) - shutil.rmtree(cache_directory) + if os.path.isdir(cache_directory): + print("Clearing old cache directory") + print(cache_directory) + shutil.rmtree(cache_directory) n_cache_dir = os.path.join(cache_directory, "network") e_cache_dir = os.path.join(cache_directory, "export") @@ -529,58 +530,58 @@ b_cache_dir = os.path.join(user_directory, "artist-backgrounds") if not os.path.isdir(n_cache_dir): - os.makedirs(n_cache_dir) + os.makedirs(n_cache_dir) if not os.path.isdir(e_cache_dir): - os.makedirs(e_cache_dir) + os.makedirs(e_cache_dir) if not os.path.isdir(g_cache_dir): - os.makedirs(g_cache_dir) + os.makedirs(g_cache_dir) if not os.path.isdir(a_cache_dir): - os.makedirs(a_cache_dir) + os.makedirs(a_cache_dir) if not os.path.isdir(b_cache_dir): - os.makedirs(b_cache_dir) + os.makedirs(b_cache_dir) if not os.path.isdir(r_cache_dir): - os.makedirs(r_cache_dir) + os.makedirs(r_cache_dir) if not os.path.isdir(os.path.join(user_directory, "artist-pictures")): - os.makedirs(os.path.join(user_directory, "artist-pictures")) + os.makedirs(os.path.join(user_directory, "artist-pictures")) if not os.path.isdir(os.path.join(user_directory, "theme")): - os.makedirs(os.path.join(user_directory, "theme")) + os.makedirs(os.path.join(user_directory, "theme")) if system == 'linux': - system_config_directory = GLib.get_user_config_dir() - xdg_dir_file = os.path.join(system_config_directory, 'user-dirs.dirs') - - if os.path.isfile(xdg_dir_file): - with open(xdg_dir_file) as f: - for line in f.readlines(): - if line.startswith("XDG_MUSIC_DIR="): - music_directory = os.path.expanduser( - os.path.expandvars(line.split("=")[1].strip().replace('"', ""))) - print(f"Found XDG-Music: {music_directory}") - if line.startswith("XDG_DOWNLOAD_DIR="): - target = os.path.expanduser(os.path.expandvars(line.split("=")[1].strip().replace('"', ""))) - if os.path.isdir(target): - download_directory = target - print(f"Found XDG-Downloads: {download_directory}") + system_config_directory = GLib.get_user_config_dir() + xdg_dir_file = os.path.join(system_config_directory, 'user-dirs.dirs') + + if os.path.isfile(xdg_dir_file): + with open(xdg_dir_file) as f: + for line in f.readlines(): + if line.startswith("XDG_MUSIC_DIR="): + music_directory = os.path.expanduser( + os.path.expandvars(line.split("=")[1].strip().replace('"', ""))) + print(f"Found XDG-Music: {music_directory}") + if line.startswith("XDG_DOWNLOAD_DIR="): + target = os.path.expanduser(os.path.expandvars(line.split("=")[1].strip().replace('"', ""))) + if os.path.isdir(target): + download_directory = target + print(f"Found XDG-Downloads: {download_directory}") if os.getenv('XDG_MUSIC_DIR'): - music_directory = os.getenv('XDG_MUSIC_DIR') - print("Override music to: " + music_directory) + music_directory = os.getenv('XDG_MUSIC_DIR') + print("Override music to: " + music_directory) if os.getenv('XDG_DOWNLOAD_DIR'): - download_directory = os.getenv('XDG_DOWNLOAD_DIR') - print("Override downloads to: " + download_directory) + download_directory = os.getenv('XDG_DOWNLOAD_DIR') + print("Override downloads to: " + download_directory) if music_directory: - music_directory = os.path.expandvars(music_directory) + music_directory = os.path.expandvars(music_directory) if download_directory: - download_directory = os.path.expandvars(download_directory) + download_directory = os.path.expandvars(download_directory) if not os.path.isdir(music_directory): - music_directory = None + music_directory = None print('Install directory: ' + install_directory) @@ -588,48 +589,51 @@ # Things for detecting and launching programs outside of flatpak sandbox def whicher(target) -> bool | str: - try: - if flatpak_mode: - complete = subprocess.run(shlex.split("flatpak-spawn --host which " + target), stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - r = complete.stdout.decode() - return "bin/" + target in r - return shutil.which(target) - except Exception: - return False + try: + if flatpak_mode: + complete = subprocess.run( + shlex.split("flatpak-spawn --host which " + target), stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + r = complete.stdout.decode() + return "bin/" + target in r + return shutil.which(target) + except Exception: + return False launch_prefix = "" if flatpak_mode: - launch_prefix = "flatpak-spawn --host " + launch_prefix = "flatpak-spawn --host " pid = os.getpid() if not macos: - icon = IMG_Load(os.path.join(asset_directory, "icon-64.png").encode()) + icon = IMG_Load(os.path.join(asset_directory, "icon-64.png").encode()) else: - icon = IMG_Load(os.path.join(asset_directory, "tau-mac.png").encode()) + icon = IMG_Load(os.path.join(asset_directory, "tau-mac.png").encode()) SDL_SetWindowIcon(t_window, icon) if not phone: - if window_size[0] != logical_size[0]: - SDL_SetWindowMinimumSize(t_window, 560, 330) - else: - SDL_SetWindowMinimumSize(t_window, round(560 * scale), round(330 * scale)) + if window_size[0] != logical_size[0]: + SDL_SetWindowMinimumSize(t_window, 560, 330) + else: + SDL_SetWindowMinimumSize(t_window, round(560 * scale), round(330 * scale)) max_window_tex = 1000 if window_size[0] > max_window_tex or window_size[1] > max_window_tex: - while window_size[0] > max_window_tex: - max_window_tex += 1000 - while window_size[1] > max_window_tex: - max_window_tex += 1000 + while window_size[0] > max_window_tex: + max_window_tex += 1000 + while window_size[1] > max_window_tex: + max_window_tex += 1000 -main_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, max_window_tex, - max_window_tex) -main_texture_overlay_temp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, - max_window_tex, max_window_tex) +main_texture = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, max_window_tex, + max_window_tex) +main_texture_overlay_temp = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, + max_window_tex, max_window_tex) overlay_texture_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 300, 300) SDL_SetTextureBlendMode(overlay_texture_texture, SDL_BLENDMODE_BLEND) @@ -638,8 +642,9 @@ def whicher(target) -> bool | str: SDL_RenderClear(renderer) SDL_SetRenderTarget(renderer, None) -tracklist_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, max_window_tex, - max_window_tex) +tracklist_texture = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, max_window_tex, + max_window_tex) tracklist_texture_rect = SDL_Rect(0, 0, max_window_tex, max_window_tex) SDL_SetTextureBlendMode(tracklist_texture, SDL_BLENDMODE_BLEND) @@ -665,123 +670,123 @@ def whicher(target) -> bool | str: class LoadImageAsset: - assets = [] + assets = [] - def __init__(self, path, is_full_path=False, reload=False, scale_name=""): - if not reload: - self.assets.append(self) + def __init__(self, path, is_full_path=False, reload=False, scale_name=""): + if not reload: + self.assets.append(self) - self.path = path - self.scale_name = scale_name + self.path = path + self.scale_name = scale_name - raw_image = IMG_Load(self.path.encode()) - self.sdl_texture = SDL_CreateTextureFromSurface(renderer, raw_image) + raw_image = IMG_Load(self.path.encode()) + self.sdl_texture = SDL_CreateTextureFromSurface(renderer, raw_image) - p_w = pointer(c_int(0)) - p_h = pointer(c_int(0)) - SDL_QueryTexture(self.sdl_texture, None, None, p_w, p_h) + p_w = pointer(c_int(0)) + p_h = pointer(c_int(0)) + SDL_QueryTexture(self.sdl_texture, None, None, p_w, p_h) - if is_full_path: - SDL_SetTextureAlphaMod(self.sdl_texture, prefs.custom_bg_opacity) + if is_full_path: + SDL_SetTextureAlphaMod(self.sdl_texture, prefs.custom_bg_opacity) - self.rect = SDL_Rect(0, 0, p_w.contents.value, p_h.contents.value) - SDL_FreeSurface(raw_image) - self.w = p_w.contents.value - self.h = p_h.contents.value + self.rect = SDL_Rect(0, 0, p_w.contents.value, p_h.contents.value) + SDL_FreeSurface(raw_image) + self.w = p_w.contents.value + self.h = p_h.contents.value - def reload(self): - SDL_DestroyTexture(self.sdl_texture) - if self.scale_name: - self.path = os.path.join(scaled_asset_directory, self.scale_name) - self.__init__(self.path, reload=True, scale_name=self.scale_name) + def reload(self): + SDL_DestroyTexture(self.sdl_texture) + if self.scale_name: + self.path = os.path.join(scaled_asset_directory, self.scale_name) + self.__init__(self.path, reload=True, scale_name=self.scale_name) - def render(self, x, y, colour=None): - self.rect.x = round(x) - self.rect.y = round(y) - SDL_RenderCopy(renderer, self.sdl_texture, None, self.rect) + def render(self, x, y, colour=None): + self.rect.x = round(x) + self.rect.y = round(y) + SDL_RenderCopy(renderer, self.sdl_texture, None, self.rect) class WhiteModImageAsset: - assets = [] - - def __init__(self, path, reload=False, scale_name=""): - if not reload: - self.assets.append(self) - self.path = path - self.scale_name = scale_name - raw_image = IMG_Load(path.encode()) - self.sdl_texture = SDL_CreateTextureFromSurface(renderer, raw_image) - self.colour = [255, 255, 255, 255] - p_w = pointer(c_int(0)) - p_h = pointer(c_int(0)) - SDL_QueryTexture(self.sdl_texture, None, None, p_w, p_h) - self.rect = SDL_Rect(0, 0, p_w.contents.value, p_h.contents.value) - SDL_FreeSurface(raw_image) - self.w = p_w.contents.value - self.h = p_h.contents.value - - def reload(self): - SDL_DestroyTexture(self.sdl_texture) - if self.scale_name: - self.path = os.path.join(scaled_asset_directory, self.scale_name) - self.__init__(self.path, reload=True, scale_name=self.scale_name) - - def render(self, x, y, colour): - if colour != self.colour: - SDL_SetTextureColorMod(self.sdl_texture, colour[0], colour[1], colour[2]) - SDL_SetTextureAlphaMod(self.sdl_texture, colour[3]) - self.colour = colour - self.rect.x = round(x) - self.rect.y = round(y) - SDL_RenderCopy(renderer, self.sdl_texture, None, self.rect) + assets = [] + + def __init__(self, path, reload=False, scale_name=""): + if not reload: + self.assets.append(self) + self.path = path + self.scale_name = scale_name + raw_image = IMG_Load(path.encode()) + self.sdl_texture = SDL_CreateTextureFromSurface(renderer, raw_image) + self.colour = [255, 255, 255, 255] + p_w = pointer(c_int(0)) + p_h = pointer(c_int(0)) + SDL_QueryTexture(self.sdl_texture, None, None, p_w, p_h) + self.rect = SDL_Rect(0, 0, p_w.contents.value, p_h.contents.value) + SDL_FreeSurface(raw_image) + self.w = p_w.contents.value + self.h = p_h.contents.value + + def reload(self): + SDL_DestroyTexture(self.sdl_texture) + if self.scale_name: + self.path = os.path.join(scaled_asset_directory, self.scale_name) + self.__init__(self.path, reload=True, scale_name=self.scale_name) + + def render(self, x, y, colour): + if colour != self.colour: + SDL_SetTextureColorMod(self.sdl_texture, colour[0], colour[1], colour[2]) + SDL_SetTextureAlphaMod(self.sdl_texture, colour[3]) + self.colour = colour + self.rect.x = round(x) + self.rect.y = round(y) + SDL_RenderCopy(renderer, self.sdl_texture, None, self.rect) loaded_asset_dc = {} def asset_loader(name, mod=False): - if name in loaded_asset_dc: - return loaded_asset_dc[name] + if name in loaded_asset_dc: + return loaded_asset_dc[name] - target = os.path.join(scaled_asset_directory, name) - if mod: - item = WhiteModImageAsset(target, scale_name=name) - else: - item = LoadImageAsset(target, scale_name=name) - loaded_asset_dc[name] = item - return item + target = os.path.join(scaled_asset_directory, name) + if mod: + item = WhiteModImageAsset(target, scale_name=name) + else: + item = LoadImageAsset(target, scale_name=name) + loaded_asset_dc[name] = item + return item # loading_image = asset_loader('loading.png') if maximized: - i_x = pointer(c_int(0)) - i_y = pointer(c_int(0)) - - time.sleep(0.02) - SDL_PumpEvents() - SDL_GetWindowSize(t_window, i_x, i_y) - logical_size[0] = i_x.contents.value - logical_size[1] = i_y.contents.value - SDL_GL_GetDrawableSize(t_window, i_x, i_y) - window_size[0] = i_x.contents.value - window_size[1] = i_y.contents.value + i_x = pointer(c_int(0)) + i_y = pointer(c_int(0)) + + time.sleep(0.02) + SDL_PumpEvents() + SDL_GetWindowSize(t_window, i_x, i_y) + logical_size[0] = i_x.contents.value + logical_size[1] = i_y.contents.value + SDL_GL_GetDrawableSize(t_window, i_x, i_y) + window_size[0] = i_x.contents.value + window_size[1] = i_y.contents.value # loading_image.render(window_size[0] // 2 - loading_image.w // 2, window_size[1] // 2 - loading_image.h // 2) # SDL_RenderPresent(renderer) # if install_directory != config_directory and not os.path.isfile(os.path.join(config_directory, "config.txt")): -# print("Config file is missing... copying template from program files") -# shutil.copy(os.path.join(install_directory, "config.txt"), config_directory) +# print("Config file is missing... copying template from program files") +# shutil.copy(os.path.join(install_directory, "config.txt"), config_directory) if install_directory != config_directory and not os.path.isfile(os.path.join(config_directory, "input.txt")): - print("Input config file is missing... copying template from program files") - shutil.copy(os.path.join(install_directory, "input.txt"), config_directory) + print("Input config file is missing... copying template from program files") + shutil.copy(os.path.join(install_directory, "input.txt"), config_directory) last_fm_enable = False if snap_mode: - discord_allow = False + discord_allow = False musicbrainzngs.set_useragent("TauonMusicBox", n_version, "https://github.com/Taiko2k/Tauon") @@ -790,9 +795,9 @@ def asset_loader(name, mod=False): win_ver = platform.release() platform_system = platform.system() try: - win_ver = int(win_ver) + win_ver = int(win_ver) except Exception: - win_ver = 0 + win_ver = 0 # print(arch) @@ -800,36 +805,36 @@ def asset_loader(name, mod=False): # Detect locale for translations (currently none available) def _(message): - return message + return message try: - py_locale.setlocale(py_locale.LC_ALL, '') + py_locale.setlocale(py_locale.LC_ALL, '') except Exception: - print("SET LOCALE ERROR") + print("SET LOCALE ERROR") # ------------------------------------------------ if system == "windows": - os.environ["PYSDL2_DLL_PATH"] = install_directory + "\\lib" + os.environ["PYSDL2_DLL_PATH"] = install_directory + "\\lib" elif not msys and not macos: - try: - gi.require_version("Notify", "0.7") - except Exception: - gi.require_version("Notify", "0.8") - from gi.repository import Notify + try: + gi.require_version("Notify", "0.7") + except Exception: + gi.require_version("Notify", "0.8") + from gi.repository import Notify def no_padding(info): - # this will remove all padding - return 0 + # this will remove all padding + return 0 wayland = True if not os.environ.get('SDL_VIDEODRIVER') == "wayland": - wayland = False - os.environ['GDK_BACKEND'] = "x11" + wayland = False + os.environ['GDK_BACKEND'] = "x11" # Setting various timers @@ -882,26 +887,26 @@ def no_padding(info): # Variables now go in the gui, pctl, input and prefs class instances. The following just haven't been moved yet. class DConsole: - def __init__(self): - self.messages = [] - self.show = False + def __init__(self): + self.messages = [] + self.show = False - def print(self, message, level=0): + def print(self, message, level=0): - if len(self.messages) > 50: - del self.messages[0] + if len(self.messages) > 50: + del self.messages[0] - dtime = datetime.datetime.now() + dtime = datetime.datetime.now() - first = True - for line in message.split("\n"): - if first: - first = False - else: - level = -1 - self.messages.append((line, level, dtime, Timer())) + first = True + for line in message.split("\n"): + if first: + first = False + else: + level = -1 + self.messages.append((line, level, dtime, Timer())) - print(message) + print(message) console = DConsole() @@ -988,46 +993,48 @@ def print(self, message, level=0): # Player Variables---------------------------------------------------------------------------- format_colours = { # These are the colours used for the label icon in UI 'track info box' - "MP3": [255, 130, 80, 255], # Burnt orange - "FLAC": [156, 249, 79, 255], # Bright lime green - "M4A": [81, 220, 225, 255], # Soft cyan - "AIFF": [81, 220, 225, 255], # Soft cyan - "OGG": [244, 244, 78, 255], # Light yellow - "OGA": [244, 244, 78, 255], # Light yellow - "WMA": [213, 79, 247, 255], # Magenta - "APE": [247, 79, 79, 255], # Deep pink - "TTA": [94, 78, 244, 255], # Purple - "OPUS": [247, 79, 146, 255], # Pink - "AAC": [79, 247, 168, 255], # Teal - "WV": [229, 23, 18, 255], # Deep red - "PLEX": [229, 160, 13, 255], # Orange-brown - "KOEL": [111, 98, 190, 255], # Lavender - "TAU": [111, 98, 190, 255], # Lavender - "SUB": [235, 140, 20, 255], # Golden yellow - "SPTY": [30, 215, 96, 255], # Bright green - "TIDAL": [0, 0, 0, 255], # Black - "JELY": [190, 100, 210, 255], # Fuchsia - "XM": [50, 50, 50, 255], # Grey - "MOD": [50, 50, 50, 255], # Grey - "S3M": [50, 50, 50, 255], # Grey - "IT": [50, 50, 50, 255], # Grey - "MPTM": [50, 50, 50, 255], # Grey - "AY": [237, 212, 255, 255], # Pastel purple - "GBS": [255, 165, 0, 255], # Vibrant orange - "GYM": [0, 191, 255, 255], # Bright blue - "HES": [176, 224, 230, 255], # Light blue-green - "KSS": [255, 255, 153, 255], # Bright yellow - "NSF": [255, 140, 0, 255], # Deep orange - "NSFE": [255, 140, 0, 255], # Deep orange - "SAP": [152, 255, 152, 255], # Light green - "SPC": [255, 128, 0, 255], # Bright orange - "VGM": [0, 128, 255, 255], # Deep blue - "VGZ": [0, 128, 255, 255], # Deep blue + "MP3": [255, 130, 80, 255], # Burnt orange + "FLAC": [156, 249, 79, 255], # Bright lime green + "M4A": [81, 220, 225, 255], # Soft cyan + "AIFF": [81, 220, 225, 255], # Soft cyan + "OGG": [244, 244, 78, 255], # Light yellow + "OGA": [244, 244, 78, 255], # Light yellow + "WMA": [213, 79, 247, 255], # Magenta + "APE": [247, 79, 79, 255], # Deep pink + "TTA": [94, 78, 244, 255], # Purple + "OPUS": [247, 79, 146, 255], # Pink + "AAC": [79, 247, 168, 255], # Teal + "WV": [229, 23, 18, 255], # Deep red + "PLEX": [229, 160, 13, 255], # Orange-brown + "KOEL": [111, 98, 190, 255], # Lavender + "TAU": [111, 98, 190, 255], # Lavender + "SUB": [235, 140, 20, 255], # Golden yellow + "SPTY": [30, 215, 96, 255], # Bright green + "TIDAL": [0, 0, 0, 255], # Black + "JELY": [190, 100, 210, 255], # Fuchsia + "XM": [50, 50, 50, 255], # Grey + "MOD": [50, 50, 50, 255], # Grey + "S3M": [50, 50, 50, 255], # Grey + "IT": [50, 50, 50, 255], # Grey + "MPTM": [50, 50, 50, 255], # Grey + "AY": [237, 212, 255, 255], # Pastel purple + "GBS": [255, 165, 0, 255], # Vibrant orange + "GYM": [0, 191, 255, 255], # Bright blue + "HES": [176, 224, 230, 255], # Light blue-green + "KSS": [255, 255, 153, 255], # Bright yellow + "NSF": [255, 140, 0, 255], # Deep orange + "NSFE": [255, 140, 0, 255], # Deep orange + "SAP": [152, 255, 152, 255], # Light green + "SPC": [255, 128, 0, 255], # Bright orange + "VGM": [0, 128, 255, 255], # Deep blue + "VGZ": [0, 128, 255, 255], # Deep blue } # These will be the extensions of files to be added when importing -DA_Formats = {'mp3', 'wav', 'opus', 'flac', 'ape', 'aiff', - 'm4a', 'ogg', 'oga', 'aac', 'tta', 'wv', 'wma'} +DA_Formats = { + 'mp3', 'wav', 'opus', 'flac', 'ape', 'aiff', + 'm4a', 'ogg', 'oga', 'aac', 'tta', 'wv', 'wma' +} VID_Formats = {'mp4', "webm"} @@ -1041,10 +1048,10 @@ def print(self, message, level=0): Archive_Formats = {'zip'} if whicher('unrar'): - Archive_Formats.add("rar") + Archive_Formats.add("rar") if whicher('7z'): - Archive_Formats.add("7z") + Archive_Formats.add("7z") cargo = [] @@ -1132,10 +1139,10 @@ def pl_gen( def queue_item_gen(trackid, position, pl_id, type=0, album_stage=0): - # type; 0 is track, 1 is album - auto_stop = False + # type; 0 is track, 1 is album + auto_stop = False - return [trackid, position, pl_id, type, album_stage, uid_gen(), auto_stop] + return [trackid, position, pl_id, type, album_stage, uid_gen(), auto_stop] default_playlist = multi_playlist[0][2] @@ -1178,1064 +1185,1066 @@ def queue_item_gen(trackid, position, pl_id, type=0, album_stage=0): class Prefs: # Used to hold any kind of settings - def __init__(self): - self.colour_from_image = False - self.dim_art = False - self.prefer_side = True # Saves whether side panel is shown or not - self.pause_fade_time = 400 - self.change_volume_fade_time = 400 - self.cross_fade_time = 700 # 700 - self.volume_wheel_increment = 2 - self.encoder_output = user_directory + '/encoder/' - if music_directory is not None: - self.encoder_output = music_directory + '/encode-output/' - self.rename_folder_template = " - " - self.rename_tracks_template = ". - .<ext>" + def __init__(self): + self.colour_from_image = False + self.dim_art = False + self.prefer_side = True # Saves whether side panel is shown or not + self.pause_fade_time = 400 + self.change_volume_fade_time = 400 + self.cross_fade_time = 700 # 700 + self.volume_wheel_increment = 2 + self.encoder_output = user_directory + '/encoder/' + if music_directory is not None: + self.encoder_output = music_directory + '/encode-output/' + self.rename_folder_template = "<albumartist> - <album>" + self.rename_tracks_template = "<tn>. <artist> - <title>.<ext>" - self.enable_web = False - self.allow_remote = False - self.expose_web = True + self.enable_web = False + self.allow_remote = False + self.expose_web = True - self.enable_transcode = True - self.show_rym = False - self.show_band = False - self.show_wiki = False - self.show_transfer = True - self.show_queue = True - self.prefer_bottom_title = True - self.append_date = True + self.enable_transcode = True + self.show_rym = False + self.show_band = False + self.show_wiki = False + self.show_transfer = True + self.show_queue = True + self.prefer_bottom_title = True + self.append_date = True - self.transcode_codec = 'opus' - self.transcode_mode = 'single' - self.transcode_bitrate = 64 + self.transcode_codec = 'opus' + self.transcode_mode = 'single' + self.transcode_bitrate = 64 - # self.line_style = 1 - self.device = 1 - self.device_name = "" + # self.line_style = 1 + self.device = 1 + self.device_name = "" - self.cache_gallery = True - self.gallery_row_scroll = True - self.gallery_scroll_wheel_px = 90 + self.cache_gallery = True + self.gallery_row_scroll = True + self.gallery_scroll_wheel_px = 90 - self.playlist_font_size = 15 - self.playlist_row_height = 27 + self.playlist_font_size = 15 + self.playlist_row_height = 27 - self.tag_editor_name = "" - self.tag_editor_target = "" - self.tag_editor_path = "" + self.tag_editor_name = "" + self.tag_editor_target = "" + self.tag_editor_path = "" - self.use_title = False - self.auto_extract = False - self.auto_del_zip = False - self.pl_thumb = False + self.use_title = False + self.auto_extract = False + self.auto_del_zip = False + self.pl_thumb = False - self.use_custom_fonts = False - self.linux_font = "Noto Sans, Noto Sans CJK JP, Arial," - self.linux_font_semibold = "Noto Sans, Noto Sans CJK JP, Arial, Medium" - self.linux_font_bold = "Noto Sans, Noto Sans CJK JP, Bold" - self.linux_font_condensed = "Noto Sans, Extra-Condensed" - self.linux_font_condensed_bold = "Noto Sans, Extra-Condensed Bold" + self.use_custom_fonts = False + self.linux_font = "Noto Sans, Noto Sans CJK JP, Arial," + self.linux_font_semibold = "Noto Sans, Noto Sans CJK JP, Arial, Medium" + self.linux_font_bold = "Noto Sans, Noto Sans CJK JP, Bold" + self.linux_font_condensed = "Noto Sans, Extra-Condensed" + self.linux_font_condensed_bold = "Noto Sans, Extra-Condensed Bold" - self.spec2_scroll = True + self.spec2_scroll = True - self.spec2_p_base = [10, 10, 100] - self.spec2_p_multiply = [0.5, 1, 1] + self.spec2_p_base = [10, 10, 100] + self.spec2_p_multiply = [0.5, 1, 1] - self.spec2_base = [10, 10, 100] - self.spec2_multiply = [0.5, 1, 1] - self.spec2_colour_setting = 'custom' + self.spec2_base = [10, 10, 100] + self.spec2_multiply = [0.5, 1, 1] + self.spec2_colour_setting = 'custom' - self.auto_lfm = False - self.scrobble_mark = False - self.enable_mpris = True + self.auto_lfm = False + self.scrobble_mark = False + self.enable_mpris = True - self.replay_gain = 0 # 0=off 1=track 2=album - self.replay_preamp = 0 # db - self.radio_page_lyrics = True + self.replay_gain = 0 # 0=off 1=track 2=album + self.replay_preamp = 0 # db + self.radio_page_lyrics = True - self.show_gimage = False - self.end_setting = "stop" - self.show_gen = False - self.show_lyrics_side = True + self.show_gimage = False + self.end_setting = "stop" + self.show_gen = False + self.show_lyrics_side = True - self.log_vol = False + self.log_vol = False - self.ui_scale: float = scale + self.ui_scale: float = scale - # if flatpak_mode: + # if flatpak_mode: - self.transcode_opus_as = False + self.transcode_opus_as = False - self.discord_active = False - self.discord_ready = False - self.disconnect_discord = False + self.discord_active = False + self.discord_ready = False + self.disconnect_discord = False - self.monitor_downloads = True - self.extract_to_music = False + self.monitor_downloads = True + self.extract_to_music = False - self.enable_lb = False - self.lb_token = "" + self.enable_lb = False + self.lb_token = "" - self.use_jump_crossfade = True - self.use_transition_crossfade = False - self.use_pause_fade = True + self.use_jump_crossfade = True + self.use_transition_crossfade = False + self.use_pause_fade = True - self.show_notifications = True + self.show_notifications = True - self.true_shuffle = True - self.append_total_time = False - self.backend = 4 # 2 gstreamer, 4 phazor + self.true_shuffle = True + self.append_total_time = False + self.backend = 4 # 2 gstreamer, 4 phazor - self.album_repeat_mode = False # passed to pctl - self.album_shuffle_mode = False # passed to pctl + self.album_repeat_mode = False # passed to pctl + self.album_shuffle_mode = False # passed to pctl - self.finish_current = False # Finish current album when adding to queue + self.finish_current = False # Finish current album when adding to queue - self.reload_play_state = False # Resume playback on app restart - self.resume_play_wake = False # Resume playback on wake - self.reload_state = None + self.reload_play_state = False # Resume playback on app restart + self.resume_play_wake = False # Resume playback on wake + self.reload_state = None - self.mono = False + self.mono = False - self.last_fm_token = None - self.last_fm_username = "" + self.last_fm_token = None + self.last_fm_username = "" - self.use_card_style = True + self.use_card_style = True - self.plex_username = "" - self.plex_password = "" - self.plex_servername = "" + self.plex_username = "" + self.plex_password = "" + self.plex_servername = "" - self.koel_username = "admin@example.com" - self.koel_password = "admin" - self.koel_server_url = "http://localhost:8050" + self.koel_username = "admin@example.com" + self.koel_password = "admin" + self.koel_server_url = "http://localhost:8050" - self.auto_lyrics = False # Function has been disabled - self.jelly_username = "" - self.jelly_password = "" - self.jelly_server_url = "http://localhost:8096" + self.auto_lyrics = False # Function has been disabled + self.jelly_username = "" + self.jelly_password = "" + self.jelly_server_url = "http://localhost:8096" - self.auto_lyrics_checked = [] + self.auto_lyrics_checked = [] - self.show_side_art = True - self.always_pin_playlists = True + self.show_side_art = True + self.always_pin_playlists = True - self.user_directory = user_directory - self.cache_directory = cache_directory + self.user_directory = user_directory + self.cache_directory = cache_directory - self.window_opacity = window_opacity - self.gallery_single_click = True - self.custom_bg_opacity = 40 + self.window_opacity = window_opacity + self.gallery_single_click = True + self.custom_bg_opacity = 40 - self.tabs_on_top = True - self.desktop = desktop + self.tabs_on_top = True + self.desktop = desktop - self.dc_device = False # (BASS) Disconnect device on pause - if desktop == "KDE": - self.dc_device = True + self.dc_device = False # (BASS) Disconnect device on pause + if desktop == "KDE": + self.dc_device = True - self.showcase_vis = True - self.show_lyrics_showcase = True + self.showcase_vis = True + self.show_lyrics_showcase = True - self.spec2_colour_mode = 0 - self.flatpak_mode = flatpak_mode + self.spec2_colour_mode = 0 + self.flatpak_mode = flatpak_mode - self.device_buffer = 80 + self.device_buffer = 80 - self.eq = [0.0] * 10 - self.use_eq = False + self.eq = [0.0] * 10 + self.use_eq = False - self.bio_large = False - self.discord_allow = discord_allow - self.discord_show = False + self.bio_large = False + self.discord_allow = discord_allow + self.discord_show = False - self.min_to_tray = False + self.min_to_tray = False - self.guitar_chords = False - self.prefer_synced_lyrics = True - self.sync_lyrics_time_offset = 0 + self.guitar_chords = False + self.prefer_synced_lyrics = True + self.sync_lyrics_time_offset = 0 - self.playback_follow_cursor = False - self.short_buffer = False + self.playback_follow_cursor = False + self.short_buffer = False - self.gst_output = "rgvolume pre-amp=-2 fallback-gain=-6 ! autoaudiosink" + self.gst_output = "rgvolume pre-amp=-2 fallback-gain=-6 ! autoaudiosink" - self.art_bg = False - self.art_bg_stronger = 1 - self.art_bg_opacity = 10 - self.art_bg_blur = 9 - self.art_bg_always_blur = False + self.art_bg = False + self.art_bg_stronger = 1 + self.art_bg_opacity = 10 + self.art_bg_blur = 9 + self.art_bg_always_blur = False - self.random_mode = False - self.repeat_mode = False + self.random_mode = False + self.repeat_mode = False - self.failed_artists = [] - self.failed_background_artists = [] + self.failed_artists = [] + self.failed_background_artists = [] - self.artist_list = False - self.auto_sort = False + self.artist_list = False + self.auto_sort = False - self.transcode_inplace = False + self.transcode_inplace = False - self.bg_showcase_only = False + self.bg_showcase_only = False - self.lyrics_enables = [] + self.lyrics_enables = [] - self.fatvap = "6b2a9499238ce6416783fc8129b8ac67" + self.fatvap = "6b2a9499238ce6416783fc8129b8ac67" - self.fanart_notify = True - self.discogs_pat = "" + self.fanart_notify = True + self.discogs_pat = "" - self.artist_list_prefer_album_artist = True + self.artist_list_prefer_album_artist = True - self.mini_mode_mode = 0 - self.dc_device_setting = "on" + self.mini_mode_mode = 0 + self.dc_device_setting = "on" - self.download_dir1 = "" - self.dd_index = False + self.download_dir1 = "" + self.dd_index = False - self.metadata_page_port = 7590 + self.metadata_page_port = 7590 - self.custom_encoder_output = "" - self.column_aa_fallback_artist = False + self.custom_encoder_output = "" + self.column_aa_fallback_artist = False - self.meta_persists_stop = False - self.meta_shows_selected = False - self.meta_shows_selected_always = False + self.meta_persists_stop = False + self.meta_shows_selected = False + self.meta_shows_selected_always = False - self.left_align_album_artist_title = False - self.stop_notifications_mini_mode = False - self.scale_want = 1 - self.x_scale = True - self.hide_queue = True - self.show_playlist_list = True - self.thin_gallery_borders = False - self.show_current_on_transition = False + self.left_align_album_artist_title = False + self.stop_notifications_mini_mode = False + self.scale_want = 1 + self.x_scale = True + self.hide_queue = True + self.show_playlist_list = True + self.thin_gallery_borders = False + self.show_current_on_transition = False - self.force_subpixel_text = False - if gtk_settings: - if gtk_settings.get_property("gtk-xft-rgba") == "rgb": - self.force_subpixel_text = True + self.force_subpixel_text = False + if gtk_settings: + if gtk_settings.get_property("gtk-xft-rgba") == "rgb": + self.force_subpixel_text = True - self.chart_rows = 3 - self.chart_columns = 3 - self.chart_bg = [7, 7, 7] - self.chart_text = True - self.chart_font = "Monospace 10" - self.chart_tile = False + self.chart_rows = 3 + self.chart_columns = 3 + self.chart_bg = [7, 7, 7] + self.chart_text = True + self.chart_font = "Monospace 10" + self.chart_tile = False - self.chart_cascade = False - self.chart_c1 = 5 - self.chart_c2 = 6 - self.chart_c3 = 10 - self.chart_d1 = 2 - self.chart_d2 = 2 - self.chart_d3 = 2 + self.chart_cascade = False + self.chart_c1 = 5 + self.chart_c2 = 6 + self.chart_c3 = 10 + self.chart_d1 = 2 + self.chart_d2 = 2 + self.chart_d3 = 2 - self.art_in_top_panel = True - self.always_art_header = False + self.art_in_top_panel = True + self.always_art_header = False - # self.center_bg = True - self.ui_lang = 'auto' - self.side_panel_layout = 0 - self.use_absolute_track_index = False + # self.center_bg = True + self.ui_lang = 'auto' + self.side_panel_layout = 0 + self.use_absolute_track_index = False - self.hide_bottom_title = True - self.auto_goto_playing = False + self.hide_bottom_title = True + self.auto_goto_playing = False - self.diacritic_search = True - self.increase_gallery_row_spacing = False - self.center_gallery_text = False + self.diacritic_search = True + self.increase_gallery_row_spacing = False + self.center_gallery_text = False - self.tracklist_y_text_offset = 0 - self.theme_name = "Turbo" - self.left_panel_mode = "playlist" + self.tracklist_y_text_offset = 0 + self.theme_name = "Turbo" + self.left_panel_mode = "playlist" - self.folder_tree_codec_colours = False + self.folder_tree_codec_colours = False - self.network_stream_bitrate = 0 # 0 is off + self.network_stream_bitrate = 0 # 0 is off - self.show_side_lyrics_art_panel = True + self.show_side_lyrics_art_panel = True - self.gst_use_custom_output = False + self.gst_use_custom_output = False - self.notify_include_album = True + self.notify_include_album = True - self.auto_dl_artist_data = False + self.auto_dl_artist_data = False - self.enable_fanart_artist = False - self.enable_fanart_bg = False - self.enable_fanart_cover = False + self.enable_fanart_artist = False + self.enable_fanart_bg = False + self.enable_fanart_cover = False - self.always_auto_update_playlists = False + self.always_auto_update_playlists = False - self.subsonic_server = "http://localhost:4040" - self.subsonic_user = "" - self.subsonic_password = "" - self.subsonic_password_plain = False + self.subsonic_server = "http://localhost:4040" + self.subsonic_user = "" + self.subsonic_password = "" + self.subsonic_password_plain = False - self.subsonic_playlists = {} + self.subsonic_playlists = {} - self.write_ratings = False - self.rating_playtime_stars = False - - self.lyrics_subs = {} - - self.radio_urls = [] - - self.lyric_metadata_panel_top = False - self.showcase_overlay_texture = False - - self.sync_target = "" - self.sync_deletes = False - self.sync_playlist = None - self.download_playlist = None - - self.sep_genre_multi = False - self.topchart_sorts_played = True - - self.spot_client = "" - self.spot_secret = "" - self.spot_username = "" - self.spot_password = "" - self.spot_mode = False - self.launch_spotify_web = False - self.launch_spotify_local = False - self.remove_network_tracks = False - self.bypass_transcode = False - self.force_hide_max_button = False - self.zoom_art = False - self.auto_rec = False - self.radio_record_codec = "OPUS" - self.pa_fast_seek = False - self.precache = False - self.cache_list = [] - self.cache_limit = 2000 # in mb - self.save_window_position = True - self.spotify_token = "" - self.always_ffmpeg = False - - self.use_libre_fm = False - self.back_restarts = False - - self.old_playlist_box_position = 0 - self.listenbrainz_url = "" - self.maloja_enable = False - self.maloja_url = "" - self.maloja_key = "" - - self.scrobble_hold = False - - self.artist_list_sort_mode = "alpha" - - self.phazor_device_selected = "Default" - self.phazor_devices = ["Default"] - self.bg_flips = set() - self.use_tray = False - self.tray_show_title = False - self.drag_to_unpin = True - self.enable_remote = False - - self.artist_list_style = 1 - self.discord_enable = False - self.stop_end_queue = False + self.write_ratings = False + self.rating_playtime_stars = False + + self.lyrics_subs = {} + + self.radio_urls = [] + + self.lyric_metadata_panel_top = False + self.showcase_overlay_texture = False + + self.sync_target = "" + self.sync_deletes = False + self.sync_playlist = None + self.download_playlist = None + + self.sep_genre_multi = False + self.topchart_sorts_played = True + + self.spot_client = "" + self.spot_secret = "" + self.spot_username = "" + self.spot_password = "" + self.spot_mode = False + self.launch_spotify_web = False + self.launch_spotify_local = False + self.remove_network_tracks = False + self.bypass_transcode = False + self.force_hide_max_button = False + self.zoom_art = False + self.auto_rec = False + self.radio_record_codec = "OPUS" + self.pa_fast_seek = False + self.precache = False + self.cache_list = [] + self.cache_limit = 2000 # in mb + self.save_window_position = True + self.spotify_token = "" + self.always_ffmpeg = False + + self.use_libre_fm = False + self.back_restarts = False + + self.old_playlist_box_position = 0 + self.listenbrainz_url = "" + self.maloja_enable = False + self.maloja_url = "" + self.maloja_key = "" + + self.scrobble_hold = False + + self.artist_list_sort_mode = "alpha" + + self.phazor_device_selected = "Default" + self.phazor_devices = ["Default"] + self.bg_flips = set() + self.use_tray = False + self.tray_show_title = False + self.drag_to_unpin = True + self.enable_remote = False + + self.artist_list_style = 1 + self.discord_enable = False + self.stop_end_queue = False - self.block_suspend = False - self.smart_bypass = True - self.seek_interval = 15 - self.shuffle_lock = False - self.album_shuffle_lock_mode = False - self.premium = False - self.power_save = False - if macos or phone: - self.power_save = True - self.left_window_control = macos or left_window_control - self.macstyle = macos or detect_macstyle - self.radio_thumb_bans = [] - self.show_nag = False - - self.playlist_exports = {} - self.show_chromecast = False - - self.samplerate = 48000 - self.resample = 1 - self.volume_power = 2 - - self.tmp_cache = True - - self.sat_url = "" - self.lyrics_font_size = 15 - - self.use_gamepad = True - self.avoid_resampling = False - self.use_scancodes = False - - self.artist_list_threshold = 4 - self.allow_video_formats = True - self.mini_mode_on_top = True - self.tray_theme = "pink" - - self.lastfm_pull_love = False - self.row_title_format = 1 - self.row_title_genre = False - self.row_title_separator_type = 1 - self.search_on_letter = True - - self.gallery_combine_disc = False - self.pipewire = False - self.tidal_quality = 1 + self.block_suspend = False + self.smart_bypass = True + self.seek_interval = 15 + self.shuffle_lock = False + self.album_shuffle_lock_mode = False + self.premium = False + self.power_save = False + if macos or phone: + self.power_save = True + self.left_window_control = macos or left_window_control + self.macstyle = macos or detect_macstyle + self.radio_thumb_bans = [] + self.show_nag = False + + self.playlist_exports = {} + self.show_chromecast = False + + self.samplerate = 48000 + self.resample = 1 + self.volume_power = 2 + + self.tmp_cache = True + + self.sat_url = "" + self.lyrics_font_size = 15 + + self.use_gamepad = True + self.avoid_resampling = False + self.use_scancodes = False + + self.artist_list_threshold = 4 + self.allow_video_formats = True + self.mini_mode_on_top = True + self.tray_theme = "pink" + + self.lastfm_pull_love = False + self.row_title_format = 1 + self.row_title_genre = False + self.row_title_separator_type = 1 + self.search_on_letter = True + + self.gallery_combine_disc = False + self.pipewire = False + self.tidal_quality = 1 prefs = Prefs() def open_uri(uri:str): - print("OPEN URI") - load_order = LoadClass() + print("OPEN URI") + load_order = LoadClass() - for w in range(len(pctl.multi_playlist)): - if pctl.multi_playlist[w][0] == "Default": - load_order.playlist = pctl.multi_playlist[w][6] - break - else: - pctl.multi_playlist.append(pl_gen()) - load_order.playlist = pctl.multi_playlist[len(pctl.multi_playlist) - 1][6] - switch_playlist(len(pctl.multi_playlist) - 1) + for w in range(len(pctl.multi_playlist)): + if pctl.multi_playlist[w][0] == "Default": + load_order.playlist = pctl.multi_playlist[w][6] + break + else: + pctl.multi_playlist.append(pl_gen()) + load_order.playlist = pctl.multi_playlist[len(pctl.multi_playlist) - 1][6] + switch_playlist(len(pctl.multi_playlist) - 1) - load_order.target = str(urllib.parse.unquote(uri)).replace("file:///", "/").replace("\r", "") + load_order.target = str(urllib.parse.unquote(uri)).replace("file:///", "/").replace("\r", "") - if gui.auto_play_import is False: - load_order.play = True - gui.auto_play_import = True + if gui.auto_play_import is False: + load_order.play = True + gui.auto_play_import = True - load_orders.append(copy.deepcopy(load_order)) - gui.update += 1 + load_orders.append(copy.deepcopy(load_order)) + gui.update += 1 class GuiVar: # Use to hold any variables for use in relation to UI - def update_layout(self): - global update_layout - update_layout = True - - def show_message(self, line1, line2="", line3="", mode="info"): - show_message(line1, line2, line3, mode=mode) - - def delay_frame(self, t): - gui.frame_callback_list.append(TestTimer(t)) - - def destroy_textures(self): - SDL_DestroyTexture(self.spec4_tex) - SDL_DestroyTexture(self.spec1_tex) - SDL_DestroyTexture(self.spec2_tex) - SDL_DestroyTexture(self.spec_level_tex) - - # def test_text_input(self): - # if self.text_input_request and not self.text_input_active: - # SDL_StartTextInput() - # self.update += 1 - # if not self.text_input_request and self.text_input_active: - # SDL_StopTextInput() - # self.text_input_request = False - - def rescale(self): - self.spec_y = int(round(5 * self.scale)) - self.spec_w = int(round(80 * self.scale)) - self.spec_h = int(round(20 * self.scale)) - self.spec1_rec = SDL_Rect(0, self.spec_y, self.spec_w, self.spec_h) - - self.spec4_y = int(round(200 * self.scale)) - self.spec4_w = int(round(322 * self.scale)) - self.spec4_h = int(round(100 * self.scale)) - self.spec4_rec = SDL_Rect(0, self.spec4_y, self.spec4_w, self.spec4_h) - - self.bar = SDL_Rect(10, 10, round(3 * self.scale), 10) # spec bar bin - self.bar4 = SDL_Rect(10, 10, round(3 * self.scale), 10) # spec bar bin - self.set_height = round(25 * self.scale) - self.panelBY = round(51 * self.scale) - self.panelY = round(30 * self.scale) - self.panelY2 = round(30 * self.scale) - self.playlist_top = self.panelY + (8 * self.scale) - self.playlist_top_bk = self.playlist_top - self.scroll_hide_box = (0, self.panelY, 28, window_size[1] - self.panelBY - self.panelY) - - self.spec2_y = int(round(22 * self.scale)) - self.spec2_w = int(round(140 * self.scale)) - self.spec2 = [0] * self.spec2_y - self.spec2_phase = 0 - self.spec2_buffers = [] - self.spec2_rec = SDL_Rect(1230, round(4 * self.scale), self.spec2_w, self.spec2_y) - self.spec2_source = SDL_Rect(900, round(4 * self.scale), self.spec2_w, self.spec2_y) - self.spec2_dest = SDL_Rect(900, round(4 * self.scale), self.spec2_w, self.spec2_y) - self.spec2_position = 0 - self.spec2_timer = Timer() - self.spec2_timer.set() - - self.level_w = 5 * self.scale - self.level_y = 16 * self.scale - self.level_s = 1 * self.scale - self.level_ww = round(79 * self.scale) - self.level_hh = round(18 * self.scale) - self.spec_level_rec = SDL_Rect(0, round(self.level_y - 10 * self.scale), round(self.level_ww), - round(self.level_hh)) - - self.spec2_tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, self.spec2_w, - self.spec2_y) - self.spec4_tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, self.spec4_w, - self.spec4_y) - self.spec1_tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, self.spec_w, - self.spec_h) - self.spec_level_tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, - self.level_ww, self.level_hh) - SDL_SetTextureBlendMode(self.spec4_tex, SDL_BLENDMODE_BLEND) - self.artist_panel_height = 320 * self.scale - self.last_artist_panel_height = self.artist_panel_height - - self.window_control_hit_area_w = 100 * self.scale - self.window_control_hit_area_h = 30 * self.scale - - def __init__(self): - - self.scale = prefs.ui_scale - - self.window_id = 0 - self.update = 2 # UPDATE - self.turbo = True - self.turbo_next = 0 - self.pl_update = 1 - self.lowered = False - self.request_raise = False - self.maximized = False - - self.message_box = False - self.message_text = "" - self.message_mode = 'info' - self.message_subtext = "" - self.message_subtext2 = "" - self.message_box_confirm_reference = None - self.message_box_use_reference = True - self.message_box_confirm_callback = None - - self.save_size = [450, 310] - self.show_playlist = True - self.show_bottom_title = False - # self.show_top_title = True - self.search_error = False - - self.level_update = False - self.level_time = Timer() - self.level_peak = [0, 0] - self.level = 0 - self.time_passed = 0 - self.level_meter_colour_mode = 3 - - self.vis = 0 # visualiser mode actual - self.vis_want = 2 # visualiser mode setting - self.spec = None - self.s_spec = [0] * 24 - self.s4_spec = [0] * 45 - self.update_spec = 0 - - # self.spec_rect = [0, 5, 80, 20] # x = 72 + 24 - 6 - 10 - - self.spec4_array = [] - - self.draw_spec4 = False - - self.combo_mode = False - self.showcase_mode = False - self.display_time_mode = 0 - - self.pl_text_real_height = 12 - self.pl_title_real_height = 11 - - self.row_extra = 0 - self.test = False - self.light_mode = False - - self.level_2_click = False - self.universal_y_text_offset = 0 - - self.star_text_y_offset = 0 - if system == "windows": - self.star_text_y_offset = -2 - - self.set_bar = True - self.set_mode = False - self.set_hold = -1 - self.set_label_hold = -1 - self.set_label_point = (0, 0) - self.set_point = 0 - self.set_old = 0 - self.pl_st = [['Artist', 156, False], ['Title', 188, False], ['T', 40, True], ['Album', 153, False], - ['P', 28, True], ['Starline', 86, True], ['Date', 48, True], ['Codec', 55, True], - ['Time', 53, True]] + def update_layout(self): + global update_layout + update_layout = True + + def show_message(self, line1, line2="", line3="", mode="info"): + show_message(line1, line2, line3, mode=mode) + + def delay_frame(self, t): + gui.frame_callback_list.append(TestTimer(t)) + + def destroy_textures(self): + SDL_DestroyTexture(self.spec4_tex) + SDL_DestroyTexture(self.spec1_tex) + SDL_DestroyTexture(self.spec2_tex) + SDL_DestroyTexture(self.spec_level_tex) + + # def test_text_input(self): + # if self.text_input_request and not self.text_input_active: + # SDL_StartTextInput() + # self.update += 1 + # if not self.text_input_request and self.text_input_active: + # SDL_StopTextInput() + # self.text_input_request = False + + def rescale(self): + self.spec_y = int(round(5 * self.scale)) + self.spec_w = int(round(80 * self.scale)) + self.spec_h = int(round(20 * self.scale)) + self.spec1_rec = SDL_Rect(0, self.spec_y, self.spec_w, self.spec_h) + + self.spec4_y = int(round(200 * self.scale)) + self.spec4_w = int(round(322 * self.scale)) + self.spec4_h = int(round(100 * self.scale)) + self.spec4_rec = SDL_Rect(0, self.spec4_y, self.spec4_w, self.spec4_h) + + self.bar = SDL_Rect(10, 10, round(3 * self.scale), 10) # spec bar bin + self.bar4 = SDL_Rect(10, 10, round(3 * self.scale), 10) # spec bar bin + self.set_height = round(25 * self.scale) + self.panelBY = round(51 * self.scale) + self.panelY = round(30 * self.scale) + self.panelY2 = round(30 * self.scale) + self.playlist_top = self.panelY + (8 * self.scale) + self.playlist_top_bk = self.playlist_top + self.scroll_hide_box = (0, self.panelY, 28, window_size[1] - self.panelBY - self.panelY) + + self.spec2_y = int(round(22 * self.scale)) + self.spec2_w = int(round(140 * self.scale)) + self.spec2 = [0] * self.spec2_y + self.spec2_phase = 0 + self.spec2_buffers = [] + self.spec2_rec = SDL_Rect(1230, round(4 * self.scale), self.spec2_w, self.spec2_y) + self.spec2_source = SDL_Rect(900, round(4 * self.scale), self.spec2_w, self.spec2_y) + self.spec2_dest = SDL_Rect(900, round(4 * self.scale), self.spec2_w, self.spec2_y) + self.spec2_position = 0 + self.spec2_timer = Timer() + self.spec2_timer.set() + + self.level_w = 5 * self.scale + self.level_y = 16 * self.scale + self.level_s = 1 * self.scale + self.level_ww = round(79 * self.scale) + self.level_hh = round(18 * self.scale) + self.spec_level_rec = SDL_Rect( + 0, round(self.level_y - 10 * self.scale), round(self.level_ww),round(self.level_hh)) + + self.spec2_tex = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, self.spec2_w, self.spec2_y) + self.spec4_tex = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, self.spec4_w, self.spec4_y) + self.spec1_tex = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, self.spec_w, self.spec_h) + self.spec_level_tex = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, self.level_ww, self.level_hh) + SDL_SetTextureBlendMode(self.spec4_tex, SDL_BLENDMODE_BLEND) + self.artist_panel_height = 320 * self.scale + self.last_artist_panel_height = self.artist_panel_height + + self.window_control_hit_area_w = 100 * self.scale + self.window_control_hit_area_h = 30 * self.scale + + def __init__(self): + + self.scale = prefs.ui_scale + + self.window_id = 0 + self.update = 2 # UPDATE + self.turbo = True + self.turbo_next = 0 + self.pl_update = 1 + self.lowered = False + self.request_raise = False + self.maximized = False + + self.message_box = False + self.message_text = "" + self.message_mode = 'info' + self.message_subtext = "" + self.message_subtext2 = "" + self.message_box_confirm_reference = None + self.message_box_use_reference = True + self.message_box_confirm_callback = None + + self.save_size = [450, 310] + self.show_playlist = True + self.show_bottom_title = False + # self.show_top_title = True + self.search_error = False + + self.level_update = False + self.level_time = Timer() + self.level_peak = [0, 0] + self.level = 0 + self.time_passed = 0 + self.level_meter_colour_mode = 3 + + self.vis = 0 # visualiser mode actual + self.vis_want = 2 # visualiser mode setting + self.spec = None + self.s_spec = [0] * 24 + self.s4_spec = [0] * 45 + self.update_spec = 0 + + # self.spec_rect = [0, 5, 80, 20] # x = 72 + 24 - 6 - 10 + + self.spec4_array = [] + + self.draw_spec4 = False + + self.combo_mode = False + self.showcase_mode = False + self.display_time_mode = 0 + + self.pl_text_real_height = 12 + self.pl_title_real_height = 11 + + self.row_extra = 0 + self.test = False + self.light_mode = False + + self.level_2_click = False + self.universal_y_text_offset = 0 + + self.star_text_y_offset = 0 + if system == "windows": + self.star_text_y_offset = -2 + + self.set_bar = True + self.set_mode = False + self.set_hold = -1 + self.set_label_hold = -1 + self.set_label_point = (0, 0) + self.set_point = 0 + self.set_old = 0 + self.pl_st = [ + ['Artist', 156, False], ['Title', 188, False], ['T', 40, True], ['Album', 153, False], + ['P', 28, True], ['Starline', 86, True], ['Date', 48, True], ['Codec', 55, True], + ['Time', 53, True]] + + for item in self.pl_st: + item[1] = item[1] * self.scale + + self.offset_extra = 0 + + self.playlist_row_height = 16 + self.playlist_text_offset = 0 + self.row_font_size = 13 + self.compact_bar = False + self.tracklist_texture_rect = tracklist_texture_rect + self.tracklist_texture = tracklist_texture - for item in self.pl_st: - item[1] = item[1] * self.scale + self.trunk_end = "..." # "…" + self.temp_themes = {} + self.theme_temp_current = -1 - self.offset_extra = 0 + self.pl_title_y_offset = 0 + self.pl_title_font_offset = -1 - self.playlist_row_height = 16 - self.playlist_text_offset = 0 - self.row_font_size = 13 - self.compact_bar = False - self.tracklist_texture_rect = tracklist_texture_rect - self.tracklist_texture = tracklist_texture + self.playlist_box_d_click = -1 - self.trunk_end = "..." # "…" - self.temp_themes = {} - self.theme_temp_current = -1 + self.gallery_show_text = True + self.bb_show_art = False - self.pl_title_y_offset = 0 - self.pl_title_font_offset = -1 + self.rename_folder_box = False - self.playlist_box_d_click = -1 + self.present = False + self.drag_source_position = (0, 0) + self.drag_source_position_persist = (0, 0) + self.album_tab_mode = False + self.main_art_box = (0, 0, 10, 10) + self.gall_tab_enter = False - self.gallery_show_text = True - self.bb_show_art = False + self.lightning_copy = False - self.rename_folder_box = False - - self.present = False - self.drag_source_position = (0, 0) - self.drag_source_position_persist = (0, 0) - self.album_tab_mode = False - self.main_art_box = (0, 0, 10, 10) - self.gall_tab_enter = False + self.gallery_animate_highlight_on = 0 - self.lightning_copy = False + self.seek_cur_show = False + self.cur_time = "0" + self.force_showcase_index = -1 - self.gallery_animate_highlight_on = 0 + self.frame_callback_list = [] - self.seek_cur_show = False - self.cur_time = "0" - self.force_showcase_index = -1 + self.playlist_left = None + self.image_downloading = False + self.tc_cancel = False + self.im_cancel = False + self.force_search = False - self.frame_callback_list = [] + self.pl_pulse = False - self.playlist_left = None - self.image_downloading = False - self.tc_cancel = False - self.im_cancel = False - self.force_search = False + self.view_name = "S" + self.restart_album_mode = False - self.pl_pulse = False + self.dtm3_index = -1 + self.dtm3_cum = 0 + self.dtm3_total = 0 + self.previous_playlist_id = "" - self.view_name = "S" - self.restart_album_mode = False + self.star_mode = "line" + self.heart_fields = [] + self.show_ratings = False - self.dtm3_index = -1 - self.dtm3_cum = 0 - self.dtm3_total = 0 - self.previous_playlist_id = "" + self.web_running = False - self.star_mode = "line" - self.heart_fields = [] - self.show_ratings = False + self.rsp = True + if phone: + self.rsp = False + self.rspw = round(300 * self.scale) + self.lsp = False + self.lspw = round(220 * self.scale) + self.plw = None - self.web_running = False - - self.rsp = True - if phone: - self.rsp = False - self.rspw = round(300 * self.scale) - self.lsp = False - self.lspw = round(220 * self.scale) - self.plw = None - - self.pref_rspw = 300 - - self.pref_gallery_w = 600 + self.pref_rspw = 300 - self.artist_info_panel = False + self.pref_gallery_w = 600 - self.show_hearts = True + self.artist_info_panel = False - self.cursor_is = 0 - self.cursor_want = 0 - # 0 standard - # 1 drag horizontal - # 2 text - # 3 hand + self.show_hearts = True - self.power_bar = None - self.gallery_scroll_field_left = 1 - self.combo_was_album = False + self.cursor_is = 0 + self.cursor_want = 0 + # 0 standard + # 1 drag horizontal + # 2 text + # 3 hand - self.gallery_positions = {} + self.power_bar = None + self.gallery_scroll_field_left = 1 + self.combo_was_album = False - self.remember_library_mode = False + self.gallery_positions = {} - self.first_in_grid = None + self.remember_library_mode = False - self.art_aspect_ratio = 1 - self.art_drawn_rect = None - self.art_unlock_ratio = False - self.art_max_ratio_lock = 1 - self.side_bar_drag_source = 0 - self.side_bar_drag_original = 0 + self.first_in_grid = None - self.scroll_direction = 0 - self.add_music_folder_ready = False + self.art_aspect_ratio = 1 + self.art_drawn_rect = None + self.art_unlock_ratio = False + self.art_max_ratio_lock = 1 + self.side_bar_drag_source = 0 + self.side_bar_drag_original = 0 - self.playlist_current_visible_tracks = 0 - self.playlist_current_visible_tracks_id = 0 + self.scroll_direction = 0 + self.add_music_folder_ready = False - self.theme_name = "" - self.rename_playlist_box = False - self.queue_frame_draw = None # Set when need draw frame later + self.playlist_current_visible_tracks = 0 + self.playlist_current_visible_tracks_id = 0 - self.mode = 1 + self.theme_name = "" + self.rename_playlist_box = False + self.queue_frame_draw = None # Set when need draw frame later - self.save_position = [0, 0] + self.mode = 1 - self.draw_vis4_top = False - # self.vis_4_colour = [0,0,0,255] - self.vis_4_colour = None + self.save_position = [0, 0] - self.layer_focus = 0 - self.tab_menu_pl = 0 + self.draw_vis4_top = False + # self.vis_4_colour = [0,0,0,255] + self.vis_4_colour = None - self.tool_tip_lock_off_f = False - self.tool_tip_lock_off_b = False + self.layer_focus = 0 + self.tab_menu_pl = 0 - self.auto_play_import = False + self.tool_tip_lock_off_f = False + self.tool_tip_lock_off_b = False - self.transcoding_batch_total = 0 - self.transcoding_bach_done = 0 + self.auto_play_import = False - self.seek_bar_rect = (0, 0, 0, 0) - self.volume_bar_rect = (0, 0, 0, 0) + self.transcoding_batch_total = 0 + self.transcoding_bach_done = 0 - self.mini_mode_return_maximized = False + self.seek_bar_rect = (0, 0, 0, 0) + self.volume_bar_rect = (0, 0, 0, 0) - self.opened_config_file = False + self.mini_mode_return_maximized = False - self.notify_main_id = None + self.opened_config_file = False - self.halt_image_rendering = False - self.generating_chart = False + self.notify_main_id = None - self.top_bar_mode2 = False - self.mode_toast_text = "" + self.halt_image_rendering = False + self.generating_chart = False - self.rescale() - # self.smooth_scrolling = False + self.top_bar_mode2 = False + self.mode_toast_text = "" - self.compact_artist_list = False + self.rescale() + # self.smooth_scrolling = False - self.rsp_full_lock = False + self.compact_artist_list = False - self.album_scroll_px = album_v_slide_value - self.queue_toast_plural = False - self.reload_theme = False - self.theme_number = 0 - self.toast_queue_object = None - self.toast_love_object = None - self.toast_love_added = True + self.rsp_full_lock = False - self.force_side_on_drag = False - self.last_left_panel_mode = "playlist" - self.showing_l_panel = False + self.album_scroll_px = album_v_slide_value + self.queue_toast_plural = False + self.reload_theme = False + self.theme_number = 0 + self.toast_queue_object = None + self.toast_love_object = None + self.toast_love_added = True - self.downloading_bass = False - self.d_click_ref = -1 + self.force_side_on_drag = False + self.last_left_panel_mode = "playlist" + self.showing_l_panel = False - self.max_window_tex = max_window_tex - self.main_texture = main_texture - self.main_texture_overlay_temp = main_texture_overlay_temp + self.downloading_bass = False + self.d_click_ref = -1 - self.preview_artist = "" - self.preview_artist_location = (0, 0) - self.preview_artist_loading = "" - self.mouse_left_window = False + self.max_window_tex = max_window_tex + self.main_texture = main_texture + self.main_texture_overlay_temp = main_texture_overlay_temp - self.rendered_playlist_position = 0 + self.preview_artist = "" + self.preview_artist_location = (0, 0) + self.preview_artist_loading = "" + self.mouse_left_window = False - self.console = console - self.show_album_ratings = False - self.gen_code_errors = False + self.rendered_playlist_position = 0 - self.regen_single = -1 - self.regen_single_id = None + self.console = console + self.show_album_ratings = False + self.gen_code_errors = False - self.tracklist_bg_is_light = False - self.clear_image_cache_next = 0 + self.regen_single = -1 + self.regen_single_id = None - self.column_d_click_timer = Timer(10) - self.column_d_click_on = -1 - self.column_sort_ani_timer = Timer(10) - self.column_sort_down_icon = asset_loader("sort-down.png", True) - self.column_sort_up_icon = asset_loader("sort-up.png", True) - self.column_sort_ani_direction = 1 - self.column_sort_ani_x = 0 + self.tracklist_bg_is_light = False + self.clear_image_cache_next = 0 - self.restore_showcase_view = False - self.restore_radio_view = False + self.column_d_click_timer = Timer(10) + self.column_d_click_on = -1 + self.column_sort_ani_timer = Timer(10) + self.column_sort_down_icon = asset_loader("sort-down.png", True) + self.column_sort_up_icon = asset_loader("sort-up.png", True) + self.column_sort_ani_direction = 1 + self.column_sort_ani_x = 0 - self.tracklist_center_mode = False - self.tracklist_inset_left = 0 - self.tracklist_inset_width = 0 - self.tracklist_highlight_width = 0 - self.tracklist_highlight_left = 0 + self.restore_showcase_view = False + self.restore_radio_view = False - self.hide_tracklist_in_gallery = False + self.tracklist_center_mode = False + self.tracklist_inset_left = 0 + self.tracklist_inset_width = 0 + self.tracklist_highlight_width = 0 + self.tracklist_highlight_left = 0 - self.saved_prime_tab = 0 - self.saved_prime_direction = 0 + self.hide_tracklist_in_gallery = False - self.stop_sync = False - self.sync_progress = "" - self.sync_speed = "" + self.saved_prime_tab = 0 + self.saved_prime_direction = 0 - self.bar_hover_timer = Timer() + self.stop_sync = False + self.sync_progress = "" + self.sync_speed = "" - self.level_decay_timer = Timer() + self.bar_hover_timer = Timer() - self.showed_title = False + self.level_decay_timer = Timer() - self.to_get = 0 - self.to_got = 0 - self.switch_showcase_off = False + self.showed_title = False - self.backend_reloading = False + self.to_get = 0 + self.to_got = 0 + self.switch_showcase_off = False - self.spot_info_icon = asset_loader("spot-info.png", True) - self.tray_active = False - self.buffering = False - self.buffering_text = "" + self.backend_reloading = False - self.update_on_drag = False - self.pl_update_on_drag = False - self.drop_playlist_target = 0 - self.discord_status = "Standby" - self.mouse_unknown = False - self.macstyle = prefs.macstyle - if macos or detect_macstyle: - self.macstyle = True - self.radio_view = False - self.window_size = window_size - self.box_over = False - self.suggest_clean_db = False - self.style_worker_timer = Timer() + self.spot_info_icon = asset_loader("spot-info.png", True) + self.tray_active = False + self.buffering = False + self.buffering_text = "" - self.shuffle_was_showcase = False - self.shuffle_was_random = True - self.shuffle_was_repeat = False + self.update_on_drag = False + self.pl_update_on_drag = False + self.drop_playlist_target = 0 + self.discord_status = "Standby" + self.mouse_unknown = False + self.macstyle = prefs.macstyle + if macos or detect_macstyle: + self.macstyle = True + self.radio_view = False + self.window_size = window_size + self.box_over = False + self.suggest_clean_db = False + self.style_worker_timer = Timer() - self.was_radio = False - self.fullscreen = False - self.mouse_in_window = True + self.shuffle_was_showcase = False + self.shuffle_was_random = True + self.shuffle_was_repeat = False - self.write_tag_in_progress = False - self.tag_write_count = 0 - # self.text_input_request = False - # self.text_input_active = False - self.center_blur_pixel = (0, 0, 0) + self.was_radio = False + self.fullscreen = False + self.mouse_in_window = True + + self.write_tag_in_progress = False + self.tag_write_count = 0 + # self.text_input_request = False + # self.text_input_active = False + self.center_blur_pixel = (0, 0, 0) gui = GuiVar() def toast(text): - gui.mode_toast_text = text - toast_mode_timer.set() - gui.frame_callback_list.append(TestTimer(1.5)) + gui.mode_toast_text = text + toast_mode_timer.set() + gui.frame_callback_list.append(TestTimer(1.5)) def set_artist_preview(path, artist, x, y): - m = min(round(500 * gui.scale), window_size[1] - (gui.panelY + gui.panelBY + 50 * gui.scale)) - artist_preview_render.load(path, box_size=(m, m)) - artist_preview_render.show = True - ah = artist_preview_render.size[1] - ay = round(y) - (ah // 2) - if ay < gui.panelY + 20 * gui.scale: - ay = gui.panelY + round(20 * gui.scale) - if ay + ah > window_size[1] - (gui.panelBY + 5 * gui.scale): - ay = window_size[1] - (gui.panelBY + ah + round(5 * gui.scale)) - gui.preview_artist = artist - gui.preview_artist_location = (x + 15 * gui.scale, - ay) + m = min(round(500 * gui.scale), window_size[1] - (gui.panelY + gui.panelBY + 50 * gui.scale)) + artist_preview_render.load(path, box_size=(m, m)) + artist_preview_render.show = True + ah = artist_preview_render.size[1] + ay = round(y) - (ah // 2) + if ay < gui.panelY + 20 * gui.scale: + ay = gui.panelY + round(20 * gui.scale) + if ay + ah > window_size[1] - (gui.panelBY + 5 * gui.scale): + ay = window_size[1] - (gui.panelBY + ah + round(5 * gui.scale)) + gui.preview_artist = artist + gui.preview_artist_location = (x + 15 * gui.scale, ay) def get_artist_preview(artist, x, y): - # show_message(_("Loading artist image...")) - - gui.preview_artist_loading = artist - artist_info_box.get_data(artist, force_dl=True) - path = artist_info_box.get_data(artist, get_img_path=True) - if not path: - show_message(_("No artist image found.")) - if not prefs.enable_fanart_artist and not verify_discogs(): - show_message(_("No artist image found."), _("No providers are enabled in settings!"), mode='warning') - gui.preview_artist_loading = "" - return - set_artist_preview(path, artist, x, y) - gui.message_box = False - gui.preview_artist_loading = "" + # show_message(_("Loading artist image...")) + + gui.preview_artist_loading = artist + artist_info_box.get_data(artist, force_dl=True) + path = artist_info_box.get_data(artist, get_img_path=True) + if not path: + show_message(_("No artist image found.")) + if not prefs.enable_fanart_artist and not verify_discogs(): + show_message(_("No artist image found."), _("No providers are enabled in settings!"), mode='warning') + gui.preview_artist_loading = "" + return + set_artist_preview(path, artist, x, y) + gui.message_box = False + gui.preview_artist_loading = "" def set_drag_source(): - gui.drag_source_position = tuple(click_location) - gui.drag_source_position_persist = tuple(click_location) + gui.drag_source_position = tuple(click_location) + gui.drag_source_position_persist = tuple(click_location) # Functions for reading and setting play counts class StarStore: - def __init__(self): - - self.db = {} - - def key(self, track_id): - - track_object = pctl.master_library[track_id] - return track_object.artist, track_object.title, track_object.filename - - def object_key(self, track): - - return track.artist, track.title, track.filename - - # Increments the play time - def add(self, index, value): - - track_object = pctl.master_library[index] - - if after_scan: - if track_object in after_scan: - return - - key = track_object.artist, track_object.title, track_object.filename - - if key in self.db: - self.db[key][0] += value - if value < 0 and self.db[key][0] < 0: - self.db[key][0] = 0 - else: - self.db[key] = [value, "", 0, 0] # Playtime in s, flags, rating, love timestamp - - # Returns the track play time - def get(self, index): - if index < 0: - return 0 - return self.db.get(self.key(index), (0,))[0] - - # Returns the track user rating - def get_rating(self, index): - key = self.key(index) - if key in self.db: - # self.db[key] - return self.db[key][2] - return 0 - - # Sets the track user rating - def set_rating(self, index, value, write=False): - key = self.key(index) - if key not in self.db: - self.db[key] = self.new_object() - self.db[key][2] = value - - tr = pctl.g(index) - if tr.file_ext == "SUB": - self.db[key][2] = math.ceil(value / 2) * 2 - shooter(subsonic.set_rating, (tr, value)) - - if prefs.write_ratings and write: - print("Writing rating..") - assert value <= 10 - assert value >= 0 - - if tr.file_ext == "OGG" or tr.file_ext == "OPUS": - tag = mutagen.oggvorbis.OggVorbis(tr.fullpath) - if value == 0: - if "FMPS_RATING" in tag: - del tag["FMPS_RATING"] - tag.save() - else: - tag["FMPS_RATING"] = ['{:.2f}'.format(value / 10)] - tag.save() - - elif tr.file_ext == "MP3": - tag = mutagen.id3.ID3(tr.fullpath) - - # if True: - # if value == 0: - # tag.delall("POPM") - # else: - # p_rating = 0 - # - # tag.add(mutagen.id3.POPM(email="Windows Media Player 9 Series", rating=int)) - - if value == 0: - changed = False - frames = tag.getall("TXXX") - for i in reversed(range(len(frames))): - if frames[i].desc.lower() == "fmps_rating": - changed = True - if changed: - tag.delall("TXXX:FMPS_RATING") - tag.save() - else: - changed = False - frames = tag.getall("TXXX") - for i in reversed(range(len(frames))): - if frames[i].desc.lower() == "fmps_rating": - frames[i].text = '{:.2f}'.format(value / 10) - changed = True - if not changed: - tag.add(mutagen.id3.TXXX(encoding=mutagen.id3.Encoding.UTF8, text='{:.2f}'.format(value / 10), - desc="FMPS_RATING")) - tag.save() - - elif tr.file_ext == "FLAC": - audio = mutagen.flac.FLAC(tr.fullpath) - tags = audio.tags - if value == 0: - if "FMPS_Rating" in tags: - del tags["FMPS_Rating"] - audio.save() - else: - tags["FMPS_Rating"] = '{:.2f}'.format(value / 10) - audio.save() - - tr.misc["FMPS_Rating"] = float(value / 10) - if value == 0: - del tr.misc["FMPS_Rating"] - - def new_object(self): - return [0, "", 0, 0] - - def get_by_object(self, track): - - return self.db.get(self.object_key(track), (0,))[0] - - def get_total(self): - - return sum(item[0] for item in self.db.values()) - - def full_get(self, index): - return self.db.get(self.key(index)) - - def remove(self, index): - key = self.key(index) - if key in self.db: - del self.db[key] - - def insert(self, index, object): - key = self.key(index) - self.db[key] = object - - def merge(self, index, object): - if object is None or object == self.new_object(): - return - key = self.key(index) - if key not in self.db: - self.db[key] = object - else: - self.db[key][0] += object[0] - self.db[key][2] = object[2] - for cha in object[1]: - if cha not in self.db[key][1]: - self.db[key][1] += cha + def __init__(self): + + self.db = {} + + def key(self, track_id): + + track_object = pctl.master_library[track_id] + return track_object.artist, track_object.title, track_object.filename + + def object_key(self, track): + + return track.artist, track.title, track.filename + + # Increments the play time + def add(self, index, value): + + track_object = pctl.master_library[index] + + if after_scan: + if track_object in after_scan: + return + + key = track_object.artist, track_object.title, track_object.filename + + if key in self.db: + self.db[key][0] += value + if value < 0 and self.db[key][0] < 0: + self.db[key][0] = 0 + else: + self.db[key] = [value, "", 0, 0] # Playtime in s, flags, rating, love timestamp + + # Returns the track play time + def get(self, index): + if index < 0: + return 0 + return self.db.get(self.key(index), (0,))[0] + + # Returns the track user rating + def get_rating(self, index): + key = self.key(index) + if key in self.db: + # self.db[key] + return self.db[key][2] + return 0 + + # Sets the track user rating + def set_rating(self, index, value, write=False): + key = self.key(index) + if key not in self.db: + self.db[key] = self.new_object() + self.db[key][2] = value + + tr = pctl.g(index) + if tr.file_ext == "SUB": + self.db[key][2] = math.ceil(value / 2) * 2 + shooter(subsonic.set_rating, (tr, value)) + + if prefs.write_ratings and write: + print("Writing rating..") + assert value <= 10 + assert value >= 0 + + if tr.file_ext == "OGG" or tr.file_ext == "OPUS": + tag = mutagen.oggvorbis.OggVorbis(tr.fullpath) + if value == 0: + if "FMPS_RATING" in tag: + del tag["FMPS_RATING"] + tag.save() + else: + tag["FMPS_RATING"] = ['{:.2f}'.format(value / 10)] + tag.save() + + elif tr.file_ext == "MP3": + tag = mutagen.id3.ID3(tr.fullpath) + + # if True: + # if value == 0: + # tag.delall("POPM") + # else: + # p_rating = 0 + # + # tag.add(mutagen.id3.POPM(email="Windows Media Player 9 Series", rating=int)) + + if value == 0: + changed = False + frames = tag.getall("TXXX") + for i in reversed(range(len(frames))): + if frames[i].desc.lower() == "fmps_rating": + changed = True + if changed: + tag.delall("TXXX:FMPS_RATING") + tag.save() + else: + changed = False + frames = tag.getall("TXXX") + for i in reversed(range(len(frames))): + if frames[i].desc.lower() == "fmps_rating": + frames[i].text = '{:.2f}'.format(value / 10) + changed = True + if not changed: + tag.add( + mutagen.id3.TXXX( + encoding=mutagen.id3.Encoding.UTF8, text='{:.2f}'.format(value / 10), + desc="FMPS_RATING")) + tag.save() + + elif tr.file_ext == "FLAC": + audio = mutagen.flac.FLAC(tr.fullpath) + tags = audio.tags + if value == 0: + if "FMPS_Rating" in tags: + del tags["FMPS_Rating"] + audio.save() + else: + tags["FMPS_Rating"] = '{:.2f}'.format(value / 10) + audio.save() + + tr.misc["FMPS_Rating"] = float(value / 10) + if value == 0: + del tr.misc["FMPS_Rating"] + + def new_object(self): + return [0, "", 0, 0] + + def get_by_object(self, track): + + return self.db.get(self.object_key(track), (0,))[0] + + def get_total(self): + + return sum(item[0] for item in self.db.values()) + + def full_get(self, index): + return self.db.get(self.key(index)) + + def remove(self, index): + key = self.key(index) + if key in self.db: + del self.db[key] + + def insert(self, index, object): + key = self.key(index) + self.db[key] = object + + def merge(self, index, object): + if object is None or object == self.new_object(): + return + key = self.key(index) + if key not in self.db: + self.db[key] = object + else: + self.db[key][0] += object[0] + self.db[key][2] = object[2] + for cha in object[1]: + if cha not in self.db[key][1]: + self.db[key][1] += cha star_store = StarStore() @@ -2243,29 +2252,29 @@ def merge(self, index, object): class AlbumStarStore: - def __init__(self): - self.db = {} + def __init__(self): + self.db = {} - def get_key(self, track_object): - artist = track_object.album_artist - if not artist: - artist = track_object.artist - return artist + ":" + track_object.album + def get_key(self, track_object): + artist = track_object.album_artist + if not artist: + artist = track_object.artist + return artist + ":" + track_object.album - def get_rating(self, track_object): - return self.db.get(self.get_key(track_object), 0) + def get_rating(self, track_object): + return self.db.get(self.get_key(track_object), 0) - def set_rating(self, track_object, rating): - self.db[self.get_key(track_object)] = rating - if track_object.file_ext == "SUB": - self.db[self.get_key(track_object)] = math.ceil(rating / 2) * 2 - subsonic.set_album_rating(track_object, rating) + def set_rating(self, track_object, rating): + self.db[self.get_key(track_object)] = rating + if track_object.file_ext == "SUB": + self.db[self.get_key(track_object)] = math.ceil(rating / 2) * 2 + subsonic.set_album_rating(track_object, rating) - def set_rating_artist_title(self, artist, album, rating): - self.db[artist + ":" + album] = rating + def set_rating_artist_title(self, artist, album, rating): + self.db[artist + ":" + album] = rating - def get_rating_artist_title(self, artist, album): - return self.db.get(artist + ":" + album, 0) + def get_rating_artist_title(self, artist, album): + return self.db.get(artist + ":" + album, 0) album_star_store = AlbumStarStore() @@ -2273,17 +2282,17 @@ def get_rating_artist_title(self, artist, album): class Fonts: # Used to hold font sizes (I forget to use this) - def __init__(self): - self.tabs = 211 - self.panel_title = 213 + def __init__(self): + self.tabs = 211 + self.panel_title = 213 - self.side_panel_line1 = 214 - self.side_panel_line2 = 13 + self.side_panel_line1 = 214 + self.side_panel_line2 = 13 - self.bottom_panel_time = 212 + self.bottom_panel_time = 212 - # if system == 'windows': - # self.bottom_panel_time = 12 # The Arial bold font is too big so just leaving this as normal. (lazy) + # if system == 'windows': + # self.bottom_panel_time = 12 # The Arial bold font is too big so just leaving this as normal. (lazy) fonts = Fonts() @@ -2291,35 +2300,35 @@ def __init__(self): class Input: # Used to keep track of button states (or should be) - def __init__(self): - self.mouse_click = False - # self.right_click = False - self.level_2_enter = False - self.key_return_press = False - self.key_tab_press = False - self.backspace_press = 0 + def __init__(self): + self.mouse_click = False + # self.right_click = False + self.level_2_enter = False + self.key_return_press = False + self.key_tab_press = False + self.backspace_press = 0 - self.media_key = "" + self.media_key = "" - def m_key_play(self): - self.media_key = "Play" - gui.update += 1 + def m_key_play(self): + self.media_key = "Play" + gui.update += 1 - def m_key_pause(self): - self.media_key = "Pause" - gui.update += 1 + def m_key_pause(self): + self.media_key = "Pause" + gui.update += 1 - def m_key_stop(self): - self.media_key = "Stop" - gui.update += 1 + def m_key_stop(self): + self.media_key = "Stop" + gui.update += 1 - def m_key_next(self): - self.media_key = "Next" - gui.update += 1 + def m_key_next(self): + self.media_key = "Next" + gui.update += 1 - def m_key_previous(self): - self.media_key = "Previous" - gui.update += 1 + def m_key_previous(self): + self.media_key = "Previous" + gui.update += 1 inp = Input() @@ -2327,67 +2336,67 @@ def m_key_previous(self): class KeyMap: - def __init__(self): + def __init__(self): - self.hits = [] # The keys hit this frame - self.maps = {} # Loaded from input.txt + self.hits = [] # The keys hit this frame + self.maps = {} # Loaded from input.txt - def load(self): + def load(self): - path = os.path.join(config_directory, "input.txt") - with open(path, encoding="utf_8") as f: - content = f.read().splitlines() - for p in content: - if len(p) == 0 or len(p) > 100: - continue - if p[0] == " " or p[0] == "#": - continue + path = os.path.join(config_directory, "input.txt") + with open(path, encoding="utf_8") as f: + content = f.read().splitlines() + for p in content: + if len(p) == 0 or len(p) > 100: + continue + if p[0] == " " or p[0] == "#": + continue - items = p.split() - if 1 < len(items) < 5: - function = items[0] + items = p.split() + if 1 < len(items) < 5: + function = items[0] - if items[1] in ("MB4", "MB5"): - key = items[1] - else: - if prefs.use_scancodes: - key = SDL_GetScancodeFromName(items[1].encode()) - else: - key = SDL_GetKeyFromName(items[1].encode()) - if key == 0: - continue + if items[1] in ("MB4", "MB5"): + key = items[1] + else: + if prefs.use_scancodes: + key = SDL_GetScancodeFromName(items[1].encode()) + else: + key = SDL_GetKeyFromName(items[1].encode()) + if key == 0: + continue - mod = [] + mod = [] - if len(items) > 2: - mod.append(items[2].lower()) - if len(items) > 3: - mod.append(items[3].lower()) + if len(items) > 2: + mod.append(items[2].lower()) + if len(items) > 3: + mod.append(items[3].lower()) - if function in self.maps: - self.maps[function].append((key, mod)) - else: - self.maps[function] = [(key, mod)] + if function in self.maps: + self.maps[function].append((key, mod)) + else: + self.maps[function] = [(key, mod)] - def test(self, function): + def test(self, function): - if not self.hits: - return False - if function not in self.maps: - return False + if not self.hits: + return False + if function not in self.maps: + return False - for code, mod in self.maps[function]: + for code, mod in self.maps[function]: - if code in self.hits: + if code in self.hits: - ctrl = (key_ctrl_down or key_rctrl_down) * 1 - shift = (key_shift_down or key_shiftr_down) * 10 - alt = (key_lalt or key_ralt) * 100 + ctrl = (key_ctrl_down or key_rctrl_down) * 1 + shift = (key_shift_down or key_shiftr_down) * 10 + alt = (key_lalt or key_ralt) * 100 - if ctrl + shift + alt == ("ctrl" in mod) * 1 + ("shift" in mod) * 10 + ("alt" in mod) * 100: - return True + if ctrl + shift + alt == ("ctrl" in mod) * 1 + ("shift" in mod) * 10 + ("alt" in mod) * 100: + return True - return False + return False keymaps = KeyMap() @@ -2395,351 +2404,351 @@ def test(self, function): def update_set(): # This is used to scale columns when windows is resized or items added/removed - wid = gui.plw - round(16 * gui.scale) - if gui.tracklist_center_mode: - wid = gui.tracklist_highlight_width - round(16 * gui.scale) + wid = gui.plw - round(16 * gui.scale) + if gui.tracklist_center_mode: + wid = gui.tracklist_highlight_width - round(16 * gui.scale) - total = 0 - for item in gui.pl_st: - if item[2] is False: - total += item[1] - else: - wid -= item[1] + total = 0 + for item in gui.pl_st: + if item[2] is False: + total += item[1] + else: + wid -= item[1] - if wid <= 75: - wid = 75 + if wid <= 75: + wid = 75 - for i in range(len(gui.pl_st)): - if gui.pl_st[i][2] is False and total: - gui.pl_st[i][1] = int(round((gui.pl_st[i][1] / total) * wid)) # + 1 + for i in range(len(gui.pl_st)): + if gui.pl_st[i][2] is False and total: + gui.pl_st[i][1] = int(round((gui.pl_st[i][1] / total) * wid)) # + 1 def auto_size_columns(): - fixed_n = 0 + fixed_n = 0 - wid = gui.plw - round(16 * gui.scale) - if gui.tracklist_center_mode: - wid = gui.tracklist_highlight_width - round(16 * gui.scale) + wid = gui.plw - round(16 * gui.scale) + if gui.tracklist_center_mode: + wid = gui.tracklist_highlight_width - round(16 * gui.scale) - total = wid - for item in gui.pl_st: + total = wid + for item in gui.pl_st: - if item[2]: - fixed_n += 1 + if item[2]: + fixed_n += 1 - if item[0] == "Lyrics": - item[1] = round(50 * gui.scale) - total -= round(50 * gui.scale) + if item[0] == "Lyrics": + item[1] = round(50 * gui.scale) + total -= round(50 * gui.scale) - if item[0] == "Rating": - item[1] = round(80 * gui.scale) - total -= round(80 * gui.scale) + if item[0] == "Rating": + item[1] = round(80 * gui.scale) + total -= round(80 * gui.scale) - if item[0] == "Starline": - item[1] = round(78 * gui.scale) - total -= round(78 * gui.scale) + if item[0] == "Starline": + item[1] = round(78 * gui.scale) + total -= round(78 * gui.scale) - if item[0] == "Time": - item[1] = round(58 * gui.scale) - total -= round(58 * gui.scale) + if item[0] == "Time": + item[1] = round(58 * gui.scale) + total -= round(58 * gui.scale) - if item[0] == "Codec": - item[1] = round(58 * gui.scale) - total -= round(58 * gui.scale) + if item[0] == "Codec": + item[1] = round(58 * gui.scale) + total -= round(58 * gui.scale) - if item[0] == "P" or item[0] == "S" or item[0] == "#": - item[1] = round(32 * gui.scale) - total -= round(32 * gui.scale) + if item[0] == "P" or item[0] == "S" or item[0] == "#": + item[1] = round(32 * gui.scale) + total -= round(32 * gui.scale) - if item[0] == "Date": - item[1] = round(55 * gui.scale) - total -= round(55 * gui.scale) + if item[0] == "Date": + item[1] = round(55 * gui.scale) + total -= round(55 * gui.scale) - if item[0] == "Bitrate": - item[1] = round(67 * gui.scale) - total -= round(67 * gui.scale) + if item[0] == "Bitrate": + item[1] = round(67 * gui.scale) + total -= round(67 * gui.scale) - if item[0] == "❤": - item[1] = round(27 * gui.scale) - total -= round(27 * gui.scale) + if item[0] == "❤": + item[1] = round(27 * gui.scale) + total -= round(27 * gui.scale) - vr = len(gui.pl_st) - fixed_n + vr = len(gui.pl_st) - fixed_n - if vr > 0 and total > 50: + if vr > 0 and total > 50: - space = round(total / vr) + space = round(total / vr) - for item in gui.pl_st: - if not item[2]: - item[1] = space + for item in gui.pl_st: + if not item[2]: + item[1] = space - gui.pl_update += 1 - update_set() + gui.pl_update += 1 + update_set() class ColoursClass: # Used to store colour values for UI elements. These are changed for themes. - def grey(self, value): - return [value, value, value, 255] + def grey(self, value): + return [value, value, value, 255] - def alpha_grey(self, value): - return [255, 255, 255, value] + def alpha_grey(self, value): + return [255, 255, 255, value] - def grey_blend_bg(self, value): - return alpha_blend((255, 255, 255, value), self.box_background) + def grey_blend_bg(self, value): + return alpha_blend((255, 255, 255, value), self.box_background) - def __init__(self): + def __init__(self): - self.deco = None - self.column_colours = {} - self.column_colours_playing = {} + self.deco = None + self.column_colours = {} + self.column_colours_playing = {} - self.last_album = "" - self.link_text = [100, 200, 252, 255] + self.last_album = "" + self.link_text = [100, 200, 252, 255] - self.tb_line = self.grey(21) # not currently used - self.art_box = self.grey(24) + self.tb_line = self.grey(21) # not currently used + self.art_box = self.grey(24) - self.volume_bar_background = self.grey(30) - self.volume_bar_fill = self.grey(125) - self.seek_bar_background = self.grey(30) - self.seek_bar_fill = self.grey(80) + self.volume_bar_background = self.grey(30) + self.volume_bar_fill = self.grey(125) + self.seek_bar_background = self.grey(30) + self.seek_bar_fill = self.grey(80) - self.tab_text_active = self.grey(230) - self.tab_text = self.grey(215) - self.tab_background = self.grey(25) - self.tab_highlight = self.grey(40) - self.tab_background_active = self.grey(45) + self.tab_text_active = self.grey(230) + self.tab_text = self.grey(215) + self.tab_background = self.grey(25) + self.tab_highlight = self.grey(40) + self.tab_background_active = self.grey(45) - self.title_text = [190, 190, 190, 255] - self.index_text = self.grey(70) - self.time_text = self.grey(180) - self.artist_text = [195, 255, 104, 255] - self.album_text = [245, 240, 90, 255] + self.title_text = [190, 190, 190, 255] + self.index_text = self.grey(70) + self.time_text = self.grey(180) + self.artist_text = [195, 255, 104, 255] + self.album_text = [245, 240, 90, 255] - self.index_playing = self.grey(190) - self.artist_playing = [195, 255, 104, 255] - self.album_playing = [245, 240, 90, 255] - self.title_playing = self.grey(230) + self.index_playing = self.grey(190) + self.artist_playing = [195, 255, 104, 255] + self.album_playing = [245, 240, 90, 255] + self.title_playing = self.grey(230) - self.time_playing = [180, 194, 107, 255] + self.time_playing = [180, 194, 107, 255] - self.playlist_text_missing = self.grey(85) - self.bar_time = self.grey(70) + self.playlist_text_missing = self.grey(85) + self.bar_time = self.grey(70) - self.top_panel_background = self.grey(15) - self.status_text_over = rgb_add_hls(self.top_panel_background, 0, 0.83, 0) - self.status_text_normal = rgb_add_hls(self.top_panel_background, 0, 0.30, -0.15) + self.top_panel_background = self.grey(15) + self.status_text_over = rgb_add_hls(self.top_panel_background, 0, 0.83, 0) + self.status_text_normal = rgb_add_hls(self.top_panel_background, 0, 0.30, -0.15) - self.side_panel_background = self.grey(18) - self.gallery_background = self.side_panel_background - self.playlist_panel_background = self.grey(21) - self.bottom_panel_colour = self.grey(15) + self.side_panel_background = self.grey(18) + self.gallery_background = self.side_panel_background + self.playlist_panel_background = self.grey(21) + self.bottom_panel_colour = self.grey(15) - self.row_playing_highlight = [255, 255, 255, 4] - self.row_select_highlight = [255, 255, 255, 5] + self.row_playing_highlight = [255, 255, 255, 4] + self.row_select_highlight = [255, 255, 255, 5] - self.side_bar_line1 = self.grey(230) - self.side_bar_line2 = self.grey(210) + self.side_bar_line1 = self.grey(230) + self.side_bar_line2 = self.grey(210) - self.mode_button_off = self.grey(50) - self.mode_button_over = self.grey(200) - self.mode_button_active = self.grey(190) + self.mode_button_off = self.grey(50) + self.mode_button_over = self.grey(200) + self.mode_button_active = self.grey(190) - self.media_buttons_over = self.grey(220) - self.media_buttons_active = self.grey(220) - self.media_buttons_off = self.grey(55) + self.media_buttons_over = self.grey(220) + self.media_buttons_active = self.grey(220) + self.media_buttons_off = self.grey(55) - self.star_line = [100, 100, 100, 255] - self.star_line_playing = None - self.folder_title = [130, 130, 130, 255] - self.folder_line = [40, 40, 40, 255] + self.star_line = [100, 100, 100, 255] + self.star_line_playing = None + self.folder_title = [130, 130, 130, 255] + self.folder_line = [40, 40, 40, 255] - self.scroll_colour = [45, 45, 45, 255] - - self.level_1_bg = [0, 30, 0, 255] - self.level_2_bg = [30, 30, 0, 255] - self.level_3_bg = [30, 0, 0, 255] - self.level_green = [20, 120, 20, 255] - self.level_red = [190, 30, 30, 255] - self.level_yellow = [135, 135, 30, 255] + self.scroll_colour = [45, 45, 45, 255] - self.vis_colour = self.grey(200) - self.vis_bg = [0, 0, 0, 255] - - self.menu_background = None # self.grey(12) - self.menu_highlight_background = None - self.menu_text = [230, 230, 230, 255] - self.menu_text_disabled = self.grey(50) - self.menu_icons = [255, 255, 255, 25] - self.menu_tab = self.grey(30) + self.level_1_bg = [0, 30, 0, 255] + self.level_2_bg = [30, 30, 0, 255] + self.level_3_bg = [30, 0, 0, 255] + self.level_green = [20, 120, 20, 255] + self.level_red = [190, 30, 30, 255] + self.level_yellow = [135, 135, 30, 255] - self.gallery_highlight = self.artist_playing + self.vis_colour = self.grey(200) + self.vis_bg = [0, 0, 0, 255] + + self.menu_background = None # self.grey(12) + self.menu_highlight_background = None + self.menu_text = [230, 230, 230, 255] + self.menu_text_disabled = self.grey(50) + self.menu_icons = [255, 255, 255, 25] + self.menu_tab = self.grey(30) - self.status_info_text = [245, 205, 0, 255] - self.streaming_text = [220, 75, 60, 255] - self.lyrics = self.grey(245) + self.gallery_highlight = self.artist_playing - self.corner_button = [255, 255, 255, 50] # [60, 60, 60, 255] - self.corner_button_active = [255, 255, 255, 230] # [230, 230, 230, 255] + self.status_info_text = [245, 205, 0, 255] + self.streaming_text = [220, 75, 60, 255] + self.lyrics = self.grey(245) - self.window_buttons_bg = [0, 0, 0, 50] - self.window_buttons_bg_over = [255, 255, 255, 10] # [80, 80, 80, 120] - self.window_buttons_icon_over = (255, 255, 255, 60) - self.window_button_icon_off = (255, 255, 255, 40) - self.window_button_x_on = None - self.window_button_x_off = self.window_button_icon_off + self.corner_button = [255, 255, 255, 50] # [60, 60, 60, 255] + self.corner_button_active = [255, 255, 255, 230] # [230, 230, 230, 255] - self.message_box_bg = self.grey(0) - self.message_box_text = self.grey(230) + self.window_buttons_bg = [0, 0, 0, 50] + self.window_buttons_bg_over = [255, 255, 255, 10] # [80, 80, 80, 120] + self.window_buttons_icon_over = (255, 255, 255, 60) + self.window_button_icon_off = (255, 255, 255, 40) + self.window_button_x_on = None + self.window_button_x_off = self.window_button_icon_off - self.sys_title = self.grey(220) - self.sys_title_strong = self.grey(230) - self.lm = False + self.message_box_bg = self.grey(0) + self.message_box_text = self.grey(230) - self.pluse_colour = [244, 212, 66, 255] + self.sys_title = self.grey(220) + self.sys_title_strong = self.grey(230) + self.lm = False - self.mini_mode_background = [19, 19, 19, 255] - self.mini_mode_border = [45, 45, 45, 255] - self.mini_mode_text_1 = [255, 255, 255, 240] - self.mini_mode_text_2 = [255, 255, 255, 77] + self.pluse_colour = [244, 212, 66, 255] - self.queue_drag_indicator_colour = [200, 50, 240, 255] - - self.playlist_box_background = self.side_panel_background + self.mini_mode_background = [19, 19, 19, 255] + self.mini_mode_border = [45, 45, 45, 255] + self.mini_mode_text_1 = [255, 255, 255, 240] + self.mini_mode_text_2 = [255, 255, 255, 77] - self.bar_title_text = None + self.queue_drag_indicator_colour = [200, 50, 240, 255] + + self.playlist_box_background = self.side_panel_background - self.corner_icon = [40, 40, 40, 255] - self.queue_background = None # self.side_panel_background #self.grey(18) # 18 - self.queue_card_background = self.grey(23) + self.bar_title_text = None - self.column_bar_background = [30, 30, 30, 255] - self.column_grip = [255, 255, 255, 14] - self.column_bar_text = [240, 240, 240, 255] - - self.window_frame = [30, 30, 30, 255] - - self.box_background = [16, 16, 16, 255] - self.box_border = rgb_add_hls(self.box_background, 0, 0.17, 0) - self.box_text_border = rgb_add_hls(self.box_background, 0, 0.1, 0) - self.box_text_label = rgb_add_hls(self.box_background, 0, 0.32, -0.1) - self.box_sub_highlight = rgb_add_hls(self.box_background, 0, 0.07, -0.05) # 58, 47, 85 - self.box_check_border = [255, 255, 255, 18] - - self.box_title_text = self.grey(245) - self.box_text = self.grey(240) - self.box_sub_text = self.grey_blend_bg(225) - self.box_input_text = self.grey(225) - self.box_button_text_highlight = self.grey(250) - self.box_button_text = self.grey(225) - self.box_button_background = alpha_blend([255, 255, 255, 11], self.box_background) - self.box_thumb_background = None - self.box_button_background_highlight = alpha_blend([255, 255, 255, 20], self.box_background) - - self.artist_bio_background = [27, 27, 27, 255] - self.artist_bio_text = [230, 230, 230, 255] - - def post_config(self): - - if self.box_thumb_background is None: - self.box_thumb_background = alpha_mod(self.box_button_background, 175) - - # Pre calculate alpha blend for spec background - self.vis_bg[0] = int(0.05 * 255 + (1 - 0.05) * self.top_panel_background[0]) - self.vis_bg[1] = int(0.05 * 255 + (1 - 0.05) * self.top_panel_background[1]) - self.vis_bg[2] = int(0.05 * 255 + (1 - 0.05) * self.top_panel_background[2]) - - self.message_box_bg = self.box_background - self.sys_tab_bg = self.tab_background - self.sys_tab_hl = self.tab_background_active - self.toggle_box_on = self.folder_title - self.toggle_box_on = [255, 150, 100, 255] - self.toggle_box_on = self.artist_playing - if colour_value(self.toggle_box_on) < 150: - self.toggle_box_on = [160, 160, 160, 255] - # self.time_sub = [255, 255, 255, 80]#alpha_blend([255, 255, 255, 80], self.bottom_panel_colour) - - self.time_sub = rgb_add_hls(self.bottom_panel_colour, 0, 0.29, 0) - - if test_lumi(colours.bottom_panel_colour) < 0.2: - # self.time_sub = [0, 0, 0, 80] - self.time_sub = rgb_add_hls(self.bottom_panel_colour, 0, -0.15, -0.3) - elif test_lumi(colours.bottom_panel_colour) < 0.8: - self.time_sub = [255, 255, 255, 135] - # self.time_sub = self.mode_button_off - - if self.bar_title_text is None: - self.bar_title_text = self.side_bar_line1 - - self.gallery_artist_line = alpha_mod(self.side_bar_line2, 120) - - if self.menu_highlight_background is None: - self.menu_highlight_background = [40, 40, 40, 255] - - if not self.queue_background: - self.queue_background = self.side_panel_background - - if test_lumi(self.queue_background) > 0.8: - self.queue_card_background = alpha_blend([255, 255, 255, 10], self.queue_background) - - if self.menu_background is None and not self.lm: - self.menu_background = self.bottom_panel_colour - - self.message_box_text = self.box_text - self.message_box_border = self.box_border - - if self.window_button_x_on is None: - self.window_button_x_on = self.artist_playing - - if test_lumi(self.column_bar_background) < 0.4: - self.column_bar_text = [40, 40, 40, 200] - self.column_grip = [255, 255, 255, 20] - - def light_mode(self): - - self.lm = True - self.star_line_playing = [255, 255, 255, 255] - self.sys_tab_bg = self.grey(25) - self.sys_tab_hl = self.grey(45) - # self.box_background = self.grey(30) - self.toggle_box_on = self.tab_background_active - # if colour_value(self.tab_background_active) < 250: - # self.toggle_box_on = [255, 255, 255, 200] - - # self.time_sub = [0, 0, 0, 200] - self.gallery_artist_line = self.grey(40) - # self.bar_title_text = self.grey(30) - self.status_text_normal = self.grey(70) - self.status_text_over = self.grey(40) - self.status_info_text = [40, 40, 40, 255] - - # self.bar_title_text = self.grey(255) - self.vis_bg = [235, 235, 235, 255] - # self.menu_background = [240, 240, 240, 250] - # self.menu_text = self.grey(40) - # self.menu_text_disabled = self.grey(180) - # self.menu_highlight_background = [200, 200, 200, 250] - if self.menu_background is None: - self.menu_background = [15, 15, 15, 250] - if not self.menu_icons: - self.menu_icons = [0, 0, 0, 40] - - # self.menu_background = [40, 40, 40, 250] - # self.menu_text = self.grey(220) - # self.menu_text_disabled = self.grey(120) - # self.menu_highlight_background = [120, 80, 220, 250] - - self.corner_button = self.grey(160) - self.corner_button_active = self.grey(35) - # self.window_buttons_bg = [0, 0, 0, 5] - self.message_box_bg = [245, 245, 245, 255] - self.message_box_text = self.grey(20) - self.message_box_border = self.grey(40) - self.gallery_background = self.grey(230) - self.gallery_artist_line = self.grey(40) - self.pluse_colour = [212, 66, 244, 255] - - # view_box.off_colour = self.grey(200) + self.corner_icon = [40, 40, 40, 255] + self.queue_background = None # self.side_panel_background #self.grey(18) # 18 + self.queue_card_background = self.grey(23) + + self.column_bar_background = [30, 30, 30, 255] + self.column_grip = [255, 255, 255, 14] + self.column_bar_text = [240, 240, 240, 255] + + self.window_frame = [30, 30, 30, 255] + + self.box_background = [16, 16, 16, 255] + self.box_border = rgb_add_hls(self.box_background, 0, 0.17, 0) + self.box_text_border = rgb_add_hls(self.box_background, 0, 0.1, 0) + self.box_text_label = rgb_add_hls(self.box_background, 0, 0.32, -0.1) + self.box_sub_highlight = rgb_add_hls(self.box_background, 0, 0.07, -0.05) # 58, 47, 85 + self.box_check_border = [255, 255, 255, 18] + + self.box_title_text = self.grey(245) + self.box_text = self.grey(240) + self.box_sub_text = self.grey_blend_bg(225) + self.box_input_text = self.grey(225) + self.box_button_text_highlight = self.grey(250) + self.box_button_text = self.grey(225) + self.box_button_background = alpha_blend([255, 255, 255, 11], self.box_background) + self.box_thumb_background = None + self.box_button_background_highlight = alpha_blend([255, 255, 255, 20], self.box_background) + + self.artist_bio_background = [27, 27, 27, 255] + self.artist_bio_text = [230, 230, 230, 255] + + def post_config(self): + + if self.box_thumb_background is None: + self.box_thumb_background = alpha_mod(self.box_button_background, 175) + + # Pre calculate alpha blend for spec background + self.vis_bg[0] = int(0.05 * 255 + (1 - 0.05) * self.top_panel_background[0]) + self.vis_bg[1] = int(0.05 * 255 + (1 - 0.05) * self.top_panel_background[1]) + self.vis_bg[2] = int(0.05 * 255 + (1 - 0.05) * self.top_panel_background[2]) + + self.message_box_bg = self.box_background + self.sys_tab_bg = self.tab_background + self.sys_tab_hl = self.tab_background_active + self.toggle_box_on = self.folder_title + self.toggle_box_on = [255, 150, 100, 255] + self.toggle_box_on = self.artist_playing + if colour_value(self.toggle_box_on) < 150: + self.toggle_box_on = [160, 160, 160, 255] + # self.time_sub = [255, 255, 255, 80]#alpha_blend([255, 255, 255, 80], self.bottom_panel_colour) + + self.time_sub = rgb_add_hls(self.bottom_panel_colour, 0, 0.29, 0) + + if test_lumi(colours.bottom_panel_colour) < 0.2: + # self.time_sub = [0, 0, 0, 80] + self.time_sub = rgb_add_hls(self.bottom_panel_colour, 0, -0.15, -0.3) + elif test_lumi(colours.bottom_panel_colour) < 0.8: + self.time_sub = [255, 255, 255, 135] + # self.time_sub = self.mode_button_off + + if self.bar_title_text is None: + self.bar_title_text = self.side_bar_line1 + + self.gallery_artist_line = alpha_mod(self.side_bar_line2, 120) + + if self.menu_highlight_background is None: + self.menu_highlight_background = [40, 40, 40, 255] + + if not self.queue_background: + self.queue_background = self.side_panel_background + + if test_lumi(self.queue_background) > 0.8: + self.queue_card_background = alpha_blend([255, 255, 255, 10], self.queue_background) + + if self.menu_background is None and not self.lm: + self.menu_background = self.bottom_panel_colour + + self.message_box_text = self.box_text + self.message_box_border = self.box_border + + if self.window_button_x_on is None: + self.window_button_x_on = self.artist_playing + + if test_lumi(self.column_bar_background) < 0.4: + self.column_bar_text = [40, 40, 40, 200] + self.column_grip = [255, 255, 255, 20] + + def light_mode(self): + + self.lm = True + self.star_line_playing = [255, 255, 255, 255] + self.sys_tab_bg = self.grey(25) + self.sys_tab_hl = self.grey(45) + # self.box_background = self.grey(30) + self.toggle_box_on = self.tab_background_active + # if colour_value(self.tab_background_active) < 250: + # self.toggle_box_on = [255, 255, 255, 200] + + # self.time_sub = [0, 0, 0, 200] + self.gallery_artist_line = self.grey(40) + # self.bar_title_text = self.grey(30) + self.status_text_normal = self.grey(70) + self.status_text_over = self.grey(40) + self.status_info_text = [40, 40, 40, 255] + + # self.bar_title_text = self.grey(255) + self.vis_bg = [235, 235, 235, 255] + # self.menu_background = [240, 240, 240, 250] + # self.menu_text = self.grey(40) + # self.menu_text_disabled = self.grey(180) + # self.menu_highlight_background = [200, 200, 200, 250] + if self.menu_background is None: + self.menu_background = [15, 15, 15, 250] + if not self.menu_icons: + self.menu_icons = [0, 0, 0, 40] + + # self.menu_background = [40, 40, 40, 250] + # self.menu_text = self.grey(220) + # self.menu_text_disabled = self.grey(120) + # self.menu_highlight_background = [120, 80, 220, 250] + + self.corner_button = self.grey(160) + self.corner_button_active = self.grey(35) + # self.window_buttons_bg = [0, 0, 0, 5] + self.message_box_bg = [245, 245, 245, 255] + self.message_box_text = self.grey(20) + self.message_box_border = self.grey(40) + self.gallery_background = self.grey(230) + self.gallery_artist_line = self.grey(40) + self.pluse_colour = [212, 66, 244, 255] + + # view_box.off_colour = self.grey(200) colours = ColoursClass() @@ -2747,37 +2756,37 @@ def light_mode(self): def set_colour(colour): - SDL_SetRenderDrawColor(renderer, colour[0], colour[1], colour[2], colour[3]) + SDL_SetRenderDrawColor(renderer, colour[0], colour[1], colour[2], colour[3]) def get_themes(deco=False): - themes = [] # full, name - decos = {} - direcs = [install_directory + '/theme'] - if user_directory != install_directory: - direcs.append(user_directory + '/theme') - - def scan_folders(folders): - for folder in folders: - if not os.path.isdir(folder): - continue - paths = [os.path.join(folder, f) for f in os.listdir(folder)] - for path in paths: - if os.path.islink(path): - path = os.readlink(path) - if os.path.isfile(path): - if path[-7:] == '.ttheme': - themes.append((path, os.path.basename(path).split(".")[0])) - elif path[-6:] == '.tdeco': - decos[os.path.basename(path).split(".")[0]] = path - elif os.path.isdir(path): - scan_folders([path]) - - scan_folders(direcs) - themes.sort() - if deco: - return decos - return themes + themes = [] # full, name + decos = {} + direcs = [install_directory + '/theme'] + if user_directory != install_directory: + direcs.append(user_directory + '/theme') + + def scan_folders(folders): + for folder in folders: + if not os.path.isdir(folder): + continue + paths = [os.path.join(folder, f) for f in os.listdir(folder)] + for path in paths: + if os.path.islink(path): + path = os.readlink(path) + if os.path.isfile(path): + if path[-7:] == '.ttheme': + themes.append((path, os.path.basename(path).split(".")[0])) + elif path[-6:] == '.tdeco': + decos[os.path.basename(path).split(".")[0]] = path + elif os.path.isdir(path): + scan_folders([path]) + + scan_folders(direcs) + themes.sort() + if deco: + return decos + return themes # This is legacy. New settings are added straight to the save list (need to overhaul) @@ -2839,17 +2848,17 @@ def __init__(self) -> None: self.misc: list = {} def get_end_folder(direc): - for w in range(len(direc)): - if direc[-w - 1] == '\\' or direc[-w - 1] == '/': - direc = direc[-w:] - return direc - return None + for w in range(len(direc)): + if direc[-w - 1] == '\\' or direc[-w - 1] == '/': + direc = direc[-w:] + return direc + return None def set_path(nt, path): - nt.fullpath = path.replace('\\', '/') - nt.filename = os.path.basename(path) - nt.parent_folder_path = os.path.dirname(path.replace('\\', '/')) - nt.parent_folder_name = get_end_folder(os.path.dirname(path)) - nt.file_ext = os.path.splitext(os.path.basename(path))[1][1:].upper() + nt.fullpath = path.replace('\\', '/') + nt.filename = os.path.basename(path) + nt.parent_folder_path = os.path.dirname(path.replace('\\', '/')) + nt.parent_folder_name = get_end_folder(os.path.dirname(path)) + nt.file_ext = os.path.splitext(os.path.basename(path))[1][1:].upper() class LoadClass: """Object for import track jobs (passed to worker thread)""" @@ -2892,38 +2901,38 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" try: - sp1 = user_directory + "/star.p" - sp2 = user_directory + "/star.p.backup" + sp1 = user_directory + "/star.p" + sp2 = user_directory + "/star.p.backup" - s1 = 0 - s2 = 0 + s1 = 0 + s2 = 0 - if os.path.isfile(sp1): - s1 = os.path.getsize(sp1) - if os.path.isfile(sp2): - s2 = os.path.getsize(sp2) - to_load = sp1 - if s2 > s1: - print("Loading backup star.p") - to_load = sp2 + if os.path.isfile(sp1): + s1 = os.path.getsize(sp1) + if os.path.isfile(sp2): + s2 = os.path.getsize(sp2) + to_load = sp1 + if s2 > s1: + print("Loading backup star.p") + to_load = sp2 - star_store.db = pickle.load(open(to_load, "rb")) + star_store.db = pickle.load(open(to_load, "rb")) except Exception: - print('No existing star.p file') + print('No existing star.p file') try: - album_star_store.db = pickle.load(open(user_directory + "/album-star.p", "rb")) + album_star_store.db = pickle.load(open(user_directory + "/album-star.p", "rb")) except Exception: - print('No existing album-star.p file') + print('No existing album-star.p file') try: - if os.path.isfile(user_directory + "/lyrics_substitutions.json"): - with open(user_directory + "/lyrics_substitutions.json", 'r') as f: - prefs.lyrics_subs = json.load(f) + if os.path.isfile(user_directory + "/lyrics_substitutions.json"): + with open(user_directory + "/lyrics_substitutions.json", 'r') as f: + prefs.lyrics_subs = json.load(f) except Exception: - print("Error loading lyrics_substitutions.json") + print("Error loading lyrics_substitutions.json") perf_timer.set() @@ -2931,41 +2940,41 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" primary_stations = [] station = { - 'title': "SomaFM Groove Salad", - "stream_url": "http://ice3.somafm.com/groovesalad-128-mp3", - 'country': 'USA', - 'website_url': 'http://somafm.com/groovesalad', - 'icon': 'https://somafm.com/logos/120/groovesalad120.png' + 'title': "SomaFM Groove Salad", + "stream_url": "http://ice3.somafm.com/groovesalad-128-mp3", + 'country': 'USA', + 'website_url': 'http://somafm.com/groovesalad', + 'icon': 'https://somafm.com/logos/120/groovesalad120.png' } primary_stations.append(station) station = { - 'title': "SomaFM PopTron", - "stream_url": "http://ice3.somafm.com/poptron-128-mp3", - 'country': 'USA', - 'website_url': 'http://somafm.com/poptron/', - 'icon': 'https://somafm.com/logos/120/poptron120.jpg' + 'title': "SomaFM PopTron", + "stream_url": "http://ice3.somafm.com/poptron-128-mp3", + 'country': 'USA', + 'website_url': 'http://somafm.com/poptron/', + 'icon': 'https://somafm.com/logos/120/poptron120.jpg' } primary_stations.append(station) station = { - 'title': "SomaFM Vaporwaves", - "stream_url": "http://ice4.somafm.com/vaporwaves-128-mp3", - 'country': 'USA', - 'website_url': 'https://somafm.com/vaporwaves', - 'icon': 'https://somafm.com/img3/vaporwaves400.png' + 'title': "SomaFM Vaporwaves", + "stream_url": "http://ice4.somafm.com/vaporwaves-128-mp3", + 'country': 'USA', + 'website_url': 'https://somafm.com/vaporwaves', + 'icon': 'https://somafm.com/img3/vaporwaves400.png' } primary_stations.append(station) station = { - 'title': "DKFM Shoegaze Radio", - "stream_url": "https://kathy.torontocast.com:2005/stream", - 'country': 'Canada', - 'website_url': 'https://decayfm.com', - 'icon': 'https://cdn-profiles.tunein.com/s193842/images/logod.png' + 'title': "DKFM Shoegaze Radio", + "stream_url": "https://kathy.torontocast.com:2005/stream", + 'country': 'Canada', + 'website_url': 'https://decayfm.com', + 'icon': 'https://cdn-profiles.tunein.com/s193842/images/logod.png' } primary_stations.append(station) for item in primary_stations: - radio_playlists[0]["items"].append(item) + radio_playlists[0]["items"].append(item) radio_playlist_viewing = 0 @@ -2973,11 +2982,11 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" def pumper(): - if macos: - return - while pump: - time.sleep(0.005) - SDL_PumpEvents() + if macos: + return + while pump: + time.sleep(0.005) + SDL_PumpEvents() shoot_pump = threading.Thread(target=pumper) @@ -2985,391 +2994,391 @@ def pumper(): shoot_pump.start() for t in range(2): - try: - - # if os.path.isfile(user_directory + "/state.p.backup") and ( - # - # not os.path.isfile(user_directory + "/state.p") or - # os.path.getsize(user_directory + "/state.p") < 100 - # ) - if t == 0: - state_file = open(user_directory + "/state.p", "rb") - if t == 1: - state_file = open(user_directory + "/state.p.backup", "rb") - - # def tt(): - # while True: - # print(state_file.tell()) - # time.sleep(0.01) - # shooter(tt) - - save = pickle.load(state_file) - - if t == 1: - print("Using backup state") - - if save[63] is not None: - prefs.ui_scale = save[63] - # prefs.ui_scale = 1.3 - # gui.__init__() - - if save[0] is not None: - master_library = save[0] - master_count = save[1] - playlist_playing = save[2] - playlist_active = save[3] - playlist_view_position = save[4] - multi_playlist = save[5] - volume = save[6] - QUE = save[7] - playing_in_queue = save[8] - default_playlist = save[9] - # playlist_playing = save[10] - # cue_list = save[11] - # radio_field_text = save[12] - theme = save[13] - folder_image_offsets = save[14] - # lfm_username = save[15] - # lfm_hash = save[16] - db_version = save[17] - view_prefs = save[18] - # window_size = save[19] - gui.save_size = copy.copy(save[19]) - gui.rspw = save[20] - # savetime = save[21] - gui.vis_want = save[22] - selected_in_playlist = save[23] - if save[24] is not None: - album_mode_art_size = save[24] - if save[25] is not None: - draw_border = save[25] - if save[26] is not None: - prefs.enable_web = save[26] - if save[27] is not None: - prefs.allow_remote = save[27] - if save[28] is not None: - prefs.expose_web = save[28] - if save[29] is not None: - prefs.enable_transcode = save[29] - if save[30] is not None: - prefs.show_rym = save[30] - # if save[31] is not None: - # combo_mode_art_size = save[31] - if save[32] is not None: - gui.maximized = save[32] - if save[33] is not None: - prefs.prefer_bottom_title = save[33] - if save[34] is not None: - gui.display_time_mode = save[34] - # if save[35] is not None: - # prefs.transcode_mode = save[35] - if save[36] is not None: - prefs.transcode_codec = save[36] - if save[37] is not None: - prefs.transcode_bitrate = save[37] - # if save[38] is not None: - # prefs.line_style = save[38] - # if save[39] is not None: - # prefs.cache_gallery = save[39] - if save[40] is not None: - prefs.playlist_font_size = save[40] - if save[41] is not None: - prefs.use_title = save[41] - if save[42] is not None: - gui.pl_st = save[42] - # if save[43] is not None: - # gui.set_mode = save[43] - # gui.set_bar = gui.set_mode - if save[45] is not None: - prefs.playlist_row_height = save[45] - if save[46] is not None: - prefs.show_wiki = save[46] - if save[47] is not None: - prefs.auto_extract = save[47] - if save[48] is not None: - prefs.colour_from_image = save[48] - if save[49] is not None: - gui.set_bar = save[49] - if save[50] is not None: - gui.gallery_show_text = save[50] - if save[51] is not None: - gui.bb_show_art = save[51] - # if save[52] is not None: - # gui.show_stars = save[52] - if save[53] is not None: - prefs.auto_lfm = save[53] - if save[54] is not None: - prefs.scrobble_mark = save[54] - if save[55] is not None: - prefs.replay_gain = save[55] - # if save[56] is not None: - # prefs.radio_page_lyrics = save[56] - if save[57] is not None: - prefs.show_gimage = save[57] - if save[58] is not None: - prefs.end_setting = save[58] - if save[59] is not None: - prefs.show_gen = save[59] - # if save[60] is not None: - # url_saves = save[60] - if save[61] is not None: - prefs.auto_del_zip = save[61] - if save[62] is not None: - gui.level_meter_colour_mode = save[62] - if save[64] is not None: - prefs.show_lyrics_side = save[64] - # if save[65] is not None: - # prefs.last_device = save[65] - if save[66] is not None: - gui.restart_album_mode = save[66] - if save[67] is not None: - album_playlist_width = save[67] - if save[68] is not None: - prefs.transcode_opus_as = save[68] - if save[69] is not None: - gui.star_mode = save[69] - if save[70] is not None: - gui.rsp = save[70] - if save[71] is not None: - gui.lsp = save[71] - if save[72] is not None: - gui.rspw = save[72] - if save[73] is not None: - gui.pref_gallery_w = save[73] - if save[74] is not None: - gui.pref_rspw = save[74] - if save[75] is not None: - gui.show_hearts = save[75] - if save[76] is not None: - prefs.monitor_downloads = save[76] - if save[77] is not None: - gui.artist_info_panel = save[77] - if save[78] is not None: - prefs.extract_to_music = save[78] - if save[79] is not None: - prefs.enable_lb = save[79] - # if save[80] is not None: - # prefs.lb_token = save[80] - # if prefs.lb_token is None: - # prefs.lb_token = "" - if save[81] is not None: - rename_files_previous = save[81] - if save[82] is not None: - rename_folder_previous = save[82] - if save[83] is not None: - prefs.use_jump_crossfade = save[83] - if save[84] is not None: - prefs.use_transition_crossfade = save[84] - if save[85] is not None: - prefs.show_notifications = save[85] - # if save[86] is not None: - # prefs.true_shuffle = save[86] - if save[87] is not None: - gui.remember_library_mode = save[87] - # if save[88] is not None: - # prefs.show_queue = save[88] - # if save[89] is not None: - # prefs.show_transfer = save[89] - if save[90] is not None: - p_force_queue = save[90] - if save[91] is not None: - prefs.use_pause_fade = save[91] - if save[92] is not None: - prefs.append_total_time = save[92] - if save[93] is not None: - prefs.backend = save[93] # moved to config file - if save[94] is not None: - prefs.album_shuffle_mode = save[94] - if save[95] is not None: - prefs.album_repeat_mode = save[95] - # if save[96] is not None: - # prefs.finish_current = save[96] - if save[97] is not None: - reload_state = save[97] - # if save[98] is not None: - # prefs.reload_play_state = save[98] - if save[99] is not None: - prefs.last_fm_token = save[99] - if save[100] is not None: - prefs.last_fm_username = save[100] - # if save[101] is not None: - # prefs.use_card_style = save[101] - # if save[102] is not None: - # prefs.auto_lyrics = save[102] - if save[103] is not None: - prefs.auto_lyrics_checked = save[103] - if save[104] is not None: - prefs.show_side_art = save[104] - if save[105] is not None: - prefs.window_opacity = save[105] - if save[106] is not None: - prefs.gallery_single_click = save[106] - if save[107] is not None: - prefs.tabs_on_top = save[107] - if save[108] is not None: - prefs.showcase_vis = save[108] - if save[109] is not None: - prefs.spec2_colour_mode = save[109] - # if save[110] is not None: - # prefs.device_buffer = save[110] - if save[111] is not None: - prefs.use_eq = save[111] - if save[112] is not None: - prefs.eq = save[112] - if save[113] is not None: - prefs.bio_large = save[113] - if save[114] is not None: - prefs.discord_show = save[114] - if save[115] is not None: - prefs.min_to_tray = save[115] - if save[116] is not None: - prefs.guitar_chords = save[116] - if save[117] is not None: - prefs.playback_follow_cursor = save[117] - if save[118] is not None: - prefs.art_bg = save[118] - if save[119] is not None: - prefs.random_mode = save[119] - if save[120] is not None: - prefs.repeat_mode = save[120] - if save[121] is not None: - prefs.art_bg_stronger = save[121] - if save[122] is not None: - prefs.art_bg_always_blur = save[122] - if save[123] is not None: - prefs.failed_artists = save[123] - if save[124] is not None: - prefs.artist_list = save[124] - if save[125] is not None: - prefs.auto_sort = save[125] - if save[126] is not None: - prefs.lyrics_enables = save[126] - if save[127] is not None: - prefs.fanart_notify = save[127] - if save[128] is not None: - prefs.bg_showcase_only = save[128] - if save[129] is not None: - prefs.discogs_pat = save[129] - if save[130] is not None: - prefs.mini_mode_mode = save[130] - if save[131] is not None: - after_scan = save[131] - if save[132] is not None: - gui.gallery_positions = save[132] - if save[133] is not None: - prefs.chart_bg = save[133] - if save[134] is not None: - prefs.left_panel_mode = save[134] - if save[135] is not None: - gui.last_left_panel_mode = save[135] - # if save[136] is not None: - # prefs.gst_device = save[136] - if save[137] is not None: - search_string_cache = save[137] - if save[138] is not None: - search_dia_string_cache = save[138] - if save[139] is not None: - gen_codes = save[139] - if save[140] is not None: - gui.show_ratings = save[140] - if save[141] is not None: - gui.show_album_ratings = save[141] - if save[142] is not None: - prefs.radio_urls = save[142] - if save[143] is not None: - gui.restore_showcase_view = save[143] - if save[144] is not None: - gui.saved_prime_tab = save[144] - if save[145] is not None: - gui.saved_prime_direction = save[145] - if save[146] is not None: - prefs.sync_playlist = save[146] - if save[147] is not None: - prefs.spot_client = save[147] - if save[148] is not None: - prefs.spot_secret = save[148] - if save[149] is not None: - prefs.show_band = save[149] - if save[150] is not None: - prefs.download_playlist = save[150] - if save[151] is not None: - spot_cache_saved_albums = save[151] - if save[152] is not None: - prefs.auto_rec = save[152] - if save[153] is not None: - prefs.spotify_token = save[153] - if save[154] is not None: - prefs.use_libre_fm = save[154] - if save[155] is not None: - prefs.old_playlist_box_position = save[155] - if save[156] is not None: - prefs.artist_list_sort_mode = save[156] - if save[157] is not None: - prefs.phazor_device_selected = save[157] - if save[158] is not None: - prefs.failed_background_artists = save[158] - if save[159] is not None: - prefs.bg_flips = save[159] - if save[160] is not None: - prefs.tray_show_title = save[160] - if save[161] is not None: - prefs.artist_list_style = save[161] - if save[162] is not None: - ds = save[162] - for d in ds: - nt = TrackClass() - nt.__dict__.update(d) - master_library[d["index"]] = nt - if save[163] is not None: - prefs.premium = save[163] - if save[164] is not None: - gui.restore_radio_view = save[164] - if save[165] is not None: - radio_playlists = save[165] - if save[166] is not None: - radio_playlist_viewing = save[166] - if save[167] is not None: - prefs.radio_thumb_bans = save[167] - if save[168] is not None: - prefs.playlist_exports = save[168] - if save[169] is not None: - prefs.show_chromecast = save[169] - if save[170] is not None: - prefs.cache_list = save[170] - if save[171] is not None: - prefs.shuffle_lock = save[171] - if save[172] is not None: - prefs.album_shuffle_lock_mode = save[172] - if save[173] is not None: - gui.was_radio = save[173] - if save[174] is not None: - prefs.spot_username = save[174] - if save[175] is not None: - prefs.spot_password = save[175] - if save[176] is not None: - prefs.artist_list_threshold = save[176] - if save[177] is not None: - prefs.tray_theme = save[177] - if save[178] is not None: - prefs.row_title_format = save[178] - if save[179] is not None: - prefs.row_title_genre = save[179] - if save[180] is not None: - prefs.row_title_separator_type = save[180] - if save[181] is not None: - prefs.replay_preamp = save[181] - if save[182] is not None: - prefs.gallery_combine_disc = save[182] - - state_file.close() - del save - break - - except IndexError: - break - except Exception: - if os.path.isfile(user_directory + "/state.p"): - print('Error loading save file') + try: + + # if os.path.isfile(user_directory + "/state.p.backup") and ( + # + # not os.path.isfile(user_directory + "/state.p") or + # os.path.getsize(user_directory + "/state.p") < 100 + # ) + if t == 0: + state_file = open(user_directory + "/state.p", "rb") + if t == 1: + state_file = open(user_directory + "/state.p.backup", "rb") + + # def tt(): + # while True: + # print(state_file.tell()) + # time.sleep(0.01) + # shooter(tt) + + save = pickle.load(state_file) + + if t == 1: + print("Using backup state") + + if save[63] is not None: + prefs.ui_scale = save[63] + # prefs.ui_scale = 1.3 + # gui.__init__() + + if save[0] is not None: + master_library = save[0] + master_count = save[1] + playlist_playing = save[2] + playlist_active = save[3] + playlist_view_position = save[4] + multi_playlist = save[5] + volume = save[6] + QUE = save[7] + playing_in_queue = save[8] + default_playlist = save[9] + # playlist_playing = save[10] + # cue_list = save[11] + # radio_field_text = save[12] + theme = save[13] + folder_image_offsets = save[14] + # lfm_username = save[15] + # lfm_hash = save[16] + db_version = save[17] + view_prefs = save[18] + # window_size = save[19] + gui.save_size = copy.copy(save[19]) + gui.rspw = save[20] + # savetime = save[21] + gui.vis_want = save[22] + selected_in_playlist = save[23] + if save[24] is not None: + album_mode_art_size = save[24] + if save[25] is not None: + draw_border = save[25] + if save[26] is not None: + prefs.enable_web = save[26] + if save[27] is not None: + prefs.allow_remote = save[27] + if save[28] is not None: + prefs.expose_web = save[28] + if save[29] is not None: + prefs.enable_transcode = save[29] + if save[30] is not None: + prefs.show_rym = save[30] + # if save[31] is not None: + # combo_mode_art_size = save[31] + if save[32] is not None: + gui.maximized = save[32] + if save[33] is not None: + prefs.prefer_bottom_title = save[33] + if save[34] is not None: + gui.display_time_mode = save[34] + # if save[35] is not None: + # prefs.transcode_mode = save[35] + if save[36] is not None: + prefs.transcode_codec = save[36] + if save[37] is not None: + prefs.transcode_bitrate = save[37] + # if save[38] is not None: + # prefs.line_style = save[38] + # if save[39] is not None: + # prefs.cache_gallery = save[39] + if save[40] is not None: + prefs.playlist_font_size = save[40] + if save[41] is not None: + prefs.use_title = save[41] + if save[42] is not None: + gui.pl_st = save[42] + # if save[43] is not None: + # gui.set_mode = save[43] + # gui.set_bar = gui.set_mode + if save[45] is not None: + prefs.playlist_row_height = save[45] + if save[46] is not None: + prefs.show_wiki = save[46] + if save[47] is not None: + prefs.auto_extract = save[47] + if save[48] is not None: + prefs.colour_from_image = save[48] + if save[49] is not None: + gui.set_bar = save[49] + if save[50] is not None: + gui.gallery_show_text = save[50] + if save[51] is not None: + gui.bb_show_art = save[51] + # if save[52] is not None: + # gui.show_stars = save[52] + if save[53] is not None: + prefs.auto_lfm = save[53] + if save[54] is not None: + prefs.scrobble_mark = save[54] + if save[55] is not None: + prefs.replay_gain = save[55] + # if save[56] is not None: + # prefs.radio_page_lyrics = save[56] + if save[57] is not None: + prefs.show_gimage = save[57] + if save[58] is not None: + prefs.end_setting = save[58] + if save[59] is not None: + prefs.show_gen = save[59] + # if save[60] is not None: + # url_saves = save[60] + if save[61] is not None: + prefs.auto_del_zip = save[61] + if save[62] is not None: + gui.level_meter_colour_mode = save[62] + if save[64] is not None: + prefs.show_lyrics_side = save[64] + # if save[65] is not None: + # prefs.last_device = save[65] + if save[66] is not None: + gui.restart_album_mode = save[66] + if save[67] is not None: + album_playlist_width = save[67] + if save[68] is not None: + prefs.transcode_opus_as = save[68] + if save[69] is not None: + gui.star_mode = save[69] + if save[70] is not None: + gui.rsp = save[70] + if save[71] is not None: + gui.lsp = save[71] + if save[72] is not None: + gui.rspw = save[72] + if save[73] is not None: + gui.pref_gallery_w = save[73] + if save[74] is not None: + gui.pref_rspw = save[74] + if save[75] is not None: + gui.show_hearts = save[75] + if save[76] is not None: + prefs.monitor_downloads = save[76] + if save[77] is not None: + gui.artist_info_panel = save[77] + if save[78] is not None: + prefs.extract_to_music = save[78] + if save[79] is not None: + prefs.enable_lb = save[79] + # if save[80] is not None: + # prefs.lb_token = save[80] + # if prefs.lb_token is None: + # prefs.lb_token = "" + if save[81] is not None: + rename_files_previous = save[81] + if save[82] is not None: + rename_folder_previous = save[82] + if save[83] is not None: + prefs.use_jump_crossfade = save[83] + if save[84] is not None: + prefs.use_transition_crossfade = save[84] + if save[85] is not None: + prefs.show_notifications = save[85] + # if save[86] is not None: + # prefs.true_shuffle = save[86] + if save[87] is not None: + gui.remember_library_mode = save[87] + # if save[88] is not None: + # prefs.show_queue = save[88] + # if save[89] is not None: + # prefs.show_transfer = save[89] + if save[90] is not None: + p_force_queue = save[90] + if save[91] is not None: + prefs.use_pause_fade = save[91] + if save[92] is not None: + prefs.append_total_time = save[92] + if save[93] is not None: + prefs.backend = save[93] # moved to config file + if save[94] is not None: + prefs.album_shuffle_mode = save[94] + if save[95] is not None: + prefs.album_repeat_mode = save[95] + # if save[96] is not None: + # prefs.finish_current = save[96] + if save[97] is not None: + reload_state = save[97] + # if save[98] is not None: + # prefs.reload_play_state = save[98] + if save[99] is not None: + prefs.last_fm_token = save[99] + if save[100] is not None: + prefs.last_fm_username = save[100] + # if save[101] is not None: + # prefs.use_card_style = save[101] + # if save[102] is not None: + # prefs.auto_lyrics = save[102] + if save[103] is not None: + prefs.auto_lyrics_checked = save[103] + if save[104] is not None: + prefs.show_side_art = save[104] + if save[105] is not None: + prefs.window_opacity = save[105] + if save[106] is not None: + prefs.gallery_single_click = save[106] + if save[107] is not None: + prefs.tabs_on_top = save[107] + if save[108] is not None: + prefs.showcase_vis = save[108] + if save[109] is not None: + prefs.spec2_colour_mode = save[109] + # if save[110] is not None: + # prefs.device_buffer = save[110] + if save[111] is not None: + prefs.use_eq = save[111] + if save[112] is not None: + prefs.eq = save[112] + if save[113] is not None: + prefs.bio_large = save[113] + if save[114] is not None: + prefs.discord_show = save[114] + if save[115] is not None: + prefs.min_to_tray = save[115] + if save[116] is not None: + prefs.guitar_chords = save[116] + if save[117] is not None: + prefs.playback_follow_cursor = save[117] + if save[118] is not None: + prefs.art_bg = save[118] + if save[119] is not None: + prefs.random_mode = save[119] + if save[120] is not None: + prefs.repeat_mode = save[120] + if save[121] is not None: + prefs.art_bg_stronger = save[121] + if save[122] is not None: + prefs.art_bg_always_blur = save[122] + if save[123] is not None: + prefs.failed_artists = save[123] + if save[124] is not None: + prefs.artist_list = save[124] + if save[125] is not None: + prefs.auto_sort = save[125] + if save[126] is not None: + prefs.lyrics_enables = save[126] + if save[127] is not None: + prefs.fanart_notify = save[127] + if save[128] is not None: + prefs.bg_showcase_only = save[128] + if save[129] is not None: + prefs.discogs_pat = save[129] + if save[130] is not None: + prefs.mini_mode_mode = save[130] + if save[131] is not None: + after_scan = save[131] + if save[132] is not None: + gui.gallery_positions = save[132] + if save[133] is not None: + prefs.chart_bg = save[133] + if save[134] is not None: + prefs.left_panel_mode = save[134] + if save[135] is not None: + gui.last_left_panel_mode = save[135] + # if save[136] is not None: + # prefs.gst_device = save[136] + if save[137] is not None: + search_string_cache = save[137] + if save[138] is not None: + search_dia_string_cache = save[138] + if save[139] is not None: + gen_codes = save[139] + if save[140] is not None: + gui.show_ratings = save[140] + if save[141] is not None: + gui.show_album_ratings = save[141] + if save[142] is not None: + prefs.radio_urls = save[142] + if save[143] is not None: + gui.restore_showcase_view = save[143] + if save[144] is not None: + gui.saved_prime_tab = save[144] + if save[145] is not None: + gui.saved_prime_direction = save[145] + if save[146] is not None: + prefs.sync_playlist = save[146] + if save[147] is not None: + prefs.spot_client = save[147] + if save[148] is not None: + prefs.spot_secret = save[148] + if save[149] is not None: + prefs.show_band = save[149] + if save[150] is not None: + prefs.download_playlist = save[150] + if save[151] is not None: + spot_cache_saved_albums = save[151] + if save[152] is not None: + prefs.auto_rec = save[152] + if save[153] is not None: + prefs.spotify_token = save[153] + if save[154] is not None: + prefs.use_libre_fm = save[154] + if save[155] is not None: + prefs.old_playlist_box_position = save[155] + if save[156] is not None: + prefs.artist_list_sort_mode = save[156] + if save[157] is not None: + prefs.phazor_device_selected = save[157] + if save[158] is not None: + prefs.failed_background_artists = save[158] + if save[159] is not None: + prefs.bg_flips = save[159] + if save[160] is not None: + prefs.tray_show_title = save[160] + if save[161] is not None: + prefs.artist_list_style = save[161] + if save[162] is not None: + ds = save[162] + for d in ds: + nt = TrackClass() + nt.__dict__.update(d) + master_library[d["index"]] = nt + if save[163] is not None: + prefs.premium = save[163] + if save[164] is not None: + gui.restore_radio_view = save[164] + if save[165] is not None: + radio_playlists = save[165] + if save[166] is not None: + radio_playlist_viewing = save[166] + if save[167] is not None: + prefs.radio_thumb_bans = save[167] + if save[168] is not None: + prefs.playlist_exports = save[168] + if save[169] is not None: + prefs.show_chromecast = save[169] + if save[170] is not None: + prefs.cache_list = save[170] + if save[171] is not None: + prefs.shuffle_lock = save[171] + if save[172] is not None: + prefs.album_shuffle_lock_mode = save[172] + if save[173] is not None: + gui.was_radio = save[173] + if save[174] is not None: + prefs.spot_username = save[174] + if save[175] is not None: + prefs.spot_password = save[175] + if save[176] is not None: + prefs.artist_list_threshold = save[176] + if save[177] is not None: + prefs.tray_theme = save[177] + if save[178] is not None: + prefs.row_title_format = save[178] + if save[179] is not None: + prefs.row_title_genre = save[179] + if save[180] is not None: + prefs.row_title_separator_type = save[180] + if save[181] is not None: + prefs.replay_preamp = save[181] + if save[182] is not None: + prefs.gallery_combine_disc = save[182] + + state_file.close() + del save + break + + except IndexError: + break + except Exception: + if os.path.isfile(user_directory + "/state.p"): + print('Error loading save file') core_timer.set() print(f"Database loaded in {round(perf_timer.get(), 3)} seconds.") @@ -3377,9 +3386,9 @@ def pumper(): perf_timer.set() keys = set(master_library.keys()) for pl in multi_playlist: - keys -= set(pl[2]) + keys -= set(pl[2]) if len(keys) > 5000: - gui.suggest_clean_db = True + gui.suggest_clean_db = True # print(f"Database scanned in {round(perf_timer.get(), 3)} seconds.") pump = False @@ -3387,506 +3396,510 @@ def pumper(): # temporary if window_size is None: - window_size = window_default_size - gui.rspw = 200 + window_size = window_default_size + gui.rspw = 200 def track_number_process(line): - line = str(line).split("/", 1)[0].lstrip("0") - if prefs.dd_index and len(line) == 1: - return "0" + line - return line + line = str(line).split("/", 1)[0].lstrip("0") + if prefs.dd_index and len(line) == 1: + return "0" + line + return line def advance_theme(): - global theme + global theme - theme += 1 - gui.reload_theme = True + theme += 1 + gui.reload_theme = True def get_theme_number(name): - if name == "Mindaro": - return 0 - themes = get_themes() - for i, theme in enumerate(themes): - if theme[1] == name: - return i + 1 - return 0 + if name == "Mindaro": + return 0 + themes = get_themes() + for i, theme in enumerate(themes): + if theme[1] == name: + return i + 1 + return 0 def get_theme_name(number): - if number == 0: - return 'Mindaro' - number -= 1 - themes = get_themes() - print((number, themes)) - if len(themes) > number: - return themes[number][1] - return "" + if number == 0: + return 'Mindaro' + number -= 1 + themes = get_themes() + print((number, themes)) + if len(themes) > number: + return themes[number][1] + return "" # Upgrading from older versions if db_version > 0: - if db_version <= 0.8: - print("Updating database from version 0.8 to 0.9") - for key, value in master_library.items(): - setattr(master_library[key], 'skips', 0) - - if db_version <= 0.9: - print("Updating database from version 0.9 to 1.1") - for key, value in master_library.items(): - setattr(master_library[key], 'comment', "") - - if db_version <= 1.1: - print("Updating database from version 1.1 to 1.2") - for key, value in master_library.items(): - setattr(master_library[key], 'album_artist', "") - - if db_version <= 1.2: - print("Updating database to version 1.3") - for key, value in master_library.items(): - setattr(master_library[key], 'disc_number', "") - setattr(master_library[key], 'disc_total', "") - - if db_version <= 1.3: - print("Updating database to version 1.4") - for key, value in master_library.items(): - setattr(master_library[key], 'lyrics', "") - setattr(master_library[key], 'track_total', "") - show_message( - "Upgrade complete. Note: New attributes such as disk number won't show for existing tracks (delete state.p to reset)") - - if db_version <= 1.4: - print("Updating database to version 1.5") - for playlist in multi_playlist: - playlist.append(uid_gen()) - - if db_version <= 1.5: - print("Updating database to version 1.6") - for i in range(len(multi_playlist)): - if len(multi_playlist[i]) == 7: - multi_playlist[i].append("") - - if db_version <= 1.6: - print("Updating preferences to 1.7") - # gui.show_stars = False - if install_mode: - # shutil.copy(install_directory + "/config.txt", user_directory) - print("Rewrote user config file") - - if db_version <= 1.7: - print("Updating database to version 1.8") - if install_mode: - print(".... Overwriting user config file") - # shutil.copy(install_directory + "/config.txt", user_directory) - - try: - print(".... Updating playtime database") - - old = star_store.db - # perf_timer.set() - old_total = sum(old.values()) - # print(perf_timer.get()) - print("Old total: ", end='') - print(old_total) - star_store.db = {} - - new = {} - for track in master_library.values(): - key = track.title + track.filename - if key in old: - n_value = [old[key], ""] - n_key = star_store.object_key(track) - star_store.db[n_key] = n_value - - print("New total: ", end='') - diff = old_total - star_store.get_total() - print(int(diff), end='') - print(" Secconds could not be matched to tracks. Total playtime won't be affected") - star_store.db[("", "", "LOST")] = [diff, ""] - print("Upgrade Complete") - except Exception: - print("Error upgrading database") - show_message(_("Error loading old database, did the program not exit properly after updating? Oh well.")) - - if db_version <= 1.8: - print("Updating database to 1.9") - for key, value in master_library.items(): - setattr(master_library[key], 'track_gain', None) - setattr(master_library[key], 'album_gain', None) - show_message(_("Upgrade complete. Run a tag rescan if you want enable ReplayGain")) - - if db_version <= 1.9: - print("Updating database to version 2.0") - for key, value in master_library.items(): - setattr(master_library[key], 'modified_time', 0) - show_message(_("Upgrade complete. New sorting option may require tag rescan.")) - - if db_version <= 2.0: - print("Updating database to version 2.1") - for key, value in master_library.items(): - setattr(master_library[key], 'is_embed_cue', False) - setattr(master_library[key], 'cue_sheet', "") - show_message(_("Updated to v2.6.3")) - - if db_version <= 2.1: - print("Updating database to version 2.1") - for key, value in master_library.items(): - setattr(master_library[key], 'lfm_friend_likes', set()) - - if db_version <= 2.2: - for i in range(len(multi_playlist)): - if len(multi_playlist[i]) < 9: - multi_playlist[i].append(True) - - if db_version <= 2.3: - print("Updating database to version 2.4") - for key, value in master_library.items(): - setattr(master_library[key], 'bit_depth', 0) - - if db_version <= 2.4: - if theme > 0: - theme += 1 - - if db_version <= 2.5: - print("Updating database to version 2.6") - for key, value in master_library.items(): - setattr(master_library[key], 'is_network', False) - # for i in range(len(multi_playlist)): - # if len(multi_playlist[i]) < 10: - # multi_playlist[i].append(False) - - if db_version <= 26: - print("Updating database to version 27") - for i in range(len(multi_playlist)): - if len(multi_playlist[i]) == 9: - multi_playlist[i].append(False) - - if db_version <= 27: - print("Updating database to version 28") - for i in range(len(multi_playlist)): - if len(multi_playlist[i]) <= 10: - multi_playlist[i].append("") - - if db_version <= 29: - print("Updating database to version 30") - for key, value in master_library.items(): - setattr(master_library[key], 'composer', "") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("global-search G Ctrl\n") - f.write("cycle-theme-reverse\n") - f.write("reload-theme F10\n") - - show_message(_("Welcome to v4.4.0. Run a tag rescan if you want enable Composer metadata.")) - - if db_version <= 30: - for i, item in enumerate(p_force_queue): - try: - assert item[6] - except Exception: - p_force_queue[i].append(False) - - if db_version <= 31: - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("love-selected\n") - gui.set_bar = True - - if db_version <= 32: - if theme > 1: - theme += 1 - - if db_version <= 33: - print("Update to db 34") - for key, value in master_library.items(): - if not hasattr(master_library[key], 'misc'): - setattr(master_library[key], 'misc', {}) - - if db_version <= 34: - print("Update to dv 35") - # Moved to after config load - - if db_version <= 35: - print("Updating database to version 36") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("toggle-show-art H Ctrl\n") - - if db_version <= 37: - print("Updating database to version 38") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("toggle-console `\n") - - if db_version <= 38: - print("Updating database to version 39") - - for key, value in star_store.db.items(): - print(value) - if len(value) == 2: - value.append(0) - star_store.db[key] = value - - if db_version <= 39: - print("Updating database to version 40") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - f = open(os.path.join(config_directory, "input.txt"), 'r') - text = f.read() - f.close() - lines = text.splitlines() - if "l ctrl" not in text.lower(): - f = open(os.path.join(config_directory, "input.txt"), 'w') - for line in lines: - line = line.strip() - if line == "love-selected": - line = "love-selected L Ctrl" - f.write(line + "\n") - f.close() - - if db_version <= 40: - print("Updating database to version 41") - old = copy.deepcopy(prefs.lyrics_enables) - prefs.lyrics_enables.clear() - if "apiseeds" in old: - prefs.lyrics_enables.append("Apiseeds") - if "lyricwiki" in old: - prefs.lyrics_enables.append("LyricWiki") - if "genius" in old: - prefs.lyrics_enables.append("Genius") - - if db_version <= 41: - print("Updating database to version 42") - - for key, value in gen_codes.items(): - gen_codes[key] = value.replace("f\"", "p\"") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - f = open(os.path.join(config_directory, "input.txt"), 'r') - text = f.read() - f.close() - lines = text.splitlines() - - f = open(os.path.join(config_directory, "input.txt"), 'w') - for line in lines: - line = line.strip() - if "rename-playlist" in line: - - f.write(line + "\n") - - line = "new-playlist T Ctrl\n" - f.write(line) - - line = "\nnew-generator-playlist\n" - f.write(line) - if "e ctrl" in text.lower(): - line = "edit-generator\n\n" - else: - line = "edit-generator E Ctrl\n\n" - f.write(line) - - line = "search-lyrics-selected\n" - f.write(line) - line = "substitute-search-selected" - - f.write(line + "\n") - - f.close() - - if db_version <= 42: - print("Updating database to version 43") - - if db_version <= 43: - print("Updating database to version 44") - # Repair db - for key, value in star_store.db.items(): - if len(value) == 2: - value.append(0) - star_store.db[key] = value - - if db_version <= 44: - print("Updating database to version 45") - print("Cleaning cache directory") - for item in os.listdir(cache_directory): - path = os.path.join(cache_directory, item) - if "-lfm." in item or "-ftv." in item or "-dcg." in item: - os.rename(path, os.path.join(a_cache_dir, item)) - for item in os.listdir(cache_directory): - path = os.path.join(cache_directory, item) - if os.path.isfile(path): - os.remove(path) - - if db_version <= 45: - print("Updating database to version 46") - for p in multi_playlist: - if type(p[7]) != list: - p[7] = [p[7]] - - if db_version <= 46: - print("Updating database to version 47") - for p in multi_playlist: - if type(p[7]) != list: - p[7] = [p[7]] - - if db_version <= 47: - print("Updating database to version 48") - if os.path.isfile(os.path.join(user_directory, "spot-r-token")): - show_message(_("Welcome to v6.1.0. Due to changes, please re-authorise Spotify"), - _("You can do this by clicking 'Forget Account', then 'Authroise' in Settings > Accounts > Spotify")) - - if db_version <= 48: - print("Fix bad upgrade, now 49") - for key, value in master_library.items(): - if not hasattr(master_library[key], 'url_key'): - setattr(master_library[key], 'url_key', "") - if not hasattr(master_library[key], 'art_url_key'): - setattr(master_library[key], 'art_url_key', "") - - if db_version <= 49: - print("Updating database to version 50") - if os.path.isfile(os.path.join(user_directory, "spot-r-token")): - show_message(_("Welcome to v6.3.0. Due to an upgrade, please re-authorise Spotify"), - _("You can do this by clicking 'Authroise' in Settings > Accounts > Spotify")) - os.remove(os.path.join(user_directory, "spot-r-token")) - - if db_version <= 54: - print("Updating database to version 55") - for key, value in master_library.items(): - setattr(master_library[key], 'lfm_scrobbles', 0) - - if db_version <= 55: - print("Update to db 56") - for key, value in master_library.items(): - - if hasattr(value, "track_gain"): - if value.track_gain != 0: - value.misc["replaygain_track_gain"] = value.track_gain - del value.track_gain - - if hasattr(value, "album_gain"): - if value.album_gain != 0: - value.misc["replaygain_album_gain"] = value.album_gain - del value.album_gain - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("toggle-right-panel MB5\n") - f.write("toggle-gallery MB4\n") - - if db_version <= 56: - print("Update to db 57") - if "Apiseeds" in prefs.lyrics_enables: - prefs.lyrics_enables.remove("Apiseeds") - prefs.lyrics_enables.append("Happi") - - if db_version <= 57: - print("Updating database to version 58") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\nregenerate-playlist R Alt\n") - f.write("clear-queue Q Shift Alt\n") - f.write("resize-window-16:9 F11 Alt\n") - f.write("delete-playlist-force W Shift Ctrl\n") - - if db_version <= 58: - print("Updating database to version 59") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\nrandom-album ; Alt\n") - - if db_version <= 59: - print("Updating database to version 60") - - if prefs.spotify_token: - show_message(_("Upgrade to v6.5.1. It looks like you are using Spotify."), - _("Please click 'Authorise' again in the settings")) - prefs.spotify_token = "" - - if db_version <= 60: - print("Updating database to version 61") - - token_path = os.path.join(user_directory, "spot-token-pkce") - if os.path.exists(token_path): - prefs.spotify_token = "" - os.remove(token_path) - show_message(_("Upgrade to v6.5.3 complete"), - _("It looks like you are using Spotify. Please re-setup Spotify again in the settings")) - - if db_version <= 61: - print("Updating database to version 62") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\ntransfer-playtime-to P Ctrl Shift\n") - - if db_version <= 62: - print("Updating database to version 63") - for item in gui.pl_st: - if item[0] == "T": - item[0] = "#" - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'r') as f: - lines = f.readlines() - with open(os.path.join(config_directory, "input.txt"), 'w') as f: - for line in lines: - if line == "vol-up Up Shift\n" or line == "vol-down Down Shift\n": - continue - f.write(line) - f.write("\n") - f.write("shift-up Up Shift\n") - f.write("shift-down Down Shift\n") - f.write("vol-up Up Ctrl\n") - f.write("vol-down Down Ctrl\n") - - if db_version <= 63: - print("Updating database to version 64") - if prefs.radio_urls: - radio_playlists[0]["items"].extend(prefs.radio_urls) - prefs.radio_urls = [] - # prefs.show_nag = True - - if db_version <= 64: - print("Updating database to version 65") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\nescape Escape\n") - f.write("toggle-mute M Ctrl\n") - - if db_version <= 65: - print("Updating database to version 66") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\ntoggle-artistinfo O Ctrl\n") - f.write("cycle-theme ] Ctrl\n") - f.write("cycle-theme-reverse [ Ctrl\n") - - if db_version <= 66: - print("Updating database to version 67") - for key, value in star_store.db.items(): - if len(value) == 3: - value.append(0) - star_store.db[key] = value - - if db_version <= 67: - print("Updating database to version 68") - for p in multi_playlist: - if len(p) == 11: - p.append(False) + if db_version <= 0.8: + print("Updating database from version 0.8 to 0.9") + for key, value in master_library.items(): + setattr(master_library[key], 'skips', 0) + + if db_version <= 0.9: + print("Updating database from version 0.9 to 1.1") + for key, value in master_library.items(): + setattr(master_library[key], 'comment', "") + + if db_version <= 1.1: + print("Updating database from version 1.1 to 1.2") + for key, value in master_library.items(): + setattr(master_library[key], 'album_artist', "") + + if db_version <= 1.2: + print("Updating database to version 1.3") + for key, value in master_library.items(): + setattr(master_library[key], 'disc_number', "") + setattr(master_library[key], 'disc_total', "") + + if db_version <= 1.3: + print("Updating database to version 1.4") + for key, value in master_library.items(): + setattr(master_library[key], 'lyrics', "") + setattr(master_library[key], 'track_total', "") + show_message( + "Upgrade complete. Note: New attributes such as disk number won't show for existing tracks (delete state.p to reset)") + + if db_version <= 1.4: + print("Updating database to version 1.5") + for playlist in multi_playlist: + playlist.append(uid_gen()) + + if db_version <= 1.5: + print("Updating database to version 1.6") + for i in range(len(multi_playlist)): + if len(multi_playlist[i]) == 7: + multi_playlist[i].append("") + + if db_version <= 1.6: + print("Updating preferences to 1.7") + # gui.show_stars = False + if install_mode: + # shutil.copy(install_directory + "/config.txt", user_directory) + print("Rewrote user config file") + + if db_version <= 1.7: + print("Updating database to version 1.8") + if install_mode: + print(".... Overwriting user config file") + # shutil.copy(install_directory + "/config.txt", user_directory) + + try: + print(".... Updating playtime database") + + old = star_store.db + # perf_timer.set() + old_total = sum(old.values()) + # print(perf_timer.get()) + print("Old total: ", end='') + print(old_total) + star_store.db = {} + + new = {} + for track in master_library.values(): + key = track.title + track.filename + if key in old: + n_value = [old[key], ""] + n_key = star_store.object_key(track) + star_store.db[n_key] = n_value + + print("New total: ", end='') + diff = old_total - star_store.get_total() + print(int(diff), end='') + print(" Secconds could not be matched to tracks. Total playtime won't be affected") + star_store.db[("", "", "LOST")] = [diff, ""] + print("Upgrade Complete") + except Exception: + print("Error upgrading database") + show_message(_("Error loading old database, did the program not exit properly after updating? Oh well.")) + + if db_version <= 1.8: + print("Updating database to 1.9") + for key, value in master_library.items(): + setattr(master_library[key], 'track_gain', None) + setattr(master_library[key], 'album_gain', None) + show_message(_("Upgrade complete. Run a tag rescan if you want enable ReplayGain")) + + if db_version <= 1.9: + print("Updating database to version 2.0") + for key, value in master_library.items(): + setattr(master_library[key], 'modified_time', 0) + show_message(_("Upgrade complete. New sorting option may require tag rescan.")) + + if db_version <= 2.0: + print("Updating database to version 2.1") + for key, value in master_library.items(): + setattr(master_library[key], 'is_embed_cue', False) + setattr(master_library[key], 'cue_sheet', "") + show_message(_("Updated to v2.6.3")) + + if db_version <= 2.1: + print("Updating database to version 2.1") + for key, value in master_library.items(): + setattr(master_library[key], 'lfm_friend_likes', set()) + + if db_version <= 2.2: + for i in range(len(multi_playlist)): + if len(multi_playlist[i]) < 9: + multi_playlist[i].append(True) + + if db_version <= 2.3: + print("Updating database to version 2.4") + for key, value in master_library.items(): + setattr(master_library[key], 'bit_depth', 0) + + if db_version <= 2.4: + if theme > 0: + theme += 1 + + if db_version <= 2.5: + print("Updating database to version 2.6") + for key, value in master_library.items(): + setattr(master_library[key], 'is_network', False) + # for i in range(len(multi_playlist)): + # if len(multi_playlist[i]) < 10: + # multi_playlist[i].append(False) + + if db_version <= 26: + print("Updating database to version 27") + for i in range(len(multi_playlist)): + if len(multi_playlist[i]) == 9: + multi_playlist[i].append(False) + + if db_version <= 27: + print("Updating database to version 28") + for i in range(len(multi_playlist)): + if len(multi_playlist[i]) <= 10: + multi_playlist[i].append("") + + if db_version <= 29: + print("Updating database to version 30") + for key, value in master_library.items(): + setattr(master_library[key], 'composer', "") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("global-search G Ctrl\n") + f.write("cycle-theme-reverse\n") + f.write("reload-theme F10\n") + + show_message(_("Welcome to v4.4.0. Run a tag rescan if you want enable Composer metadata.")) + + if db_version <= 30: + for i, item in enumerate(p_force_queue): + try: + assert item[6] + except Exception: + p_force_queue[i].append(False) + + if db_version <= 31: + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("love-selected\n") + gui.set_bar = True + + if db_version <= 32: + if theme > 1: + theme += 1 + + if db_version <= 33: + print("Update to db 34") + for key, value in master_library.items(): + if not hasattr(master_library[key], 'misc'): + setattr(master_library[key], 'misc', {}) + + if db_version <= 34: + print("Update to dv 35") + # Moved to after config load + + if db_version <= 35: + print("Updating database to version 36") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("toggle-show-art H Ctrl\n") + + if db_version <= 37: + print("Updating database to version 38") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("toggle-console `\n") + + if db_version <= 38: + print("Updating database to version 39") + + for key, value in star_store.db.items(): + print(value) + if len(value) == 2: + value.append(0) + star_store.db[key] = value + + if db_version <= 39: + print("Updating database to version 40") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + f = open(os.path.join(config_directory, "input.txt"), 'r') + text = f.read() + f.close() + lines = text.splitlines() + if "l ctrl" not in text.lower(): + f = open(os.path.join(config_directory, "input.txt"), 'w') + for line in lines: + line = line.strip() + if line == "love-selected": + line = "love-selected L Ctrl" + f.write(line + "\n") + f.close() + + if db_version <= 40: + print("Updating database to version 41") + old = copy.deepcopy(prefs.lyrics_enables) + prefs.lyrics_enables.clear() + if "apiseeds" in old: + prefs.lyrics_enables.append("Apiseeds") + if "lyricwiki" in old: + prefs.lyrics_enables.append("LyricWiki") + if "genius" in old: + prefs.lyrics_enables.append("Genius") + + if db_version <= 41: + print("Updating database to version 42") + + for key, value in gen_codes.items(): + gen_codes[key] = value.replace("f\"", "p\"") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + f = open(os.path.join(config_directory, "input.txt"), 'r') + text = f.read() + f.close() + lines = text.splitlines() + + f = open(os.path.join(config_directory, "input.txt"), 'w') + for line in lines: + line = line.strip() + if "rename-playlist" in line: + + f.write(line + "\n") + + line = "new-playlist T Ctrl\n" + f.write(line) + + line = "\nnew-generator-playlist\n" + f.write(line) + if "e ctrl" in text.lower(): + line = "edit-generator\n\n" + else: + line = "edit-generator E Ctrl\n\n" + f.write(line) + + line = "search-lyrics-selected\n" + f.write(line) + line = "substitute-search-selected" + + f.write(line + "\n") + + f.close() + + if db_version <= 42: + print("Updating database to version 43") + + if db_version <= 43: + print("Updating database to version 44") + # Repair db + for key, value in star_store.db.items(): + if len(value) == 2: + value.append(0) + star_store.db[key] = value + + if db_version <= 44: + print("Updating database to version 45") + print("Cleaning cache directory") + for item in os.listdir(cache_directory): + path = os.path.join(cache_directory, item) + if "-lfm." in item or "-ftv." in item or "-dcg." in item: + os.rename(path, os.path.join(a_cache_dir, item)) + for item in os.listdir(cache_directory): + path = os.path.join(cache_directory, item) + if os.path.isfile(path): + os.remove(path) + + if db_version <= 45: + print("Updating database to version 46") + for p in multi_playlist: + if type(p[7]) != list: + p[7] = [p[7]] + + if db_version <= 46: + print("Updating database to version 47") + for p in multi_playlist: + if type(p[7]) != list: + p[7] = [p[7]] + + if db_version <= 47: + print("Updating database to version 48") + if os.path.isfile(os.path.join(user_directory, "spot-r-token")): + show_message( + _("Welcome to v6.1.0. Due to changes, please re-authorise Spotify"), + _("You can do this by clicking 'Forget Account', then 'Authroise' in Settings > Accounts > Spotify")) + + if db_version <= 48: + print("Fix bad upgrade, now 49") + for key, value in master_library.items(): + if not hasattr(master_library[key], 'url_key'): + setattr(master_library[key], 'url_key', "") + if not hasattr(master_library[key], 'art_url_key'): + setattr(master_library[key], 'art_url_key', "") + + if db_version <= 49: + print("Updating database to version 50") + if os.path.isfile(os.path.join(user_directory, "spot-r-token")): + show_message( + _("Welcome to v6.3.0. Due to an upgrade, please re-authorise Spotify"), + _("You can do this by clicking 'Authroise' in Settings > Accounts > Spotify")) + os.remove(os.path.join(user_directory, "spot-r-token")) + + if db_version <= 54: + print("Updating database to version 55") + for key, value in master_library.items(): + setattr(master_library[key], 'lfm_scrobbles', 0) + + if db_version <= 55: + print("Update to db 56") + for key, value in master_library.items(): + + if hasattr(value, "track_gain"): + if value.track_gain != 0: + value.misc["replaygain_track_gain"] = value.track_gain + del value.track_gain + + if hasattr(value, "album_gain"): + if value.album_gain != 0: + value.misc["replaygain_album_gain"] = value.album_gain + del value.album_gain + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("toggle-right-panel MB5\n") + f.write("toggle-gallery MB4\n") + + if db_version <= 56: + print("Update to db 57") + if "Apiseeds" in prefs.lyrics_enables: + prefs.lyrics_enables.remove("Apiseeds") + prefs.lyrics_enables.append("Happi") + + if db_version <= 57: + print("Updating database to version 58") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("\nregenerate-playlist R Alt\n") + f.write("clear-queue Q Shift Alt\n") + f.write("resize-window-16:9 F11 Alt\n") + f.write("delete-playlist-force W Shift Ctrl\n") + + if db_version <= 58: + print("Updating database to version 59") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("\nrandom-album ; Alt\n") + + if db_version <= 59: + print("Updating database to version 60") + + if prefs.spotify_token: + show_message( + _("Upgrade to v6.5.1. It looks like you are using Spotify."), + _("Please click 'Authorise' again in the settings")) + prefs.spotify_token = "" + + if db_version <= 60: + print("Updating database to version 61") + + token_path = os.path.join(user_directory, "spot-token-pkce") + if os.path.exists(token_path): + prefs.spotify_token = "" + os.remove(token_path) + show_message( + _("Upgrade to v6.5.3 complete"), + _("It looks like you are using Spotify. Please re-setup Spotify again in the settings")) + + if db_version <= 61: + print("Updating database to version 62") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("\ntransfer-playtime-to P Ctrl Shift\n") + + if db_version <= 62: + print("Updating database to version 63") + for item in gui.pl_st: + if item[0] == "T": + item[0] = "#" + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'r') as f: + lines = f.readlines() + with open(os.path.join(config_directory, "input.txt"), 'w') as f: + for line in lines: + if line == "vol-up Up Shift\n" or line == "vol-down Down Shift\n": + continue + f.write(line) + f.write("\n") + f.write("shift-up Up Shift\n") + f.write("shift-down Down Shift\n") + f.write("vol-up Up Ctrl\n") + f.write("vol-down Down Ctrl\n") + + if db_version <= 63: + print("Updating database to version 64") + if prefs.radio_urls: + radio_playlists[0]["items"].extend(prefs.radio_urls) + prefs.radio_urls = [] + # prefs.show_nag = True + + if db_version <= 64: + print("Updating database to version 65") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("\nescape Escape\n") + f.write("toggle-mute M Ctrl\n") + + if db_version <= 65: + print("Updating database to version 66") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), 'a') as f: + f.write("\ntoggle-artistinfo O Ctrl\n") + f.write("cycle-theme ] Ctrl\n") + f.write("cycle-theme-reverse [ Ctrl\n") + + if db_version <= 66: + print("Updating database to version 67") + for key, value in star_store.db.items(): + if len(value) == 3: + value.append(0) + star_store.db[key] = value + + if db_version <= 67: + print("Updating database to version 68") + for p in multi_playlist: + if len(p) == 11: + p.append(False) if playing_in_queue > len(QUE) - 1: - playing_in_queue = len(QUE) - 1 + playing_in_queue = len(QUE) - 1 shoot = threading.Thread(target=keymaps.load) shoot.daemon = True @@ -3897,544 +3910,612 @@ def get_theme_name(number): download_directories = [] if os.path.isdir(download_directory): - download_directories.append(download_directory) + download_directories.append(download_directory) if music_directory is not None and os.path.isdir(music_directory): - download_directories.append(music_directory) + download_directories.append(music_directory) cf = Config() def save_prefs(): - cf.update_value("sync-bypass-transcode", prefs.bypass_transcode) - cf.update_value("sync-bypass-low-bitrate", prefs.smart_bypass) - cf.update_value("radio-record-codec", prefs.radio_record_codec) - - cf.update_value("plex-username", prefs.plex_username) - cf.update_value("plex-password", prefs.plex_password) - cf.update_value("plex-servername", prefs.plex_servername) - - cf.update_value("subsonic-username", prefs.subsonic_user) - cf.update_value("subsonic-password", prefs.subsonic_password) - cf.update_value("subsonic-password-plain", prefs.subsonic_password_plain) - cf.update_value("subsonic-server-url", prefs.subsonic_server) - - cf.update_value("jelly-username", prefs.jelly_username) - cf.update_value("jelly-password", prefs.jelly_password) - cf.update_value("jelly-server-url", prefs.jelly_server_url) - - cf.update_value("koel-username", prefs.koel_username) - cf.update_value("koel-password", prefs.koel_password) - cf.update_value("koel-server-url", prefs.koel_server_url) - cf.update_value("stream-bitrate", prefs.network_stream_bitrate) - - cf.update_value("display-language", prefs.ui_lang) - # cf.update_value("decode-search", prefs.diacritic_search) - - # cf.update_value("use-log-volume-scale", prefs.log_vol) - # cf.update_value("audio-backend", prefs.backend) - cf.update_value("use-pipewire", prefs.pipewire) - cf.update_value("seek-interval", prefs.seek_interval) - cf.update_value("pause-fade-time", prefs.pause_fade_time) - cf.update_value("cross-fade-time", prefs.cross_fade_time) - cf.update_value("device-buffer-ms", prefs.device_buffer) - cf.update_value("output-samplerate", prefs.samplerate) - cf.update_value("resample-quality", prefs.resample) - cf.update_value("avoid_resampling", prefs.avoid_resampling) - # cf.update_value("fast-scrubbing", prefs.pa_fast_seek) - cf.update_value("precache-local-files", prefs.precache) - cf.update_value("cache-use-tmp", prefs.tmp_cache) - cf.update_value("cache-limit", prefs.cache_limit) - cf.update_value("always-ffmpeg", prefs.always_ffmpeg) - cf.update_value("volume-curve", prefs.volume_power) - # cf.update_value("force-mono", prefs.mono) - # cf.update_value("disconnect-device-pause", prefs.dc_device_setting) - # cf.update_value("use-short-buffering", prefs.short_buffer) - - # cf.update_value("gst-output", prefs.gst_output) - # cf.update_value("gst-use-custom-output", prefs.gst_use_custom_output) - - cf.update_value("separate-multi-genre", prefs.sep_genre_multi) - - cf.update_value("tag-editor-name", prefs.tag_editor_name) - cf.update_value("tag-editor-target", prefs.tag_editor_target) - - cf.update_value("playback-follow-cursor", prefs.playback_follow_cursor) - cf.update_value("spotify-prefer-web", prefs.launch_spotify_web) - cf.update_value("spotify-allow-local", prefs.launch_spotify_local) - cf.update_value("back-restarts", prefs.back_restarts) - cf.update_value("end-queue-stop", prefs.stop_end_queue) - cf.update_value("block-suspend", prefs.block_suspend) - cf.update_value("allow-video-formats", prefs.allow_video_formats) - - cf.update_value("ui-scale", prefs.scale_want) - cf.update_value("auto-scale", prefs.x_scale) - cf.update_value("tracklist-y-text-offset", prefs.tracklist_y_text_offset) - cf.update_value("theme-name", prefs.theme_name) - cf.update_value("mac-style", prefs.macstyle) - cf.update_value("allow-art-zoom", prefs.zoom_art) - - cf.update_value("scroll-gallery-by-row", prefs.gallery_row_scroll) - cf.update_value("prefs.gallery_scroll_wheel_px", prefs.gallery_row_scroll) - cf.update_value("scroll-spectrogram", prefs.spec2_scroll) - cf.update_value("mascot-opacity", prefs.custom_bg_opacity) - cf.update_value("synced-lyrics-time-offset", prefs.sync_lyrics_time_offset) - - cf.update_value("artist-list-prefers-album-artist", prefs.artist_list_prefer_album_artist) - cf.update_value("side-panel-info-persists", prefs.meta_persists_stop) - cf.update_value("side-panel-info-selected", prefs.meta_shows_selected) - cf.update_value("side-panel-info-selected-always", prefs.meta_shows_selected_always) - cf.update_value("mini-mode-avoid-notifications", prefs.stop_notifications_mini_mode) - cf.update_value("hide-queue-when-empty", prefs.hide_queue) - # cf.update_value("show-playlist-list", prefs.show_playlist_list) - cf.update_value("enable-art-header-bar", prefs.art_in_top_panel) - cf.update_value("always-art-header-bar", prefs.always_art_header) - # cf.update_value("prefer-center-bg", prefs.center_bg) - cf.update_value("showcase-texture-background", prefs.showcase_overlay_texture) - cf.update_value("side-panel-style", prefs.side_panel_layout) - cf.update_value("side-lyrics-art", prefs.show_side_lyrics_art_panel) - cf.update_value("side-lyrics-art-on-top", prefs.lyric_metadata_panel_top) - cf.update_value("absolute-track-indices", prefs.use_absolute_track_index) - cf.update_value("auto-hide-bottom-title", prefs.hide_bottom_title) - cf.update_value("auto-show-playing", prefs.auto_goto_playing) - cf.update_value("notify-include-album", prefs.notify_include_album) - cf.update_value("show-rating-hint", prefs.rating_playtime_stars) - cf.update_value("drag-tab-to-unpin", prefs.drag_to_unpin) - - cf.update_value("gallery-thin-borders", prefs.thin_gallery_borders) - cf.update_value("increase-row-spacing", prefs.increase_gallery_row_spacing) - cf.update_value("gallery-center-text", prefs.center_gallery_text) - - cf.update_value("use-custom-fonts", prefs.use_custom_fonts) - cf.update_value("font-main-standard", prefs.linux_font) - cf.update_value("font-main-medium", prefs.linux_font_semibold) - cf.update_value("font-main-bold", prefs.linux_font_bold) - cf.update_value("font-main-condensed", prefs.linux_font_condensed) - cf.update_value("font-main-condensed-bold", prefs.linux_font_condensed_bold) - - cf.update_value("force-subpixel-text", prefs.force_subpixel_text) - - cf.update_value("double-digit-indices", prefs.dd_index) - cf.update_value("column-album-artist-fallsback", prefs.column_aa_fallback_artist) - cf.update_value("left-aligned-album-artist-title", prefs.left_align_album_artist_title) - cf.update_value("import-auto-sort", prefs.auto_sort) - - cf.update_value("encode-output-dir", prefs.custom_encoder_output) - cf.update_value("sync-device-music-dir", prefs.sync_target) - cf.update_value("add_download_directory", prefs.download_dir1) - - cf.update_value("use-system-tray", prefs.use_tray) - cf.update_value("use-gamepad", prefs.use_gamepad) - cf.update_value("enable-remote-interface", prefs.enable_remote) - - cf.update_value("enable-mpris", prefs.enable_mpris) - cf.update_value("hide-maximize-button", prefs.force_hide_max_button) - cf.update_value("restore-window-position", prefs.save_window_position) - cf.update_value("mini-mode-always-on-top", prefs.mini_mode_on_top) - cf.update_value("resume-playback-on-restart", prefs.reload_play_state) - cf.update_value("resume-playback-on-wake", prefs.resume_play_wake) - cf.update_value("auto-dl-artist-data", prefs.auto_dl_artist_data) - - cf.update_value("fanart.tv-cover", prefs.enable_fanart_cover) - cf.update_value("fanart.tv-artist", prefs.enable_fanart_artist) - cf.update_value("fanart.tv-background", prefs.enable_fanart_bg) - cf.update_value("auto-update-playlists", prefs.always_auto_update_playlists) - cf.update_value("write-ratings-to-tag", prefs.write_ratings) - cf.update_value("enable-spotify", prefs.spot_mode) - cf.update_value("enable-discord-rpc", prefs.discord_enable) - cf.update_value("auto-search-lyrics", prefs.auto_lyrics) - cf.update_value("shortcuts-ignore-keymap", prefs.use_scancodes) - cf.update_value("alpha_key_activate_search", prefs.search_on_letter) - - cf.update_value("discogs-personal-access-token", prefs.discogs_pat) - cf.update_value("listenbrainz-token", prefs.lb_token) - cf.update_value("custom-listenbrainz-url", prefs.listenbrainz_url) - - cf.update_value("maloja-key", prefs.maloja_key) - cf.update_value("maloja-url", prefs.maloja_url) - cf.update_value("maloja-enable", prefs.maloja_enable) - - cf.update_value("tau-url", prefs.sat_url) - - cf.update_value("lastfm-pull-love", prefs.lastfm_pull_love) - - cf.update_value("broadcast-page-port", prefs.metadata_page_port) - cf.update_value("show-current-on-transition", prefs.show_current_on_transition) - - cf.update_value("chart-columns", prefs.chart_columns) - cf.update_value("chart-rows", prefs.chart_rows) - cf.update_value("chart-uses-text", prefs.chart_text) - cf.update_value("chart-font", prefs.chart_font) - cf.update_value("chart-sorts-top-played", prefs.topchart_sorts_played) - - if os.path.isdir(config_directory): - cf.dump(os.path.join(config_directory, "tauon.conf")) - else: - print("ERROR: Missing config directory") + cf.update_value("sync-bypass-transcode", prefs.bypass_transcode) + cf.update_value("sync-bypass-low-bitrate", prefs.smart_bypass) + cf.update_value("radio-record-codec", prefs.radio_record_codec) + + cf.update_value("plex-username", prefs.plex_username) + cf.update_value("plex-password", prefs.plex_password) + cf.update_value("plex-servername", prefs.plex_servername) + + cf.update_value("subsonic-username", prefs.subsonic_user) + cf.update_value("subsonic-password", prefs.subsonic_password) + cf.update_value("subsonic-password-plain", prefs.subsonic_password_plain) + cf.update_value("subsonic-server-url", prefs.subsonic_server) + + cf.update_value("jelly-username", prefs.jelly_username) + cf.update_value("jelly-password", prefs.jelly_password) + cf.update_value("jelly-server-url", prefs.jelly_server_url) + + cf.update_value("koel-username", prefs.koel_username) + cf.update_value("koel-password", prefs.koel_password) + cf.update_value("koel-server-url", prefs.koel_server_url) + cf.update_value("stream-bitrate", prefs.network_stream_bitrate) + + cf.update_value("display-language", prefs.ui_lang) + # cf.update_value("decode-search", prefs.diacritic_search) + + # cf.update_value("use-log-volume-scale", prefs.log_vol) + # cf.update_value("audio-backend", prefs.backend) + cf.update_value("use-pipewire", prefs.pipewire) + cf.update_value("seek-interval", prefs.seek_interval) + cf.update_value("pause-fade-time", prefs.pause_fade_time) + cf.update_value("cross-fade-time", prefs.cross_fade_time) + cf.update_value("device-buffer-ms", prefs.device_buffer) + cf.update_value("output-samplerate", prefs.samplerate) + cf.update_value("resample-quality", prefs.resample) + cf.update_value("avoid_resampling", prefs.avoid_resampling) + # cf.update_value("fast-scrubbing", prefs.pa_fast_seek) + cf.update_value("precache-local-files", prefs.precache) + cf.update_value("cache-use-tmp", prefs.tmp_cache) + cf.update_value("cache-limit", prefs.cache_limit) + cf.update_value("always-ffmpeg", prefs.always_ffmpeg) + cf.update_value("volume-curve", prefs.volume_power) + # cf.update_value("force-mono", prefs.mono) + # cf.update_value("disconnect-device-pause", prefs.dc_device_setting) + # cf.update_value("use-short-buffering", prefs.short_buffer) + + # cf.update_value("gst-output", prefs.gst_output) + # cf.update_value("gst-use-custom-output", prefs.gst_use_custom_output) + + cf.update_value("separate-multi-genre", prefs.sep_genre_multi) + + cf.update_value("tag-editor-name", prefs.tag_editor_name) + cf.update_value("tag-editor-target", prefs.tag_editor_target) + + cf.update_value("playback-follow-cursor", prefs.playback_follow_cursor) + cf.update_value("spotify-prefer-web", prefs.launch_spotify_web) + cf.update_value("spotify-allow-local", prefs.launch_spotify_local) + cf.update_value("back-restarts", prefs.back_restarts) + cf.update_value("end-queue-stop", prefs.stop_end_queue) + cf.update_value("block-suspend", prefs.block_suspend) + cf.update_value("allow-video-formats", prefs.allow_video_formats) + + cf.update_value("ui-scale", prefs.scale_want) + cf.update_value("auto-scale", prefs.x_scale) + cf.update_value("tracklist-y-text-offset", prefs.tracklist_y_text_offset) + cf.update_value("theme-name", prefs.theme_name) + cf.update_value("mac-style", prefs.macstyle) + cf.update_value("allow-art-zoom", prefs.zoom_art) + + cf.update_value("scroll-gallery-by-row", prefs.gallery_row_scroll) + cf.update_value("prefs.gallery_scroll_wheel_px", prefs.gallery_row_scroll) + cf.update_value("scroll-spectrogram", prefs.spec2_scroll) + cf.update_value("mascot-opacity", prefs.custom_bg_opacity) + cf.update_value("synced-lyrics-time-offset", prefs.sync_lyrics_time_offset) + + cf.update_value("artist-list-prefers-album-artist", prefs.artist_list_prefer_album_artist) + cf.update_value("side-panel-info-persists", prefs.meta_persists_stop) + cf.update_value("side-panel-info-selected", prefs.meta_shows_selected) + cf.update_value("side-panel-info-selected-always", prefs.meta_shows_selected_always) + cf.update_value("mini-mode-avoid-notifications", prefs.stop_notifications_mini_mode) + cf.update_value("hide-queue-when-empty", prefs.hide_queue) + # cf.update_value("show-playlist-list", prefs.show_playlist_list) + cf.update_value("enable-art-header-bar", prefs.art_in_top_panel) + cf.update_value("always-art-header-bar", prefs.always_art_header) + # cf.update_value("prefer-center-bg", prefs.center_bg) + cf.update_value("showcase-texture-background", prefs.showcase_overlay_texture) + cf.update_value("side-panel-style", prefs.side_panel_layout) + cf.update_value("side-lyrics-art", prefs.show_side_lyrics_art_panel) + cf.update_value("side-lyrics-art-on-top", prefs.lyric_metadata_panel_top) + cf.update_value("absolute-track-indices", prefs.use_absolute_track_index) + cf.update_value("auto-hide-bottom-title", prefs.hide_bottom_title) + cf.update_value("auto-show-playing", prefs.auto_goto_playing) + cf.update_value("notify-include-album", prefs.notify_include_album) + cf.update_value("show-rating-hint", prefs.rating_playtime_stars) + cf.update_value("drag-tab-to-unpin", prefs.drag_to_unpin) + + cf.update_value("gallery-thin-borders", prefs.thin_gallery_borders) + cf.update_value("increase-row-spacing", prefs.increase_gallery_row_spacing) + cf.update_value("gallery-center-text", prefs.center_gallery_text) + + cf.update_value("use-custom-fonts", prefs.use_custom_fonts) + cf.update_value("font-main-standard", prefs.linux_font) + cf.update_value("font-main-medium", prefs.linux_font_semibold) + cf.update_value("font-main-bold", prefs.linux_font_bold) + cf.update_value("font-main-condensed", prefs.linux_font_condensed) + cf.update_value("font-main-condensed-bold", prefs.linux_font_condensed_bold) + + cf.update_value("force-subpixel-text", prefs.force_subpixel_text) + + cf.update_value("double-digit-indices", prefs.dd_index) + cf.update_value("column-album-artist-fallsback", prefs.column_aa_fallback_artist) + cf.update_value("left-aligned-album-artist-title", prefs.left_align_album_artist_title) + cf.update_value("import-auto-sort", prefs.auto_sort) + + cf.update_value("encode-output-dir", prefs.custom_encoder_output) + cf.update_value("sync-device-music-dir", prefs.sync_target) + cf.update_value("add_download_directory", prefs.download_dir1) + + cf.update_value("use-system-tray", prefs.use_tray) + cf.update_value("use-gamepad", prefs.use_gamepad) + cf.update_value("enable-remote-interface", prefs.enable_remote) + + cf.update_value("enable-mpris", prefs.enable_mpris) + cf.update_value("hide-maximize-button", prefs.force_hide_max_button) + cf.update_value("restore-window-position", prefs.save_window_position) + cf.update_value("mini-mode-always-on-top", prefs.mini_mode_on_top) + cf.update_value("resume-playback-on-restart", prefs.reload_play_state) + cf.update_value("resume-playback-on-wake", prefs.resume_play_wake) + cf.update_value("auto-dl-artist-data", prefs.auto_dl_artist_data) + + cf.update_value("fanart.tv-cover", prefs.enable_fanart_cover) + cf.update_value("fanart.tv-artist", prefs.enable_fanart_artist) + cf.update_value("fanart.tv-background", prefs.enable_fanart_bg) + cf.update_value("auto-update-playlists", prefs.always_auto_update_playlists) + cf.update_value("write-ratings-to-tag", prefs.write_ratings) + cf.update_value("enable-spotify", prefs.spot_mode) + cf.update_value("enable-discord-rpc", prefs.discord_enable) + cf.update_value("auto-search-lyrics", prefs.auto_lyrics) + cf.update_value("shortcuts-ignore-keymap", prefs.use_scancodes) + cf.update_value("alpha_key_activate_search", prefs.search_on_letter) + + cf.update_value("discogs-personal-access-token", prefs.discogs_pat) + cf.update_value("listenbrainz-token", prefs.lb_token) + cf.update_value("custom-listenbrainz-url", prefs.listenbrainz_url) + + cf.update_value("maloja-key", prefs.maloja_key) + cf.update_value("maloja-url", prefs.maloja_url) + cf.update_value("maloja-enable", prefs.maloja_enable) + + cf.update_value("tau-url", prefs.sat_url) + + cf.update_value("lastfm-pull-love", prefs.lastfm_pull_love) + + cf.update_value("broadcast-page-port", prefs.metadata_page_port) + cf.update_value("show-current-on-transition", prefs.show_current_on_transition) + + cf.update_value("chart-columns", prefs.chart_columns) + cf.update_value("chart-rows", prefs.chart_rows) + cf.update_value("chart-uses-text", prefs.chart_text) + cf.update_value("chart-font", prefs.chart_font) + cf.update_value("chart-sorts-top-played", prefs.topchart_sorts_played) + + if os.path.isdir(config_directory): + cf.dump(os.path.join(config_directory, "tauon.conf")) + else: + print("ERROR: Missing config directory") def load_prefs(): - cf.reset() - cf.load(os.path.join(config_directory, "tauon.conf")) - - cf.add_comment("Tauon Music Box configuration file") - cf.br() - cf.add_comment( - "This file will be regenerated while app is running. Formatting and additional comments will be lost.") - cf.add_comment("Tip: Use TOML syntax highlighting") - - cf.br() - cf.add_text("[audio]") - - # prefs.backend = cf.sync_add("int", "audio-backend", prefs.backend, "4: Built in backend (Phazor), 2: GStreamer") - prefs.pipewire = cf.sync_add("bool", "use-pipewire", prefs.pipewire, - "Experimental setting to use Pipewire native only.") - - prefs.seek_interval = cf.sync_add("int", "seek-interval", prefs.seek_interval, - "In s. Interval to seek when using keyboard shortcut. Default is 15.") - # prefs.pause_fade_time = cf.sync_add("int", "pause-fade-time", prefs.pause_fade_time, "In milliseconds. Default is 400. (GStreamer Only)") - - if prefs.pause_fade_time < 100: - prefs.pause_fade_time = 100 - if prefs.pause_fade_time > 5000: - prefs.pause_fade_time = 5000 - - prefs.cross_fade_time = cf.sync_add("int", "cross-fade-time", prefs.cross_fade_time, - "In ms. Min: 200, Max: 2000, Default: 700. Applies to track change crossfades. End of track is always gapless.") - - prefs.device_buffer = cf.sync_add("int", "device-buffer-ms", prefs.device_buffer, "Default: 80") - #prefs.samplerate = cf.sync_add("int", "output-samplerate", prefs.samplerate, - # "In hz. Default: 48000, alt: 44100. (restart app to apply change)") - prefs.avoid_resampling = cf.sync_add("bool", "avoid_resampling", prefs.avoid_resampling, - "Only implemented for FLAC, MP3, OGG, OPUS") - prefs.resample = cf.sync_add("int", "resample-quality", prefs.resample, - "0=best, 1=medium, 2=fast, 3=fastest. Default: 1. (applies on restart)") - if prefs.resample < 0 or prefs.resample > 4: - prefs.resample = 1 - # prefs.pa_fast_seek = cf.sync_add("bool", "fast-scrubbing", prefs.pa_fast_seek, "Seek without a delay but may cause audible popping") - prefs.cache_limit = cf.sync_add("int", "cache-limit", prefs.cache_limit, - "Limit size of network audio file cache. In MB.") - prefs.tmp_cache = cf.sync_add("bool", "cache-use-tmp", prefs.tmp_cache, - "Use /tmp for cache. When enabled, above setting overridden to a small value. (applies on restart)") - prefs.precache = cf.sync_add("bool", "precache-local-files", prefs.precache, - "Cache files from local sources too. (Useful for mounted network drives)") - prefs.always_ffmpeg = cf.sync_add("bool", "always-ffmpeg", prefs.always_ffmpeg, - "Prefer decoding using FFMPEG. Fixes stuttering on Raspberry Pi OS.") - prefs.volume_power = cf.sync_add("int", "volume-curve", prefs.volume_power, - "1=Linear volume control. Values above one give greater control bias over lower volume range. Default: 2") - - # prefs.mono = cf.sync_add("bool", "force-mono", prefs.mono, "This is a placeholder setting and currently has no effect.") - # prefs.dc_device_setting = cf.sync_add("string", "disconnect-device-pause", prefs.dc_device_setting, "Can be \"on\" or \"off\". BASS only. When off, connection to device will he held open.") - # prefs.short_buffer = cf.sync_add("bool", "use-short-buffering", prefs.short_buffer, "BASS only.") - - # cf.br() - # cf.add_text("[audio (gstreamer only)]") - # - # prefs.gst_output = cf.sync_add("string", "gst-output", prefs.gst_output, "GStreamer output pipeline specification. Only used with GStreamer backend.") - # prefs.gst_use_custom_output = cf.sync_add("bool", "gst-use-custom-output", prefs.gst_use_custom_output, "Set this to true to apply any manual edits of the above string.") - - if prefs.dc_device_setting == 'on': - prefs.dc_device = True - elif prefs.dc_device_setting == 'off': - prefs.dc_device = False - - cf.br() - cf.add_text("[locale]") - prefs.ui_lang = cf.sync_add("string", "display-language", prefs.ui_lang, "Override display language to use if " - "available. E.g. \"en\", \"ja\", \"zh_CH\". " - "Default: \"auto\"") - # prefs.diacritic_search = cf.sync_add("bool", "decode-search", prefs.diacritic_search, "Allow searching of diacritics etc using ascii in search functions. (Disablng may speed up search)") - cf.br() - cf.add_text("[search]") - prefs.sep_genre_multi = cf.sync_add("bool", "separate-multi-genre", prefs.sep_genre_multi, - "If true, the standard genre result will exclude results from multi-value tags. These will be included in a separate result.") - - cf.br() - cf.add_text("[tag-editor]") - if system == 'windows' or msys: - prefs.tag_editor_name = cf.sync_add("string", "tag-editor-name", "Picard", "Name to display in UI.") - prefs.tag_editor_target = cf.sync_add("string", "tag-editor-target", - "C:\\Program Files (x86)\\MusicBrainz Picard\\picard.exe", - "The path of the exe to run.") - else: - prefs.tag_editor_name = cf.sync_add("string", "tag-editor-name", "Picard", "Name to display in UI.") - prefs.tag_editor_target = cf.sync_add("string", "tag-editor-target", "picard", - "The name of the binary to call.") - - cf.br() - cf.add_text("[playback]") - prefs.playback_follow_cursor = cf.sync_add("bool", "playback-follow-cursor", prefs.playback_follow_cursor, - "When advancing, always play the track that is selected.") - prefs.launch_spotify_web = cf.sync_add("bool", "spotify-prefer-web", prefs.launch_spotify_web, - "Launch the web client rather than attempting to launch the desktop client.") - prefs.launch_spotify_local = cf.sync_add("bool", "spotify-allow-local", prefs.launch_spotify_local, - "Play Spotify audio through Tauon.") - prefs.back_restarts = cf.sync_add("bool", "back-restarts", prefs.back_restarts, - "Pressing the back button restarts playing track on first press.") - prefs.stop_end_queue = cf.sync_add("bool", "end-queue-stop", prefs.stop_end_queue, - "Queue will always enable auto-stop on last track") - prefs.block_suspend = cf.sync_add("bool", "block-suspend", prefs.block_suspend, - "Prevent system suspend during playback") - prefs.allow_video_formats = cf.sync_add("bool", "allow-video-formats", prefs.allow_video_formats, - "Allow the import of MP4 and WEBM formats") - if prefs.allow_video_formats: - for item in VID_Formats: - if item not in DA_Formats: - DA_Formats.add(item) - - cf.br() - cf.add_text("[HiDPI]") - prefs.scale_want = cf.sync_add("float", "ui-scale", prefs.scale_want, - "UI scale factor. Default is 1.0, try increase if using a HiDPI display.") - prefs.x_scale = cf.sync_add("bool", "auto-scale", prefs.x_scale, "Automatically choose above setting") - prefs.tracklist_y_text_offset = cf.sync_add("int", "tracklist-y-text-offset", prefs.tracklist_y_text_offset, - "If you're using a UI scale, you may need to tweak this.") - - cf.br() - cf.add_text("[ui]") - - prefs.theme_name = cf.sync_add("string", "theme-name", prefs.theme_name) - macstyle = cf.sync_add("bool", "mac-style", prefs.macstyle, "Use macOS style window buttons") - prefs.zoom_art = cf.sync_add("bool", "allow-art-zoom", prefs.zoom_art) - prefs.gallery_row_scroll = cf.sync_add("bool", "scroll-gallery-by-row", True) - prefs.gallery_scroll_wheel_px = cf.sync_add("int", "scroll-gallery-distance", 90, - "Only has effect if scroll-gallery-by-row is false.") - prefs.spec2_scroll = cf.sync_add("bool", "scroll-spectrogram", prefs.spec2_scroll) - prefs.custom_bg_opacity = cf.sync_add("int", "mascot-opacity", prefs.custom_bg_opacity) - if prefs.custom_bg_opacity < 0 or prefs.custom_bg_opacity > 100: - prefs.custom_bg_opacity = 40 - print("Warning: Invalid value for mascot-opacity") - - prefs.sync_lyrics_time_offset = cf.sync_add("int", "synced-lyrics-time-offset", prefs.sync_lyrics_time_offset, - "In milliseconds. May be negative.") - prefs.artist_list_prefer_album_artist = cf.sync_add("bool", "artist-list-prefers-album-artist", - prefs.artist_list_prefer_album_artist, - "May require restart for change to take effect.") - prefs.meta_persists_stop = cf.sync_add("bool", "side-panel-info-persists", prefs.meta_persists_stop, - "Show album art and metadata of last played track when stopped.") - prefs.meta_shows_selected = cf.sync_add("bool", "side-panel-info-selected", prefs.meta_shows_selected, - "Show album art and metadata of selected track when stopped. (overides above setting)") - prefs.meta_shows_selected_always = cf.sync_add("bool", "side-panel-info-selected-always", - prefs.meta_shows_selected_always, - "Show album art and metadata of selected track at all times. (overides the above 2 settings)") - prefs.stop_notifications_mini_mode = cf.sync_add("bool", "mini-mode-avoid-notifications", - prefs.stop_notifications_mini_mode, - "Avoid sending track change notifications when in Mini Mode") - prefs.hide_queue = cf.sync_add("bool", "hide-queue-when-empty", prefs.hide_queue) - # prefs.show_playlist_list = cf.sync_add("bool", "show-playlist-list", prefs.show_playlist_list) - - prefs.show_current_on_transition = cf.sync_add("bool", "show-current-on-transition", - prefs.show_current_on_transition, - "Always jump to new playing track even with natural transition (broken setting, is always enabled") - prefs.art_in_top_panel = cf.sync_add("bool", "enable-art-header-bar", prefs.art_in_top_panel, - "Show art in top panel when window is narrow") - prefs.always_art_header = cf.sync_add("bool", "always-art-header-bar", prefs.always_art_header, - "Show art in top panel at any size. (Requires enable-art-header-bar)") - - # prefs.center_bg = cf.sync_add("bool", "prefer-center-bg", prefs.center_bg, "Always center art for the background art function") - prefs.showcase_overlay_texture = cf.sync_add("bool", "showcase-texture-background", prefs.showcase_overlay_texture, - "Draw pattern over background art") - prefs.side_panel_layout = cf.sync_add("int", "side-panel-style", prefs.side_panel_layout, "0:default, 1:centered") - prefs.show_side_lyrics_art_panel = cf.sync_add("bool", "side-lyrics-art", prefs.show_side_lyrics_art_panel) - prefs.lyric_metadata_panel_top = cf.sync_add("bool", "side-lyrics-art-on-top", prefs.lyric_metadata_panel_top) - prefs.use_absolute_track_index = cf.sync_add("bool", "absolute-track-indices", prefs.use_absolute_track_index, - "For playlists with titles disabled only") - prefs.hide_bottom_title = cf.sync_add("bool", "auto-hide-bottom-title", prefs.hide_bottom_title, - "Hide title in bottom panel when already shown in side panel") - prefs.auto_goto_playing = cf.sync_add("bool", "auto-show-playing", prefs.auto_goto_playing, - "Show playing track in current playlist on track and playlist change even if not the playing playlist") - - prefs.notify_include_album = cf.sync_add("bool", "notify-include-album", prefs.notify_include_album, - "Include album name in track change notifications") - prefs.rating_playtime_stars = cf.sync_add("bool", "show-rating-hint", prefs.rating_playtime_stars, - "Indicate playtime in rating stars") - - prefs.drag_to_unpin = cf.sync_add("bool", "drag-tab-to-unpin", prefs.drag_to_unpin, - "Dragging a tab off the top-panel un-pins it") - - cf.br() - cf.add_text("[gallery]") - prefs.thin_gallery_borders = cf.sync_add("bool", "gallery-thin-borders", prefs.thin_gallery_borders) - prefs.increase_gallery_row_spacing = cf.sync_add("bool", "increase-row-spacing", prefs.increase_gallery_row_spacing) - prefs.center_gallery_text = cf.sync_add("bool", "gallery-center-text", prefs.center_gallery_text) - - # show-current-on-transition", prefs.show_current_on_transition) - if system != 'windows': - cf.br() - cf.add_text("[fonts]") - cf.add_comment("Changes will require app restart.") - prefs.use_custom_fonts = cf.sync_add("bool", "use-custom-fonts", prefs.use_custom_fonts, - "Setting to false will reset below settings to default on restart") - if prefs.use_custom_fonts: - prefs.linux_font = cf.sync_add("string", "font-main-standard", prefs.linux_font, - "Suggested alternate: Liberation Sans") - prefs.linux_font_semibold = cf.sync_add("string", "font-main-medium", prefs.linux_font_semibold) - prefs.linux_font_bold = cf.sync_add("string", "font-main-bold", prefs.linux_font_bold) - prefs.linux_font_condensed = cf.sync_add("string", "font-main-condensed", prefs.linux_font_condensed) - prefs.linux_font_condensed_bold = cf.sync_add("string", "font-main-condensed-bold", prefs.linux_font_condensed_bold) - - else: - cf.sync_add("string", "font-main-standard", prefs.linux_font, "Suggested alternate: Liberation Sans") - cf.sync_add("string", "font-main-medium", prefs.linux_font_semibold) - cf.sync_add("string", "font-main-bold", prefs.linux_font_bold) - cf.sync_add("string", "font-main-condensed", prefs.linux_font_condensed) - cf.sync_add("string", "font-main-condensed-bold", prefs.linux_font_condensed_bold) - - # prefs.force_subpixel_text = cf.sync_add("bool", "force-subpixel-text", prefs.force_subpixel_text, "(Subpixel rendering defaults to off with Flatpak)") - - cf.br() - cf.add_text("[tracklist]") - prefs.dd_index = cf.sync_add("bool", "double-digit-indices", prefs.dd_index) - prefs.column_aa_fallback_artist = cf.sync_add("bool", "column-album-artist-fallsback", - prefs.column_aa_fallback_artist, - "'Album artist' column shows 'artist' if otherwise blank.") - prefs.left_align_album_artist_title = cf.sync_add("bool", "left-aligned-album-artist-title", - prefs.left_align_album_artist_title, - "Show 'Album artist' in the folder/album title. Uses colour 'column-album-artist' from theme file") - prefs.auto_sort = cf.sync_add("bool", "import-auto-sort", prefs.auto_sort, - "This setting is deprecated and will be removed in a future version") - - cf.br() - cf.add_text("[transcode]") - prefs.bypass_transcode = cf.sync_add("bool", "sync-bypass-transcode", prefs.bypass_transcode, - "Don't transcode files with sync function") - prefs.smart_bypass = cf.sync_add("bool", "sync-bypass-low-bitrate", prefs.smart_bypass, - "Skip transcode of <=128kbs folders") - prefs.radio_record_codec = cf.sync_add("string", "radio-record-codec", prefs.radio_record_codec, - "Can be OPUS, OGG, FLAC, or MP3. Default: OPUS") - - cf.br() - cf.add_text("[directories]") - cf.add_comment("Use full paths") - prefs.sync_target = cf.sync_add("string", "sync-device-music-dir", prefs.sync_target) - prefs.custom_encoder_output = cf.sync_add("string", "encode-output-dir", prefs.custom_encoder_output, - "E.g. \"/home/example/music/output\". If left blank, encode-output in home music dir will be used.") - if prefs.custom_encoder_output: - prefs.encoder_output = prefs.custom_encoder_output - prefs.download_dir1 = cf.sync_add("string", "add_download_directory", prefs.download_dir1, - "Add another folder to monitor in addition to home downloads and music.") - if prefs.download_dir1 and prefs.download_dir1 not in download_directories: - if os.path.isdir(prefs.download_dir1): - download_directories.append(prefs.download_dir1) - else: - print("Warning: Invalid download directory in config") - - cf.br() - cf.add_text("[app]") - prefs.enable_remote = cf.sync_add("bool", "enable-remote-interface", prefs.enable_remote, - "For use with Tauon Music Remote for Android") - prefs.use_gamepad = cf.sync_add("bool", "use-gamepad", prefs.use_gamepad, "Use game controller for UI control, restart on change.") - prefs.use_tray = cf.sync_add("bool", "use-system-tray", prefs.use_tray) - prefs.force_hide_max_button = cf.sync_add("bool", "hide-maximize-button", prefs.force_hide_max_button) - prefs.save_window_position = cf.sync_add("bool", "restore-window-position", prefs.save_window_position, - "Save and restore the last window position on desktop on open") - prefs.mini_mode_on_top = cf.sync_add("bool", "mini-mode-always-on-top", prefs.mini_mode_on_top) - prefs.enable_mpris = cf.sync_add("bool", "enable-mpris", prefs.enable_mpris) - prefs.reload_play_state = cf.sync_add("bool", "resume-playback-on-restart", prefs.reload_play_state) - prefs.resume_play_wake = cf.sync_add("bool", "resume-playback-on-wake", prefs.resume_play_wake) - prefs.auto_dl_artist_data = cf.sync_add("bool", "auto-dl-artist-data", prefs.auto_dl_artist_data, - "Enable automatic downloading of thumbnails in artist list") - prefs.enable_fanart_cover = cf.sync_add("bool", "fanart.tv-cover", prefs.enable_fanart_cover) - prefs.enable_fanart_artist = cf.sync_add("bool", "fanart.tv-artist", prefs.enable_fanart_artist) - prefs.enable_fanart_bg = cf.sync_add("bool", "fanart.tv-background", prefs.enable_fanart_bg) - prefs.always_auto_update_playlists = cf.sync_add("bool", "auto-update-playlists", - prefs.always_auto_update_playlists, - "Automatically update generator playlists") - prefs.write_ratings = cf.sync_add("bool", "write-ratings-to-tag", prefs.write_ratings, - "This writes FMPS_Rating tags on disk. Only writing to MP3, OGG and FLAC files is currently supported.") - prefs.spot_mode = cf.sync_add("bool", "enable-spotify", prefs.spot_mode, "Enable Spotify specific features") - prefs.discord_enable = cf.sync_add("bool", "enable-discord-rpc", prefs.discord_enable, - "Show track info in running Discord application") - prefs.auto_lyrics = cf.sync_add("bool", "auto-search-lyrics", prefs.auto_lyrics, - "Automatically search internet for lyrics when display is wanted") - - prefs.use_scancodes = cf.sync_add("bool", "shortcuts-ignore-keymap", prefs.use_scancodes, - "When enabled, shortcuts will map to the physical keyboard layout") - prefs.search_on_letter = cf.sync_add("bool", "alpha_key_activate_search", prefs.search_on_letter, - "When enabled, pressing single letter keyboard key will activate the global search") - - cf.br() - cf.add_text("[tokens]") - temp = cf.sync_add("string", "discogs-personal-access-token", prefs.discogs_pat, - "Used for sourcing of artist thumbnails.") - if not temp: - prefs.discogs_pat = "" - elif len(temp) != 40: - print("Warning: Invalid discogs token in config") - else: - prefs.discogs_pat = temp - - prefs.listenbrainz_url = cf.sync_add("string", "custom-listenbrainz-url", prefs.listenbrainz_url, - "Specify a custom Listenbrainz compatible api url. E.g. \"https://example.tld/apis/listenbrainz/\" Default: Blank") - prefs.lb_token = cf.sync_add("string", "listenbrainz-token", prefs.lb_token) - - cf.br() - cf.add_text("[tauon_satellite]") - prefs.sat_url = cf.sync_add("string", "tau-url", prefs.sat_url, "Exclude the port") - - cf.br() - cf.add_text("[lastfm]") - prefs.lastfm_pull_love = cf.sync_add("bool", "lastfm-pull-love", prefs.lastfm_pull_love, - "Overwrite local love status on scrobble") - - - cf.br() - cf.add_text("[maloja_account]") - prefs.maloja_url = cf.sync_add("string", "maloja-url", prefs.maloja_url, - "A Maloja server URL, e.g. http://localhost:32400") - prefs.maloja_key = cf.sync_add("string", "maloja-key", prefs.maloja_key, "One of your Maloja API keys") - prefs.maloja_enable = cf.sync_add("bool", "maloja-enable", prefs.maloja_enable) - - cf.br() - cf.add_text("[plex_account]") - prefs.plex_username = cf.sync_add("string", "plex-username", prefs.plex_username, - "Probably the email address you used to make your PLEX account.") - prefs.plex_password = cf.sync_add("string", "plex-password", prefs.plex_password, - "The password associated with your PLEX account.") - prefs.plex_servername = cf.sync_add("string", "plex-servername", prefs.plex_servername, - "Probably your servers hostname.") - - cf.br() - cf.add_text("[subsonic_account]") - prefs.subsonic_user = cf.sync_add("string", "subsonic-username", prefs.subsonic_user) - prefs.subsonic_password = cf.sync_add("string", "subsonic-password", prefs.subsonic_password) - prefs.subsonic_password_plain = cf.sync_add("bool", "subsonic-password-plain", prefs.subsonic_password_plain) - prefs.subsonic_server = cf.sync_add("string", "subsonic-server-url", prefs.subsonic_server) - - cf.br() - cf.add_text("[koel_account]") - prefs.koel_username = cf.sync_add("string", "koel-username", prefs.koel_username, "E.g. admin@example.com") - prefs.koel_password = cf.sync_add("string", "koel-password", prefs.koel_password, "The default is admin") - prefs.koel_server_url = cf.sync_add("string", "koel-server-url", prefs.koel_server_url, - "The URL or IP:Port where the Koel server is hosted. E.g. http://localhost:8050 or https://localhost:8060") - prefs.koel_server_url = prefs.koel_server_url.rstrip("/") - - cf.br() - cf.add_text("[jellyfin_account]") - prefs.jelly_username = cf.sync_add("string", "jelly-username", prefs.jelly_username, "") - prefs.jelly_password = cf.sync_add("string", "jelly-password", prefs.jelly_password, "") - prefs.jelly_server_url = cf.sync_add("string", "jelly-server-url", prefs.jelly_server_url, - "The IP:Port where the jellyfin server is hosted.") - prefs.jelly_server_url = prefs.jelly_server_url.rstrip("/") - - cf.br() - cf.add_text("[network]") - prefs.network_stream_bitrate = cf.sync_add("int", "stream-bitrate", prefs.network_stream_bitrate, - "Optional bitrate koel/subsonic should transcode to (Server may need to be configured for this). Set to 0 to disable transcoding.") - - cf.br() - cf.add_text("[listenalong]") - prefs.metadata_page_port = cf.sync_add("int", "broadcast-page-port", prefs.metadata_page_port, - "Change applies on app restart or setting re-enable") - - cf.br() - cf.add_text("[chart]") - prefs.chart_columns = cf.sync_add("int", "chart-columns", prefs.chart_columns) - prefs.chart_rows = cf.sync_add("int", "chart-rows", prefs.chart_rows) - prefs.chart_text = cf.sync_add("bool", "chart-uses-text", prefs.chart_text) - prefs.topchart_sorts_played = cf.sync_add("bool", "chart-sorts-top-played", prefs.topchart_sorts_played) - prefs.chart_font = cf.sync_add("string", "chart-font", prefs.chart_font, - "Format is fontname + size. Default is Monospace 10") + cf.reset() + cf.load(os.path.join(config_directory, "tauon.conf")) + + cf.add_comment("Tauon Music Box configuration file") + cf.br() + cf.add_comment( + "This file will be regenerated while app is running. Formatting and additional comments will be lost.") + cf.add_comment("Tip: Use TOML syntax highlighting") + + cf.br() + cf.add_text("[audio]") + + # prefs.backend = cf.sync_add("int", "audio-backend", prefs.backend, "4: Built in backend (Phazor), 2: GStreamer") + prefs.pipewire = cf.sync_add( + "bool", "use-pipewire", prefs.pipewire, + "Experimental setting to use Pipewire native only.") + + prefs.seek_interval = cf.sync_add( + "int", "seek-interval", prefs.seek_interval, + "In s. Interval to seek when using keyboard shortcut. Default is 15.") + # prefs.pause_fade_time = cf.sync_add("int", "pause-fade-time", prefs.pause_fade_time, "In milliseconds. Default is 400. (GStreamer Only)") + + if prefs.pause_fade_time < 100: + prefs.pause_fade_time = 100 + if prefs.pause_fade_time > 5000: + prefs.pause_fade_time = 5000 + + prefs.cross_fade_time = cf.sync_add( + "int", "cross-fade-time", prefs.cross_fade_time, + "In ms. Min: 200, Max: 2000, Default: 700. Applies to track change crossfades. End of track is always gapless.") + + prefs.device_buffer = cf.sync_add("int", "device-buffer-ms", prefs.device_buffer, "Default: 80") + #prefs.samplerate = cf.sync_add( + # "int", "output-samplerate", prefs.samplerate, + # "In hz. Default: 48000, alt: 44100. (restart app to apply change)") + prefs.avoid_resampling = cf.sync_add( + "bool", "avoid_resampling", prefs.avoid_resampling, + "Only implemented for FLAC, MP3, OGG, OPUS") + prefs.resample = cf.sync_add( + "int", "resample-quality", prefs.resample, + "0=best, 1=medium, 2=fast, 3=fastest. Default: 1. (applies on restart)") + if prefs.resample < 0 or prefs.resample > 4: + prefs.resample = 1 + # prefs.pa_fast_seek = cf.sync_add("bool", "fast-scrubbing", prefs.pa_fast_seek, "Seek without a delay but may cause audible popping") + prefs.cache_limit = cf.sync_add( + "int", "cache-limit", prefs.cache_limit, + "Limit size of network audio file cache. In MB.") + prefs.tmp_cache = cf.sync_add( + "bool", "cache-use-tmp", prefs.tmp_cache, + "Use /tmp for cache. When enabled, above setting overridden to a small value. (applies on restart)") + prefs.precache = cf.sync_add( + "bool", "precache-local-files", prefs.precache, + "Cache files from local sources too. (Useful for mounted network drives)") + prefs.always_ffmpeg = cf.sync_add( + "bool", "always-ffmpeg", prefs.always_ffmpeg, + "Prefer decoding using FFMPEG. Fixes stuttering on Raspberry Pi OS.") + prefs.volume_power = cf.sync_add( + "int", "volume-curve", prefs.volume_power, + "1=Linear volume control. Values above one give greater control bias over lower volume range. Default: 2") + + # prefs.mono = cf.sync_add("bool", "force-mono", prefs.mono, "This is a placeholder setting and currently has no effect.") + # prefs.dc_device_setting = cf.sync_add("string", "disconnect-device-pause", prefs.dc_device_setting, "Can be \"on\" or \"off\". BASS only. When off, connection to device will he held open.") + # prefs.short_buffer = cf.sync_add("bool", "use-short-buffering", prefs.short_buffer, "BASS only.") + + # cf.br() + # cf.add_text("[audio (gstreamer only)]") + # + # prefs.gst_output = cf.sync_add("string", "gst-output", prefs.gst_output, "GStreamer output pipeline specification. Only used with GStreamer backend.") + # prefs.gst_use_custom_output = cf.sync_add("bool", "gst-use-custom-output", prefs.gst_use_custom_output, "Set this to true to apply any manual edits of the above string.") + + if prefs.dc_device_setting == 'on': + prefs.dc_device = True + elif prefs.dc_device_setting == 'off': + prefs.dc_device = False + + cf.br() + cf.add_text("[locale]") + prefs.ui_lang = cf.sync_add( + "string", "display-language", prefs.ui_lang, "Override display language to use if " + "available. E.g. \"en\", \"ja\", \"zh_CH\". " + "Default: \"auto\"") + # prefs.diacritic_search = cf.sync_add("bool", "decode-search", prefs.diacritic_search, "Allow searching of diacritics etc using ascii in search functions. (Disablng may speed up search)") + cf.br() + cf.add_text("[search]") + prefs.sep_genre_multi = cf.sync_add( + "bool", "separate-multi-genre", prefs.sep_genre_multi, + "If true, the standard genre result will exclude results from multi-value tags. These will be included in a separate result.") + + cf.br() + cf.add_text("[tag-editor]") + if system == 'windows' or msys: + prefs.tag_editor_name = cf.sync_add("string", "tag-editor-name", "Picard", "Name to display in UI.") + prefs.tag_editor_target = cf.sync_add( + "string", "tag-editor-target", + "C:\\Program Files (x86)\\MusicBrainz Picard\\picard.exe", + "The path of the exe to run.") + else: + prefs.tag_editor_name = cf.sync_add("string", "tag-editor-name", "Picard", "Name to display in UI.") + prefs.tag_editor_target = cf.sync_add( + "string", "tag-editor-target", "picard", + "The name of the binary to call.") + + cf.br() + cf.add_text("[playback]") + prefs.playback_follow_cursor = cf.sync_add( + "bool", "playback-follow-cursor", prefs.playback_follow_cursor, + "When advancing, always play the track that is selected.") + prefs.launch_spotify_web = cf.sync_add( + "bool", "spotify-prefer-web", prefs.launch_spotify_web, + "Launch the web client rather than attempting to launch the desktop client.") + prefs.launch_spotify_local = cf.sync_add( + "bool", "spotify-allow-local", prefs.launch_spotify_local, + "Play Spotify audio through Tauon.") + prefs.back_restarts = cf.sync_add( + "bool", "back-restarts", prefs.back_restarts, + "Pressing the back button restarts playing track on first press.") + prefs.stop_end_queue = cf.sync_add( + "bool", "end-queue-stop", prefs.stop_end_queue, + "Queue will always enable auto-stop on last track") + prefs.block_suspend = cf.sync_add( + "bool", "block-suspend", prefs.block_suspend, + "Prevent system suspend during playback") + prefs.allow_video_formats = cf.sync_add( + "bool", "allow-video-formats", prefs.allow_video_formats, + "Allow the import of MP4 and WEBM formats") + if prefs.allow_video_formats: + for item in VID_Formats: + if item not in DA_Formats: + DA_Formats.add(item) + + cf.br() + cf.add_text("[HiDPI]") + prefs.scale_want = cf.sync_add( + "float", "ui-scale", prefs.scale_want, + "UI scale factor. Default is 1.0, try increase if using a HiDPI display.") + prefs.x_scale = cf.sync_add("bool", "auto-scale", prefs.x_scale, "Automatically choose above setting") + prefs.tracklist_y_text_offset = cf.sync_add( + "int", "tracklist-y-text-offset", prefs.tracklist_y_text_offset, + "If you're using a UI scale, you may need to tweak this.") + + cf.br() + cf.add_text("[ui]") + + prefs.theme_name = cf.sync_add("string", "theme-name", prefs.theme_name) + macstyle = cf.sync_add("bool", "mac-style", prefs.macstyle, "Use macOS style window buttons") + prefs.zoom_art = cf.sync_add("bool", "allow-art-zoom", prefs.zoom_art) + prefs.gallery_row_scroll = cf.sync_add("bool", "scroll-gallery-by-row", True) + prefs.gallery_scroll_wheel_px = cf.sync_add("int", "scroll-gallery-distance", 90, + "Only has effect if scroll-gallery-by-row is false.") + prefs.spec2_scroll = cf.sync_add("bool", "scroll-spectrogram", prefs.spec2_scroll) + prefs.custom_bg_opacity = cf.sync_add("int", "mascot-opacity", prefs.custom_bg_opacity) + if prefs.custom_bg_opacity < 0 or prefs.custom_bg_opacity > 100: + prefs.custom_bg_opacity = 40 + print("Warning: Invalid value for mascot-opacity") + + prefs.sync_lyrics_time_offset = cf.sync_add( + "int", "synced-lyrics-time-offset", prefs.sync_lyrics_time_offset, + "In milliseconds. May be negative.") + prefs.artist_list_prefer_album_artist = cf.sync_add( + "bool", "artist-list-prefers-album-artist", + prefs.artist_list_prefer_album_artist, + "May require restart for change to take effect.") + prefs.meta_persists_stop = cf.sync_add( + "bool", "side-panel-info-persists", prefs.meta_persists_stop, + "Show album art and metadata of last played track when stopped.") + prefs.meta_shows_selected = cf.sync_add( + "bool", "side-panel-info-selected", prefs.meta_shows_selected, + "Show album art and metadata of selected track when stopped. (overides above setting)") + prefs.meta_shows_selected_always = cf.sync_add( + "bool", "side-panel-info-selected-always", + prefs.meta_shows_selected_always, + "Show album art and metadata of selected track at all times. (overides the above 2 settings)") + prefs.stop_notifications_mini_mode = cf.sync_add( + "bool", "mini-mode-avoid-notifications", + prefs.stop_notifications_mini_mode, + "Avoid sending track change notifications when in Mini Mode") + prefs.hide_queue = cf.sync_add("bool", "hide-queue-when-empty", prefs.hide_queue) + # prefs.show_playlist_list = cf.sync_add("bool", "show-playlist-list", prefs.show_playlist_list) + + prefs.show_current_on_transition = cf.sync_add( + "bool", "show-current-on-transition", + prefs.show_current_on_transition, + "Always jump to new playing track even with natural transition (broken setting, is always enabled") + prefs.art_in_top_panel = cf.sync_add( + "bool", "enable-art-header-bar", prefs.art_in_top_panel, + "Show art in top panel when window is narrow") + prefs.always_art_header = cf.sync_add( + "bool", "always-art-header-bar", prefs.always_art_header, + "Show art in top panel at any size. (Requires enable-art-header-bar)") + + # prefs.center_bg = cf.sync_add("bool", "prefer-center-bg", prefs.center_bg, "Always center art for the background art function") + prefs.showcase_overlay_texture = cf.sync_add( + "bool", "showcase-texture-background", prefs.showcase_overlay_texture, + "Draw pattern over background art") + prefs.side_panel_layout = cf.sync_add("int", "side-panel-style", prefs.side_panel_layout, "0:default, 1:centered") + prefs.show_side_lyrics_art_panel = cf.sync_add("bool", "side-lyrics-art", prefs.show_side_lyrics_art_panel) + prefs.lyric_metadata_panel_top = cf.sync_add("bool", "side-lyrics-art-on-top", prefs.lyric_metadata_panel_top) + prefs.use_absolute_track_index = cf.sync_add( + "bool", "absolute-track-indices", prefs.use_absolute_track_index, + "For playlists with titles disabled only") + prefs.hide_bottom_title = cf.sync_add( + "bool", "auto-hide-bottom-title", prefs.hide_bottom_title, + "Hide title in bottom panel when already shown in side panel") + prefs.auto_goto_playing = cf.sync_add( + "bool", "auto-show-playing", prefs.auto_goto_playing, + "Show playing track in current playlist on track and playlist change even if not the playing playlist") + + prefs.notify_include_album = cf.sync_add( + "bool", "notify-include-album", prefs.notify_include_album, + "Include album name in track change notifications") + prefs.rating_playtime_stars = cf.sync_add( + "bool", "show-rating-hint", prefs.rating_playtime_stars, + "Indicate playtime in rating stars") + + prefs.drag_to_unpin = cf.sync_add( + "bool", "drag-tab-to-unpin", prefs.drag_to_unpin, + "Dragging a tab off the top-panel un-pins it") + + cf.br() + cf.add_text("[gallery]") + prefs.thin_gallery_borders = cf.sync_add("bool", "gallery-thin-borders", prefs.thin_gallery_borders) + prefs.increase_gallery_row_spacing = cf.sync_add("bool", "increase-row-spacing", prefs.increase_gallery_row_spacing) + prefs.center_gallery_text = cf.sync_add("bool", "gallery-center-text", prefs.center_gallery_text) + + # show-current-on-transition", prefs.show_current_on_transition) + if system != 'windows': + cf.br() + cf.add_text("[fonts]") + cf.add_comment("Changes will require app restart.") + prefs.use_custom_fonts = cf.sync_add( + "bool", "use-custom-fonts", prefs.use_custom_fonts, + "Setting to false will reset below settings to default on restart") + if prefs.use_custom_fonts: + prefs.linux_font = cf.sync_add( + "string", "font-main-standard", prefs.linux_font, + "Suggested alternate: Liberation Sans") + prefs.linux_font_semibold = cf.sync_add("string", "font-main-medium", prefs.linux_font_semibold) + prefs.linux_font_bold = cf.sync_add("string", "font-main-bold", prefs.linux_font_bold) + prefs.linux_font_condensed = cf.sync_add("string", "font-main-condensed", prefs.linux_font_condensed) + prefs.linux_font_condensed_bold = cf.sync_add("string", "font-main-condensed-bold", prefs.linux_font_condensed_bold) + + else: + cf.sync_add("string", "font-main-standard", prefs.linux_font, "Suggested alternate: Liberation Sans") + cf.sync_add("string", "font-main-medium", prefs.linux_font_semibold) + cf.sync_add("string", "font-main-bold", prefs.linux_font_bold) + cf.sync_add("string", "font-main-condensed", prefs.linux_font_condensed) + cf.sync_add("string", "font-main-condensed-bold", prefs.linux_font_condensed_bold) + + # prefs.force_subpixel_text = cf.sync_add("bool", "force-subpixel-text", prefs.force_subpixel_text, "(Subpixel rendering defaults to off with Flatpak)") + + cf.br() + cf.add_text("[tracklist]") + prefs.dd_index = cf.sync_add("bool", "double-digit-indices", prefs.dd_index) + prefs.column_aa_fallback_artist = cf.sync_add( + "bool", "column-album-artist-fallsback", + prefs.column_aa_fallback_artist, + "'Album artist' column shows 'artist' if otherwise blank.") + prefs.left_align_album_artist_title = cf.sync_add( + "bool", "left-aligned-album-artist-title", + prefs.left_align_album_artist_title, + "Show 'Album artist' in the folder/album title. Uses colour 'column-album-artist' from theme file") + prefs.auto_sort = cf.sync_add( + "bool", "import-auto-sort", prefs.auto_sort, + "This setting is deprecated and will be removed in a future version") + + cf.br() + cf.add_text("[transcode]") + prefs.bypass_transcode = cf.sync_add( + "bool", "sync-bypass-transcode", prefs.bypass_transcode, + "Don't transcode files with sync function") + prefs.smart_bypass = cf.sync_add("bool", "sync-bypass-low-bitrate", prefs.smart_bypass, + "Skip transcode of <=128kbs folders") + prefs.radio_record_codec = cf.sync_add("string", "radio-record-codec", prefs.radio_record_codec, + "Can be OPUS, OGG, FLAC, or MP3. Default: OPUS") + + cf.br() + cf.add_text("[directories]") + cf.add_comment("Use full paths") + prefs.sync_target = cf.sync_add("string", "sync-device-music-dir", prefs.sync_target) + prefs.custom_encoder_output = cf.sync_add( + "string", "encode-output-dir", prefs.custom_encoder_output, + "E.g. \"/home/example/music/output\". If left blank, encode-output in home music dir will be used.") + if prefs.custom_encoder_output: + prefs.encoder_output = prefs.custom_encoder_output + prefs.download_dir1 = cf.sync_add( + "string", "add_download_directory", prefs.download_dir1, + "Add another folder to monitor in addition to home downloads and music.") + if prefs.download_dir1 and prefs.download_dir1 not in download_directories: + if os.path.isdir(prefs.download_dir1): + download_directories.append(prefs.download_dir1) + else: + print("Warning: Invalid download directory in config") + + cf.br() + cf.add_text("[app]") + prefs.enable_remote = cf.sync_add( + "bool", "enable-remote-interface", prefs.enable_remote, + "For use with Tauon Music Remote for Android") + prefs.use_gamepad = cf.sync_add("bool", "use-gamepad", prefs.use_gamepad, "Use game controller for UI control, restart on change.") + prefs.use_tray = cf.sync_add("bool", "use-system-tray", prefs.use_tray) + prefs.force_hide_max_button = cf.sync_add("bool", "hide-maximize-button", prefs.force_hide_max_button) + prefs.save_window_position = cf.sync_add( + "bool", "restore-window-position", prefs.save_window_position, + "Save and restore the last window position on desktop on open") + prefs.mini_mode_on_top = cf.sync_add("bool", "mini-mode-always-on-top", prefs.mini_mode_on_top) + prefs.enable_mpris = cf.sync_add("bool", "enable-mpris", prefs.enable_mpris) + prefs.reload_play_state = cf.sync_add("bool", "resume-playback-on-restart", prefs.reload_play_state) + prefs.resume_play_wake = cf.sync_add("bool", "resume-playback-on-wake", prefs.resume_play_wake) + prefs.auto_dl_artist_data = cf.sync_add( + "bool", "auto-dl-artist-data", prefs.auto_dl_artist_data, + "Enable automatic downloading of thumbnails in artist list") + prefs.enable_fanart_cover = cf.sync_add("bool", "fanart.tv-cover", prefs.enable_fanart_cover) + prefs.enable_fanart_artist = cf.sync_add("bool", "fanart.tv-artist", prefs.enable_fanart_artist) + prefs.enable_fanart_bg = cf.sync_add("bool", "fanart.tv-background", prefs.enable_fanart_bg) + prefs.always_auto_update_playlists = cf.sync_add( + "bool", "auto-update-playlists", + prefs.always_auto_update_playlists, + "Automatically update generator playlists") + prefs.write_ratings = cf.sync_add( + "bool", "write-ratings-to-tag", prefs.write_ratings, + "This writes FMPS_Rating tags on disk. Only writing to MP3, OGG and FLAC files is currently supported.") + prefs.spot_mode = cf.sync_add("bool", "enable-spotify", prefs.spot_mode, "Enable Spotify specific features") + prefs.discord_enable = cf.sync_add( + "bool", "enable-discord-rpc", prefs.discord_enable, + "Show track info in running Discord application") + prefs.auto_lyrics = cf.sync_add( + "bool", "auto-search-lyrics", prefs.auto_lyrics, + "Automatically search internet for lyrics when display is wanted") + + prefs.use_scancodes = cf.sync_add( + "bool", "shortcuts-ignore-keymap", prefs.use_scancodes, + "When enabled, shortcuts will map to the physical keyboard layout") + prefs.search_on_letter = cf.sync_add("bool", "alpha_key_activate_search", prefs.search_on_letter, + "When enabled, pressing single letter keyboard key will activate the global search") + + cf.br() + cf.add_text("[tokens]") + temp = cf.sync_add( + "string", "discogs-personal-access-token", prefs.discogs_pat, + "Used for sourcing of artist thumbnails.") + if not temp: + prefs.discogs_pat = "" + elif len(temp) != 40: + print("Warning: Invalid discogs token in config") + else: + prefs.discogs_pat = temp + + prefs.listenbrainz_url = cf.sync_add( + "string", "custom-listenbrainz-url", prefs.listenbrainz_url, + "Specify a custom Listenbrainz compatible api url. E.g. \"https://example.tld/apis/listenbrainz/\" Default: Blank") + prefs.lb_token = cf.sync_add("string", "listenbrainz-token", prefs.lb_token) + + cf.br() + cf.add_text("[tauon_satellite]") + prefs.sat_url = cf.sync_add("string", "tau-url", prefs.sat_url, "Exclude the port") + + cf.br() + cf.add_text("[lastfm]") + prefs.lastfm_pull_love = cf.sync_add( + "bool", "lastfm-pull-love", prefs.lastfm_pull_love, + "Overwrite local love status on scrobble") + + + cf.br() + cf.add_text("[maloja_account]") + prefs.maloja_url = cf.sync_add( + "string", "maloja-url", prefs.maloja_url, + "A Maloja server URL, e.g. http://localhost:32400") + prefs.maloja_key = cf.sync_add("string", "maloja-key", prefs.maloja_key, "One of your Maloja API keys") + prefs.maloja_enable = cf.sync_add("bool", "maloja-enable", prefs.maloja_enable) + + cf.br() + cf.add_text("[plex_account]") + prefs.plex_username = cf.sync_add( + "string", "plex-username", prefs.plex_username, + "Probably the email address you used to make your PLEX account.") + prefs.plex_password = cf.sync_add( + "string", "plex-password", prefs.plex_password, + "The password associated with your PLEX account.") + prefs.plex_servername = cf.sync_add( + "string", "plex-servername", prefs.plex_servername, + "Probably your servers hostname.") + + cf.br() + cf.add_text("[subsonic_account]") + prefs.subsonic_user = cf.sync_add("string", "subsonic-username", prefs.subsonic_user) + prefs.subsonic_password = cf.sync_add("string", "subsonic-password", prefs.subsonic_password) + prefs.subsonic_password_plain = cf.sync_add("bool", "subsonic-password-plain", prefs.subsonic_password_plain) + prefs.subsonic_server = cf.sync_add("string", "subsonic-server-url", prefs.subsonic_server) + + cf.br() + cf.add_text("[koel_account]") + prefs.koel_username = cf.sync_add("string", "koel-username", prefs.koel_username, "E.g. admin@example.com") + prefs.koel_password = cf.sync_add("string", "koel-password", prefs.koel_password, "The default is admin") + prefs.koel_server_url = cf.sync_add( + "string", "koel-server-url", prefs.koel_server_url, + "The URL or IP:Port where the Koel server is hosted. E.g. http://localhost:8050 or https://localhost:8060") + prefs.koel_server_url = prefs.koel_server_url.rstrip("/") + + cf.br() + cf.add_text("[jellyfin_account]") + prefs.jelly_username = cf.sync_add("string", "jelly-username", prefs.jelly_username, "") + prefs.jelly_password = cf.sync_add("string", "jelly-password", prefs.jelly_password, "") + prefs.jelly_server_url = cf.sync_add( + "string", "jelly-server-url", prefs.jelly_server_url, + "The IP:Port where the jellyfin server is hosted.") + prefs.jelly_server_url = prefs.jelly_server_url.rstrip("/") + + cf.br() + cf.add_text("[network]") + prefs.network_stream_bitrate = cf.sync_add( + "int", "stream-bitrate", prefs.network_stream_bitrate, + "Optional bitrate koel/subsonic should transcode to (Server may need to be configured for this). Set to 0 to disable transcoding.") + + cf.br() + cf.add_text("[listenalong]") + prefs.metadata_page_port = cf.sync_add( + "int", "broadcast-page-port", prefs.metadata_page_port, + "Change applies on app restart or setting re-enable") + + cf.br() + cf.add_text("[chart]") + prefs.chart_columns = cf.sync_add("int", "chart-columns", prefs.chart_columns) + prefs.chart_rows = cf.sync_add("int", "chart-rows", prefs.chart_rows) + prefs.chart_text = cf.sync_add("bool", "chart-uses-text", prefs.chart_text) + prefs.topchart_sorts_played = cf.sync_add("bool", "chart-sorts-top-played", prefs.topchart_sorts_played) + prefs.chart_font = cf.sync_add( + "string", "chart-font", prefs.chart_font, + "Format is fontname + size. Default is Monospace 10") load_prefs() @@ -4442,54 +4523,54 @@ def load_prefs(): # Temporary if 0 < db_version <= 34: - prefs.theme_name = get_theme_name(theme) + prefs.theme_name = get_theme_name(theme) if 0 < db_version <= 66: - prefs.device_buffer = 80 + prefs.device_buffer = 80 if 0 < db_version <= 53: - print("Resetting fonts to defaults") - prefs.linux_font = "Noto Sans" - prefs.linux_font_semibold = "Noto Sans Medium" - prefs.linux_font_bold = "Noto Sans Bold" - save_prefs() + print("Resetting fonts to defaults") + prefs.linux_font = "Noto Sans" + prefs.linux_font_semibold = "Noto Sans Medium" + prefs.linux_font_bold = "Noto Sans Bold" + save_prefs() lang = "" locale_dir = os.path.join(install_directory, "locale") if flatpak_mode: - locale_dir = "/app/share/locale" + locale_dir = "/app/share/locale" elif install_directory.startswith("/opt/") or install_directory.startswith("/usr/"): - locale_dir = "/usr/share/locale" + locale_dir = "/usr/share/locale" lang = [] if prefs.ui_lang != "auto" or prefs.ui_lang == "": - lang = [prefs.ui_lang] + lang = [prefs.ui_lang] if lang: - # Force set lang - f = gettext.find('tauon', localedir=locale_dir, languages=lang) + # Force set lang + f = gettext.find('tauon', localedir=locale_dir, languages=lang) - if f: - translation = gettext.translation('tauon', localedir=locale_dir, languages=lang) - translation.install() - _ = translation.gettext + if f: + translation = gettext.translation('tauon', localedir=locale_dir, languages=lang) + translation.install() + _ = translation.gettext - print("Translation file loaded") - else: - print("No translation file available") + print("Translation file loaded") + else: + print("No translation file available") else: - # Auto detect lang - f = gettext.find('tauon', localedir=locale_dir) + # Auto detect lang + f = gettext.find('tauon', localedir=locale_dir) - if f: - translation = gettext.translation('tauon', localedir=locale_dir) - translation.install() - _ = translation.gettext + if f: + translation = gettext.translation('tauon', localedir=locale_dir) + translation.install() + _ = translation.gettext - print("Translation file loaded") - # else: - # print("No translation file available") + print("Translation file loaded") + # else: + # print("No translation file available") # ---- @@ -4497,364 +4578,364 @@ def load_prefs(): SDL_GetWindowWMInfo(t_window, sss) if prefs.use_gamepad: - SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) + SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) smtc = False if msys and win_ver >= 10: - #print(sss.info.win.window) - try: - sm = ctypes.cdll.LoadLibrary(os.path.join(install_directory, "lib", "TauonSMTC.dll")) - - def SMTC_button_callback(button): - - if button == 1: - inp.media_key = 'Play' - if button == 2: - inp.media_key = 'Pause' - if button == 3: - inp.media_key = "Next" - if button == 4: - inp.media_key = "Previous" - if button == 5: - inp.media_key = "Stop" - gui.update += 1 - tauon.wake() - - close_callback = ctypes.WINFUNCTYPE(ctypes.c_void_p, ctypes.c_int)(SMTC_button_callback) - smtc = sm.init(close_callback) == 0 - except Exception: - print("Failed to load TauonSMTC.dll") + #print(sss.info.win.window) + try: + sm = ctypes.cdll.LoadLibrary(os.path.join(install_directory, "lib", "TauonSMTC.dll")) + + def SMTC_button_callback(button): + + if button == 1: + inp.media_key = 'Play' + if button == 2: + inp.media_key = 'Pause' + if button == 3: + inp.media_key = "Next" + if button == 4: + inp.media_key = "Previous" + if button == 5: + inp.media_key = "Stop" + gui.update += 1 + tauon.wake() + + close_callback = ctypes.WINFUNCTYPE(ctypes.c_void_p, ctypes.c_int)(SMTC_button_callback) + smtc = sm.init(close_callback) == 0 + except Exception: + print("Failed to load TauonSMTC.dll") def auto_scale(): - old = prefs.scale_want - - if prefs.x_scale: - if sss.subsystem in (SDL_SYSWM_WAYLAND, SDL_SYSWM_COCOA, SDL_SYSWM_UNKNOWN): - prefs.scale_want = window_size[0] / logical_size[0] - if old != prefs.scale_want: - print("Applying scale based on buffer size") - elif sss.subsystem == SDL_SYSWM_X11: - if xdpi > 40: - prefs.scale_want = xdpi / 96 - if old != prefs.scale_want: - print("Applying scale based on xft setting") - - prefs.scale_want = round(round(prefs.scale_want / 0.05) * 0.05, 2) - - if prefs.scale_want == 0.95: - prefs.scale_want = 1.0 - if prefs.scale_want == 1.05: - prefs.scale_want = 1.0 - if prefs.scale_want == 1.95: - prefs.scale_want = 2.0 - if prefs.scale_want == 2.05: - prefs.scale_want = 2.0 - - if old != prefs.scale_want: - print(f"Using UI scale: {prefs.scale_want}") - - if prefs.scale_want < 0.5: - prefs.scale_want = 1.0 - - if window_size[0] < (560 * prefs.scale_want) * 0.9 or window_size[1] < (330 * prefs.scale_want) * 0.9: - print("Window overscale!") - show_message(_("Detected unsuitable UI scaling."), _("Scaling setting reset to 1x")) - prefs.scale_want = 1.0 + old = prefs.scale_want + + if prefs.x_scale: + if sss.subsystem in (SDL_SYSWM_WAYLAND, SDL_SYSWM_COCOA, SDL_SYSWM_UNKNOWN): + prefs.scale_want = window_size[0] / logical_size[0] + if old != prefs.scale_want: + print("Applying scale based on buffer size") + elif sss.subsystem == SDL_SYSWM_X11: + if xdpi > 40: + prefs.scale_want = xdpi / 96 + if old != prefs.scale_want: + print("Applying scale based on xft setting") + + prefs.scale_want = round(round(prefs.scale_want / 0.05) * 0.05, 2) + + if prefs.scale_want == 0.95: + prefs.scale_want = 1.0 + if prefs.scale_want == 1.05: + prefs.scale_want = 1.0 + if prefs.scale_want == 1.95: + prefs.scale_want = 2.0 + if prefs.scale_want == 2.05: + prefs.scale_want = 2.0 + + if old != prefs.scale_want: + print(f"Using UI scale: {prefs.scale_want}") + + if prefs.scale_want < 0.5: + prefs.scale_want = 1.0 + + if window_size[0] < (560 * prefs.scale_want) * 0.9 or window_size[1] < (330 * prefs.scale_want) * 0.9: + print("Window overscale!") + show_message(_("Detected unsuitable UI scaling."), _("Scaling setting reset to 1x")) + prefs.scale_want = 1.0 auto_scale() def scale_assets(scale_want, force=False): - global scaled_asset_directory - if scale_want != 1: - scaled_asset_directory = os.path.join(user_directory, "scaled-icons") - if not os.path.exists(scaled_asset_directory) or len(os.listdir(svg_directory)) != len( - os.listdir(scaled_asset_directory)): - print("Force rerender icons") - force = True - else: - scaled_asset_directory = asset_directory - - if scale_want != prefs.ui_scale or force: - - if scale_want != 1: - if os.path.isdir(scaled_asset_directory) and scaled_asset_directory != asset_directory: - shutil.rmtree(scaled_asset_directory) - from t_modules.t_svgout import render_icons - - if scaled_asset_directory != asset_directory: - print("Rendering icons...") - render_icons(svg_directory, scaled_asset_directory, scale_want) - - print("Done rendering icons") - - diff_ratio = scale_want / prefs.ui_scale - prefs.ui_scale = scale_want - prefs.playlist_row_height = round(22 * prefs.ui_scale) - - # Save user values - column_backup = gui.pl_st - rspw = gui.pref_rspw - grspw = gui.pref_gallery_w - - gui.destroy_textures() - gui.rescale() - - # Scale saved values - gui.pl_st = column_backup - for item in gui.pl_st: - item[1] *= diff_ratio - gui.pref_rspw = rspw * diff_ratio - gui.pref_gallery_w = grspw * diff_ratio - global album_mode_art_size - album_mode_art_size = int(album_mode_art_size * diff_ratio) + global scaled_asset_directory + if scale_want != 1: + scaled_asset_directory = os.path.join(user_directory, "scaled-icons") + if not os.path.exists(scaled_asset_directory) or len(os.listdir(svg_directory)) != len( + os.listdir(scaled_asset_directory)): + print("Force rerender icons") + force = True + else: + scaled_asset_directory = asset_directory + + if scale_want != prefs.ui_scale or force: + + if scale_want != 1: + if os.path.isdir(scaled_asset_directory) and scaled_asset_directory != asset_directory: + shutil.rmtree(scaled_asset_directory) + from t_modules.t_svgout import render_icons + + if scaled_asset_directory != asset_directory: + print("Rendering icons...") + render_icons(svg_directory, scaled_asset_directory, scale_want) + + print("Done rendering icons") + + diff_ratio = scale_want / prefs.ui_scale + prefs.ui_scale = scale_want + prefs.playlist_row_height = round(22 * prefs.ui_scale) + + # Save user values + column_backup = gui.pl_st + rspw = gui.pref_rspw + grspw = gui.pref_gallery_w + + gui.destroy_textures() + gui.rescale() + + # Scale saved values + gui.pl_st = column_backup + for item in gui.pl_st: + item[1] *= diff_ratio + gui.pref_rspw = rspw * diff_ratio + gui.pref_gallery_w = grspw * diff_ratio + global album_mode_art_size + album_mode_art_size = int(album_mode_art_size * diff_ratio) scale_assets(scale_want=prefs.scale_want) try: - # star_lines = view_prefs['star-lines'] - update_title = view_prefs['update-title'] - prefs.prefer_side = view_prefs['side-panel'] - prefs.dim_art = False # view_prefs['dim-art'] - #gui.turbo = view_prefs['level-meter'] - # pl_follow = view_prefs['pl-follow'] - scroll_enable = view_prefs['scroll-enable'] - break_enable = view_prefs['break-enable'] - # dd_index = view_prefs['dd-index'] - # custom_line_mode = view_prefs['custom-line'] - # thick_lines = view_prefs['thick-lines'] - prefs.append_date = view_prefs['append-date'] + # star_lines = view_prefs['star-lines'] + update_title = view_prefs['update-title'] + prefs.prefer_side = view_prefs['side-panel'] + prefs.dim_art = False # view_prefs['dim-art'] + #gui.turbo = view_prefs['level-meter'] + # pl_follow = view_prefs['pl-follow'] + scroll_enable = view_prefs['scroll-enable'] + break_enable = view_prefs['break-enable'] + # dd_index = view_prefs['dd-index'] + # custom_line_mode = view_prefs['custom-line'] + # thick_lines = view_prefs['thick-lines'] + prefs.append_date = view_prefs['append-date'] except Exception: - print("warning: error loading settings") + print("warning: error loading settings") if prefs.prefer_side is False: - gui.rsp = False + gui.rsp = False def get_global_mouse(): - i_y = pointer(c_int(0)) - i_x = pointer(c_int(0)) - SDL_GetGlobalMouseState(i_x, i_y) - return i_x.contents.value, i_y.contents.value + i_y = pointer(c_int(0)) + i_x = pointer(c_int(0)) + SDL_GetGlobalMouseState(i_x, i_y) + return i_x.contents.value, i_y.contents.value def get_window_position(): - i_y = pointer(c_int(0)) - i_x = pointer(c_int(0)) - SDL_GetWindowPosition(t_window, i_x, i_y) - return i_x.contents.value, i_y.contents.value + i_y = pointer(c_int(0)) + i_x = pointer(c_int(0)) + SDL_GetWindowPosition(t_window, i_x, i_y) + return i_x.contents.value, i_y.contents.value # Access functions from libopenmpt for scanning tracker files class MOD(Structure): - _fields_ = [('ctl', c_char_p), - ('value', c_char_p)] + _fields_ = [('ctl', c_char_p), + ('value', c_char_p)] mpt = None try: - p = ctypes.util.find_library("libopenmpt") - if p: - mpt = ctypes.cdll.LoadLibrary(p) - elif msys: - mpt = ctypes.cdll.LoadLibrary("libopenmpt-0.dll") - else: - mpt = ctypes.cdll.LoadLibrary("libopenmpt.so") - - mpt.openmpt_module_create_from_memory.restype = c_void_p - mpt.openmpt_module_get_metadata.restype = c_char_p - mpt.openmpt_module_get_duration_seconds.restype = c_double + p = ctypes.util.find_library("libopenmpt") + if p: + mpt = ctypes.cdll.LoadLibrary(p) + elif msys: + mpt = ctypes.cdll.LoadLibrary("libopenmpt-0.dll") + else: + mpt = ctypes.cdll.LoadLibrary("libopenmpt.so") + + mpt.openmpt_module_create_from_memory.restype = c_void_p + mpt.openmpt_module_get_metadata.restype = c_char_p + mpt.openmpt_module_get_duration_seconds.restype = c_double except Exception: - print("Failed to load libopenmpt!") + print("Failed to load libopenmpt!") class GMETrackInfo(Structure): - _fields_ = [ - ("length", c_int), - ("intro_length", c_int), - ("loop_length", c_int), - ("play_length", c_int), - ("fade_length", c_int), - ("i5", c_int), - ("i6", c_int), - ("i7", c_int), - ("i8", c_int), - ("i9", c_int), - ("i10", c_int), - ("i11", c_int), - ("i12", c_int), - ("i13", c_int), - ("i14", c_int), - ("i15", c_int), - ("system", c_char_p), - ("game", c_char_p), - ("song", c_char_p), - ("author", c_char_p), - ("copyright", c_char_p), - ("comment", c_char_p), - ("dumper", c_char_p), - ("s7", c_char_p), - ("s8", c_char_p), - ("s9", c_char_p), - ("s10", c_char_p), - ("s11", c_char_p), - ("s12", c_char_p), - ("s13", c_char_p), - ("s14", c_char_p), - ("s15", c_char_p) - ] + _fields_ = [ + ("length", c_int), + ("intro_length", c_int), + ("loop_length", c_int), + ("play_length", c_int), + ("fade_length", c_int), + ("i5", c_int), + ("i6", c_int), + ("i7", c_int), + ("i8", c_int), + ("i9", c_int), + ("i10", c_int), + ("i11", c_int), + ("i12", c_int), + ("i13", c_int), + ("i14", c_int), + ("i15", c_int), + ("system", c_char_p), + ("game", c_char_p), + ("song", c_char_p), + ("author", c_char_p), + ("copyright", c_char_p), + ("comment", c_char_p), + ("dumper", c_char_p), + ("s7", c_char_p), + ("s8", c_char_p), + ("s9", c_char_p), + ("s10", c_char_p), + ("s11", c_char_p), + ("s12", c_char_p), + ("s13", c_char_p), + ("s14", c_char_p), + ("s15", c_char_p) + ] gme = None p = None try: - p = ctypes.util.find_library("libgme") - if p: - gme = ctypes.cdll.LoadLibrary(p) - elif msys: - gme = ctypes.cdll.LoadLibrary("libgme-0.dll") - else: - gme = ctypes.cdll.LoadLibrary("libgme.so") - - gme.gme_free_info.argtypes = [ctypes.POINTER(GMETrackInfo)] - gme.gme_track_info.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.POINTER(GMETrackInfo)), ctypes.c_int] - gme.gme_track_info.restype = ctypes.c_char_p - gme.gme_open_file.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p), ctypes.c_int] - gme.gme_open_file.restype = ctypes.c_char_p + p = ctypes.util.find_library("libgme") + if p: + gme = ctypes.cdll.LoadLibrary(p) + elif msys: + gme = ctypes.cdll.LoadLibrary("libgme-0.dll") + else: + gme = ctypes.cdll.LoadLibrary("libgme.so") + + gme.gme_free_info.argtypes = [ctypes.POINTER(GMETrackInfo)] + gme.gme_track_info.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.POINTER(GMETrackInfo)), ctypes.c_int] + gme.gme_track_info.restype = ctypes.c_char_p + gme.gme_open_file.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p), ctypes.c_int] + gme.gme_open_file.restype = ctypes.c_char_p except Exception: - print("Cannont find libgme") + print("Cannont find libgme") def use_id3(tags, nt): - def natural_get(tag, track, frame, attr): - frames = tag.getall(frame) - if frames and frames[0].text: - if track is None: - return str(frames[0].text[0]) - setattr(track, attr, str(frames[0].text[0])) - elif track is None: - return "" - else: - setattr(track, attr, "") - - tag = tags - - natural_get(tags, nt, "TIT2", "title") - natural_get(tags, nt, "TPE1", "artist") - natural_get(tags, nt, "TPE2", "album_artist") - natural_get(tags, nt, "TCON", "genre") # content type - natural_get(tags, nt, "TALB", "album") - natural_get(tags, nt, "TDRC", "date") - natural_get(tags, nt, "TCOM", "composer") - natural_get(tags, nt, "COMM", "comment") - - process_odat(nt, natural_get(tags, None, "TDOR", None)) - - frames = tag.getall("POPM") - rating = 0 - if frames: - for frame in frames: - if frame.rating: - rating = frame.rating - nt.misc['POPM'] = frame.rating - - if len(nt.comment) > 4 and nt.comment[2] == "+": - nt.comment = "" - if nt.comment[0:3] == "000": - nt.comment = "" - - frames = tag.getall("USLT") - if frames: - nt.lyrics = frames[0].text - if 0 < len(nt.lyrics) < 150: - if "unavailable" in nt.lyrics or ".com" in nt.lyrics or "www." in nt.lyrics: - nt.lyrics = "" - - frames = tag.getall("TPE1") - if frames: - d = [] - for frame in frames: - for t in frame.text: - d.append(t) - if len(d) > 1: - nt.misc['artists'] = d - nt.artist = "; ".join(d) - - frames = tag.getall("TCON") - if frames: - d = [] - for frame in frames: - for t in frame.text: - d.append(t) - if len(d) > 1: - nt.misc['genres'] = d - nt.genre = " / ".join(d) - - track_no = natural_get(tags, None, "TRCK", None) - nt.track_total = "" - nt.track_number = "" - if track_no and track_no != "null": - if "/" in track_no: - a, b = track_no.split("/") - nt.track_number = a - nt.track_total = b - else: - nt.track_number = track_no - - disc = natural_get(tags, None, "TPOS", None) # set ? or ?/? - nt.disc_total = "" - nt.disc_number = "" - if disc: - if "/" in disc: - a, b = disc.split("/") - nt.disc_number = a - nt.disc_total = b - else: - nt.disc_number = disc - - tx = tags.getall("UFID") - if tx: - for item in tx: - if item.owner == "http://musicbrainz.org": - nt.misc['musicbrainz_recordingid'] = item.data.decode() - - tx = tags.getall("TSOP") - if tx: - nt.misc["artist_sort"] = tx[0].text[0] - - tx = tags.getall("TXXX") - if tx: - for item in tx: - if item.desc == "MusicBrainz Release Track Id": - nt.misc['musicbrainz_trackid'] = item.text[0] - if item.desc == "MusicBrainz Album Id": - nt.misc['musicbrainz_albumid'] = item.text[0] - if item.desc == "MusicBrainz Release Group Id": - nt.misc['musicbrainz_releasegroupid'] = item.text[0] - if item.desc == "MusicBrainz Artist Id": - nt.misc['musicbrainz_artistids'] = list(item.text) - - try: - desc = item.desc.lower() - if desc == "replaygain_track_gain": - nt.misc['replaygain_track_gain'] = float(item.text[0].strip(" dB")) - if desc == "replaygain_track_peak": - nt.misc['replaygain_track_peak'] = float(item.text[0]) - if desc == "replaygain_album_gain": - nt.misc['replaygain_album_gain'] = float(item.text[0].strip(" dB")) - if desc == "replaygain_album_peak": - nt.misc['replaygain_album_peak'] = float(item.text[0]) - except Exception: - print("Tag Scan: Read Replay Gain MP3 error") - print(nt.fullpath) - - if item.desc == "FMPS_RATING": - nt.misc['FMPS_Rating'] = float(item.text[0]) + def natural_get(tag, track, frame, attr): + frames = tag.getall(frame) + if frames and frames[0].text: + if track is None: + return str(frames[0].text[0]) + setattr(track, attr, str(frames[0].text[0])) + elif track is None: + return "" + else: + setattr(track, attr, "") + + tag = tags + + natural_get(tags, nt, "TIT2", "title") + natural_get(tags, nt, "TPE1", "artist") + natural_get(tags, nt, "TPE2", "album_artist") + natural_get(tags, nt, "TCON", "genre") # content type + natural_get(tags, nt, "TALB", "album") + natural_get(tags, nt, "TDRC", "date") + natural_get(tags, nt, "TCOM", "composer") + natural_get(tags, nt, "COMM", "comment") + + process_odat(nt, natural_get(tags, None, "TDOR", None)) + + frames = tag.getall("POPM") + rating = 0 + if frames: + for frame in frames: + if frame.rating: + rating = frame.rating + nt.misc['POPM'] = frame.rating + + if len(nt.comment) > 4 and nt.comment[2] == "+": + nt.comment = "" + if nt.comment[0:3] == "000": + nt.comment = "" + + frames = tag.getall("USLT") + if frames: + nt.lyrics = frames[0].text + if 0 < len(nt.lyrics) < 150: + if "unavailable" in nt.lyrics or ".com" in nt.lyrics or "www." in nt.lyrics: + nt.lyrics = "" + + frames = tag.getall("TPE1") + if frames: + d = [] + for frame in frames: + for t in frame.text: + d.append(t) + if len(d) > 1: + nt.misc['artists'] = d + nt.artist = "; ".join(d) + + frames = tag.getall("TCON") + if frames: + d = [] + for frame in frames: + for t in frame.text: + d.append(t) + if len(d) > 1: + nt.misc['genres'] = d + nt.genre = " / ".join(d) + + track_no = natural_get(tags, None, "TRCK", None) + nt.track_total = "" + nt.track_number = "" + if track_no and track_no != "null": + if "/" in track_no: + a, b = track_no.split("/") + nt.track_number = a + nt.track_total = b + else: + nt.track_number = track_no + + disc = natural_get(tags, None, "TPOS", None) # set ? or ?/? + nt.disc_total = "" + nt.disc_number = "" + if disc: + if "/" in disc: + a, b = disc.split("/") + nt.disc_number = a + nt.disc_total = b + else: + nt.disc_number = disc + + tx = tags.getall("UFID") + if tx: + for item in tx: + if item.owner == "http://musicbrainz.org": + nt.misc['musicbrainz_recordingid'] = item.data.decode() + + tx = tags.getall("TSOP") + if tx: + nt.misc["artist_sort"] = tx[0].text[0] + + tx = tags.getall("TXXX") + if tx: + for item in tx: + if item.desc == "MusicBrainz Release Track Id": + nt.misc['musicbrainz_trackid'] = item.text[0] + if item.desc == "MusicBrainz Album Id": + nt.misc['musicbrainz_albumid'] = item.text[0] + if item.desc == "MusicBrainz Release Group Id": + nt.misc['musicbrainz_releasegroupid'] = item.text[0] + if item.desc == "MusicBrainz Artist Id": + nt.misc['musicbrainz_artistids'] = list(item.text) + + try: + desc = item.desc.lower() + if desc == "replaygain_track_gain": + nt.misc['replaygain_track_gain'] = float(item.text[0].strip(" dB")) + if desc == "replaygain_track_peak": + nt.misc['replaygain_track_peak'] = float(item.text[0]) + if desc == "replaygain_album_gain": + nt.misc['replaygain_album_gain'] = float(item.text[0].strip(" dB")) + if desc == "replaygain_album_peak": + nt.misc['replaygain_album_peak'] = float(item.text[0]) + except Exception: + print("Tag Scan: Read Replay Gain MP3 error") + print(nt.fullpath) + + if item.desc == "FMPS_RATING": + nt.misc['FMPS_Rating'] = float(item.text[0]) def scan_ffprobe(nt): @@ -48701,9 +48782,9 @@ def drop_file(target): del tauon.play_lock if tauon.librespot_p: - time.sleep(1) - print("Kill liberspot") - tauon.librespot_p.kill() - #tauon.librespot_p.communicate() + time.sleep(1) + print("Kill liberspot") + tauon.librespot_p.kill() + #tauon.librespot_p.communicate() print("bye") From 1bc556db3d0f4e1bd7205f235edd2b415d8f70b4 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 17:29:51 +0100 Subject: [PATCH 03/63] t_main: Add missing imports --- t_modules/t_main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index 54abd4e39..2ca40e345 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -63,7 +63,7 @@ import zipfile from collections import OrderedDict from collections.abc import Callable -from ctypes import c_char_p, pointer, Structure +from ctypes import c_char_p, c_double, c_int, c_void_p, pointer, Structure from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING @@ -191,11 +191,14 @@ SDL_QueryTexture, SDL_Quit, SDL_QuitSubSystem, + SDL_RenderClear, SDL_RenderFillRect, + SDL_RenderPresent, SDL_RestoreWindow, SDL_SetClipboardText, SDL_SetCursor, SDL_SetRenderDrawBlendMode, + SDL_SetRenderDrawColor, SDL_SetRenderTarget, SDL_SetTextureAlphaMod, SDL_SetTextureBlendMode, @@ -221,7 +224,7 @@ rw_from_object, ) -from sdl2.sdlimage import IMG_Load_RW, IMG_Quit +from sdl2.sdlimage import IMG_Load, IMG_Load_RW, IMG_Quit from send2trash import send2trash from unidecode import unidecode From 965501232f11ba3a553f4ab448f482134cf53e46 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 17:31:53 +0100 Subject: [PATCH 04/63] Bump Gtk import to 4.0 to fix an import error/crash --- t_modules/t_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index 2ca40e345..d0feb6625 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -388,7 +388,7 @@ mac_maximize = (254, 176, 36, 255) mac_minimize = (42, 189, 49, 255) try: - gi.require_version("Gtk", "3.0") + gi.require_version("Gtk", "4.0") from gi.repository import Gtk gtk_settings = Gtk.Settings().get_default() From 601c77fd17b358a1c39b9e4ca516f827139149c0 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 18:27:33 +0100 Subject: [PATCH 05/63] t_main: Partially migrate to logging and improve exceptions --- t_modules/t_main.py | 459 ++++++++++++++++++++++++-------------------- 1 file changed, 251 insertions(+), 208 deletions(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index d0feb6625..49e54aabc 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -249,27 +249,28 @@ try: from jxlpy import JXLImagePlugin - print("Found jxlpy for JPEG XL support") + logging.info("Found jxlpy for JPEG XL support") except Exception: - pass + logging.exception("Unable to import jxlpy") try: import setproctitle setproctitle.setproctitle("tauonmb") except Exception: - print("Could not set process title.") + logging.exception("Could not set process title.") # try: # import rpc # discord_allow = True # except Exception: -# pass +# logging.exception("Unable to import rpc, Discord Rich Presence will be disabled.") try: from pypresence import Presence import asyncio discord_allow = True except Exception: + logging.exception("Unable to import python-pypresence, Discord Rich Presence will be disabled.") discord_allow = False try: @@ -288,7 +289,7 @@ t2s = opencc.OpenCC("t2s") use_cc = True except Exception: - print("OpenCC not found.") + logging.exception("OpenCC not found.") use_natsort = False try: @@ -296,7 +297,7 @@ use_natsort = True except Exception: - print("Warning: Python module natsort not found") + logging.exception("Python module natsort not found") # Detect platform windows_native = False @@ -353,7 +354,7 @@ t_agent = h.agent dev_mode = h.dev_mode instance_lock = h.lock -print(f"Window size: {window_size}") +logging.info(f"Window size: {window_size}") should_save_state = True @@ -400,7 +401,7 @@ if "close" in str(gtk_settings.get_property("gtk-decoration-layout")).split(":")[0]: left_window_control = True gtk_theme = str(gtk_settings.get_property("gtk-theme-name")).lower() - #print(f"GTK theme is: {gtk_theme}") + #logging.info(f"GTK theme is: {gtk_theme}") for k, v in mac_styles.items(): if k in gtk_theme: detect_macstyle = True @@ -410,7 +411,7 @@ mac_minimize = v[2] except Exception: - print("Error accessing GTK settings") + logging.exception("Error accessing GTK settings") # if system == "windows" or msys: # os.environ["PYSDL2_DLL_PATH"] = install_directory + "\\lib" @@ -449,7 +450,7 @@ snap_mode = True if install_directory[:5] == "/app/": # Flatpak mode - print("Detected running as Flatpak") + logging.info("Detected running as Flatpak") # [old / no longer used] Symlink fontconfig from host system as workaround for poor font rendering if os.path.exists(os.path.join(home_directory, ".var/app/com.github.taiko2k.tauonmb/config")): @@ -462,10 +463,10 @@ # if os.path.isdir(flatpak_fcfg) and not os.path.islink(flatpak_fcfg): # shutil.rmtree(flatpak_fcfg) if os.path.islink(flatpak_fcfg): - print("-- Symlink to fonconfig exists, removing") + logging.info("-- Symlink to fonconfig exists, removing") os.unlink(flatpak_fcfg) # else: - # print("-- Symlinking user fonconfig") + # logging.info("-- Symlinking user fonconfig") # #os.symlink(host_fcfg, flatpak_fcfg) flatpak_mode = True @@ -484,13 +485,13 @@ os.makedirs(config_directory) if snap_mode: - print("Installed as Snap") + logging.info("Installed as Snap") elif flatpak_mode: - print("Installed as Flatpak") + logging.info("Installed as Flatpak") else: - print("Running from installed location") + logging.info("Running from installed location") - print("User files location: " + user_directory) + logging.info("User files location: " + user_directory) if not os.path.isdir(os.path.join(user_directory, "encoder")): os.makedirs(os.path.join(user_directory, "encoder")) @@ -503,15 +504,15 @@ # user_directory = os.path.expanduser('~').replace("\\", '/') + "/Music/TauonMusicBox" # config_directory = user_directory # cache_directory = user_directory + "\\cache" -# print("User Directroy: ", end="") -# print(user_directory) +# logging.info("User Directroy: ", end="") +# logging.info(user_directory) # install_mode = True # if not os.path.isdir(user_directory): # os.makedirs(user_directory) else: - print("Running in portable mode") + logging.info("Running in portable mode") user_directory = os.path.join(install_directory, "user-data") config_directory = user_directory @@ -521,8 +522,8 @@ if not os.path.isfile(os.path.join(user_directory, "state.p")): if os.path.isdir(cache_directory): - print("Clearing old cache directory") - print(cache_directory) + logging.info("Clearing old cache directory") + logging.info(cache_directory) shutil.rmtree(cache_directory) n_cache_dir = os.path.join(cache_directory, "network") @@ -562,21 +563,21 @@ if line.startswith("XDG_MUSIC_DIR="): music_directory = os.path.expanduser( os.path.expandvars(line.split("=")[1].strip().replace('"', ""))) - print(f"Found XDG-Music: {music_directory}") + logging.info(f"Found XDG-Music: {music_directory}") if line.startswith("XDG_DOWNLOAD_DIR="): target = os.path.expanduser(os.path.expandvars(line.split("=")[1].strip().replace('"', ""))) if os.path.isdir(target): download_directory = target - print(f"Found XDG-Downloads: {download_directory}") + logging.info(f"Found XDG-Downloads: {download_directory}") if os.getenv('XDG_MUSIC_DIR'): music_directory = os.getenv('XDG_MUSIC_DIR') - print("Override music to: " + music_directory) + logging.info("Override music to: " + music_directory) if os.getenv('XDG_DOWNLOAD_DIR'): download_directory = os.getenv('XDG_DOWNLOAD_DIR') - print("Override downloads to: " + download_directory) + logging.info("Override downloads to: " + download_directory) if music_directory: music_directory = os.path.expandvars(music_directory) @@ -586,7 +587,7 @@ if not os.path.isdir(music_directory): music_directory = None -print('Install directory: ' + install_directory) +logging.info('Install directory: ' + install_directory) old_backend = 2 @@ -601,6 +602,7 @@ def whicher(target) -> bool | str: return "bin/" + target in r return shutil.which(target) except Exception: + logging.exception("Failed to run flatpak-spawn") return False @@ -779,11 +781,11 @@ def asset_loader(name, mod=False): # SDL_RenderPresent(renderer) # if install_directory != config_directory and not os.path.isfile(os.path.join(config_directory, "config.txt")): -# print("Config file is missing... copying template from program files") +# logging.info("Config file is missing... copying template from program files") # shutil.copy(os.path.join(install_directory, "config.txt"), config_directory) if install_directory != config_directory and not os.path.isfile(os.path.join(config_directory, "input.txt")): - print("Input config file is missing... copying template from program files") + logging.info("Input config file is missing... copying template from program files") shutil.copy(os.path.join(install_directory, "input.txt"), config_directory) last_fm_enable = False @@ -800,10 +802,11 @@ def asset_loader(name, mod=False): try: win_ver = int(win_ver) except Exception: + logging.exception("Failed getting Windows version from platform.release()") win_ver = 0 -# print(arch) +# logging.info(arch) # ----------------------------------------------------------- # Detect locale for translations (currently none available) @@ -814,7 +817,7 @@ def _(message): try: py_locale.setlocale(py_locale.LC_ALL, '') except Exception: - print("SET LOCALE ERROR") + logging.exception("SET LOCALE ERROR") # ------------------------------------------------ @@ -824,6 +827,7 @@ def _(message): try: gi.require_version("Notify", "0.7") except Exception: + logging.exception("Failed importing gi Notify 0.7, will try 0.8") gi.require_version("Notify", "0.8") from gi.repository import Notify @@ -909,7 +913,7 @@ def print(self, message, level=0): level = -1 self.messages.append((line, level, dtime, Timer())) - print(message) + logging.info(message) console = DConsole() @@ -1599,7 +1603,7 @@ def __init__(self): def open_uri(uri:str): - print("OPEN URI") + logging.info("OPEN URI") load_order = LoadClass() for w in range(len(pctl.multi_playlist)): @@ -2150,7 +2154,7 @@ def set_rating(self, index, value, write=False): shooter(subsonic.set_rating, (tr, value)) if prefs.write_ratings and write: - print("Writing rating..") + logging.info("Writing rating..") assert value <= 10 assert value >= 0 @@ -2916,26 +2920,26 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" s2 = os.path.getsize(sp2) to_load = sp1 if s2 > s1: - print("Loading backup star.p") + logging.info("Loading backup star.p") to_load = sp2 star_store.db = pickle.load(open(to_load, "rb")) except Exception: - print('No existing star.p file') + logging.exception('No existing star.p file') try: album_star_store.db = pickle.load(open(user_directory + "/album-star.p", "rb")) except Exception: - print('No existing album-star.p file') + logging.exception('No existing album-star.p file') try: if os.path.isfile(user_directory + "/lyrics_substitutions.json"): with open(user_directory + "/lyrics_substitutions.json", 'r') as f: prefs.lyrics_subs = json.load(f) except Exception: - print("Error loading lyrics_substitutions.json") + logging.exception("Error loading lyrics_substitutions.json") perf_timer.set() @@ -3011,14 +3015,14 @@ def pumper(): # def tt(): # while True: - # print(state_file.tell()) + # logging.info(state_file.tell()) # time.sleep(0.01) # shooter(tt) save = pickle.load(state_file) if t == 1: - print("Using backup state") + logging.info("Using backup state") if save[63] is not None: prefs.ui_scale = save[63] @@ -3378,13 +3382,15 @@ def pumper(): break except IndexError: + logging.exception("Index error") break except Exception: + logging.exception("Failed to load save file") if os.path.isfile(user_directory + "/state.p"): - print('Error loading save file') + logging.error('Error loading save file') core_timer.set() -print(f"Database loaded in {round(perf_timer.get(), 3)} seconds.") +logging.info(f"Database loaded in {round(perf_timer.get(), 3)} seconds.") perf_timer.set() keys = set(master_library.keys()) @@ -3392,7 +3398,7 @@ def pumper(): keys -= set(pl[2]) if len(keys) > 5000: gui.suggest_clean_db = True -# print(f"Database scanned in {round(perf_timer.get(), 3)} seconds.") +# logging.info(f"Database scanned in {round(perf_timer.get(), 3)} seconds.") pump = False shoot_pump.join() @@ -3432,7 +3438,7 @@ def get_theme_name(number): return 'Mindaro' number -= 1 themes = get_themes() - print((number, themes)) + logging.info((number, themes)) if len(themes) > number: return themes[number][1] return "" @@ -4086,7 +4092,7 @@ def save_prefs(): if os.path.isdir(config_directory): cf.dump(os.path.join(config_directory, "tauon.conf")) else: - print("ERROR: Missing config directory") + logging.error("Missing config directory") def load_prefs(): @@ -4243,7 +4249,7 @@ def load_prefs(): prefs.custom_bg_opacity = cf.sync_add("int", "mascot-opacity", prefs.custom_bg_opacity) if prefs.custom_bg_opacity < 0 or prefs.custom_bg_opacity > 100: prefs.custom_bg_opacity = 40 - print("Warning: Invalid value for mascot-opacity") + logging.warning("Invalid value for mascot-opacity") prefs.sync_lyrics_time_offset = cf.sync_add( "int", "synced-lyrics-time-offset", prefs.sync_lyrics_time_offset, @@ -4381,7 +4387,7 @@ def load_prefs(): if os.path.isdir(prefs.download_dir1): download_directories.append(prefs.download_dir1) else: - print("Warning: Invalid download directory in config") + logging.warning("Invalid download directory in config") cf.br() cf.add_text("[app]") @@ -4433,7 +4439,7 @@ def load_prefs(): if not temp: prefs.discogs_pat = "" elif len(temp) != 40: - print("Warning: Invalid discogs token in config") + logging.warning("Invalid discogs token in config") else: prefs.discogs_pat = temp @@ -4530,7 +4536,7 @@ def load_prefs(): if 0 < db_version <= 66: prefs.device_buffer = 80 if 0 < db_version <= 53: - print("Resetting fonts to defaults") + logging.info("Resetting fonts to defaults") prefs.linux_font = "Noto Sans" prefs.linux_font_semibold = "Noto Sans Medium" prefs.linux_font_bold = "Noto Sans Bold" @@ -4558,9 +4564,9 @@ def load_prefs(): translation.install() _ = translation.gettext - print("Translation file loaded") + logging.info("Translation file loaded") else: - print("No translation file available") + logging.info("No translation file available") else: # Auto detect lang @@ -4571,9 +4577,9 @@ def load_prefs(): translation.install() _ = translation.gettext - print("Translation file loaded") + logging.info("Translation file loaded") # else: - # print("No translation file available") + # logging.info("No translation file available") # ---- @@ -4587,7 +4593,7 @@ def load_prefs(): if msys and win_ver >= 10: - #print(sss.info.win.window) + #logging.info(sss.info.win.window) try: sm = ctypes.cdll.LoadLibrary(os.path.join(install_directory, "lib", "TauonSMTC.dll")) @@ -4609,7 +4615,7 @@ def SMTC_button_callback(button): close_callback = ctypes.WINFUNCTYPE(ctypes.c_void_p, ctypes.c_int)(SMTC_button_callback) smtc = sm.init(close_callback) == 0 except Exception: - print("Failed to load TauonSMTC.dll") + logging.exception("Failed to load TauonSMTC.dll") def auto_scale(): @@ -4619,12 +4625,12 @@ def auto_scale(): if sss.subsystem in (SDL_SYSWM_WAYLAND, SDL_SYSWM_COCOA, SDL_SYSWM_UNKNOWN): prefs.scale_want = window_size[0] / logical_size[0] if old != prefs.scale_want: - print("Applying scale based on buffer size") + logging.info("Applying scale based on buffer size") elif sss.subsystem == SDL_SYSWM_X11: if xdpi > 40: prefs.scale_want = xdpi / 96 if old != prefs.scale_want: - print("Applying scale based on xft setting") + logging.info("Applying scale based on xft setting") prefs.scale_want = round(round(prefs.scale_want / 0.05) * 0.05, 2) @@ -4638,13 +4644,13 @@ def auto_scale(): prefs.scale_want = 2.0 if old != prefs.scale_want: - print(f"Using UI scale: {prefs.scale_want}") + logging.info(f"Using UI scale: {prefs.scale_want}") if prefs.scale_want < 0.5: prefs.scale_want = 1.0 if window_size[0] < (560 * prefs.scale_want) * 0.9 or window_size[1] < (330 * prefs.scale_want) * 0.9: - print("Window overscale!") + logging.info("Window overscale!") show_message(_("Detected unsuitable UI scaling."), _("Scaling setting reset to 1x")) prefs.scale_want = 1.0 @@ -4657,7 +4663,7 @@ def scale_assets(scale_want, force=False): scaled_asset_directory = os.path.join(user_directory, "scaled-icons") if not os.path.exists(scaled_asset_directory) or len(os.listdir(svg_directory)) != len( os.listdir(scaled_asset_directory)): - print("Force rerender icons") + logging.info("Force rerender icons") force = True else: scaled_asset_directory = asset_directory @@ -4670,10 +4676,10 @@ def scale_assets(scale_want, force=False): from t_modules.t_svgout import render_icons if scaled_asset_directory != asset_directory: - print("Rendering icons...") + logging.info("Rendering icons...") render_icons(svg_directory, scaled_asset_directory, scale_want) - print("Done rendering icons") + logging.info("Done rendering icons") diff_ratio = scale_want / prefs.ui_scale prefs.ui_scale = scale_want @@ -4713,7 +4719,7 @@ def scale_assets(scale_want, force=False): # thick_lines = view_prefs['thick-lines'] prefs.append_date = view_prefs['append-date'] except Exception: - print("warning: error loading settings") + logging.exception("Failed to load settings!") if prefs.prefer_side is False: gui.rsp = False @@ -4753,7 +4759,7 @@ class MOD(Structure): mpt.openmpt_module_get_metadata.restype = c_char_p mpt.openmpt_module_get_duration_seconds.restype = c_double except Exception: - print("Failed to load libopenmpt!") + logging.exception("Failed to load libopenmpt!") @@ -4812,7 +4818,7 @@ class GMETrackInfo(Structure): gme.gme_open_file.restype = ctypes.c_char_p except Exception: - print("Cannont find libgme") + logging.exception("Cannont find libgme") def use_id3(tags, nt): def natural_get(tag, track, frame, attr): @@ -4934,8 +4940,8 @@ def natural_get(tag, track, frame, attr): if desc == "replaygain_album_peak": nt.misc['replaygain_album_peak'] = float(item.text[0]) except Exception: - print("Tag Scan: Read Replay Gain MP3 error") - print(nt.fullpath) + logging.exception("Tag Scan: Read Replay Gain MP3 error") + logging.exception(nt.fullpath) if item.desc == "FMPS_RATING": nt.misc['FMPS_Rating'] = float(item.text[0]) @@ -4951,37 +4957,37 @@ def scan_ffprobe(nt): "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) nt.length = float(result.stdout.decode()) except Exception: - print("FFPROBE couldn't supply a duration") + logging.exception("FFPROBE couldn't supply a duration") try: result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=title", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) nt.title = str(result.stdout.decode()) except Exception: - print("FFPROBE couldn't supply a title") + logging.exception("FFPROBE couldn't supply a title") try: result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=artist", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) nt.artist = str(result.stdout.decode()) except Exception: - print("FFPROBE couldn't supply a artist") + logging.exception("FFPROBE couldn't supply a artist") try: result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=album", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) nt.album = str(result.stdout.decode()) except Exception: - print("FFPROBE couldn't supply a album") + logging.exception("FFPROBE couldn't supply a album") try: result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=date", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) nt.date = str(result.stdout.decode()) except Exception: - print("FFPROBE couldn't supply a date") + logging.exception("FFPROBE couldn't supply a date") try: result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=track", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) nt.track_number = str(result.stdout.decode()) except Exception: - print("FFPROBE couldn't supply a track") + logging.exception("FFPROBE couldn't supply a track") # This function takes a track object and scans metadata for it. (Filepath needs to be set) @@ -5042,6 +5048,7 @@ def tag_scan(nt): try: st = int(s[1]) except Exception: + logging.exception("Failed to assign st to int") continue if st == n: nt.title = s[2].split(' - ')[0].replace("\\", "") @@ -5108,6 +5115,7 @@ def tag_scan(nt): nt.track_number = audio.track_number except Exception: + logging.exception("Failed saving WAV file as a Track, will try again differently") audio = mutagen.File(nt.fullpath) nt.samplerate = audio.info.sample_rate nt.bitrate = audio.info.bitrate // 1000 @@ -5231,7 +5239,7 @@ def tag_scan(nt): try: audio = mutagen.File(nt.fullpath) except Exception: - print("Mutagen scan failed, falling back to FFPROBE") + logging.exception("Mutagen scan failed, falling back to FFPROBE") scan_ffprobe(nt) return nt @@ -5249,7 +5257,7 @@ def tag_scan(nt): result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) nt.length = float(result.stdout.decode()) except Exception: - print("FFPROBE couldn't supply a duration") + logging.exception("FFPROBE couldn't supply a duration") if type(audio.tags) == mutagen.mp4.MP4Tags: tags = audio.tags @@ -5306,7 +5314,8 @@ def in_get(key, tags): use_id3(audio.tags, nt) - except Exception as e: + except Exception: + logging.exception("Failed loading file through Mutagen") raise @@ -5322,15 +5331,14 @@ def in_get(key, tags): nt.misc["artists"].append(a) - except Exception as err: - #raise + except Exception: try: if Exception is UnicodeDecodeError: - print("Unicode decode error on file:", nt.fullpath, "\n", err) + logging.exception("Unicode decode error on file:", nt.fullpath, "\n") else: - print("Error: Tag read failed on file:", nt.fullpath, "\n", err) + logging.exception("Error: Tag read failed on file:", nt.fullpath, "\n") except Exception: - print("Error printing error. Non utf8 not allowed:", nt.fullpath.encode('utf-8', 'surrogateescape').decode('utf-8', 'replace'), "\n", err) + logging.exception("Error printing error. Non utf8 not allowed:", nt.fullpath.encode('utf-8', 'surrogateescape').decode('utf-8', 'replace'), "\n") return nt return nt @@ -5621,13 +5629,13 @@ def radio_progress(self): self.update_tag_history() if radiobox.loaded_url not in radiobox.websocket_source_urls: pctl.radio_image_bin = None - print("NEXT RADIO TRACK") + logging.info("NEXT RADIO TRACK") try: get_radio_art() except Exception: # raise - print("Get art error") + logging.exception("Get art error") pctl.notify_update(mpris=False) if pctl.mpris: @@ -5661,7 +5669,7 @@ def notify_update(self, mpris=True): try: tauon.tray_lock.release() except Exception: - pass + logging.exception("Failed to release tray_lock") if mpris and smtc: tr = pctl.playing_object() @@ -5675,8 +5683,7 @@ def notify_update(self, mpris=True): try: image_path = tauon.thumb_tracks.path(tr) except Exception: - pass - #raise + logging.exception("Failed to set image_path from thumb_tracks.path") if image_path is None: image_path = "" @@ -6218,6 +6225,7 @@ def back(self): try: p = self.playing_playlist().index(self.track_queue[self.queue_step]) except Exception: + logging.exception("Failed to change playing_playlist") p = random.randrange(len(self.playing_playlist())) if p is not None: self.playlist_playing_position = p @@ -6231,7 +6239,7 @@ def back(self): self.queue_step -= 1 self.play_target(jump=True) else: - print("BACK: NO CASE!") + logging.info("BACK: NO CASE!") self.show_current() if self.active_playlist_viewing == self.active_playlist_playing: @@ -6261,7 +6269,7 @@ def stop(self, block=False, run=False): try: tm.player_lock.release() except Exception: - pass + logging.exception("Failed to release player_lock") self.record_stream = False if len(self.track_queue) > 0: @@ -6289,7 +6297,7 @@ def stop(self, block=False, run=False): sleep_timeout(lambda: tauon.stream_proxy.download_running, 2) if spot_ctl.playing or spot_ctl.coasting: - print("Spotify stop") + logging.info("Spotify stop") spot_ctl.control("stop") self.notify_update() @@ -7115,7 +7123,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, self.playlist_playing_position = self.playing_playlist().index( self.track_queue[self.queue_step]) except Exception: - pass + logging.exception("Failed to set playlist_playing_position") if len(self.playing_playlist()) == self.playlist_playing_position + 1: return @@ -7337,7 +7345,7 @@ def g_open_encode_out(a, b, c): de_notify_support = True except Exception: - print("Failed init notifications") + logging.exception("Failed init notifications") if de_notify_support: song_notification = Notify.Notification.new("Next track notification") @@ -7377,8 +7385,8 @@ def notify_song(notify_of_end=False, delay=0.0): if not notify_of_end: i_path = thumb_tracks.path(track) except Exception: - print(track.fullpath.encode('utf-8', 'replace').decode("utf-8")) - print("Thumbnail error") + logging.exception(track.fullpath.encode('utf-8', 'replace').decode("utf-8")) + logging.error("Thumbnail error") top_line = track.title @@ -7467,8 +7475,10 @@ def auth2(self): except Exception as e: if 'Unauthorized Token' in str(e): + logging.exception("Not authorized") show_message(_("Error - Not authorized"), mode='error') else: + logging.exception("Unknown error") show_message(_("Error"), _('Unknown error.'), mode='error') if not toggle_lfm_auto(mode=1): @@ -7511,8 +7521,8 @@ def connect(self, m_notify=True): return True except Exception as e: + logging.exception("Error connecting to Last.fm network") show_message(_("Error connecting to Last.fm network"), str(e), mode='warning') - # print(e) return False def toggle(self): @@ -7534,7 +7544,7 @@ def last_fm_only_connect(self): except Exception as e: show_message(_("Error communicating with Last.fm network"), str(e), mode='warning') - print(e) + logging.exception("Error communicating with Last.fm network") return False def no_user_connect(self): @@ -7547,7 +7557,7 @@ def no_user_connect(self): except Exception as e: show_message(_("Error communicating with Last.fm network"), str(e), mode='warning') - print(e) + logging.exception("Error communicating with Last.fm network") return False def get_all_scrobbles_estimate_time(self): @@ -7607,13 +7617,13 @@ def get_all_scrobbles(self): track.lfm_scrobbles = value touched.append(track.index) except Exception: + logging.exception("Scanning failed. Try again?") gui.pl_update += 1 - # raise self.scanning_scrobbles = False show_message(_("Scanning failed. Try again?"), mode="error") return - print(perf_timer.get()) + logging.info(perf_timer.get()) gui.pl_update += 1 self.scanning_scrobbles = False tauon.bg_save() @@ -7637,7 +7647,7 @@ def artist_info(self, artist): return True, bio, "", mbid, url except Exception: - print("last.fm get artist info failed") + logging.exception("last.fm get artist info failed") return False, "", "", "", "" @@ -7655,7 +7665,7 @@ def artist_mbid(self, artist): mbid = l_artist.get_mbid() return mbid except Exception: - print("last.fm get artist mbid info failed") + logging.exception("last.fm get artist mbid info failed") return "" @@ -7672,18 +7682,18 @@ def sync_pull_love(self, track_object): try: track = self.network.get_track(track_object.artist, track_object.title) if not track: - print("Get love: track not found") + logging.error("Get love: track not found") return track.username = prefs.last_fm_username remote_loved = track.get_userloved() if track_object.title != track.get_correction() or track_object.artist != track.get_artist().get_correction(): - print(f"Pylast/lastfm bug workaround. API thought {track_object.artist} - {track_object.title} loved status was: {remote_loved}") + logging.warning(f"Pylast/lastfm bug workaround. API thought {track_object.artist} - {track_object.title} loved status was: {remote_loved}") return if remote_loved is None: - print("Error getting loved status") + logging.error("Error getting loved status") return local_loved = love(set=False, track_id=track_object.index, notify=False, sync=False) @@ -7691,7 +7701,7 @@ def sync_pull_love(self, track_object): if remote_loved != local_loved: love(set=True, track_id=track_object.index, notify=False, sync=False) except Exception: - print("Failed to pull love") + logging.exception("Failed to pull love") def scrobble(self, track_object, timestamp=None): if not last_fm_enable: @@ -7711,7 +7721,7 @@ def scrobble(self, track_object, timestamp=None): artist = get_artist_strip_feat(track_object) album_artist = track_object.album_artist - print("submitting scrobble...") + logging.info("Submitting scrobble...") # Act try: @@ -7724,7 +7734,7 @@ def scrobble(self, track_object, timestamp=None): self.network.scrobble(artist=artist, title=title, album=album, timestamp=timestamp) else: self.network.scrobble(artist=artist, title=title, timestamp=timestamp) - # print('Scrobbled') + # logging.info('Scrobbled') # Pull loved status @@ -7732,20 +7742,20 @@ def scrobble(self, track_object, timestamp=None): else: - print("Not sent, incomplete metadata") + logging.warning("Not sent, incomplete metadata") except Exception as e: - + logging.exception("Failed to Scrobble!") if 'retry' in str(e): - print("Retrying...") + logging.warning("Retrying in a couple seconds...") time.sleep(7) try: self.network.scrobble(artist=artist, title=title, timestamp=timestamp) - # print('Scrobbled') + # logging.info('Scrobbled') return True except Exception: - pass + logging.exception("Failed to retry!") # show_message(_("Error: Could not scrobble. ", str(e), mode='warning') console.print("Error connecting to last.fm", level=5) @@ -7811,7 +7821,7 @@ def get_friends_love(self): try: username = prefs.last_fm_username - print(f"Username is {username}") + logging.info(f"Username is {username}") if not username: self.scanning_friends = False @@ -7827,12 +7837,12 @@ def get_friends_love(self): show_message(_("Getting friend data..."), _("This may take a very long time."), mode='info') for friend in friends: self.scanning_username = friend.name - print("Getting friend loves: " + friend.name) + logging.info("Getting friend loves: " + friend.name) try: loves = friend.get_loved_tracks(limit=None) except Exception: - continue + logging.exception("Failed to get_loved_tracks!") for track in loves: title = track.track.title.casefold() @@ -7841,11 +7851,12 @@ def get_friends_love(self): if tr.title.casefold() == title and tr.artist.casefold() == artist: tr.lfm_friend_likes.add(friend.name) - print("MATCH") - print(" " + artist + " - " + title) - print(" ----- " + friend.name) + logging.info("MATCH") + logging.info(" " + artist + " - " + title) + logging.info(" ----- " + friend.name) except Exception: + logging.exception("There was an error getting friends loves") show_message(_("There was an error getting friends loves"), "", mode='warning') self.scanning_friends = False @@ -7862,19 +7873,19 @@ def dl_love(self): return if len(username) > 25: - print("abort due to long username") + logging.error("Aborted due to long username") return self.scanning_loves = True - print("Connect for friend scan") + logging.info("Connect for friend scan") try: if self.network is None: self.no_user_connect() self.network.enable_rate_limit() - print("Get user...") + logging.info("Get user...") lastfm_user = self.network.get_user(username) tracks = lastfm_user.get_loved_tracks(limit=None) @@ -7888,14 +7899,14 @@ def dl_love(self): for index, tr in pctl.master_library.items(): if tr.title.casefold() == title and tr.artist.casefold() == artist: matches += 1 - print("MATCH:") - print(" " + artist + " - " + title) + logging.info("MATCH:") + logging.info(" " + artist + " - " + title) star = star_store.full_get(index) if star is None: star = star_store.new_object() if "L" not in star[1]: updated += 1 - print(" NEW LOVE") + logging.info(" NEW LOVE") star[1] += "L" star_store.insert(index, star) @@ -7914,6 +7925,7 @@ def dl_love(self): show_message(_("Of {N} loved tracks, no matches were found in local db").format(N=str(len(tracks)))) return except Exception: + logging.exception("This doesn't seem to be working :(") show_message(_("This doesn't seem to be working :("), mode='error') self.scanning_loves = False @@ -7940,10 +7952,10 @@ def update(self, track_object): artist=artist, title=title, album=album) return 0 else: - print("Not sent, incomplete metadata") + logging.error("Not sent, incomplete metadata") return 0 except Exception as e: - + logging.exception("Error connecting to last.fm.") console.print("Error connecting to last.fm.", level=3) console.print("-- " + str(e), level=3) # print(e) @@ -24290,18 +24302,18 @@ def get_album_art_url(tr): tr.misc['musicbrainz_releasegroupid'] = release_group_id #print("got release group id") except Exception: - #print("Error lookup mbid for discord") + #logging.info("Error lookup mbid for discord") pctl.album_mbid_release_group_cache[(artist, tr.album)] = None if not release_id: try: - #print("lookup release id") + #logging.info("lookup release id") s = musicbrainzngs.search_releases(tr.album, artist=artist, limit=1) release_id = s['release-list'][0]['id'] tr.misc['musicbrainz_albumid'] = release_id - #print("got release group id") + #logging.info("got release group id") except Exception: - #print("Error lookup mbid for discord") + logging.exception("Error lookup mbid for discord") pctl.album_mbid_release_cache[(artist, tr.album)] = None image_data = None @@ -24321,8 +24333,10 @@ def get_album_art_url(tr): image_data = response.json() final_id = release_group_id except (requests.RequestException, ValueError): - #print("no image found for release group") + logging.exception("No image found for release group") pctl.album_mbid_release_group_cache[(artist, tr.album)] = None + except Exception: + logging.exception("Unknown error finding image for release group") if release_id and not image_data: url = pctl.mbid_image_url_cache.get(release_id) @@ -24333,13 +24347,13 @@ def get_album_art_url(tr): url = f"{base_url}{release_id}" try: - #print("lookup image url from album id") + #logging.print("lookup image url from album id") response = requests.get(url) response.raise_for_status() image_data = response.json() final_id = release_id except (requests.RequestException, ValueError): - #print("no image found for album id") + logging.exception("No image found for album id") pctl.album_mbid_release_cache[(artist, tr.album)] = None if image_data: @@ -24489,6 +24503,7 @@ def discord_loop(): break except Exception: + logging.exception("Error connecting to Discord - is Discord running?") # show_message(_("Error connecting to Discord", mode='error') gui.discord_status = _("Error - Discord not running?") prefs.disconnect_discord = False @@ -24677,13 +24692,13 @@ def transcode_single(item, manual_directroy=None, manual_name=None): path = os.path.join(tmp_cache_dir(), str(t.index)) if os.path.exists(path): os.remove(path) - print("Downloading file...") + logging.info("Downloading file...") with requests.get(url, params=params) as response, open(path, 'wb') as out_file: out_file.write(response.content) - print("Download complete") + logging.info("Download complete") cleanup = True except Exception: - print("Error downloading file") + logging.exception("Error downloading file") dl_use -= 1 if not os.path.isfile(path): @@ -24725,7 +24740,7 @@ def transcode_single(item, manual_directroy=None, manual_name=None): command += '"' + target_out.replace('"', '\\"') + '"' - # print(shlex.split(command)) + # logging.info(shlex.split(command)) startupinfo = None if system == 'windows' or msys: startupinfo = subprocess.STARTUPINFO() @@ -24737,11 +24752,11 @@ def transcode_single(item, manual_directroy=None, manual_name=None): subprocess.call(command, stdout=subprocess.PIPE, shell=False, startupinfo=startupinfo) - print("FFmpeg finished") + logging.info("FFmpeg finished") if codec == "opus" and prefs.transcode_opus_as: codec = 'ogg' - # print(target_out) + # logging.info(target_out) if manual_name is None: final_out = output + out_line + "." + codec @@ -24753,10 +24768,10 @@ def transcode_single(item, manual_directroy=None, manual_name=None): os.rename(target_out, final_out) if prefs.transcode_inplace and not t.is_network and not t.is_cue: - print("MOVE AND REPLACE!") + logging.info("MOVE AND REPLACE!") if os.path.isfile(final_out) and os.path.getsize(final_out) > 1000: new_name = os.path.join(t.parent_folder_path, final_name) - print(new_name) + logging.info(new_name) shutil.move(final_out, new_name) old_key = star_store.key(track) @@ -24765,13 +24780,13 @@ def transcode_single(item, manual_directroy=None, manual_name=None): try: send2trash(pctl.master_library[track].fullpath) except Exception: - print("File trash error") + logging.exception("File trash error") if os.path.isfile(pctl.master_library[track].fullpath): try: os.remove(pctl.master_library[track].fullpath) except Exception: - print("File detete error") + logging.exception("File delete error") pctl.master_library[track].fullpath = new_name pctl.master_library[track].file_ext = codec.upper() @@ -24898,6 +24913,7 @@ def cue_scan(content, tn): # try: # bitrate = audio.info.bitrate # except Exception: + # logging.exception("Failed to set audio bitrate") # bitrate = 0 if PERFORMER == "": @@ -25311,7 +25327,7 @@ def render(self): try: worker2_lock.release() except Exception: - pass + logging.exception("Failed to release worker2 lock") if input_text or key_backspace_press: self.input_timer.set() @@ -25325,7 +25341,7 @@ def render(self): self.sip = True worker2_lock.release() except Exception: - pass + logging.exception("Failed to release worker2 lock") if self.input_timer.get() < 10: gui.frame_callback_list.append(TestTimer(0.1)) @@ -25490,7 +25506,7 @@ def render(self): try: gall_ren.lock.release() except Exception: - pass + logging.exception("Failed to release gall_ren lock") # Result text if n in (0, 5, 6, 7, 8, 10): # Bold @@ -26317,11 +26333,13 @@ def add_from_cue(path): content = f.readlines() console.print("-- Reading as UTF-8") except Exception: + logging.exception("Failed opening file as UTF-8") try: with open(path, encoding="utf_16") as f: content = f.readlines() console.print("-- Reading as UTF-16") except Exception: + logging.exception("Failed opening file as UTF-16") try: j = False try: @@ -26334,13 +26352,14 @@ def add_from_cue(path): console.print("-- Reading as SHIFT-JIS") break except Exception: - pass + logging.exception("Failed opening file as shiftjis") if not j: with open(path, encoding='windows-1251') as f: content = f.readlines() console.print("-- Fallback encoding read as windows-1251") except Exception: + logging.exception("Abort: Can't detect encoding of CUE file") console.print("-- Abort: Can't detect encoding of CUE file") return 1 @@ -26574,6 +26593,7 @@ def add_from_cue(path): added.append(track.index) except Exception as e: + logging.exception("Internal error processing CUE file") console.print("-- Internal error in processing CUE file:") console.print(str(e)) console.print(traceback.format_exc()) @@ -26584,7 +26604,7 @@ def add_file(path, force_scan=False): global to_got if not os.path.isfile(path): - print("file to import missing") + logging.error("File to import missing") return 0 if os.path.splitext(path)[1][1:] in {"CUE", 'cue'}: @@ -26592,7 +26612,7 @@ def add_file(path, force_scan=False): return 0 if path.lower().endswith('.xspf'): - print('found XSPF file at: ' + path) + logging.info('Found XSPF file at: ' + path) load_xspf(path) return 0 @@ -26807,7 +26827,7 @@ def gets(direc, force_scan=False): else: items_in_dir.sort() except PermissionError: - + logging.exception("Permission error accessing one or more files") if snap_mode: show_message(_("Permission error accessing one or more files."), _("If this location is on external media, see https://") + "github.com/Taiko2k/TauonMusicBox/wiki/Snap-Permissions", @@ -26816,6 +26836,9 @@ def gets(direc, force_scan=False): show_message(_("Permission error accessing one or more files"), mode='warning') return + except Exception: + logging.exception("Unknown error accessing one or more files") + return for q in range(len(items_in_dir)): if items_in_dir[q][0] == ".": @@ -26929,11 +26952,12 @@ def cache_paths(): try: if check_auto_update_okay(code, pl=i): if not pl_is_locked(i): - print("Reloading smart playlist: " + plist[0]) + logging.info("Reloading smart playlist: " + plist[0]) regenerate_playlist(i, silent=True) time.sleep(0.02) except Exception: - pass + logging.exception("Failed to handle playlist") + tree_view_box.clear_all() if tauon.worker_save_state and \ @@ -26966,6 +26990,7 @@ def cache_paths(): try: shutil.copytree(job[0], job[1]) except Exception: + logging.exception("Failed to copy directory") move_in_progress = False gui.update += 1 show_message(_("The folder copy has failed!"), _('Some files may have been written.'), mode='warning') @@ -26976,6 +27001,7 @@ def cache_paths(): shutil.rmtree(job[0]) except Exception: + logging.exception("Failed to delete directory") show_message(_("Something has gone horribly wrong!"), _("Could not delete {name}").format(name=job[0]), mode='error') gui.update += 1 move_in_progress = False @@ -27120,7 +27146,7 @@ def cache_paths(): break else: - print("Codec error") + logging.error("Codec error") output_dir = prefs.encoder_output + folder_name + "/" if prefs.transcode_inplace: @@ -27128,7 +27154,7 @@ def cache_paths(): try: os.remove(remove_target) except Exception: - print("Encode folder not removed") + logging.exception("Encode folder not removed") reload_metadata(folder_items[0]) else: album_art_gen.save_thumb(pctl.g(folder_items[0]), (1080, 1080), output_dir + "cover") @@ -27140,6 +27166,7 @@ def cache_paths(): gui.update += 1 except Exception: + logging.exception("Transcode failed") transcode_state = "Transcode Error" time.sleep(0.2) show_message(_("Transcode failed."), _("An error was encountered."), mode='error') @@ -28049,7 +28076,7 @@ def toggle_eq(mode=0): def reload_backend(): gui.backend_reloading = True - print("Reload backend...") + logging.info("Reload backend...") wait = 0 pre_state = pctl.stop(True) @@ -28061,7 +28088,7 @@ def reload_backend(): try: tm.player_lock.release() except Exception: - pass + logging.exception("Failed to release player_lock") pctl.playerCommand = "unload" pctl.playerCommandReady = True @@ -28108,6 +28135,7 @@ def gen_chart(): prefs.chart_font, prefs.chart_tile, cascade) except Exception: + logging.exception("There was an error generating the chart") gui.generating_chart = False show_message(_("There was an error generating the chart"), _("Sorry!"), mode='error') return @@ -29290,6 +29318,7 @@ def last_fm_box(self, x0, y0, w0, h0): else: show_message(_("The Maloja server returned an error"), r.text, mode='warning') except Exception: + logging.exception("Could not communicate with the Maloja server") show_message(_("Could not communicate with the Maloja server"), mode='warning') y += round(30 * gui.scale) @@ -30777,7 +30806,7 @@ def stats(self, x0, y0, w0, h0): if self.click: gen_codec_pl(key) except Exception: - print("Error draw ext bar") + logging.exception("Error draw ext bar") def config_v(self, x0, y0, w0, h0): @@ -36043,12 +36072,12 @@ def is_m3u(self, url): def extract_stream_m3u(self, url, recursion_limit=5): if recursion_limit <= 0: return None - print("Fetching M3U...") + logging.info("Fetching M3U...") try: response = requests.get(url) if response.status_code != 200: - print(f"M3U Fetch error code: {response.status_code}") + logging.error(f"M3U Fetch error code: {response.status_code}") return None content = response.text @@ -36065,19 +36094,19 @@ def extract_stream_m3u(self, url, recursion_limit=5): return None - except Exception as e: - print(f"Error: {e}") + except Exception: + logging.exception("Failed to extract M3U") return None def start(self, item): url = item["stream_url"] - print("Start radio") - print(url) + logging.info("Start radio") + logging.info(url) if self.is_m3u(url): url = self.extract_stream_m3u(url) - print(f"Extracted URL is: {url}") + logging.info(f"Extracted URL is: {url}") if not url: - print("Failed to extract stream from M3U") + logging.info("Failed to extract stream from M3U") return if self.load_connecting: @@ -36088,9 +36117,9 @@ def start(self, item): try: self.websocket.close() - print("Websocket closed") + logging.info("Websocket closed") except Exception: - print("No socket to close?") + logging.exception("No socket to close?") self.playing_title = "" self.playing_title = item["title"] @@ -36229,11 +36258,11 @@ def on_message(ws, message): pctl.radio_image_bin = io.BytesIO(art_response.content) pctl.radio_image_bin.seek(0) radiobox.dummy_track.art_url_key = "ok" - print("Got new art") + logging.info("Got new art") except Exception: - print("No image") + logging.exception("No image") if pctl.radio_image_bin: pctl.radio_image_bin.close() pctl.radio_image_bin = None @@ -36241,12 +36270,12 @@ def on_message(ws, message): gui.update += 1 def on_error(ws, error): - pass - print(error) +# pass + logging.error(error) def on_close(ws): - pass - print("### closed ###") +# pass + logging.info("### closed ###") def on_open(ws): def run(*args): @@ -36309,7 +36338,7 @@ def browser_get_hosts(self): if host_addr[0] not in hosts: hosts.append(host_addr[0]) except Exception: - print("Ip lookup fail") + logging.exception("IPv4 lookup fail") # sort list of names hosts.sort() @@ -37696,7 +37725,7 @@ def save_fanart_artist_thumb(mbid, filepath, preview=False): prefs.fanart_notify = False show_message(_("Notice: Artist image sourced from fanart.tv"), _("They encourage you to contribute at {link}").format(link="https://fanart.tv"), mode='link') - print("Found artist thumbnail from fanart.tv") + logging.info("Found artist thumbnail from fanart.tv") class ArtistList: @@ -37776,7 +37805,7 @@ def load_img(self, artist): self.thumb_cache[artist] = [texture, sdl_rect] except Exception: - print("Artist thumbnail processing error") + logging.exception("Artist thumbnail processing error") self.thumb_cache[artist] = None elif artist in prefs.failed_artists: @@ -37820,7 +37849,7 @@ def worker(self): got_image = False try: # Lookup artist info on last.fm - print("lastfm lookup artist: " + artist) + logging.info("lastfm lookup artist: " + artist) mbid = lastfm.artist_mbid(artist) get_lfm_wait_timer.set() # if data[0] is not False: @@ -37837,19 +37866,19 @@ def worker(self): got_image = True except Exception: - print("Failed to find image from fanart.tv") + logging.exception("Failed to find image from fanart.tv") if not got_image and verify_discogs(): try: save_discogs_artist_thumb(artist, filepath4) except Exception: - print("Failed to find image from discogs") + logging.exception("Failed to find image from discogs") if os.path.exists(filepath3) or os.path.exists(filepath4): gui.update += 1 else: if artist not in prefs.failed_artists: - print("Failed featching: " + artist) + logging.error("Failed fetching: " + artist) prefs.failed_artists.append(artist) self.to_fetch = "" @@ -37933,7 +37962,7 @@ def prep(self): all.sort(key=lambda y: y.lower().removeprefix("the ")) except Exception: - print("Album scan failure") + logging.exception("Album scan failure") time.sleep(4) return @@ -40338,7 +40367,7 @@ def draw(self, x, y, w, h): def get_data(self, artist, get_img_path=False, force_dl=False): if not get_img_path: - print("Load Bio Data") + logging.info("Load Bio Data") if artist is None and not get_img_path: self.artist_on = artist @@ -40377,7 +40406,7 @@ def get_data(self, artist, get_img_path=False, force_dl=False): try: if os.path.isfile(text_filepath): - print("Load cached bio and image") + logging.info("Load cached bio and image") artist_picture_render.show = False @@ -40425,7 +40454,7 @@ def get_data(self, artist, get_img_path=False, force_dl=False): f = open(text_filepath, 'w', encoding='utf-8') f.write(self.text) f.close() - print("save bio text") + logging.info("Save bio text") artist_picture_render.show = False if data[3] and prefs.enable_fanart_artist: @@ -40435,7 +40464,7 @@ def get_data(self, artist, get_img_path=False, force_dl=False): artist_picture_render.show = True except Exception: - print("Failed to find image from fanart.tv") + logging.exception("Failed to find image from fanart.tv") if not artist_picture_render.show: if verify_discogs(): try: @@ -40444,7 +40473,7 @@ def get_data(self, artist, get_img_path=False, force_dl=False): artist_picture_render.show = True except Exception: - print("Failed to find image from discogs") + logging.exception("Failed to find image from discogs") if not artist_picture_render.show and data[4]: try: r = requests.get(data[4]) @@ -40458,9 +40487,8 @@ def get_data(self, artist, get_img_path=False, force_dl=False): f.write(r.content) artist_picture_render.load(standard_path, box_size) artist_picture_render.show = True - except Exception as e: - print("error scraping art") - print(str(e)) + except Exception: + logging.exception("Failed to scrape art") # Trigger reload of thumbnail in artist list box for key, value in list(artist_list_box.thumb_cache.items()): @@ -40493,13 +40521,14 @@ def get_data(self, artist, get_img_path=False, force_dl=False): # gui.update = 2 # # except HTTPError as e: # # self.status = e - # # print("request failed") + # # logging.exception("request failed") # except Exception: - # print("request failed") + # logging.exception("request failed") # self.status = "Request Failed" except Exception: + logging.exception("Failed to load bio") self.status = _("Load Failed") self.artist_on = artist @@ -40675,6 +40704,7 @@ def fetch(self, track): self.ready[cache_title] = 1 except Exception: + logging.exception("Could not find matching track on GuitarParty") show_message(_("Could not find matching track on GuitarParty")) inp.mouse_click = False self.ready[cache_title] = 2 @@ -40906,7 +40936,7 @@ def loader(self): f.close() src.seek(0) else: - # print("no icon") + # logging.info("no icon") self.cache[key] = [0, ] continue @@ -40915,7 +40945,7 @@ def loader(self): if im.mode != "RGBA": im = im.convert("RGBA") except Exception: - print("malform get radio thumb") + logging.exception("malform get radio thumb") self.cache[key] = [0, ] if station.get("icon") and station.get("icon") not in prefs.radio_thumb_bans: prefs.radio_thumb_bans.append(station.get("icon")) @@ -42052,8 +42082,8 @@ def scan(self): try: stamp = os.path.getmtime(path) except Exception: + logging.exception(f"Failed to scan item at {path}") self.done.add(path) - print(f"Failed to scan item at {path}") continue min_age = (time.time() - stamp) / 60 @@ -42102,9 +42132,12 @@ def scan(self): try: size = get_folder_size(path) except FileNotFoundError: + logging.warning(f"Failed to find watched folder {path}, deleting from watchlist") if path in self.watching: del self.watching[path] continue + except Exception: + logging.exception("Unkown error getting folder size") if path in self.watching: # Check if size is stable, then scan for audio files if size == self.watching[path]: @@ -42309,6 +42342,7 @@ def download_img(link, target_folder, track): gui.image_downloading = False except Exception as e: + logging.exception("Image download failed") show_message(_("Image download failed."), str(e), mode='warning') gui.image_downloading = False @@ -42541,6 +42575,7 @@ def check_playback_running(self): try: tm.d['caster'] = [enc, [tauon], None] except Exception: + logging.exception("Failed to cast, trying differently") tm.d['caster'] = [lambda: x, [tauon], None] tm.d['worker'] = [worker1, (), None] @@ -43455,10 +43490,13 @@ def save_state(): continue export_playlist_box.run_export(item, key, warnings=False) - print("done") + logging.info("done") except PermissionError: + logging.exception("Permission error encountered while writing database") show_message(_("Permission error encountered while writing database"), "error") + except Exception: + logging.exception("Unkown error encountered while writing database") SDL_StartTextInput() @@ -43800,6 +43838,7 @@ def drop_file(target): try: console.print(f"Found game controller: {SDL_GameControllerNameForIndex(event.cdevice.which).decode()}") except Exception: + logging.exception("Error get game controller") console.print("Error get game controller") if event.type == SDL_CONTROLLERAXISMOTION and prefs.use_gamepad: @@ -44280,7 +44319,7 @@ def drop_file(target): try: tm.player_lock.release() except Exception: - pass + logging.exception("Failed to release player lock") if gui.frame_callback_list: i = len(gui.frame_callback_list) - 1 @@ -45134,7 +45173,7 @@ def drop_file(target): load_theme(colours, theme_item[0]) deco.load(colours.deco) - print("Applying theme: " + gui.theme_name) + logging.info("Applying theme: " + gui.theme_name) if colours.lm: info_icon.colour = [60, 60, 60, 255] @@ -45157,6 +45196,7 @@ def drop_file(target): radiorandom_icon.colour = [153, 229, 133, 255] except Exception: + logging.exception("Error loading theme file") raise show_message(_("Error loading theme file"), "", mode='warning') @@ -46188,7 +46228,7 @@ def drop_file(target): gallery_pulse_top.render(window_size[0] - gui.rspw, gui.panelY, gui.rspw - round(16 * gui.scale), 20 * gui.scale) except Exception: - print("Gallery render error!") + logging.exception("Gallery render error!") # END POWER BAR ------------------------ # End of gallery view @@ -48656,7 +48696,10 @@ def drop_file(target): else: console.print("Dev mode, skip auto saving playtime") except PermissionError: + logging.exception("Permission error encountered while writing database") show_message(_("Permission error encountered while writing database"), "error") + except Exception: + logging.exception("Unknown error encountered while writing database") time_last_save = pctl.total_playtime # Always render at least one frame per minute (to avoid SDL bugs I guess) @@ -48675,7 +48718,7 @@ def drop_file(target): # Send scrobble if pending if lfm_scrobbler.queue and not lfm_scrobbler.running: lfm_scrobbler.start_queue() - print("Sending scrobble before close...") + logging.info("Sending scrobble before close...") if gui.mode < 3: old_window_position = get_window_position() @@ -48711,19 +48754,19 @@ def drop_file(target): pickle.dump(star_store.db, open(user_directory + "/star.p.backup" + str(date.month), "wb")) if tauon.stream_proxy and tauon.stream_proxy.download_running: - print("Stopping stream...") + logging.info("Stopping stream...") tauon.stream_proxy.stop() time.sleep(2) try: tm.player_lock.release() except Exception: - pass + logging.exception("Failed to release player_lock") try: tauon.radio_server.server_close() except Exception: - pass + logging.exception("Failed to close radio server") if system == "windows" or msys: tray.stop() @@ -48736,18 +48779,18 @@ def drop_file(target): g_tc_notify.close() Notify.uninit() except Exception: - print("uninit notification error") + logging.exception("uninit notification error") if macos: try: tap.stop() except Exception: - pass + logging.exception("Failed to stop tap") try: instance_lock.close() except Exception: - print("No lock object to close") + logging.exception("No lock object to close") IMG_Quit() @@ -48760,21 +48803,21 @@ def drop_file(target): cache_dir = tmp_cache_dir() if os.path.isdir(cache_dir): - print("Clear tmp cache") + logging.info("Clearing tmp cache") shutil.rmtree(cache_dir) if not tauon.quick_close: while tm.check_playback_running(): time.sleep(0.2) if exit_timer.get() > 2: - print("Phazor unload timeout") + logging.warning("Phazor unload timeout") break while lfm_scrobbler.running: time.sleep(0.2) lfm_scrobbler.running = False if exit_timer.get() > 15: - print("Scrobble wait timeout") + logging.warning("Scrobble wait timeout") break if tauon.sleep_lock is not None: @@ -48786,8 +48829,8 @@ def drop_file(target): if tauon.librespot_p: time.sleep(1) - print("Kill liberspot") + logging.info("Killing librespot") tauon.librespot_p.kill() #tauon.librespot_p.communicate() -print("bye") +logging.info("Bye!") From 956e67650fc886f62453e9a6bc2f477a8ac9022d Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 18:28:08 +0100 Subject: [PATCH 06/63] t_main: Fix pylast import --- t_modules/t_main.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index 49e54aabc..1d9193e70 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -273,15 +273,6 @@ logging.exception("Unable to import python-pypresence, Discord Rich Presence will be disabled.") discord_allow = False -try: - import pylast - last_fm_enable = True - if pyinstaller_mode: - pylast.SSL_CONTEXT.load_verify_locations(os.path.join(install_directory, "certifi", "cacert.pem")) -except Exception: - last_fm_enable = False - print("PyLast moduel not found, last fm will be disabled.") - use_cc = False try: import opencc @@ -358,6 +349,15 @@ should_save_state = True +try: + import pylast + last_fm_enable = True + if pyinstaller_mode: + pylast.SSL_CONTEXT.load_verify_locations(os.path.join(install_directory, "certifi", "cacert.pem")) +except Exception: + logging.exception("PyLast module not found, last fm will be disabled.") + last_fm_enable = False + if not windows_native: import gi from gi.repository import GLib From f89ac4c60417adb3ebd8ded2763586011fde407b Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 18:39:44 +0100 Subject: [PATCH 07/63] t_main: Add missing import --- t_modules/t_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index 1d9193e70..b5ebe7ce6 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -63,7 +63,7 @@ import zipfile from collections import OrderedDict from collections.abc import Callable -from ctypes import c_char_p, c_double, c_int, c_void_p, pointer, Structure +from ctypes import c_char_p, c_double, c_int, c_uint32, c_void_p, pointer, Structure from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING From 9bd629a448dccc0127b1ba2f09ab9e96ae4d3f3a Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 19:12:50 +0100 Subject: [PATCH 08/63] t_main: Logging improvements --- t_modules/t_main.py | 56 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index b5ebe7ce6..68932deb8 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -504,8 +504,7 @@ # user_directory = os.path.expanduser('~').replace("\\", '/') + "/Music/TauonMusicBox" # config_directory = user_directory # cache_directory = user_directory + "\\cache" -# logging.info("User Directroy: ", end="") -# logging.info(user_directory) +# logging.info(f"User Directory: {user_directory}") # install_mode = True # if not os.path.isdir(user_directory): # os.makedirs(user_directory) @@ -898,7 +897,7 @@ def __init__(self): self.messages = [] self.show = False - def print(self, message, level=0): + def print(self, message: str, level: int = 0): if len(self.messages) > 50: del self.messages[0] @@ -5013,11 +5012,11 @@ def tag_scan(nt): emu = ctypes.c_void_p() track_info = ctypes.POINTER(GMETrackInfo)() err = gme.gme_open_file(nt.fullpath.encode("utf-8"), ctypes.byref(emu), -1) - #print(err) + #logging.error(err) if not err: n = nt.subtrack err = gme.gme_track_info(emu, byref(track_info), n) - #print(err) + #logging.error(err) if not err: nt.length = track_info.contents.play_length / 1000 nt.title = track_info.contents.song.decode("utf-8") @@ -5127,11 +5126,11 @@ def tag_scan(nt): elif nt.file_ext == "OPUS" or nt.file_ext == "OGG" or nt.file_ext == "OGA": - # print("get opus") + #logging.info("get opus") audio = Opus(nt.fullpath) audio.read() - # print(audio.title) + #logging.info(audio.title) nt.length = audio.length nt.title = audio.title @@ -5167,7 +5166,7 @@ def tag_scan(nt): # # def getter(audio, key, type): # # if # t = audio.tags - # print(t.keys()) + # logging.info(t.keys()) # nt.size = os.path.getsize(nt.fullpath) # nt.title = str(t.get("title", "")) # nt.album = str(t.get("album", "")) @@ -5181,7 +5180,7 @@ def tag_scan(nt): audio = Ape(nt.fullpath) audio.read() - # print(audio.title) + # logging.info(audio.title) # nt.length = audio.length nt.title = audio.title @@ -5205,7 +5204,7 @@ def tag_scan(nt): audio = Ape(nt.fullpath) audio.read() - # print(audio.title) + # logging.info(audio.title) nt.length = audio.length nt.title = audio.title @@ -5689,7 +5688,7 @@ def notify_update(self, mpris=True): image_path = "" image_path = image_path.replace("/", "\\") - #print(image_path) + #logging.info(image_path) sm.update(state, tr.title.encode("utf-16"), len(tr.title), tr.artist.encode("utf-16"), len(tr.artist), image_path.encode("utf-16"), len(image_path)) @@ -5852,13 +5851,13 @@ def show(self): def show_current(self, select=True, playing=True, quiet=False, this_only=False, highlight=False, index=None, no_switch=False, folder_list=True): - # print("show------") - # print(select) - # print(playing) - # print(quiet) - # print(this_only) - # print(highlight) - # print("--------") + # logging.info("show------") + # logging.info(select) + # logging.info(playing) + # logging.info(quiet) + # logging.info(this_only) + # logging.info(highlight) + # logging.info("--------") console.print("DEBUG: Position set by show playing") global shift_selection @@ -10341,6 +10340,7 @@ class XcursorImage(ctypes.Structure): try: xcu = ctypes.cdll.LoadLibrary("libXcursor.so") except Exception: + logging.exception("Failed to load libXcursor.so, will try libXcursor.so.1") xcu = ctypes.cdll.LoadLibrary("libXcursor.so.1") xcu.XcursorLibraryLoadImage.restype = ctypes.POINTER(XcursorImage) @@ -10366,7 +10366,7 @@ def get_xcursor(name): SDL_SetCursor(cursor_standard) except Exception: - print("Error loading xcursor") + logging.exception("Error loading xcursor") if not maximized and gui.maximized: @@ -43248,9 +43248,9 @@ def window_is_focused(): # thread safe? def save_state(): if should_save_state: - print("Writing database to disk... ", end="") + logging.info("Writing database to disk... ") else: - print("Dev mode, not saving state... ") + logging.warning("Dev mode, not saving state... ") return # view_prefs['star-lines'] = star_lines @@ -43490,7 +43490,7 @@ def save_state(): continue export_playlist_box.run_export(item, key, warnings=False) - logging.info("done") + logging.info("Done writing database") except PermissionError: logging.exception("Permission error encountered while writing database") @@ -48293,7 +48293,7 @@ def drop_file(target): input_text = "" gui.update -= 1 - # print("FRAME " + str(core_timer.get())) + # logging.info("FRAME " + str(core_timer.get())) if gui.update > 1: gui.update = 1 gui.present = True @@ -48306,7 +48306,7 @@ def drop_file(target): # if gui.vis == 1 and pctl.playing_state != 1 and gui.level_peak != [0, 0] and gui.turbo: # - # # print(gui.level_peak) + # # logging.info(gui.level_peak) # gui.time_passed = gui.level_time.hit() # if gui.time_passed > 1: # gui.time_passed = 0 @@ -48333,7 +48333,7 @@ def drop_file(target): # Scrolling spectrogram # if not vis_update: - # print("No UPDATE " + str(random.randint(1,50))) + # logging.info("No UPDATE " + str(random.randint(1,50))) if len(gui.spec2_buffers) > 0 and gui.spec2_timer.get() > 0.04: # gui.spec2_timer.force_set(gui.spec2_timer.get() - 0.04) gui.spec2_timer.set() @@ -48361,7 +48361,7 @@ def drop_file(target): # # else: - # print("animation stall" + str(random.randint(1, 10))) + # logging.info("animation stall" + str(random.randint(1, 10))) if prefs.spec2_scroll: @@ -48738,7 +48738,7 @@ def drop_file(target): pctl.playerCommandReady = True if prefs.reload_play_state and pctl.playing_state in (1, 2): - print("Saving play state...") + logging.info("Saving play state...") prefs.reload_state = (pctl.playing_state, pctl.playing_time) if should_save_state: @@ -48796,7 +48796,7 @@ def drop_file(target): IMG_Quit() SDL_QuitSubSystem(SDL_INIT_EVERYTHING) SDL_Quit() -# print("SDL unloaded") +#logging.info("SDL unloaded") exit_timer = Timer() exit_timer.set() From 63dd33a6ef4c19ae45da7e6f208e9fa69d9ba1fa Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 19:29:54 +0100 Subject: [PATCH 09/63] t_main: Split migration code into t_db_migrate --- t_modules/t_db_migrate.py | 503 ++++++++++++++++++++++++++++++++++++++ t_modules/t_main.py | 489 ++---------------------------------- 2 files changed, 527 insertions(+), 465 deletions(-) create mode 100644 t_modules/t_db_migrate.py diff --git a/t_modules/t_db_migrate.py b/t_modules/t_db_migrate.py new file mode 100644 index 000000000..ea1ea0661 --- /dev/null +++ b/t_modules/t_db_migrate.py @@ -0,0 +1,503 @@ +"""Upgrade from older versions""" +from __future__ import annotations + +import copy +import logging +import os +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from t_modules.t_main import GuiVar, Prefs, StarStore, TauonPlaylist + + +def database_migrate( + *, + db_version: float, + master_library: dict, + install_mode: bool, + multi_playlist: list[TauonPlaylist], + star_store: StarStore, + a_cache_dir: str, + cache_directory: str, + config_directory: str, + install_directory: str, + user_directory: str, + gui: GuiVar, + gen_codes: dict, + prefs: Prefs, + radio_playlists: list[TauonPlaylist], + p_force_queue: list, + theme: int, +) -> tuple[dict, list[TauonPlaylist], StarStore, list, int, Prefs, GuiVar, dict, list[TauonPlaylist]] | None: + """Migrate database to a newer version if we're behind + + Returns all the objects that could've been possibly changed: + master_library, multi_playlist, star_store, p_force_queue, theme, prefs, gui, gen_codes, radio_playlists + """ + from t_modules.t_main import show_message, uid_gen + + if db_version <= 0: + logging.error("Called database_migrate with db_version equal to or below 0!") + return None + + logging.warning(f"Running migrations as DB version was {db_version}!") + if db_version <= 0.8: + logging.info("Updating database from version 0.8 to 0.9") + for key, value in master_library.items(): + setattr(master_library[key], "skips", 0) + + if db_version <= 0.9: + logging.info("Updating database from version 0.9 to 1.1") + for key, value in master_library.items(): + setattr(master_library[key], "comment", "") + + if db_version <= 1.1: + logging.info("Updating database from version 1.1 to 1.2") + for key, value in master_library.items(): + setattr(master_library[key], "album_artist", "") + + if db_version <= 1.2: + logging.info("Updating database to version 1.3") + for key, value in master_library.items(): + setattr(master_library[key], "disc_number", "") + setattr(master_library[key], "disc_total", "") + + if db_version <= 1.3: + logging.info("Updating database to version 1.4") + for key, value in master_library.items(): + setattr(master_library[key], "lyrics", "") + setattr(master_library[key], "track_total", "") + show_message( + "Upgrade complete. Note: New attributes such as disk number won't show for existing tracks (delete state.p to reset)") + + if db_version <= 1.4: + logging.info("Updating database to version 1.5") + for playlist in multi_playlist: + playlist.append(uid_gen()) + + if db_version <= 1.5: + logging.info("Updating database to version 1.6") + for i in range(len(multi_playlist)): + if len(multi_playlist[i]) == 7: + multi_playlist[i].append("") + + if db_version <= 1.6: + logging.info("Updating preferences to 1.7") + # gui.show_stars = False + if install_mode: + # shutil.copy(install_directory + "/config.txt", user_directory) + logging.info("Rewrote user config file") + + if db_version <= 1.7: + logging.info("Updating database to version 1.8") + if install_mode: + logging.info(".... Overwriting user config file") + # shutil.copy(install_directory + "/config.txt", user_directory) + + try: + logging.info(".... Updating playtime database") + + old = star_store.db + # perf_timer.set() + old_total = sum(old.values()) + # logging.info(perf_timer.get()) + logging.info(f"Old total: {old_total}") + star_store.db = {} + + new = {} + for track in master_library.values(): + key = track.title + track.filename + if key in old: + n_value = [old[key], ""] + n_key = star_store.object_key(track) + star_store.db[n_key] = n_value + + diff = old_total - star_store.get_total() + logging.info(f"New total: {int(diff)} Seconds could not be matched to tracks. Total playtime won't be affected") + star_store.db[("", "", "LOST")] = [diff, ""] + logging.info("Upgrade Complete") + except Exception: + logging.exception("Error upgrading database") + show_message(_("Error loading old database, did the program not exit properly after updating? Oh well.")) + + if db_version <= 1.8: + logging.info("Updating database to 1.9") + for key, value in master_library.items(): + setattr(master_library[key], "track_gain", None) + setattr(master_library[key], "album_gain", None) + show_message(_("Upgrade complete. Run a tag rescan if you want enable ReplayGain")) + + if db_version <= 1.9: + logging.info("Updating database to version 2.0") + for key, value in master_library.items(): + setattr(master_library[key], "modified_time", 0) + show_message(_("Upgrade complete. New sorting option may require tag rescan.")) + + if db_version <= 2.0: + logging.info("Updating database to version 2.1") + for key, value in master_library.items(): + setattr(master_library[key], "is_embed_cue", False) + setattr(master_library[key], "cue_sheet", "") + show_message(_("Updated to v2.6.3")) + + if db_version <= 2.1: + logging.info("Updating database to version 2.1") + for key, value in master_library.items(): + setattr(master_library[key], "lfm_friend_likes", set()) + + if db_version <= 2.2: + for i in range(len(multi_playlist)): + if len(multi_playlist[i]) < 9: + multi_playlist[i].append(True) + + if db_version <= 2.3: + logging.info("Updating database to version 2.4") + for key, value in master_library.items(): + setattr(master_library[key], "bit_depth", 0) + + if db_version <= 2.4: + if theme > 0: + theme += 1 + + if db_version <= 2.5: + logging.info("Updating database to version 2.6") + for key, value in master_library.items(): + setattr(master_library[key], "is_network", False) + # for i in range(len(multi_playlist)): + # if len(multi_playlist[i]) < 10: + # multi_playlist[i].append(False) + + if db_version <= 26: + logging.info("Updating database to version 27") + for i in range(len(multi_playlist)): + if len(multi_playlist[i]) == 9: + multi_playlist[i].append(False) + + if db_version <= 27: + logging.info("Updating database to version 28") + for i in range(len(multi_playlist)): + if len(multi_playlist[i]) <= 10: + multi_playlist[i].append("") + + if db_version <= 29: + logging.info("Updating database to version 30") + for key, value in master_library.items(): + setattr(master_library[key], "composer", "") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("global-search G Ctrl\n") + f.write("cycle-theme-reverse\n") + f.write("reload-theme F10\n") + + show_message(_("Welcome to v4.4.0. Run a tag rescan if you want enable Composer metadata.")) + + if db_version <= 30: + for i, item in enumerate(p_force_queue): + try: + assert item[6] + except Exception: + logging.exception("Error asserting item[6]") + p_force_queue[i].append(False) + + if db_version <= 31: + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("love-selected\n") + gui.set_bar = True + + if db_version <= 32: + if theme > 1: + theme += 1 + + if db_version <= 33: + logging.info("Update to db 34") + for key, value in master_library.items(): + if not hasattr(master_library[key], "misc"): + setattr(master_library[key], "misc", {}) + + if db_version <= 34: + logging.info("Update to dv 35") + # Moved to after config load + + if db_version <= 35: + logging.info("Updating database to version 36") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("toggle-show-art H Ctrl\n") + + if db_version <= 37: + logging.info("Updating database to version 38") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("toggle-console `\n") + + if db_version <= 38: + logging.info("Updating database to version 39") + + for key, value in star_store.db.items(): + logging.info(value) + if len(value) == 2: + value.append(0) + star_store.db[key] = value + + if db_version <= 39: + logging.info("Updating database to version 40") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + f = open(os.path.join(config_directory, "input.txt"), "r") + text = f.read() + f.close() + lines = text.splitlines() + if "l ctrl" not in text.lower(): + f = open(os.path.join(config_directory, "input.txt"), "w") + for line in lines: + line = line.strip() + if line == "love-selected": + line = "love-selected L Ctrl" + f.write(line + "\n") + f.close() + + if db_version <= 40: + logging.info("Updating database to version 41") + old = copy.deepcopy(prefs.lyrics_enables) + prefs.lyrics_enables.clear() + if "apiseeds" in old: + prefs.lyrics_enables.append("Apiseeds") + if "lyricwiki" in old: + prefs.lyrics_enables.append("LyricWiki") + if "genius" in old: + prefs.lyrics_enables.append("Genius") + + if db_version <= 41: + logging.info("Updating database to version 42") + + for key, value in gen_codes.items(): + gen_codes[key] = value.replace("f\"", "p\"") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + f = open(os.path.join(config_directory, "input.txt"), "r") + text = f.read() + f.close() + lines = text.splitlines() + + f = open(os.path.join(config_directory, "input.txt"), "w") + for line in lines: + line = line.strip() + if "rename-playlist" in line: + + f.write(line + "\n") + + line = "new-playlist T Ctrl\n" + f.write(line) + + line = "\nnew-generator-playlist\n" + f.write(line) + if "e ctrl" in text.lower(): + line = "edit-generator\n\n" + else: + line = "edit-generator E Ctrl\n\n" + f.write(line) + + line = "search-lyrics-selected\n" + f.write(line) + line = "substitute-search-selected" + + f.write(line + "\n") + + f.close() + + if db_version <= 42: + logging.info("Updating database to version 43") + + if db_version <= 43: + logging.info("Updating database to version 44") + # Repair db + for key, value in star_store.db.items(): + if len(value) == 2: + value.append(0) + star_store.db[key] = value + + if db_version <= 44: + logging.info("Updating database to version 45") + logging.info("Cleaning cache directory") + for item in os.listdir(cache_directory): + path = os.path.join(cache_directory, item) + if "-lfm." in item or "-ftv." in item or "-dcg." in item: + os.rename(path, os.path.join(a_cache_dir, item)) + for item in os.listdir(cache_directory): + path = os.path.join(cache_directory, item) + if os.path.isfile(path): + os.remove(path) + + if db_version <= 45: + logging.info("Updating database to version 46") + for p in multi_playlist: + if type(p[7]) != list: + p[7] = [p[7]] + + if db_version <= 46: + logging.info("Updating database to version 47") + for p in multi_playlist: + if type(p[7]) != list: + p[7] = [p[7]] + + if db_version <= 47: + logging.info("Updating database to version 48") + if os.path.isfile(os.path.join(user_directory, "spot-r-token")): + show_message( + _("Welcome to v6.1.0. Due to changes, please re-authorise Spotify"), + _("You can do this by clicking 'Forget Account', then 'Authroise' in Settings > Accounts > Spotify")) + + if db_version <= 48: + logging.info("Fix bad upgrade, now 49") + for key, value in master_library.items(): + if not hasattr(master_library[key], "url_key"): + setattr(master_library[key], "url_key", "") + if not hasattr(master_library[key], "art_url_key"): + setattr(master_library[key], "art_url_key", "") + + if db_version <= 49: + logging.info("Updating database to version 50") + if os.path.isfile(os.path.join(user_directory, "spot-r-token")): + show_message( + _("Welcome to v6.3.0. Due to an upgrade, please re-authorise Spotify"), + _("You can do this by clicking 'Authroise' in Settings > Accounts > Spotify")) + os.remove(os.path.join(user_directory, "spot-r-token")) + + if db_version <= 54: + logging.info("Updating database to version 55") + for key, value in master_library.items(): + setattr(master_library[key], "lfm_scrobbles", 0) + + if db_version <= 55: + logging.info("Update to db 56") + for key, value in master_library.items(): + + if hasattr(value, "track_gain"): + if value.track_gain != 0: + value.misc["replaygain_track_gain"] = value.track_gain + del value.track_gain + + if hasattr(value, "album_gain"): + if value.album_gain != 0: + value.misc["replaygain_album_gain"] = value.album_gain + del value.album_gain + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("toggle-right-panel MB5\n") + f.write("toggle-gallery MB4\n") + + if db_version <= 56: + logging.info("Update to db 57") + if "Apiseeds" in prefs.lyrics_enables: + prefs.lyrics_enables.remove("Apiseeds") + prefs.lyrics_enables.append("Happi") + + if db_version <= 57: + logging.info("Updating database to version 58") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("\nregenerate-playlist R Alt\n") + f.write("clear-queue Q Shift Alt\n") + f.write("resize-window-16:9 F11 Alt\n") + f.write("delete-playlist-force W Shift Ctrl\n") + + if db_version <= 58: + logging.info("Updating database to version 59") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("\nrandom-album ; Alt\n") + + if db_version <= 59: + logging.info("Updating database to version 60") + + if prefs.spotify_token: + show_message( + _("Upgrade to v6.5.1. It looks like you are using Spotify."), + _("Please click 'Authorise' again in the settings")) + prefs.spotify_token = "" + + if db_version <= 60: + logging.info("Updating database to version 61") + + token_path = os.path.join(user_directory, "spot-token-pkce") + if os.path.exists(token_path): + prefs.spotify_token = "" + os.remove(token_path) + show_message( + _("Upgrade to v6.5.3 complete"), + _("It looks like you are using Spotify. Please re-setup Spotify again in the settings")) + + if db_version <= 61: + logging.info("Updating database to version 62") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("\ntransfer-playtime-to P Ctrl Shift\n") + + if db_version <= 62: + logging.info("Updating database to version 63") + for item in gui.pl_st: + if item[0] == "T": + item[0] = "#" + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "r") as f: + lines = f.readlines() + with open(os.path.join(config_directory, "input.txt"), "w") as f: + for line in lines: + if line == "vol-up Up Shift\n" or line == "vol-down Down Shift\n": + continue + f.write(line) + f.write("\n") + f.write("shift-up Up Shift\n") + f.write("shift-down Down Shift\n") + f.write("vol-up Up Ctrl\n") + f.write("vol-down Down Ctrl\n") + + if db_version <= 63: + logging.info("Updating database to version 64") + if prefs.radio_urls: + radio_playlists[0]["items"].extend(prefs.radio_urls) + prefs.radio_urls = [] + # prefs.show_nag = True + + if db_version <= 64: + logging.info("Updating database to version 65") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("\nescape Escape\n") + f.write("toggle-mute M Ctrl\n") + + if db_version <= 65: + logging.info("Updating database to version 66") + + if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): + with open(os.path.join(config_directory, "input.txt"), "a") as f: + f.write("\ntoggle-artistinfo O Ctrl\n") + f.write("cycle-theme ] Ctrl\n") + f.write("cycle-theme-reverse [ Ctrl\n") + + if db_version <= 66: + logging.info("Updating database to version 67") + for key, value in star_store.db.items(): + if len(value) == 3: + value.append(0) + star_store.db[key] = value + + if db_version <= 67: + logging.info("Updating database to version 68") + for p in multi_playlist: + if len(p) == 11: + p.append(False) + + + return master_library, multi_playlist, star_store, p_force_queue, theme, prefs, gui, gen_codes, radio_playlists diff --git a/t_modules/t_main.py b/t_modules/t_main.py index 68932deb8..20e5779cd 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -231,6 +231,7 @@ from t_modules import t_bootstrap from t_modules.t_config import Config from t_modules.t_extra import * +from t_modules.t_db_migrate import database_migrate from t_modules.t_draw import TDraw, QuickThumbnail from t_modules.t_jellyfin import Jellyfin from t_modules.t_launch import * @@ -1183,7 +1184,8 @@ def queue_item_gen(trackid, position, pl_id, type=0, album_stage=0): volume = 75 folder_image_offsets = {} -db_version = 0.0 +db_version: float = 0.0 +latest_db_version: float = 68 albums = [] album_position = 0 @@ -3442,469 +3444,26 @@ def get_theme_name(number): return themes[number][1] return "" - -# Upgrading from older versions -if db_version > 0: - - if db_version <= 0.8: - print("Updating database from version 0.8 to 0.9") - for key, value in master_library.items(): - setattr(master_library[key], 'skips', 0) - - if db_version <= 0.9: - print("Updating database from version 0.9 to 1.1") - for key, value in master_library.items(): - setattr(master_library[key], 'comment', "") - - if db_version <= 1.1: - print("Updating database from version 1.1 to 1.2") - for key, value in master_library.items(): - setattr(master_library[key], 'album_artist', "") - - if db_version <= 1.2: - print("Updating database to version 1.3") - for key, value in master_library.items(): - setattr(master_library[key], 'disc_number', "") - setattr(master_library[key], 'disc_total', "") - - if db_version <= 1.3: - print("Updating database to version 1.4") - for key, value in master_library.items(): - setattr(master_library[key], 'lyrics', "") - setattr(master_library[key], 'track_total', "") - show_message( - "Upgrade complete. Note: New attributes such as disk number won't show for existing tracks (delete state.p to reset)") - - if db_version <= 1.4: - print("Updating database to version 1.5") - for playlist in multi_playlist: - playlist.append(uid_gen()) - - if db_version <= 1.5: - print("Updating database to version 1.6") - for i in range(len(multi_playlist)): - if len(multi_playlist[i]) == 7: - multi_playlist[i].append("") - - if db_version <= 1.6: - print("Updating preferences to 1.7") - # gui.show_stars = False - if install_mode: - # shutil.copy(install_directory + "/config.txt", user_directory) - print("Rewrote user config file") - - if db_version <= 1.7: - print("Updating database to version 1.8") - if install_mode: - print(".... Overwriting user config file") - # shutil.copy(install_directory + "/config.txt", user_directory) - - try: - print(".... Updating playtime database") - - old = star_store.db - # perf_timer.set() - old_total = sum(old.values()) - # print(perf_timer.get()) - print("Old total: ", end='') - print(old_total) - star_store.db = {} - - new = {} - for track in master_library.values(): - key = track.title + track.filename - if key in old: - n_value = [old[key], ""] - n_key = star_store.object_key(track) - star_store.db[n_key] = n_value - - print("New total: ", end='') - diff = old_total - star_store.get_total() - print(int(diff), end='') - print(" Secconds could not be matched to tracks. Total playtime won't be affected") - star_store.db[("", "", "LOST")] = [diff, ""] - print("Upgrade Complete") - except Exception: - print("Error upgrading database") - show_message(_("Error loading old database, did the program not exit properly after updating? Oh well.")) - - if db_version <= 1.8: - print("Updating database to 1.9") - for key, value in master_library.items(): - setattr(master_library[key], 'track_gain', None) - setattr(master_library[key], 'album_gain', None) - show_message(_("Upgrade complete. Run a tag rescan if you want enable ReplayGain")) - - if db_version <= 1.9: - print("Updating database to version 2.0") - for key, value in master_library.items(): - setattr(master_library[key], 'modified_time', 0) - show_message(_("Upgrade complete. New sorting option may require tag rescan.")) - - if db_version <= 2.0: - print("Updating database to version 2.1") - for key, value in master_library.items(): - setattr(master_library[key], 'is_embed_cue', False) - setattr(master_library[key], 'cue_sheet', "") - show_message(_("Updated to v2.6.3")) - - if db_version <= 2.1: - print("Updating database to version 2.1") - for key, value in master_library.items(): - setattr(master_library[key], 'lfm_friend_likes', set()) - - if db_version <= 2.2: - for i in range(len(multi_playlist)): - if len(multi_playlist[i]) < 9: - multi_playlist[i].append(True) - - if db_version <= 2.3: - print("Updating database to version 2.4") - for key, value in master_library.items(): - setattr(master_library[key], 'bit_depth', 0) - - if db_version <= 2.4: - if theme > 0: - theme += 1 - - if db_version <= 2.5: - print("Updating database to version 2.6") - for key, value in master_library.items(): - setattr(master_library[key], 'is_network', False) - # for i in range(len(multi_playlist)): - # if len(multi_playlist[i]) < 10: - # multi_playlist[i].append(False) - - if db_version <= 26: - print("Updating database to version 27") - for i in range(len(multi_playlist)): - if len(multi_playlist[i]) == 9: - multi_playlist[i].append(False) - - if db_version <= 27: - print("Updating database to version 28") - for i in range(len(multi_playlist)): - if len(multi_playlist[i]) <= 10: - multi_playlist[i].append("") - - if db_version <= 29: - print("Updating database to version 30") - for key, value in master_library.items(): - setattr(master_library[key], 'composer', "") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("global-search G Ctrl\n") - f.write("cycle-theme-reverse\n") - f.write("reload-theme F10\n") - - show_message(_("Welcome to v4.4.0. Run a tag rescan if you want enable Composer metadata.")) - - if db_version <= 30: - for i, item in enumerate(p_force_queue): - try: - assert item[6] - except Exception: - p_force_queue[i].append(False) - - if db_version <= 31: - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("love-selected\n") - gui.set_bar = True - - if db_version <= 32: - if theme > 1: - theme += 1 - - if db_version <= 33: - print("Update to db 34") - for key, value in master_library.items(): - if not hasattr(master_library[key], 'misc'): - setattr(master_library[key], 'misc', {}) - - if db_version <= 34: - print("Update to dv 35") - # Moved to after config load - - if db_version <= 35: - print("Updating database to version 36") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("toggle-show-art H Ctrl\n") - - if db_version <= 37: - print("Updating database to version 38") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("toggle-console `\n") - - if db_version <= 38: - print("Updating database to version 39") - - for key, value in star_store.db.items(): - print(value) - if len(value) == 2: - value.append(0) - star_store.db[key] = value - - if db_version <= 39: - print("Updating database to version 40") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - f = open(os.path.join(config_directory, "input.txt"), 'r') - text = f.read() - f.close() - lines = text.splitlines() - if "l ctrl" not in text.lower(): - f = open(os.path.join(config_directory, "input.txt"), 'w') - for line in lines: - line = line.strip() - if line == "love-selected": - line = "love-selected L Ctrl" - f.write(line + "\n") - f.close() - - if db_version <= 40: - print("Updating database to version 41") - old = copy.deepcopy(prefs.lyrics_enables) - prefs.lyrics_enables.clear() - if "apiseeds" in old: - prefs.lyrics_enables.append("Apiseeds") - if "lyricwiki" in old: - prefs.lyrics_enables.append("LyricWiki") - if "genius" in old: - prefs.lyrics_enables.append("Genius") - - if db_version <= 41: - print("Updating database to version 42") - - for key, value in gen_codes.items(): - gen_codes[key] = value.replace("f\"", "p\"") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - f = open(os.path.join(config_directory, "input.txt"), 'r') - text = f.read() - f.close() - lines = text.splitlines() - - f = open(os.path.join(config_directory, "input.txt"), 'w') - for line in lines: - line = line.strip() - if "rename-playlist" in line: - - f.write(line + "\n") - - line = "new-playlist T Ctrl\n" - f.write(line) - - line = "\nnew-generator-playlist\n" - f.write(line) - if "e ctrl" in text.lower(): - line = "edit-generator\n\n" - else: - line = "edit-generator E Ctrl\n\n" - f.write(line) - - line = "search-lyrics-selected\n" - f.write(line) - line = "substitute-search-selected" - - f.write(line + "\n") - - f.close() - - if db_version <= 42: - print("Updating database to version 43") - - if db_version <= 43: - print("Updating database to version 44") - # Repair db - for key, value in star_store.db.items(): - if len(value) == 2: - value.append(0) - star_store.db[key] = value - - if db_version <= 44: - print("Updating database to version 45") - print("Cleaning cache directory") - for item in os.listdir(cache_directory): - path = os.path.join(cache_directory, item) - if "-lfm." in item or "-ftv." in item or "-dcg." in item: - os.rename(path, os.path.join(a_cache_dir, item)) - for item in os.listdir(cache_directory): - path = os.path.join(cache_directory, item) - if os.path.isfile(path): - os.remove(path) - - if db_version <= 45: - print("Updating database to version 46") - for p in multi_playlist: - if type(p[7]) != list: - p[7] = [p[7]] - - if db_version <= 46: - print("Updating database to version 47") - for p in multi_playlist: - if type(p[7]) != list: - p[7] = [p[7]] - - if db_version <= 47: - print("Updating database to version 48") - if os.path.isfile(os.path.join(user_directory, "spot-r-token")): - show_message( - _("Welcome to v6.1.0. Due to changes, please re-authorise Spotify"), - _("You can do this by clicking 'Forget Account', then 'Authroise' in Settings > Accounts > Spotify")) - - if db_version <= 48: - print("Fix bad upgrade, now 49") - for key, value in master_library.items(): - if not hasattr(master_library[key], 'url_key'): - setattr(master_library[key], 'url_key', "") - if not hasattr(master_library[key], 'art_url_key'): - setattr(master_library[key], 'art_url_key', "") - - if db_version <= 49: - print("Updating database to version 50") - if os.path.isfile(os.path.join(user_directory, "spot-r-token")): - show_message( - _("Welcome to v6.3.0. Due to an upgrade, please re-authorise Spotify"), - _("You can do this by clicking 'Authroise' in Settings > Accounts > Spotify")) - os.remove(os.path.join(user_directory, "spot-r-token")) - - if db_version <= 54: - print("Updating database to version 55") - for key, value in master_library.items(): - setattr(master_library[key], 'lfm_scrobbles', 0) - - if db_version <= 55: - print("Update to db 56") - for key, value in master_library.items(): - - if hasattr(value, "track_gain"): - if value.track_gain != 0: - value.misc["replaygain_track_gain"] = value.track_gain - del value.track_gain - - if hasattr(value, "album_gain"): - if value.album_gain != 0: - value.misc["replaygain_album_gain"] = value.album_gain - del value.album_gain - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("toggle-right-panel MB5\n") - f.write("toggle-gallery MB4\n") - - if db_version <= 56: - print("Update to db 57") - if "Apiseeds" in prefs.lyrics_enables: - prefs.lyrics_enables.remove("Apiseeds") - prefs.lyrics_enables.append("Happi") - - if db_version <= 57: - print("Updating database to version 58") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\nregenerate-playlist R Alt\n") - f.write("clear-queue Q Shift Alt\n") - f.write("resize-window-16:9 F11 Alt\n") - f.write("delete-playlist-force W Shift Ctrl\n") - - if db_version <= 58: - print("Updating database to version 59") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\nrandom-album ; Alt\n") - - if db_version <= 59: - print("Updating database to version 60") - - if prefs.spotify_token: - show_message( - _("Upgrade to v6.5.1. It looks like you are using Spotify."), - _("Please click 'Authorise' again in the settings")) - prefs.spotify_token = "" - - if db_version <= 60: - print("Updating database to version 61") - - token_path = os.path.join(user_directory, "spot-token-pkce") - if os.path.exists(token_path): - prefs.spotify_token = "" - os.remove(token_path) - show_message( - _("Upgrade to v6.5.3 complete"), - _("It looks like you are using Spotify. Please re-setup Spotify again in the settings")) - - if db_version <= 61: - print("Updating database to version 62") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\ntransfer-playtime-to P Ctrl Shift\n") - - if db_version <= 62: - print("Updating database to version 63") - for item in gui.pl_st: - if item[0] == "T": - item[0] = "#" - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'r') as f: - lines = f.readlines() - with open(os.path.join(config_directory, "input.txt"), 'w') as f: - for line in lines: - if line == "vol-up Up Shift\n" or line == "vol-down Down Shift\n": - continue - f.write(line) - f.write("\n") - f.write("shift-up Up Shift\n") - f.write("shift-down Down Shift\n") - f.write("vol-up Up Ctrl\n") - f.write("vol-down Down Ctrl\n") - - if db_version <= 63: - print("Updating database to version 64") - if prefs.radio_urls: - radio_playlists[0]["items"].extend(prefs.radio_urls) - prefs.radio_urls = [] - # prefs.show_nag = True - - if db_version <= 64: - print("Updating database to version 65") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\nescape Escape\n") - f.write("toggle-mute M Ctrl\n") - - if db_version <= 65: - print("Updating database to version 66") - - if install_directory != config_directory and os.path.isfile(os.path.join(config_directory, "input.txt")): - with open(os.path.join(config_directory, "input.txt"), 'a') as f: - f.write("\ntoggle-artistinfo O Ctrl\n") - f.write("cycle-theme ] Ctrl\n") - f.write("cycle-theme-reverse [ Ctrl\n") - - if db_version <= 66: - print("Updating database to version 67") - for key, value in star_store.db.items(): - if len(value) == 3: - value.append(0) - star_store.db[key] = value - - if db_version <= 67: - print("Updating database to version 68") - for p in multi_playlist: - if len(p) == 11: - p.append(False) +# Run upgrades if we're behind the current DB standard +if db_version < latest_db_version: + master_library, multi_playlist, star_store, p_force_queue, theme, prefs, gui, gen_codes, radio_playlists = database_migrate( + db_version=db_version, + master_library=master_library, + install_mode=install_mode, + multi_playlist=multi_playlist, + star_store=star_store, + install_directory=install_directory, + a_cache_dir=a_cache_dir, + cache_directory=cache_directory, + config_directory=config_directory, + user_directory=user_directory, + gui=gui, + gen_codes=gen_codes, + prefs=prefs, + radio_playlists=radio_playlists, + theme=theme, + p_force_queue=p_force_queue, + ) if playing_in_queue > len(QUE) - 1: playing_in_queue = len(QUE) - 1 @@ -43285,7 +42844,7 @@ def save_state(): folder_image_offsets, None, # lfm_username, None, # lfm_hash, - 68, # Version, used for upgrading + latest_db_version, # Used for upgrading view_prefs, gui.save_size, None, # old side panel size From ba238d3f4c0559047961c2ee0ca723b1e1b0d0dc Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 19:38:08 +0100 Subject: [PATCH 10/63] t_main: Fix always trying to cast with undefined enc parameter --- t_modules/t_main.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index 20e5779cd..f0823ea06 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -42132,10 +42132,9 @@ def check_playback_running(self): tm.ready_playback() try: - tm.d['caster'] = [enc, [tauon], None] + tm.d['caster'] = [lambda: x, [tauon], None] except Exception: - logging.exception("Failed to cast, trying differently") - tm.d['caster'] = [lambda: x, [tauon], None] + logging.exception("Failed to cast") tm.d['worker'] = [worker1, (), None] tm.d['search'] = [worker2, (), None] From 9f055d87a9dda989e71ae53073a000f564074c0d Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 19:43:22 +0100 Subject: [PATCH 11/63] t_draw+t_extra: Stop duping alpha_blend function --- t_modules/t_draw.py | 13 +------------ t_modules/t_extra.py | 3 +-- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/t_modules/t_draw.py b/t_modules/t_draw.py index d81b3cb37..9fb71c8c4 100644 --- a/t_modules/t_draw.py +++ b/t_modules/t_draw.py @@ -55,7 +55,7 @@ ) from sdl2.sdlimage import IMG_Load_RW -from t_modules.t_extra import Timer, coll_rect +from t_modules.t_extra import Timer, alpha_blend, coll_rect if TYPE_CHECKING: from sdl2 import SDL_Renderer @@ -322,17 +322,6 @@ def __del__(self) -> None: win32gui.DeleteObject(self.font.GetSafeHandle()) - - -# Performs alpha blending of one colour (RGB-A) onto another (RGB) -def alpha_blend(colour: list[int], base: list[int]) -> list[int]: - alpha = colour[3] / 255 - return [ - int(alpha * colour[0] + (1 - alpha) * base[0]), - int(alpha * colour[1] + (1 - alpha) * base[1]), - int(alpha * colour[2] + (1 - alpha) * base[2]), 255] - - perf = Timer() class TDraw: diff --git a/t_modules/t_extra.py b/t_modules/t_extra.py index c3fabfe97..f4b14706b 100644 --- a/t_modules/t_extra.py +++ b/t_modules/t_extra.py @@ -207,9 +207,8 @@ def colour_value(c1: list[int]) -> int: """Give the sum of first 3 elements in a list""" return c1[0] + c1[1] + c1[2] - def alpha_blend(colour: tuple[int, int, int, int], base: tuple[int, int, int, int]) -> list[int]: - """Perform alpha blending of one colour (rgba) onto another (rgb)""" + """Performs alpha blending of one colour (RGB-A) onto another (RGB)""" alpha = colour[3] / 255 return [ int(alpha * colour[0] + (1 - alpha) * base[0]), From 7e6c2fd8645d6d1ee34dc3048eb1f234b7e10698 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 19:46:05 +0100 Subject: [PATCH 12/63] t_main: Remove t_launch star import --- t_modules/t_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index f0823ea06..8357c78ca 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -234,7 +234,7 @@ from t_modules.t_db_migrate import database_migrate from t_modules.t_draw import TDraw, QuickThumbnail from t_modules.t_jellyfin import Jellyfin -from t_modules.t_launch import * +from t_modules.t_launch import Launch from t_modules.t_lyrics import * from t_modules.t_phazor import phazor_exists, player4 from t_modules.t_search import * From 7f9b67638c7fc195d829dcc774e7e252ad751092 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 20:39:20 +0100 Subject: [PATCH 13/63] requirements_optional.txt: Add rest of optdepends --- requirements_optional.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/requirements_optional.txt b/requirements_optional.txt index 2feab12f4..53a353e38 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,4 +1,8 @@ jxlpy +#librespot - https://github.com/kokarare1212/librespot-python/pull/286 +#picard - picard 2.12.3 requires charset-normalizer~=3.3.2, but you have charset-normalizer 3.4.0 which is incompatible. +plexapi PyChromecast +pypresence tekore tidalapi From f763381b1e05e4744bf32991292d4a153265122b Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 20:44:57 +0100 Subject: [PATCH 14/63] t_stream: Add docstring and fully use logging module --- t_modules/t_stream.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/t_modules/t_stream.py b/t_modules/t_stream.py index 3b3585ee9..9babe4e71 100644 --- a/t_modules/t_stream.py +++ b/t_modules/t_stream.py @@ -1,4 +1,4 @@ -# Tauon Music Box - URL stream download and encoding module +"""Tauon Music Box - URL stream download and encoding module""" # Copyright © 2020, Taiko2k captain(dot)gxj(at)gmail.com @@ -129,19 +129,19 @@ class InterceptedHTTPResponse: if not self.url.endswith(".ts"): r.add_header("Icy-MetaData", "1") r.add_header("User-Agent", self.tauon.t_agent) - print("Open URL.....") + logging.info("Open URL.....") r = urllib.request.urlopen(r, timeout=20, cafile=self.tauon.ca) - print("URL opened.") + logging.info("URL opened.") except Exception as e: - # TODO(Martin): Specify the exception better and turn the top part into debug statements, then only throw except when Connection fails below + # TODO(Martin): Specify the exception better and turn the top part into debug statements, then only throw except when Connection fails below logging.exception("URL error...") retry -= 1 if retry > 0 and "Temporary" in str(e): time.sleep(2) logging.debug("RETRYING...") continue - logging.exception("Connection failed") + logging.error("Connection failed") self.tauon.gui.show_message(_("Failed to establish a connection"), str(e), mode="error") return False break @@ -155,7 +155,7 @@ class InterceptedHTTPResponse: def pump(self) -> None: aud = self.tauon.aud if self.tauon.prefs.backend != 4 or not aud: - print("Radio error: Phazor not loaded") + logging.error("Radio error: Phazor not loaded") return self.pump_running = True @@ -290,12 +290,12 @@ def save_track(): os.makedirs(self.tauon.prefs.encoder_output) shutil.move(target_file, save_file) - # print(self.tauon.pctl.tag_history) - # print(old_metadata) + # logging.info(self.tauon.pctl.tag_history) + # logging.info(old_metadata) tags = self.tauon.pctl.tag_history.get(old_metadata, None) if tags: - print("Save metadata to file") - #print(tags) + logging.info("Save metadata to file") + #logging.info(tags) muta = mutagen.File(save_file, easy=True) muta["artist"] = tags.get("artist", "") muta["title"] = tags.get("title", "") @@ -513,7 +513,7 @@ def run_download(self, r: _UrlopenRet): if "=" in tag: a, b = tag.split("=", 1) if a == "StreamTitle": - #print("Set meta") + #logging.info("Set meta") self.tauon.pctl.tag_meta = b.rstrip("'").lstrip("'") break except Exception: From f28547e3abfa82aca3a986d04ce3cc4d23dd00e6 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 20:45:29 +0100 Subject: [PATCH 15/63] t_main: Stop star importing from t_stream --- t_modules/t_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t_modules/t_main.py b/t_modules/t_main.py index 8357c78ca..bba9f220a 100644 --- a/t_modules/t_main.py +++ b/t_modules/t_main.py @@ -239,7 +239,7 @@ from t_modules.t_phazor import phazor_exists, player4 from t_modules.t_search import * from t_modules.t_spot import SpotCtl -from t_modules.t_stream import * +from t_modules.t_stream import StreamEnc from t_modules.t_tagscan import Ape, Flac, M4a, Opus, Wav, parse_picture_block from t_modules.t_themeload import * from t_modules.t_tidal import Tidal From 9028d01ba4b5e5b3d5027dff9789d46bd77a06ed Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 20:59:23 +0100 Subject: [PATCH 16/63] tauon.py: Move to src/tauon/ --- tauon.py => src/tauon/tauon.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tauon.py => src/tauon/tauon.py (100%) diff --git a/tauon.py b/src/tauon/tauon.py similarity index 100% rename from tauon.py rename to src/tauon/tauon.py From 1ccf568dfb6eac6993b5af521864448dbc7513ee Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 21:04:15 +0100 Subject: [PATCH 17/63] tauon.py: Use logging for everything but initial version and copyright strings --- src/tauon/tauon.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/tauon/tauon.py b/src/tauon/tauon.py index c4ea8fced..08baf79fa 100755 --- a/src/tauon/tauon.py +++ b/src/tauon/tauon.py @@ -86,7 +86,7 @@ t_id = "tauonmb" t_agent = "TauonMusicBox/" + n_version - +# Leave these outside of logging for prettiness print(f"{t_title} {t_version}") print("Copyright 2015-2023 Taiko2k captain.gxj@gmail.com\n") @@ -179,15 +179,14 @@ def transfer_args_and_exit() -> None: fp = None dev_mode = os.path.isfile(os.path.join(install_directory, ".dev")) if dev_mode: - print("Dev mode, ignoring single instancing") + logging.warning("Dev mode, ignoring single instancing") elif sys.platform != "win32": pid_file = os.path.join(user_directory, "program.pid") fp = open(pid_file, "w") try: fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB) except OSError: - # another instance is running - print("Program is already running") + logging.exception("Another Tauon instance is already running") transfer_args_and_exit() else: if sys.platform == "win32": @@ -197,8 +196,7 @@ def transfer_args_and_exit() -> None: os.remove(pid_file) fp = open(pid_file, "w") except OSError: - # another instance is running - print("Program is already running") + logging.exception("Another Tauon instance is already running") transfer_args_and_exit() if pyinstaller_mode: os.environ["FONTCONFIG_PATH"] = os.path.join(install_directory, "etc\\fonts")#"C:\\msys64\\mingw64\\etc\\fonts" @@ -215,7 +213,7 @@ def transfer_args_and_exit() -> None: fs_mode = False if os.environ.get("GAMESCOPE_WAYLAND_DISPLAY") is not None: fs_mode = True - print("Running in GAMESCOPE MODE") + logging.info("Running in GAMESCOPE MODE") allow_hidpi = True if sys.platform == "win32" and sys.getwindowsversion().major < 10 or os.path.isfile(os.path.join(user_directory, "nohidpi")): @@ -264,12 +262,12 @@ def transfer_args_and_exit() -> None: del save except Exception: - print("Corrupted window state file?!") - print("Please restart app") + logging.exception("Corrupted window state file?!") + logging.error("Please restart app") os.remove(window_p) sys.exit(1) else: - print("No window state file") + logging.info("No window state file") if d == "GNOME": #and os.environ.get("XDG_SESSION_TYPE") and os.environ.get("XDG_SESSION_TYPE") == "wayland": @@ -284,7 +282,7 @@ def transfer_args_and_exit() -> None: os.environ["XCURSOR_THEME"] = xtheme os.environ["XCURSOR_SIZE"] = str(xsize) except Exception: - pass + logging.exception("Failed to set cursor") if os.environ.get("XDG_SESSION_TYPE") and os.environ.get("XDG_SESSION_TYPE") == "wayland": os.environ["SDL_VIDEODRIVER"] = "wayland" @@ -294,7 +292,7 @@ def transfer_args_and_exit() -> None: SDL_Init(SDL_INIT_VIDEO) err = SDL_GetError() if err and "GLX" in err.decode(): - print(f"SDL init error: {err.decode()}") + logging.error(f"SDL init error: {err.decode()}") SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, b"Tauon Music Box failed to start :(", b"Error: " + err + b".\n If you're using Flatpak, try run `$ flatpak update`", None) @@ -339,7 +337,7 @@ def transfer_args_and_exit() -> None: renderer = SDL_CreateRenderer(t_window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC) if not renderer or not t_window: - print("ERROR CREATING WINDOW!") + logging.error("ERROR CREATING WINDOW!") SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND) SDL_SetWindowOpacity(t_window, window_opacity) From 9488e79174b089a9cb8d47012e0d7407a5af9d6a Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 21:04:34 +0100 Subject: [PATCH 18/63] Bump up copyright string --- src/tauon/tauon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tauon/tauon.py b/src/tauon/tauon.py index 08baf79fa..cf7cec09e 100755 --- a/src/tauon/tauon.py +++ b/src/tauon/tauon.py @@ -88,7 +88,7 @@ # Leave these outside of logging for prettiness print(f"{t_title} {t_version}") -print("Copyright 2015-2023 Taiko2k captain.gxj@gmail.com\n") +print("Copyright 2015-2024 Taiko2k captain.gxj@gmail.com\n") # Early arg processing def transfer_args_and_exit() -> None: From fc83b373b2b87ae691c9395ba6fd8d2af5fffa7b Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 21:13:54 +0100 Subject: [PATCH 19/63] tauon.py: Migrate to pathlib --- src/tauon/tauon.py | 53 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/tauon/tauon.py b/src/tauon/tauon.py index cf7cec09e..67412750d 100755 --- a/src/tauon/tauon.py +++ b/src/tauon/tauon.py @@ -21,6 +21,7 @@ import pickle import sys from ctypes import c_int, pointer +from pathlib import Path from gi.repository import GLib from sdl2 import ( @@ -101,7 +102,7 @@ def transfer_args_and_exit() -> None: for item in sys.argv: - if not item.endswith(".py") and not item.startswith("-") and not item.endswith("exe") and (item.startswith("file://") or os.path.exists(item)): + if not item.endswith(".py") and not item.startswith("-") and not item.endswith("exe") and (item.startswith("file://") or Path(item).exists()): import base64 url = base + "open/" + base64.urlsafe_b64encode(item.encode()).decode() urllib.request.urlopen(url) @@ -136,18 +137,18 @@ def transfer_args_and_exit() -> None: if "--no-start" in sys.argv: transfer_args_and_exit() -install_directory = os.path.dirname(os.path.abspath(__file__)) +install_directory = str(Path(__file__).resolve().parent) pyinstaller_mode = False if hasattr(sys, "_MEIPASS"): pyinstaller_mode = True if install_directory.endswith("\\_internal"): pyinstaller_mode = True - install_directory = os.path.dirname(install_directory) + install_directory = str(Path(install_directory).parent) if pyinstaller_mode: os.environ["PATH"] += ":" + sys._MEIPASS - os.environ["SSL_CERT_FILE"] = os.path.join(install_directory, "certifi", "cacert.pem") + os.environ["SSL_CERT_FILE"] = Path(install_directory) / "certifi" / "cacert.pem" # If we're installed, use home data locations install_mode = False @@ -158,9 +159,9 @@ def transfer_args_and_exit() -> None: if install_directory.startswith("/usr/"): install_directory = "/usr/share/TauonMusicBox" -user_directory = os.path.join(install_directory, "user-data") +user_directory = Path(install_directory) / "user-data" config_directory = user_directory -asset_directory = os.path.join(install_directory, "assets") +asset_directory = Path(install_directory) / "assets" if install_directory.startswith("/app/"): # Its Flatpak @@ -168,20 +169,20 @@ def transfer_args_and_exit() -> None: os.environ["SDL_VIDEO_WAYLAND_WMCLASS"] = t_id os.environ["SDL_VIDEO_X11_WMCLASS"] = t_id -if os.path.isfile(os.path.join(install_directory, "portable")): +if Path(Path(install_directory) / "portable").is_file(): install_mode = False if install_mode: - user_directory = os.path.join(GLib.get_user_data_dir(), "TauonMusicBox") -if not os.path.isdir(user_directory): - os.makedirs(user_directory) + user_directory = Path(GLib.get_user_data_dir()) / "TauonMusicBox" +if not Path(user_directory).is_dir(): + Path(user_directory).mkdir(parents=True) fp = None -dev_mode = os.path.isfile(os.path.join(install_directory, ".dev")) +dev_mode = Path(Path(install_directory) / ".dev").is_file() if dev_mode: logging.warning("Dev mode, ignoring single instancing") elif sys.platform != "win32": - pid_file = os.path.join(user_directory, "program.pid") + pid_file = Path(user_directory) / "program.pid" fp = open(pid_file, "w") try: fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB) @@ -190,16 +191,16 @@ def transfer_args_and_exit() -> None: transfer_args_and_exit() else: if sys.platform == "win32": - pid_file = os.path.join(user_directory, "program.pid") + pid_file = Path(user_directory) / "program.pid" try: - if os.path.isfile(pid_file): - os.remove(pid_file) + if Path(pid_file).is_file(): + Path(pid_file).unlink() fp = open(pid_file, "w") except OSError: logging.exception("Another Tauon instance is already running") transfer_args_and_exit() if pyinstaller_mode: - os.environ["FONTCONFIG_PATH"] = os.path.join(install_directory, "etc\\fonts")#"C:\\msys64\\mingw64\\etc\\fonts" + os.environ["FONTCONFIG_PATH"] = Path(install_directory) / "etc\\fonts" #"C:\\msys64\\mingw64\\etc\\fonts" phone = False d = os.environ.get("XDG_CURRENT_DESKTOP") @@ -216,7 +217,7 @@ def transfer_args_and_exit() -> None: logging.info("Running in GAMESCOPE MODE") allow_hidpi = True -if sys.platform == "win32" and sys.getwindowsversion().major < 10 or os.path.isfile(os.path.join(user_directory, "nohidpi")): +if sys.platform == "win32" and sys.getwindowsversion().major < 10 or Path(Path(user_directory) / "nohidpi").is_file(): allow_hidpi = False SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, b"1") @@ -243,8 +244,8 @@ def transfer_args_and_exit() -> None: maximized = False old_window_position = None -window_p = os.path.join(user_directory, "window.p") -if os.path.isfile(window_p) and not fs_mode: +window_p = Path(user_directory) / "window.p" +if Path(window_p).is_file() and not fs_mode: try: state_file = open(window_p, "rb") save = pickle.load(state_file) @@ -264,7 +265,7 @@ def transfer_args_and_exit() -> None: except Exception: logging.exception("Corrupted window state file?!") logging.error("Please restart app") - os.remove(window_p) + Path(window_p).unlink() sys.exit(1) else: logging.info("No window state file") @@ -273,7 +274,7 @@ def transfer_args_and_exit() -> None: if d == "GNOME": #and os.environ.get("XDG_SESSION_TYPE") and os.environ.get("XDG_SESSION_TYPE") == "wayland": try: import gi.repository - gi.require_version("Gtk", "3.0") + gi.require_version("Gtk", "4.0") from gi.repository import Gtk gtk_settings = Gtk.Settings().get_default() @@ -286,7 +287,7 @@ def transfer_args_and_exit() -> None: if os.environ.get("XDG_SESSION_TYPE") and os.environ.get("XDG_SESSION_TYPE") == "wayland": os.environ["SDL_VIDEODRIVER"] = "wayland" -if os.path.exists(os.path.join(user_directory, "x11")): +if Path(Path(user_directory) / "x11").exists(): os.environ["SDL_VIDEODRIVER"] = "x11" SDL_Init(SDL_INIT_VIDEO) @@ -356,10 +357,10 @@ def transfer_args_and_exit() -> None: logical_size[0] = i_x.contents.value logical_size[1] = i_y.contents.value -img_path = os.path.join(asset_directory, "loading.png") +img_path = Path(asset_directory) / "loading.png" if scale != 1: - img_path2 = os.path.join(user_directory, "scaled-icons", "loading.png") - if os.path.isfile(img_path2): + img_path2 = Path(user_directory) / "scaled-icons" / "loading.png" + if Path(img_path2).is_file(): img_path = img_path2 del img_path2 @@ -414,7 +415,7 @@ def transfer_args_and_exit() -> None: else: # Using the above import method breaks previous pickles. Could be fixed # but yet to decide what best method is. - big_boy_path = os.path.join(install_directory, "t_modules/t_main.py") + big_boy_path = Path(install_directory) / "t_modules/t_main.py" f = open(big_boy_path, "rb") main = compile(f.read(), big_boy_path, "exec") f.close() From 8e374e71b9dbd963bfe1141c4134843d3287c8dd Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 21:18:56 +0100 Subject: [PATCH 20/63] tauon.py: Properly crash when assets don't exist --- src/tauon/tauon.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tauon/tauon.py b/src/tauon/tauon.py index 67412750d..89290804d 100755 --- a/src/tauon/tauon.py +++ b/src/tauon/tauon.py @@ -358,6 +358,9 @@ def transfer_args_and_exit() -> None: logical_size[1] = i_y.contents.value img_path = Path(asset_directory) / "loading.png" +if not img_path.exists(): + raise FileNotFoundError(f"{str(img_path)} not found, exiting!") + if scale != 1: img_path2 = Path(user_directory) / "scaled-icons" / "loading.png" if Path(img_path2).is_file(): From 8c4e5f0b2d00b69d07d80eff6f30ec2420c8fd07 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 21:56:35 +0100 Subject: [PATCH 21/63] Packaging: Properly package most assets and modules as such --- pyproject.toml | 13 ++++- {t_modules => src/tauon}/__init__.py | 0 {assets => src/tauon/assets}/add-station.png | Bin {assets => src/tauon/assets}/artist-list.png | Bin {assets => src/tauon/assets}/artist.png | Bin {assets => src/tauon/assets}/as.png | Bin {assets => src/tauon/assets}/band.png | Bin {assets => src/tauon/assets}/bb.png | Bin {assets => src/tauon/assets}/broadcast.png | Bin {assets => src/tauon/assets}/bubble.png | Bin {assets => src/tauon/assets}/col.png | Bin {assets => src/tauon/assets}/corner.png | Bin {assets => src/tauon/assets}/ddl.png | Bin {assets => src/tauon/assets}/dec.png | Bin {assets => src/tauon/assets}/del.png | Bin {assets => src/tauon/assets}/discord.png | Bin {assets => src/tauon/assets}/dl.png | Bin {assets => src/tauon/assets}/done.png | Bin {assets => src/tauon/assets}/error.png | Bin {assets => src/tauon/assets}/ex.png | Bin {assets => src/tauon/assets}/ext.png | Bin {assets => src/tauon/assets}/favicon.ico | Bin {assets => src/tauon/assets}/ff.png | Bin {assets => src/tauon/assets}/filter.png | Bin {assets => src/tauon/assets}/folder-list.png | Bin {assets => src/tauon/assets}/folder.png | Bin {assets => src/tauon/assets}/gallery1.png | Bin {assets => src/tauon/assets}/gallery2.png | Bin {assets => src/tauon/assets}/heart-menu.png | Bin .../tauon/assets}/heart-notify-break.png | Bin {assets => src/tauon/assets}/heart-notify.png | Bin {assets => src/tauon/assets}/heart-track.png | Bin {assets => src/tauon/assets}/icon-128.png | Bin {assets => src/tauon/assets}/icon-64.png | Bin {assets => src/tauon/assets}/icon.ico | Bin {assets => src/tauon/assets}/inc.png | Bin {assets => src/tauon/assets}/info.png | Bin {assets => src/tauon/assets}/lb-g.png | Bin {assets => src/tauon/assets}/lb-gs.png | Bin {assets => src/tauon/assets}/left-slide.png | Bin {assets => src/tauon/assets}/load-error.png | Bin {assets => src/tauon/assets}/loading.png | Bin {assets => src/tauon/assets}/lock-corner.png | Bin {assets => src/tauon/assets}/lock.png | Bin {assets => src/tauon/assets}/lyrics.png | Bin {assets => src/tauon/assets}/macstyle.png | Bin {assets => src/tauon/assets}/max.png | Bin {assets => src/tauon/assets}/mbp-g.png | Bin {assets => src/tauon/assets}/mbp-gs.png | Bin {assets => src/tauon/assets}/mini-box.png | Bin {assets => src/tauon/assets}/mod_folder.png | Bin {assets => src/tauon/assets}/new.png | Bin {assets => src/tauon/assets}/notice.png | Bin {assets => src/tauon/assets}/overflow.png | Bin {assets => src/tauon/assets}/pen.png | Bin {assets => src/tauon/assets}/play.png | Bin {assets => src/tauon/assets}/playlist.png | Bin {assets => src/tauon/assets}/power.png | Bin {assets => src/tauon/assets}/radio-menu.png | Bin {assets => src/tauon/assets}/radio.png | Bin {assets => src/tauon/assets}/radiorandom.png | Bin .../tauon/assets}/repeat-mini-mode.png | Bin {assets => src/tauon/assets}/restore.png | Bin {assets => src/tauon/assets}/return.png | Bin {assets => src/tauon/assets}/revert.png | Bin {assets => src/tauon/assets}/right-slide.png | Bin {assets => src/tauon/assets}/save-station.png | Bin {assets => src/tauon/assets}/settings2.png | Bin {assets => src/tauon/assets}/shard.png | Bin .../tauon/assets}/shuffle-mini-mode.png | Bin {assets => src/tauon/assets}/sonemic-g.png | Bin {assets => src/tauon/assets}/sonemic-gs.png | Bin {assets => src/tauon/assets}/sort-down.png | Bin {assets => src/tauon/assets}/sort-up.png | Bin {assets => src/tauon/assets}/spot-info.png | Bin .../tauon/assets}/spot-playlist.png | Bin {assets => src/tauon/assets}/spot.png | Bin {assets => src/tauon/assets}/star-half.png | Bin {assets => src/tauon/assets}/star-pc.png | Bin {assets => src/tauon/assets}/star.png | Bin .../tauon/assets}/station-search.png | Bin {assets => src/tauon/assets}/sub.png | Bin .../tauon/assets}/svg/add-station.svg | 0 .../tauon/assets}/svg/artist-list.svg | 0 {assets => src/tauon/assets}/svg/artist.svg | 0 {assets => src/tauon/assets}/svg/band.svg | 0 {assets => src/tauon/assets}/svg/bb.svg | 0 .../tauon/assets}/svg/broadcast.svg | 0 {assets => src/tauon/assets}/svg/bubble.svg | 0 {assets => src/tauon/assets}/svg/col.svg | 0 {assets => src/tauon/assets}/svg/corner.svg | 0 {assets => src/tauon/assets}/svg/ddl.svg | 0 {assets => src/tauon/assets}/svg/dec.svg | 0 {assets => src/tauon/assets}/svg/del.svg | 0 {assets => src/tauon/assets}/svg/dl.svg | 0 {assets => src/tauon/assets}/svg/done.svg | 0 {assets => src/tauon/assets}/svg/error.svg | 0 {assets => src/tauon/assets}/svg/ex.svg | 0 {assets => src/tauon/assets}/svg/ext.svg | 0 {assets => src/tauon/assets}/svg/ff.svg | 0 {assets => src/tauon/assets}/svg/filter.svg | 0 .../tauon/assets}/svg/folder-list.svg | 0 {assets => src/tauon/assets}/svg/folder.svg | 0 {assets => src/tauon/assets}/svg/gallery1.svg | 0 {assets => src/tauon/assets}/svg/gallery2.svg | 0 .../tauon/assets}/svg/heart-menu.svg | 0 .../tauon/assets}/svg/heart-notify-break.svg | 0 .../tauon/assets}/svg/heart-notify.svg | 0 .../tauon/assets}/svg/heart-track.svg | 0 {assets => src/tauon/assets}/svg/inc.svg | 0 {assets => src/tauon/assets}/svg/info.svg | 0 .../tauon/assets}/svg/left-slide.svg | 0 .../tauon/assets}/svg/load-error.svg | 0 {assets => src/tauon/assets}/svg/loading.svg | 0 .../tauon/assets}/svg/lock-corner.svg | 0 {assets => src/tauon/assets}/svg/lock.svg | 0 {assets => src/tauon/assets}/svg/lyrics.svg | 0 {assets => src/tauon/assets}/svg/macstyle.svg | 0 {assets => src/tauon/assets}/svg/max.svg | 0 {assets => src/tauon/assets}/svg/mini-box.svg | 0 .../tauon/assets}/svg/mod_folder.svg | 0 {assets => src/tauon/assets}/svg/new.svg | 0 {assets => src/tauon/assets}/svg/notice.svg | 0 {assets => src/tauon/assets}/svg/overflow.svg | 0 {assets => src/tauon/assets}/svg/pen.svg | 0 {assets => src/tauon/assets}/svg/play.svg | 0 {assets => src/tauon/assets}/svg/playlist.svg | 0 {assets => src/tauon/assets}/svg/power.svg | 0 .../tauon/assets}/svg/radio-menu.svg | 0 {assets => src/tauon/assets}/svg/radio.svg | 0 .../tauon/assets}/svg/radiorandom.svg | 0 .../tauon/assets}/svg/repeat-mini-mode.svg | 0 {assets => src/tauon/assets}/svg/restore.svg | 0 {assets => src/tauon/assets}/svg/return.svg | 0 {assets => src/tauon/assets}/svg/revert.svg | 0 .../tauon/assets}/svg/right-slide.svg | 0 .../tauon/assets}/svg/save-station.svg | 0 .../tauon/assets}/svg/settings2.svg | 0 {assets => src/tauon/assets}/svg/shard.svg | 0 .../tauon/assets}/svg/shuffle-mini-mode.svg | 0 .../tauon/assets}/svg/sort-down.svg | 0 {assets => src/tauon/assets}/svg/sort-up.svg | 0 .../tauon/assets}/svg/spot-info.svg | 0 .../tauon/assets}/svg/spot-playlist.svg | 0 {assets => src/tauon/assets}/svg/spot.svg | 0 .../tauon/assets}/svg/star-half.svg | 0 {assets => src/tauon/assets}/svg/star-pc.svg | 0 {assets => src/tauon/assets}/svg/star.svg | 0 .../tauon/assets}/svg/station-search.svg | 0 {assets => src/tauon/assets}/svg/sub.svg | 0 .../tauon/assets}/svg/tauon_repeat.svg | 0 .../tauon/assets}/svg/tauon_repeat_a.svg | 0 .../tauon/assets}/svg/tauon_repeat_off.svg | 0 .../tauon/assets}/svg/tauon_shuffle.svg | 0 .../tauon/assets}/svg/tauon_shuffle_a.svg | 0 .../tauon/assets}/svg/tauon_shuffle_off.svg | 0 {assets => src/tauon/assets}/svg/title.svg | 0 .../tauon/assets}/svg/tracks+side.svg | 0 {assets => src/tauon/assets}/svg/tracks.svg | 0 .../tauon/assets}/svg/transcode.svg | 0 .../assets}/svg/tray-indicator-default-g1.svg | 0 .../assets}/svg/tray-indicator-default.svg | 0 .../assets}/svg/tray-indicator-pause-g1.svg | 0 .../assets}/svg/tray-indicator-pause.svg | 0 .../assets}/svg/tray-indicator-play-g1.svg | 0 .../tauon/assets}/svg/tray-indicator-play.svg | 0 {assets => src/tauon/assets}/svg/unlock.svg | 0 {assets => src/tauon/assets}/svg/v4-a.svg | 0 {assets => src/tauon/assets}/svg/v4-b.svg | 0 {assets => src/tauon/assets}/svg/v4-c.svg | 0 {assets => src/tauon/assets}/svg/v4-d.svg | 0 {assets => src/tauon/assets}/svg/v4-e.svg | 0 {assets => src/tauon/assets}/svg/v4-f.svg | 0 {assets => src/tauon/assets}/svg/warning.svg | 0 {assets => src/tauon/assets}/tau-mac.icns | Bin {assets => src/tauon/assets}/tau-mac.png | Bin {assets => src/tauon/assets}/tauon_repeat.png | Bin .../tauon/assets}/tauon_repeat_a.png | Bin .../tauon/assets}/tauon_repeat_off.png | Bin .../tauon/assets}/tauon_shuffle.png | Bin .../tauon/assets}/tauon_shuffle_a.png | Bin .../tauon/assets}/tauon_shuffle_off.png | Bin {assets => src/tauon/assets}/title.png | Bin {assets => src/tauon/assets}/tracks+side.png | Bin {assets => src/tauon/assets}/tracks.png | Bin {assets => src/tauon/assets}/transcode.png | Bin {assets => src/tauon/assets}/unlock.png | Bin {assets => src/tauon/assets}/v4-a.png | Bin {assets => src/tauon/assets}/v4-b.png | Bin {assets => src/tauon/assets}/v4-c.png | Bin {assets => src/tauon/assets}/v4-d.png | Bin {assets => src/tauon/assets}/v4-e.png | Bin {assets => src/tauon/assets}/v4-f.png | Bin {assets => src/tauon/assets}/warning.png | Bin input.txt => src/tauon/input.txt | 0 src/tauon/t_modules/__init__.py | 0 .../tauon/t_modules}/t_bootstrap.py | 0 .../tauon/t_modules}/t_chrome.py | 4 +- .../tauon/t_modules}/t_config.py | 0 .../tauon/t_modules}/t_db_migrate.py | 4 +- {t_modules => src/tauon/t_modules}/t_dbus.py | 4 +- {t_modules => src/tauon/t_modules}/t_draw.py | 2 +- {t_modules => src/tauon/t_modules}/t_extra.py | 2 +- .../tauon/t_modules}/t_jellyfin.py | 4 +- .../tauon/t_modules}/t_launch.py | 2 +- .../tauon/t_modules}/t_lyrics.py | 0 {t_modules => src/tauon/t_modules}/t_main.py | 46 +++++++++--------- .../tauon/t_modules}/t_phazor.py | 4 +- .../tauon/t_modules}/t_search.py | 0 {t_modules => src/tauon/t_modules}/t_spot.py | 4 +- .../tauon/t_modules}/t_stream.py | 6 +-- .../tauon/t_modules}/t_svgout.py | 0 .../tauon/t_modules}/t_tagscan.py | 2 +- .../tauon/t_modules}/t_themeload.py | 6 +-- {t_modules => src/tauon/t_modules}/t_tidal.py | 2 +- .../tauon/t_modules}/t_topchart.py | 2 +- .../tauon/t_modules}/t_webserve.py | 4 +- src/tauon/tauon.py | 6 +-- 218 files changed, 63 insertions(+), 54 deletions(-) rename {t_modules => src/tauon}/__init__.py (100%) rename {assets => src/tauon/assets}/add-station.png (100%) rename {assets => src/tauon/assets}/artist-list.png (100%) rename {assets => src/tauon/assets}/artist.png (100%) rename {assets => src/tauon/assets}/as.png (100%) rename {assets => src/tauon/assets}/band.png (100%) rename {assets => src/tauon/assets}/bb.png (100%) rename {assets => src/tauon/assets}/broadcast.png (100%) rename {assets => src/tauon/assets}/bubble.png (100%) rename {assets => src/tauon/assets}/col.png (100%) rename {assets => src/tauon/assets}/corner.png (100%) rename {assets => src/tauon/assets}/ddl.png (100%) rename {assets => src/tauon/assets}/dec.png (100%) rename {assets => src/tauon/assets}/del.png (100%) rename {assets => src/tauon/assets}/discord.png (100%) rename {assets => src/tauon/assets}/dl.png (100%) rename {assets => src/tauon/assets}/done.png (100%) rename {assets => src/tauon/assets}/error.png (100%) rename {assets => src/tauon/assets}/ex.png (100%) rename {assets => src/tauon/assets}/ext.png (100%) rename {assets => src/tauon/assets}/favicon.ico (100%) rename {assets => src/tauon/assets}/ff.png (100%) rename {assets => src/tauon/assets}/filter.png (100%) rename {assets => src/tauon/assets}/folder-list.png (100%) rename {assets => src/tauon/assets}/folder.png (100%) rename {assets => src/tauon/assets}/gallery1.png (100%) rename {assets => src/tauon/assets}/gallery2.png (100%) rename {assets => src/tauon/assets}/heart-menu.png (100%) rename {assets => src/tauon/assets}/heart-notify-break.png (100%) rename {assets => src/tauon/assets}/heart-notify.png (100%) rename {assets => src/tauon/assets}/heart-track.png (100%) rename {assets => src/tauon/assets}/icon-128.png (100%) rename {assets => src/tauon/assets}/icon-64.png (100%) rename {assets => src/tauon/assets}/icon.ico (100%) rename {assets => src/tauon/assets}/inc.png (100%) rename {assets => src/tauon/assets}/info.png (100%) rename {assets => src/tauon/assets}/lb-g.png (100%) rename {assets => src/tauon/assets}/lb-gs.png (100%) rename {assets => src/tauon/assets}/left-slide.png (100%) rename {assets => src/tauon/assets}/load-error.png (100%) rename {assets => src/tauon/assets}/loading.png (100%) rename {assets => src/tauon/assets}/lock-corner.png (100%) rename {assets => src/tauon/assets}/lock.png (100%) rename {assets => src/tauon/assets}/lyrics.png (100%) rename {assets => src/tauon/assets}/macstyle.png (100%) rename {assets => src/tauon/assets}/max.png (100%) rename {assets => src/tauon/assets}/mbp-g.png (100%) rename {assets => src/tauon/assets}/mbp-gs.png (100%) rename {assets => src/tauon/assets}/mini-box.png (100%) rename {assets => src/tauon/assets}/mod_folder.png (100%) rename {assets => src/tauon/assets}/new.png (100%) rename {assets => src/tauon/assets}/notice.png (100%) rename {assets => src/tauon/assets}/overflow.png (100%) rename {assets => src/tauon/assets}/pen.png (100%) rename {assets => src/tauon/assets}/play.png (100%) rename {assets => src/tauon/assets}/playlist.png (100%) rename {assets => src/tauon/assets}/power.png (100%) rename {assets => src/tauon/assets}/radio-menu.png (100%) rename {assets => src/tauon/assets}/radio.png (100%) rename {assets => src/tauon/assets}/radiorandom.png (100%) rename {assets => src/tauon/assets}/repeat-mini-mode.png (100%) rename {assets => src/tauon/assets}/restore.png (100%) rename {assets => src/tauon/assets}/return.png (100%) rename {assets => src/tauon/assets}/revert.png (100%) rename {assets => src/tauon/assets}/right-slide.png (100%) rename {assets => src/tauon/assets}/save-station.png (100%) rename {assets => src/tauon/assets}/settings2.png (100%) rename {assets => src/tauon/assets}/shard.png (100%) rename {assets => src/tauon/assets}/shuffle-mini-mode.png (100%) rename {assets => src/tauon/assets}/sonemic-g.png (100%) rename {assets => src/tauon/assets}/sonemic-gs.png (100%) rename {assets => src/tauon/assets}/sort-down.png (100%) rename {assets => src/tauon/assets}/sort-up.png (100%) rename {assets => src/tauon/assets}/spot-info.png (100%) rename {assets => src/tauon/assets}/spot-playlist.png (100%) rename {assets => src/tauon/assets}/spot.png (100%) rename {assets => src/tauon/assets}/star-half.png (100%) rename {assets => src/tauon/assets}/star-pc.png (100%) rename {assets => src/tauon/assets}/star.png (100%) rename {assets => src/tauon/assets}/station-search.png (100%) rename {assets => src/tauon/assets}/sub.png (100%) rename {assets => src/tauon/assets}/svg/add-station.svg (100%) rename {assets => src/tauon/assets}/svg/artist-list.svg (100%) rename {assets => src/tauon/assets}/svg/artist.svg (100%) rename {assets => src/tauon/assets}/svg/band.svg (100%) rename {assets => src/tauon/assets}/svg/bb.svg (100%) rename {assets => src/tauon/assets}/svg/broadcast.svg (100%) rename {assets => src/tauon/assets}/svg/bubble.svg (100%) rename {assets => src/tauon/assets}/svg/col.svg (100%) rename {assets => src/tauon/assets}/svg/corner.svg (100%) rename {assets => src/tauon/assets}/svg/ddl.svg (100%) rename {assets => src/tauon/assets}/svg/dec.svg (100%) rename {assets => src/tauon/assets}/svg/del.svg (100%) rename {assets => src/tauon/assets}/svg/dl.svg (100%) rename {assets => src/tauon/assets}/svg/done.svg (100%) rename {assets => src/tauon/assets}/svg/error.svg (100%) rename {assets => src/tauon/assets}/svg/ex.svg (100%) rename {assets => src/tauon/assets}/svg/ext.svg (100%) rename {assets => src/tauon/assets}/svg/ff.svg (100%) rename {assets => src/tauon/assets}/svg/filter.svg (100%) rename {assets => src/tauon/assets}/svg/folder-list.svg (100%) rename {assets => src/tauon/assets}/svg/folder.svg (100%) rename {assets => src/tauon/assets}/svg/gallery1.svg (100%) rename {assets => src/tauon/assets}/svg/gallery2.svg (100%) rename {assets => src/tauon/assets}/svg/heart-menu.svg (100%) rename {assets => src/tauon/assets}/svg/heart-notify-break.svg (100%) rename {assets => src/tauon/assets}/svg/heart-notify.svg (100%) rename {assets => src/tauon/assets}/svg/heart-track.svg (100%) rename {assets => src/tauon/assets}/svg/inc.svg (100%) rename {assets => src/tauon/assets}/svg/info.svg (100%) rename {assets => src/tauon/assets}/svg/left-slide.svg (100%) rename {assets => src/tauon/assets}/svg/load-error.svg (100%) rename {assets => src/tauon/assets}/svg/loading.svg (100%) rename {assets => src/tauon/assets}/svg/lock-corner.svg (100%) rename {assets => src/tauon/assets}/svg/lock.svg (100%) rename {assets => src/tauon/assets}/svg/lyrics.svg (100%) rename {assets => src/tauon/assets}/svg/macstyle.svg (100%) rename {assets => src/tauon/assets}/svg/max.svg (100%) rename {assets => src/tauon/assets}/svg/mini-box.svg (100%) rename {assets => src/tauon/assets}/svg/mod_folder.svg (100%) rename {assets => src/tauon/assets}/svg/new.svg (100%) rename {assets => src/tauon/assets}/svg/notice.svg (100%) rename {assets => src/tauon/assets}/svg/overflow.svg (100%) rename {assets => src/tauon/assets}/svg/pen.svg (100%) rename {assets => src/tauon/assets}/svg/play.svg (100%) rename {assets => src/tauon/assets}/svg/playlist.svg (100%) rename {assets => src/tauon/assets}/svg/power.svg (100%) rename {assets => src/tauon/assets}/svg/radio-menu.svg (100%) rename {assets => src/tauon/assets}/svg/radio.svg (100%) rename {assets => src/tauon/assets}/svg/radiorandom.svg (100%) rename {assets => src/tauon/assets}/svg/repeat-mini-mode.svg (100%) rename {assets => src/tauon/assets}/svg/restore.svg (100%) rename {assets => src/tauon/assets}/svg/return.svg (100%) rename {assets => src/tauon/assets}/svg/revert.svg (100%) rename {assets => src/tauon/assets}/svg/right-slide.svg (100%) rename {assets => src/tauon/assets}/svg/save-station.svg (100%) rename {assets => src/tauon/assets}/svg/settings2.svg (100%) rename {assets => src/tauon/assets}/svg/shard.svg (100%) rename {assets => src/tauon/assets}/svg/shuffle-mini-mode.svg (100%) rename {assets => src/tauon/assets}/svg/sort-down.svg (100%) rename {assets => src/tauon/assets}/svg/sort-up.svg (100%) rename {assets => src/tauon/assets}/svg/spot-info.svg (100%) rename {assets => src/tauon/assets}/svg/spot-playlist.svg (100%) rename {assets => src/tauon/assets}/svg/spot.svg (100%) rename {assets => src/tauon/assets}/svg/star-half.svg (100%) rename {assets => src/tauon/assets}/svg/star-pc.svg (100%) rename {assets => src/tauon/assets}/svg/star.svg (100%) rename {assets => src/tauon/assets}/svg/station-search.svg (100%) rename {assets => src/tauon/assets}/svg/sub.svg (100%) rename {assets => src/tauon/assets}/svg/tauon_repeat.svg (100%) rename {assets => src/tauon/assets}/svg/tauon_repeat_a.svg (100%) rename {assets => src/tauon/assets}/svg/tauon_repeat_off.svg (100%) rename {assets => src/tauon/assets}/svg/tauon_shuffle.svg (100%) rename {assets => src/tauon/assets}/svg/tauon_shuffle_a.svg (100%) rename {assets => src/tauon/assets}/svg/tauon_shuffle_off.svg (100%) rename {assets => src/tauon/assets}/svg/title.svg (100%) rename {assets => src/tauon/assets}/svg/tracks+side.svg (100%) rename {assets => src/tauon/assets}/svg/tracks.svg (100%) rename {assets => src/tauon/assets}/svg/transcode.svg (100%) rename {assets => src/tauon/assets}/svg/tray-indicator-default-g1.svg (100%) rename {assets => src/tauon/assets}/svg/tray-indicator-default.svg (100%) rename {assets => src/tauon/assets}/svg/tray-indicator-pause-g1.svg (100%) rename {assets => src/tauon/assets}/svg/tray-indicator-pause.svg (100%) rename {assets => src/tauon/assets}/svg/tray-indicator-play-g1.svg (100%) rename {assets => src/tauon/assets}/svg/tray-indicator-play.svg (100%) rename {assets => src/tauon/assets}/svg/unlock.svg (100%) rename {assets => src/tauon/assets}/svg/v4-a.svg (100%) rename {assets => src/tauon/assets}/svg/v4-b.svg (100%) rename {assets => src/tauon/assets}/svg/v4-c.svg (100%) rename {assets => src/tauon/assets}/svg/v4-d.svg (100%) rename {assets => src/tauon/assets}/svg/v4-e.svg (100%) rename {assets => src/tauon/assets}/svg/v4-f.svg (100%) rename {assets => src/tauon/assets}/svg/warning.svg (100%) rename {assets => src/tauon/assets}/tau-mac.icns (100%) rename {assets => src/tauon/assets}/tau-mac.png (100%) rename {assets => src/tauon/assets}/tauon_repeat.png (100%) rename {assets => src/tauon/assets}/tauon_repeat_a.png (100%) rename {assets => src/tauon/assets}/tauon_repeat_off.png (100%) rename {assets => src/tauon/assets}/tauon_shuffle.png (100%) rename {assets => src/tauon/assets}/tauon_shuffle_a.png (100%) rename {assets => src/tauon/assets}/tauon_shuffle_off.png (100%) rename {assets => src/tauon/assets}/title.png (100%) rename {assets => src/tauon/assets}/tracks+side.png (100%) rename {assets => src/tauon/assets}/tracks.png (100%) rename {assets => src/tauon/assets}/transcode.png (100%) rename {assets => src/tauon/assets}/unlock.png (100%) rename {assets => src/tauon/assets}/v4-a.png (100%) rename {assets => src/tauon/assets}/v4-b.png (100%) rename {assets => src/tauon/assets}/v4-c.png (100%) rename {assets => src/tauon/assets}/v4-d.png (100%) rename {assets => src/tauon/assets}/v4-e.png (100%) rename {assets => src/tauon/assets}/v4-f.png (100%) rename {assets => src/tauon/assets}/warning.png (100%) rename input.txt => src/tauon/input.txt (100%) create mode 100644 src/tauon/t_modules/__init__.py rename {t_modules => src/tauon/t_modules}/t_bootstrap.py (100%) rename {t_modules => src/tauon/t_modules}/t_chrome.py (97%) rename {t_modules => src/tauon/t_modules}/t_config.py (100%) rename {t_modules => src/tauon/t_modules}/t_db_migrate.py (99%) rename {t_modules => src/tauon/t_modules}/t_dbus.py (99%) rename {t_modules => src/tauon/t_modules}/t_draw.py (99%) rename {t_modules => src/tauon/t_modules}/t_extra.py (99%) rename {t_modules => src/tauon/t_modules}/t_jellyfin.py (99%) rename {t_modules => src/tauon/t_modules}/t_launch.py (81%) rename {t_modules => src/tauon/t_modules}/t_lyrics.py (100%) rename {t_modules => src/tauon/t_modules}/t_main.py (99%) rename {t_modules => src/tauon/t_modules}/t_phazor.py (99%) rename {t_modules => src/tauon/t_modules}/t_search.py (100%) rename {t_modules => src/tauon/t_modules}/t_spot.py (99%) rename {t_modules => src/tauon/t_modules}/t_stream.py (99%) rename {t_modules => src/tauon/t_modules}/t_svgout.py (100%) rename {t_modules => src/tauon/t_modules}/t_tagscan.py (99%) rename {t_modules => src/tauon/t_modules}/t_themeload.py (98%) rename {t_modules => src/tauon/t_modules}/t_tidal.py (99%) rename {t_modules => src/tauon/t_modules}/t_topchart.py (99%) rename {t_modules => src/tauon/t_modules}/t_webserve.py (99%) diff --git a/pyproject.toml b/pyproject.toml index 82cc3374b..005ae0cfc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ dynamic = ["dependencies"] [project.gui-scripts] - tauonmb = "tauon:main" + tauonmb = "tauon.tauon:main" [project.entry-points."distutils.commands"] compile_translations = "compile_translations:main" @@ -25,20 +25,29 @@ build-backend = "setuptools.build_meta" [tool.setuptools] - include-package-data = true # https://setuptools.pypa.io/en/latest/userguide/ext_modules.html # This is terribly formatted as in TOML 1.0 it all has to be inline, can only be changed when TOML 1.1 ships ext-modules = [ {name = "phazor", sources = ["src/phazor/kissfft/kiss_fftr.c", "src/phazor/kissfft/kiss_fft.c", "src/phazor/phazor.c"], include-dirs = ["/usr/include/opus"], libraries=["samplerate", "wavpack", "opusfile", "vorbisfile", "mpg123", "FLAC", "openmpt", "gme"] }, {name = "phazor-pw", sources = ["src/phazor/kissfft/kiss_fftr.c", "src/phazor/kissfft/kiss_fft.c", "src/phazor/phazor.c"], include-dirs = ["/usr/include/opus"], libraries=["samplerate", "wavpack", "opusfile", "vorbisfile", "mpg123", "FLAC", "openmpt", "gme", "pipewire-0.3"] },] + package-dir = {"" = "src"} + # Should we care about these options or is it fine to omit them here? # -shared -o libphazor.so -fPIC -Wall -O3 -g #-Wextra # -shared -o libphazor-pipe.so -fPIC -Wall -O3 -g -DPIPE #-Wextra + packages = [ + "tauon", + "tauon.t_modules" + ] + [tool.setuptools.dynamic] dependencies = {file = "requirements.txt"} +[tool.setuptools.package-data] +"tauon" = ["assets/*", "templates/*", "theme/*", "input.txt"] + # https://github.com/microsoft/pyright/blob/main/docs/configuration.md#pyright-configuration [tool.pyright] #defineConstant = { DEBUG = true } diff --git a/t_modules/__init__.py b/src/tauon/__init__.py similarity index 100% rename from t_modules/__init__.py rename to src/tauon/__init__.py diff --git a/assets/add-station.png b/src/tauon/assets/add-station.png similarity index 100% rename from assets/add-station.png rename to src/tauon/assets/add-station.png diff --git a/assets/artist-list.png b/src/tauon/assets/artist-list.png similarity index 100% rename from assets/artist-list.png rename to src/tauon/assets/artist-list.png diff --git a/assets/artist.png b/src/tauon/assets/artist.png similarity index 100% rename from assets/artist.png rename to src/tauon/assets/artist.png diff --git a/assets/as.png b/src/tauon/assets/as.png similarity index 100% rename from assets/as.png rename to src/tauon/assets/as.png diff --git a/assets/band.png b/src/tauon/assets/band.png similarity index 100% rename from assets/band.png rename to src/tauon/assets/band.png diff --git a/assets/bb.png b/src/tauon/assets/bb.png similarity index 100% rename from assets/bb.png rename to src/tauon/assets/bb.png diff --git a/assets/broadcast.png b/src/tauon/assets/broadcast.png similarity index 100% rename from assets/broadcast.png rename to src/tauon/assets/broadcast.png diff --git a/assets/bubble.png b/src/tauon/assets/bubble.png similarity index 100% rename from assets/bubble.png rename to src/tauon/assets/bubble.png diff --git a/assets/col.png b/src/tauon/assets/col.png similarity index 100% rename from assets/col.png rename to src/tauon/assets/col.png diff --git a/assets/corner.png b/src/tauon/assets/corner.png similarity index 100% rename from assets/corner.png rename to src/tauon/assets/corner.png diff --git a/assets/ddl.png b/src/tauon/assets/ddl.png similarity index 100% rename from assets/ddl.png rename to src/tauon/assets/ddl.png diff --git a/assets/dec.png b/src/tauon/assets/dec.png similarity index 100% rename from assets/dec.png rename to src/tauon/assets/dec.png diff --git a/assets/del.png b/src/tauon/assets/del.png similarity index 100% rename from assets/del.png rename to src/tauon/assets/del.png diff --git a/assets/discord.png b/src/tauon/assets/discord.png similarity index 100% rename from assets/discord.png rename to src/tauon/assets/discord.png diff --git a/assets/dl.png b/src/tauon/assets/dl.png similarity index 100% rename from assets/dl.png rename to src/tauon/assets/dl.png diff --git a/assets/done.png b/src/tauon/assets/done.png similarity index 100% rename from assets/done.png rename to src/tauon/assets/done.png diff --git a/assets/error.png b/src/tauon/assets/error.png similarity index 100% rename from assets/error.png rename to src/tauon/assets/error.png diff --git a/assets/ex.png b/src/tauon/assets/ex.png similarity index 100% rename from assets/ex.png rename to src/tauon/assets/ex.png diff --git a/assets/ext.png b/src/tauon/assets/ext.png similarity index 100% rename from assets/ext.png rename to src/tauon/assets/ext.png diff --git a/assets/favicon.ico b/src/tauon/assets/favicon.ico similarity index 100% rename from assets/favicon.ico rename to src/tauon/assets/favicon.ico diff --git a/assets/ff.png b/src/tauon/assets/ff.png similarity index 100% rename from assets/ff.png rename to src/tauon/assets/ff.png diff --git a/assets/filter.png b/src/tauon/assets/filter.png similarity index 100% rename from assets/filter.png rename to src/tauon/assets/filter.png diff --git a/assets/folder-list.png b/src/tauon/assets/folder-list.png similarity index 100% rename from assets/folder-list.png rename to src/tauon/assets/folder-list.png diff --git a/assets/folder.png b/src/tauon/assets/folder.png similarity index 100% rename from assets/folder.png rename to src/tauon/assets/folder.png diff --git a/assets/gallery1.png b/src/tauon/assets/gallery1.png similarity index 100% rename from assets/gallery1.png rename to src/tauon/assets/gallery1.png diff --git a/assets/gallery2.png b/src/tauon/assets/gallery2.png similarity index 100% rename from assets/gallery2.png rename to src/tauon/assets/gallery2.png diff --git a/assets/heart-menu.png b/src/tauon/assets/heart-menu.png similarity index 100% rename from assets/heart-menu.png rename to src/tauon/assets/heart-menu.png diff --git a/assets/heart-notify-break.png b/src/tauon/assets/heart-notify-break.png similarity index 100% rename from assets/heart-notify-break.png rename to src/tauon/assets/heart-notify-break.png diff --git a/assets/heart-notify.png b/src/tauon/assets/heart-notify.png similarity index 100% rename from assets/heart-notify.png rename to src/tauon/assets/heart-notify.png diff --git a/assets/heart-track.png b/src/tauon/assets/heart-track.png similarity index 100% rename from assets/heart-track.png rename to src/tauon/assets/heart-track.png diff --git a/assets/icon-128.png b/src/tauon/assets/icon-128.png similarity index 100% rename from assets/icon-128.png rename to src/tauon/assets/icon-128.png diff --git a/assets/icon-64.png b/src/tauon/assets/icon-64.png similarity index 100% rename from assets/icon-64.png rename to src/tauon/assets/icon-64.png diff --git a/assets/icon.ico b/src/tauon/assets/icon.ico similarity index 100% rename from assets/icon.ico rename to src/tauon/assets/icon.ico diff --git a/assets/inc.png b/src/tauon/assets/inc.png similarity index 100% rename from assets/inc.png rename to src/tauon/assets/inc.png diff --git a/assets/info.png b/src/tauon/assets/info.png similarity index 100% rename from assets/info.png rename to src/tauon/assets/info.png diff --git a/assets/lb-g.png b/src/tauon/assets/lb-g.png similarity index 100% rename from assets/lb-g.png rename to src/tauon/assets/lb-g.png diff --git a/assets/lb-gs.png b/src/tauon/assets/lb-gs.png similarity index 100% rename from assets/lb-gs.png rename to src/tauon/assets/lb-gs.png diff --git a/assets/left-slide.png b/src/tauon/assets/left-slide.png similarity index 100% rename from assets/left-slide.png rename to src/tauon/assets/left-slide.png diff --git a/assets/load-error.png b/src/tauon/assets/load-error.png similarity index 100% rename from assets/load-error.png rename to src/tauon/assets/load-error.png diff --git a/assets/loading.png b/src/tauon/assets/loading.png similarity index 100% rename from assets/loading.png rename to src/tauon/assets/loading.png diff --git a/assets/lock-corner.png b/src/tauon/assets/lock-corner.png similarity index 100% rename from assets/lock-corner.png rename to src/tauon/assets/lock-corner.png diff --git a/assets/lock.png b/src/tauon/assets/lock.png similarity index 100% rename from assets/lock.png rename to src/tauon/assets/lock.png diff --git a/assets/lyrics.png b/src/tauon/assets/lyrics.png similarity index 100% rename from assets/lyrics.png rename to src/tauon/assets/lyrics.png diff --git a/assets/macstyle.png b/src/tauon/assets/macstyle.png similarity index 100% rename from assets/macstyle.png rename to src/tauon/assets/macstyle.png diff --git a/assets/max.png b/src/tauon/assets/max.png similarity index 100% rename from assets/max.png rename to src/tauon/assets/max.png diff --git a/assets/mbp-g.png b/src/tauon/assets/mbp-g.png similarity index 100% rename from assets/mbp-g.png rename to src/tauon/assets/mbp-g.png diff --git a/assets/mbp-gs.png b/src/tauon/assets/mbp-gs.png similarity index 100% rename from assets/mbp-gs.png rename to src/tauon/assets/mbp-gs.png diff --git a/assets/mini-box.png b/src/tauon/assets/mini-box.png similarity index 100% rename from assets/mini-box.png rename to src/tauon/assets/mini-box.png diff --git a/assets/mod_folder.png b/src/tauon/assets/mod_folder.png similarity index 100% rename from assets/mod_folder.png rename to src/tauon/assets/mod_folder.png diff --git a/assets/new.png b/src/tauon/assets/new.png similarity index 100% rename from assets/new.png rename to src/tauon/assets/new.png diff --git a/assets/notice.png b/src/tauon/assets/notice.png similarity index 100% rename from assets/notice.png rename to src/tauon/assets/notice.png diff --git a/assets/overflow.png b/src/tauon/assets/overflow.png similarity index 100% rename from assets/overflow.png rename to src/tauon/assets/overflow.png diff --git a/assets/pen.png b/src/tauon/assets/pen.png similarity index 100% rename from assets/pen.png rename to src/tauon/assets/pen.png diff --git a/assets/play.png b/src/tauon/assets/play.png similarity index 100% rename from assets/play.png rename to src/tauon/assets/play.png diff --git a/assets/playlist.png b/src/tauon/assets/playlist.png similarity index 100% rename from assets/playlist.png rename to src/tauon/assets/playlist.png diff --git a/assets/power.png b/src/tauon/assets/power.png similarity index 100% rename from assets/power.png rename to src/tauon/assets/power.png diff --git a/assets/radio-menu.png b/src/tauon/assets/radio-menu.png similarity index 100% rename from assets/radio-menu.png rename to src/tauon/assets/radio-menu.png diff --git a/assets/radio.png b/src/tauon/assets/radio.png similarity index 100% rename from assets/radio.png rename to src/tauon/assets/radio.png diff --git a/assets/radiorandom.png b/src/tauon/assets/radiorandom.png similarity index 100% rename from assets/radiorandom.png rename to src/tauon/assets/radiorandom.png diff --git a/assets/repeat-mini-mode.png b/src/tauon/assets/repeat-mini-mode.png similarity index 100% rename from assets/repeat-mini-mode.png rename to src/tauon/assets/repeat-mini-mode.png diff --git a/assets/restore.png b/src/tauon/assets/restore.png similarity index 100% rename from assets/restore.png rename to src/tauon/assets/restore.png diff --git a/assets/return.png b/src/tauon/assets/return.png similarity index 100% rename from assets/return.png rename to src/tauon/assets/return.png diff --git a/assets/revert.png b/src/tauon/assets/revert.png similarity index 100% rename from assets/revert.png rename to src/tauon/assets/revert.png diff --git a/assets/right-slide.png b/src/tauon/assets/right-slide.png similarity index 100% rename from assets/right-slide.png rename to src/tauon/assets/right-slide.png diff --git a/assets/save-station.png b/src/tauon/assets/save-station.png similarity index 100% rename from assets/save-station.png rename to src/tauon/assets/save-station.png diff --git a/assets/settings2.png b/src/tauon/assets/settings2.png similarity index 100% rename from assets/settings2.png rename to src/tauon/assets/settings2.png diff --git a/assets/shard.png b/src/tauon/assets/shard.png similarity index 100% rename from assets/shard.png rename to src/tauon/assets/shard.png diff --git a/assets/shuffle-mini-mode.png b/src/tauon/assets/shuffle-mini-mode.png similarity index 100% rename from assets/shuffle-mini-mode.png rename to src/tauon/assets/shuffle-mini-mode.png diff --git a/assets/sonemic-g.png b/src/tauon/assets/sonemic-g.png similarity index 100% rename from assets/sonemic-g.png rename to src/tauon/assets/sonemic-g.png diff --git a/assets/sonemic-gs.png b/src/tauon/assets/sonemic-gs.png similarity index 100% rename from assets/sonemic-gs.png rename to src/tauon/assets/sonemic-gs.png diff --git a/assets/sort-down.png b/src/tauon/assets/sort-down.png similarity index 100% rename from assets/sort-down.png rename to src/tauon/assets/sort-down.png diff --git a/assets/sort-up.png b/src/tauon/assets/sort-up.png similarity index 100% rename from assets/sort-up.png rename to src/tauon/assets/sort-up.png diff --git a/assets/spot-info.png b/src/tauon/assets/spot-info.png similarity index 100% rename from assets/spot-info.png rename to src/tauon/assets/spot-info.png diff --git a/assets/spot-playlist.png b/src/tauon/assets/spot-playlist.png similarity index 100% rename from assets/spot-playlist.png rename to src/tauon/assets/spot-playlist.png diff --git a/assets/spot.png b/src/tauon/assets/spot.png similarity index 100% rename from assets/spot.png rename to src/tauon/assets/spot.png diff --git a/assets/star-half.png b/src/tauon/assets/star-half.png similarity index 100% rename from assets/star-half.png rename to src/tauon/assets/star-half.png diff --git a/assets/star-pc.png b/src/tauon/assets/star-pc.png similarity index 100% rename from assets/star-pc.png rename to src/tauon/assets/star-pc.png diff --git a/assets/star.png b/src/tauon/assets/star.png similarity index 100% rename from assets/star.png rename to src/tauon/assets/star.png diff --git a/assets/station-search.png b/src/tauon/assets/station-search.png similarity index 100% rename from assets/station-search.png rename to src/tauon/assets/station-search.png diff --git a/assets/sub.png b/src/tauon/assets/sub.png similarity index 100% rename from assets/sub.png rename to src/tauon/assets/sub.png diff --git a/assets/svg/add-station.svg b/src/tauon/assets/svg/add-station.svg similarity index 100% rename from assets/svg/add-station.svg rename to src/tauon/assets/svg/add-station.svg diff --git a/assets/svg/artist-list.svg b/src/tauon/assets/svg/artist-list.svg similarity index 100% rename from assets/svg/artist-list.svg rename to src/tauon/assets/svg/artist-list.svg diff --git a/assets/svg/artist.svg b/src/tauon/assets/svg/artist.svg similarity index 100% rename from assets/svg/artist.svg rename to src/tauon/assets/svg/artist.svg diff --git a/assets/svg/band.svg b/src/tauon/assets/svg/band.svg similarity index 100% rename from assets/svg/band.svg rename to src/tauon/assets/svg/band.svg diff --git a/assets/svg/bb.svg b/src/tauon/assets/svg/bb.svg similarity index 100% rename from assets/svg/bb.svg rename to src/tauon/assets/svg/bb.svg diff --git a/assets/svg/broadcast.svg b/src/tauon/assets/svg/broadcast.svg similarity index 100% rename from assets/svg/broadcast.svg rename to src/tauon/assets/svg/broadcast.svg diff --git a/assets/svg/bubble.svg b/src/tauon/assets/svg/bubble.svg similarity index 100% rename from assets/svg/bubble.svg rename to src/tauon/assets/svg/bubble.svg diff --git a/assets/svg/col.svg b/src/tauon/assets/svg/col.svg similarity index 100% rename from assets/svg/col.svg rename to src/tauon/assets/svg/col.svg diff --git a/assets/svg/corner.svg b/src/tauon/assets/svg/corner.svg similarity index 100% rename from assets/svg/corner.svg rename to src/tauon/assets/svg/corner.svg diff --git a/assets/svg/ddl.svg b/src/tauon/assets/svg/ddl.svg similarity index 100% rename from assets/svg/ddl.svg rename to src/tauon/assets/svg/ddl.svg diff --git a/assets/svg/dec.svg b/src/tauon/assets/svg/dec.svg similarity index 100% rename from assets/svg/dec.svg rename to src/tauon/assets/svg/dec.svg diff --git a/assets/svg/del.svg b/src/tauon/assets/svg/del.svg similarity index 100% rename from assets/svg/del.svg rename to src/tauon/assets/svg/del.svg diff --git a/assets/svg/dl.svg b/src/tauon/assets/svg/dl.svg similarity index 100% rename from assets/svg/dl.svg rename to src/tauon/assets/svg/dl.svg diff --git a/assets/svg/done.svg b/src/tauon/assets/svg/done.svg similarity index 100% rename from assets/svg/done.svg rename to src/tauon/assets/svg/done.svg diff --git a/assets/svg/error.svg b/src/tauon/assets/svg/error.svg similarity index 100% rename from assets/svg/error.svg rename to src/tauon/assets/svg/error.svg diff --git a/assets/svg/ex.svg b/src/tauon/assets/svg/ex.svg similarity index 100% rename from assets/svg/ex.svg rename to src/tauon/assets/svg/ex.svg diff --git a/assets/svg/ext.svg b/src/tauon/assets/svg/ext.svg similarity index 100% rename from assets/svg/ext.svg rename to src/tauon/assets/svg/ext.svg diff --git a/assets/svg/ff.svg b/src/tauon/assets/svg/ff.svg similarity index 100% rename from assets/svg/ff.svg rename to src/tauon/assets/svg/ff.svg diff --git a/assets/svg/filter.svg b/src/tauon/assets/svg/filter.svg similarity index 100% rename from assets/svg/filter.svg rename to src/tauon/assets/svg/filter.svg diff --git a/assets/svg/folder-list.svg b/src/tauon/assets/svg/folder-list.svg similarity index 100% rename from assets/svg/folder-list.svg rename to src/tauon/assets/svg/folder-list.svg diff --git a/assets/svg/folder.svg b/src/tauon/assets/svg/folder.svg similarity index 100% rename from assets/svg/folder.svg rename to src/tauon/assets/svg/folder.svg diff --git a/assets/svg/gallery1.svg b/src/tauon/assets/svg/gallery1.svg similarity index 100% rename from assets/svg/gallery1.svg rename to src/tauon/assets/svg/gallery1.svg diff --git a/assets/svg/gallery2.svg b/src/tauon/assets/svg/gallery2.svg similarity index 100% rename from assets/svg/gallery2.svg rename to src/tauon/assets/svg/gallery2.svg diff --git a/assets/svg/heart-menu.svg b/src/tauon/assets/svg/heart-menu.svg similarity index 100% rename from assets/svg/heart-menu.svg rename to src/tauon/assets/svg/heart-menu.svg diff --git a/assets/svg/heart-notify-break.svg b/src/tauon/assets/svg/heart-notify-break.svg similarity index 100% rename from assets/svg/heart-notify-break.svg rename to src/tauon/assets/svg/heart-notify-break.svg diff --git a/assets/svg/heart-notify.svg b/src/tauon/assets/svg/heart-notify.svg similarity index 100% rename from assets/svg/heart-notify.svg rename to src/tauon/assets/svg/heart-notify.svg diff --git a/assets/svg/heart-track.svg b/src/tauon/assets/svg/heart-track.svg similarity index 100% rename from assets/svg/heart-track.svg rename to src/tauon/assets/svg/heart-track.svg diff --git a/assets/svg/inc.svg b/src/tauon/assets/svg/inc.svg similarity index 100% rename from assets/svg/inc.svg rename to src/tauon/assets/svg/inc.svg diff --git a/assets/svg/info.svg b/src/tauon/assets/svg/info.svg similarity index 100% rename from assets/svg/info.svg rename to src/tauon/assets/svg/info.svg diff --git a/assets/svg/left-slide.svg b/src/tauon/assets/svg/left-slide.svg similarity index 100% rename from assets/svg/left-slide.svg rename to src/tauon/assets/svg/left-slide.svg diff --git a/assets/svg/load-error.svg b/src/tauon/assets/svg/load-error.svg similarity index 100% rename from assets/svg/load-error.svg rename to src/tauon/assets/svg/load-error.svg diff --git a/assets/svg/loading.svg b/src/tauon/assets/svg/loading.svg similarity index 100% rename from assets/svg/loading.svg rename to src/tauon/assets/svg/loading.svg diff --git a/assets/svg/lock-corner.svg b/src/tauon/assets/svg/lock-corner.svg similarity index 100% rename from assets/svg/lock-corner.svg rename to src/tauon/assets/svg/lock-corner.svg diff --git a/assets/svg/lock.svg b/src/tauon/assets/svg/lock.svg similarity index 100% rename from assets/svg/lock.svg rename to src/tauon/assets/svg/lock.svg diff --git a/assets/svg/lyrics.svg b/src/tauon/assets/svg/lyrics.svg similarity index 100% rename from assets/svg/lyrics.svg rename to src/tauon/assets/svg/lyrics.svg diff --git a/assets/svg/macstyle.svg b/src/tauon/assets/svg/macstyle.svg similarity index 100% rename from assets/svg/macstyle.svg rename to src/tauon/assets/svg/macstyle.svg diff --git a/assets/svg/max.svg b/src/tauon/assets/svg/max.svg similarity index 100% rename from assets/svg/max.svg rename to src/tauon/assets/svg/max.svg diff --git a/assets/svg/mini-box.svg b/src/tauon/assets/svg/mini-box.svg similarity index 100% rename from assets/svg/mini-box.svg rename to src/tauon/assets/svg/mini-box.svg diff --git a/assets/svg/mod_folder.svg b/src/tauon/assets/svg/mod_folder.svg similarity index 100% rename from assets/svg/mod_folder.svg rename to src/tauon/assets/svg/mod_folder.svg diff --git a/assets/svg/new.svg b/src/tauon/assets/svg/new.svg similarity index 100% rename from assets/svg/new.svg rename to src/tauon/assets/svg/new.svg diff --git a/assets/svg/notice.svg b/src/tauon/assets/svg/notice.svg similarity index 100% rename from assets/svg/notice.svg rename to src/tauon/assets/svg/notice.svg diff --git a/assets/svg/overflow.svg b/src/tauon/assets/svg/overflow.svg similarity index 100% rename from assets/svg/overflow.svg rename to src/tauon/assets/svg/overflow.svg diff --git a/assets/svg/pen.svg b/src/tauon/assets/svg/pen.svg similarity index 100% rename from assets/svg/pen.svg rename to src/tauon/assets/svg/pen.svg diff --git a/assets/svg/play.svg b/src/tauon/assets/svg/play.svg similarity index 100% rename from assets/svg/play.svg rename to src/tauon/assets/svg/play.svg diff --git a/assets/svg/playlist.svg b/src/tauon/assets/svg/playlist.svg similarity index 100% rename from assets/svg/playlist.svg rename to src/tauon/assets/svg/playlist.svg diff --git a/assets/svg/power.svg b/src/tauon/assets/svg/power.svg similarity index 100% rename from assets/svg/power.svg rename to src/tauon/assets/svg/power.svg diff --git a/assets/svg/radio-menu.svg b/src/tauon/assets/svg/radio-menu.svg similarity index 100% rename from assets/svg/radio-menu.svg rename to src/tauon/assets/svg/radio-menu.svg diff --git a/assets/svg/radio.svg b/src/tauon/assets/svg/radio.svg similarity index 100% rename from assets/svg/radio.svg rename to src/tauon/assets/svg/radio.svg diff --git a/assets/svg/radiorandom.svg b/src/tauon/assets/svg/radiorandom.svg similarity index 100% rename from assets/svg/radiorandom.svg rename to src/tauon/assets/svg/radiorandom.svg diff --git a/assets/svg/repeat-mini-mode.svg b/src/tauon/assets/svg/repeat-mini-mode.svg similarity index 100% rename from assets/svg/repeat-mini-mode.svg rename to src/tauon/assets/svg/repeat-mini-mode.svg diff --git a/assets/svg/restore.svg b/src/tauon/assets/svg/restore.svg similarity index 100% rename from assets/svg/restore.svg rename to src/tauon/assets/svg/restore.svg diff --git a/assets/svg/return.svg b/src/tauon/assets/svg/return.svg similarity index 100% rename from assets/svg/return.svg rename to src/tauon/assets/svg/return.svg diff --git a/assets/svg/revert.svg b/src/tauon/assets/svg/revert.svg similarity index 100% rename from assets/svg/revert.svg rename to src/tauon/assets/svg/revert.svg diff --git a/assets/svg/right-slide.svg b/src/tauon/assets/svg/right-slide.svg similarity index 100% rename from assets/svg/right-slide.svg rename to src/tauon/assets/svg/right-slide.svg diff --git a/assets/svg/save-station.svg b/src/tauon/assets/svg/save-station.svg similarity index 100% rename from assets/svg/save-station.svg rename to src/tauon/assets/svg/save-station.svg diff --git a/assets/svg/settings2.svg b/src/tauon/assets/svg/settings2.svg similarity index 100% rename from assets/svg/settings2.svg rename to src/tauon/assets/svg/settings2.svg diff --git a/assets/svg/shard.svg b/src/tauon/assets/svg/shard.svg similarity index 100% rename from assets/svg/shard.svg rename to src/tauon/assets/svg/shard.svg diff --git a/assets/svg/shuffle-mini-mode.svg b/src/tauon/assets/svg/shuffle-mini-mode.svg similarity index 100% rename from assets/svg/shuffle-mini-mode.svg rename to src/tauon/assets/svg/shuffle-mini-mode.svg diff --git a/assets/svg/sort-down.svg b/src/tauon/assets/svg/sort-down.svg similarity index 100% rename from assets/svg/sort-down.svg rename to src/tauon/assets/svg/sort-down.svg diff --git a/assets/svg/sort-up.svg b/src/tauon/assets/svg/sort-up.svg similarity index 100% rename from assets/svg/sort-up.svg rename to src/tauon/assets/svg/sort-up.svg diff --git a/assets/svg/spot-info.svg b/src/tauon/assets/svg/spot-info.svg similarity index 100% rename from assets/svg/spot-info.svg rename to src/tauon/assets/svg/spot-info.svg diff --git a/assets/svg/spot-playlist.svg b/src/tauon/assets/svg/spot-playlist.svg similarity index 100% rename from assets/svg/spot-playlist.svg rename to src/tauon/assets/svg/spot-playlist.svg diff --git a/assets/svg/spot.svg b/src/tauon/assets/svg/spot.svg similarity index 100% rename from assets/svg/spot.svg rename to src/tauon/assets/svg/spot.svg diff --git a/assets/svg/star-half.svg b/src/tauon/assets/svg/star-half.svg similarity index 100% rename from assets/svg/star-half.svg rename to src/tauon/assets/svg/star-half.svg diff --git a/assets/svg/star-pc.svg b/src/tauon/assets/svg/star-pc.svg similarity index 100% rename from assets/svg/star-pc.svg rename to src/tauon/assets/svg/star-pc.svg diff --git a/assets/svg/star.svg b/src/tauon/assets/svg/star.svg similarity index 100% rename from assets/svg/star.svg rename to src/tauon/assets/svg/star.svg diff --git a/assets/svg/station-search.svg b/src/tauon/assets/svg/station-search.svg similarity index 100% rename from assets/svg/station-search.svg rename to src/tauon/assets/svg/station-search.svg diff --git a/assets/svg/sub.svg b/src/tauon/assets/svg/sub.svg similarity index 100% rename from assets/svg/sub.svg rename to src/tauon/assets/svg/sub.svg diff --git a/assets/svg/tauon_repeat.svg b/src/tauon/assets/svg/tauon_repeat.svg similarity index 100% rename from assets/svg/tauon_repeat.svg rename to src/tauon/assets/svg/tauon_repeat.svg diff --git a/assets/svg/tauon_repeat_a.svg b/src/tauon/assets/svg/tauon_repeat_a.svg similarity index 100% rename from assets/svg/tauon_repeat_a.svg rename to src/tauon/assets/svg/tauon_repeat_a.svg diff --git a/assets/svg/tauon_repeat_off.svg b/src/tauon/assets/svg/tauon_repeat_off.svg similarity index 100% rename from assets/svg/tauon_repeat_off.svg rename to src/tauon/assets/svg/tauon_repeat_off.svg diff --git a/assets/svg/tauon_shuffle.svg b/src/tauon/assets/svg/tauon_shuffle.svg similarity index 100% rename from assets/svg/tauon_shuffle.svg rename to src/tauon/assets/svg/tauon_shuffle.svg diff --git a/assets/svg/tauon_shuffle_a.svg b/src/tauon/assets/svg/tauon_shuffle_a.svg similarity index 100% rename from assets/svg/tauon_shuffle_a.svg rename to src/tauon/assets/svg/tauon_shuffle_a.svg diff --git a/assets/svg/tauon_shuffle_off.svg b/src/tauon/assets/svg/tauon_shuffle_off.svg similarity index 100% rename from assets/svg/tauon_shuffle_off.svg rename to src/tauon/assets/svg/tauon_shuffle_off.svg diff --git a/assets/svg/title.svg b/src/tauon/assets/svg/title.svg similarity index 100% rename from assets/svg/title.svg rename to src/tauon/assets/svg/title.svg diff --git a/assets/svg/tracks+side.svg b/src/tauon/assets/svg/tracks+side.svg similarity index 100% rename from assets/svg/tracks+side.svg rename to src/tauon/assets/svg/tracks+side.svg diff --git a/assets/svg/tracks.svg b/src/tauon/assets/svg/tracks.svg similarity index 100% rename from assets/svg/tracks.svg rename to src/tauon/assets/svg/tracks.svg diff --git a/assets/svg/transcode.svg b/src/tauon/assets/svg/transcode.svg similarity index 100% rename from assets/svg/transcode.svg rename to src/tauon/assets/svg/transcode.svg diff --git a/assets/svg/tray-indicator-default-g1.svg b/src/tauon/assets/svg/tray-indicator-default-g1.svg similarity index 100% rename from assets/svg/tray-indicator-default-g1.svg rename to src/tauon/assets/svg/tray-indicator-default-g1.svg diff --git a/assets/svg/tray-indicator-default.svg b/src/tauon/assets/svg/tray-indicator-default.svg similarity index 100% rename from assets/svg/tray-indicator-default.svg rename to src/tauon/assets/svg/tray-indicator-default.svg diff --git a/assets/svg/tray-indicator-pause-g1.svg b/src/tauon/assets/svg/tray-indicator-pause-g1.svg similarity index 100% rename from assets/svg/tray-indicator-pause-g1.svg rename to src/tauon/assets/svg/tray-indicator-pause-g1.svg diff --git a/assets/svg/tray-indicator-pause.svg b/src/tauon/assets/svg/tray-indicator-pause.svg similarity index 100% rename from assets/svg/tray-indicator-pause.svg rename to src/tauon/assets/svg/tray-indicator-pause.svg diff --git a/assets/svg/tray-indicator-play-g1.svg b/src/tauon/assets/svg/tray-indicator-play-g1.svg similarity index 100% rename from assets/svg/tray-indicator-play-g1.svg rename to src/tauon/assets/svg/tray-indicator-play-g1.svg diff --git a/assets/svg/tray-indicator-play.svg b/src/tauon/assets/svg/tray-indicator-play.svg similarity index 100% rename from assets/svg/tray-indicator-play.svg rename to src/tauon/assets/svg/tray-indicator-play.svg diff --git a/assets/svg/unlock.svg b/src/tauon/assets/svg/unlock.svg similarity index 100% rename from assets/svg/unlock.svg rename to src/tauon/assets/svg/unlock.svg diff --git a/assets/svg/v4-a.svg b/src/tauon/assets/svg/v4-a.svg similarity index 100% rename from assets/svg/v4-a.svg rename to src/tauon/assets/svg/v4-a.svg diff --git a/assets/svg/v4-b.svg b/src/tauon/assets/svg/v4-b.svg similarity index 100% rename from assets/svg/v4-b.svg rename to src/tauon/assets/svg/v4-b.svg diff --git a/assets/svg/v4-c.svg b/src/tauon/assets/svg/v4-c.svg similarity index 100% rename from assets/svg/v4-c.svg rename to src/tauon/assets/svg/v4-c.svg diff --git a/assets/svg/v4-d.svg b/src/tauon/assets/svg/v4-d.svg similarity index 100% rename from assets/svg/v4-d.svg rename to src/tauon/assets/svg/v4-d.svg diff --git a/assets/svg/v4-e.svg b/src/tauon/assets/svg/v4-e.svg similarity index 100% rename from assets/svg/v4-e.svg rename to src/tauon/assets/svg/v4-e.svg diff --git a/assets/svg/v4-f.svg b/src/tauon/assets/svg/v4-f.svg similarity index 100% rename from assets/svg/v4-f.svg rename to src/tauon/assets/svg/v4-f.svg diff --git a/assets/svg/warning.svg b/src/tauon/assets/svg/warning.svg similarity index 100% rename from assets/svg/warning.svg rename to src/tauon/assets/svg/warning.svg diff --git a/assets/tau-mac.icns b/src/tauon/assets/tau-mac.icns similarity index 100% rename from assets/tau-mac.icns rename to src/tauon/assets/tau-mac.icns diff --git a/assets/tau-mac.png b/src/tauon/assets/tau-mac.png similarity index 100% rename from assets/tau-mac.png rename to src/tauon/assets/tau-mac.png diff --git a/assets/tauon_repeat.png b/src/tauon/assets/tauon_repeat.png similarity index 100% rename from assets/tauon_repeat.png rename to src/tauon/assets/tauon_repeat.png diff --git a/assets/tauon_repeat_a.png b/src/tauon/assets/tauon_repeat_a.png similarity index 100% rename from assets/tauon_repeat_a.png rename to src/tauon/assets/tauon_repeat_a.png diff --git a/assets/tauon_repeat_off.png b/src/tauon/assets/tauon_repeat_off.png similarity index 100% rename from assets/tauon_repeat_off.png rename to src/tauon/assets/tauon_repeat_off.png diff --git a/assets/tauon_shuffle.png b/src/tauon/assets/tauon_shuffle.png similarity index 100% rename from assets/tauon_shuffle.png rename to src/tauon/assets/tauon_shuffle.png diff --git a/assets/tauon_shuffle_a.png b/src/tauon/assets/tauon_shuffle_a.png similarity index 100% rename from assets/tauon_shuffle_a.png rename to src/tauon/assets/tauon_shuffle_a.png diff --git a/assets/tauon_shuffle_off.png b/src/tauon/assets/tauon_shuffle_off.png similarity index 100% rename from assets/tauon_shuffle_off.png rename to src/tauon/assets/tauon_shuffle_off.png diff --git a/assets/title.png b/src/tauon/assets/title.png similarity index 100% rename from assets/title.png rename to src/tauon/assets/title.png diff --git a/assets/tracks+side.png b/src/tauon/assets/tracks+side.png similarity index 100% rename from assets/tracks+side.png rename to src/tauon/assets/tracks+side.png diff --git a/assets/tracks.png b/src/tauon/assets/tracks.png similarity index 100% rename from assets/tracks.png rename to src/tauon/assets/tracks.png diff --git a/assets/transcode.png b/src/tauon/assets/transcode.png similarity index 100% rename from assets/transcode.png rename to src/tauon/assets/transcode.png diff --git a/assets/unlock.png b/src/tauon/assets/unlock.png similarity index 100% rename from assets/unlock.png rename to src/tauon/assets/unlock.png diff --git a/assets/v4-a.png b/src/tauon/assets/v4-a.png similarity index 100% rename from assets/v4-a.png rename to src/tauon/assets/v4-a.png diff --git a/assets/v4-b.png b/src/tauon/assets/v4-b.png similarity index 100% rename from assets/v4-b.png rename to src/tauon/assets/v4-b.png diff --git a/assets/v4-c.png b/src/tauon/assets/v4-c.png similarity index 100% rename from assets/v4-c.png rename to src/tauon/assets/v4-c.png diff --git a/assets/v4-d.png b/src/tauon/assets/v4-d.png similarity index 100% rename from assets/v4-d.png rename to src/tauon/assets/v4-d.png diff --git a/assets/v4-e.png b/src/tauon/assets/v4-e.png similarity index 100% rename from assets/v4-e.png rename to src/tauon/assets/v4-e.png diff --git a/assets/v4-f.png b/src/tauon/assets/v4-f.png similarity index 100% rename from assets/v4-f.png rename to src/tauon/assets/v4-f.png diff --git a/assets/warning.png b/src/tauon/assets/warning.png similarity index 100% rename from assets/warning.png rename to src/tauon/assets/warning.png diff --git a/input.txt b/src/tauon/input.txt similarity index 100% rename from input.txt rename to src/tauon/input.txt diff --git a/src/tauon/t_modules/__init__.py b/src/tauon/t_modules/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/t_modules/t_bootstrap.py b/src/tauon/t_modules/t_bootstrap.py similarity index 100% rename from t_modules/t_bootstrap.py rename to src/tauon/t_modules/t_bootstrap.py diff --git a/t_modules/t_chrome.py b/src/tauon/t_modules/t_chrome.py similarity index 97% rename from t_modules/t_chrome.py rename to src/tauon/t_modules/t_chrome.py index d6dc7d5ed..64410b623 100644 --- a/t_modules/t_chrome.py +++ b/src/tauon/t_modules/t_chrome.py @@ -6,10 +6,10 @@ import pychromecast -from t_modules.t_extra import shooter +from tauon.t_modules.t_extra import shooter if TYPE_CHECKING: - from t_modules.t_main import Tauon + from tauon.t_modules.t_main import Tauon def get_ip() -> str: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) diff --git a/t_modules/t_config.py b/src/tauon/t_modules/t_config.py similarity index 100% rename from t_modules/t_config.py rename to src/tauon/t_modules/t_config.py diff --git a/t_modules/t_db_migrate.py b/src/tauon/t_modules/t_db_migrate.py similarity index 99% rename from t_modules/t_db_migrate.py rename to src/tauon/t_modules/t_db_migrate.py index ea1ea0661..9667827da 100644 --- a/t_modules/t_db_migrate.py +++ b/src/tauon/t_modules/t_db_migrate.py @@ -7,7 +7,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from t_modules.t_main import GuiVar, Prefs, StarStore, TauonPlaylist + from tauon.t_modules.t_main import GuiVar, Prefs, StarStore, TauonPlaylist def database_migrate( @@ -34,7 +34,7 @@ def database_migrate( Returns all the objects that could've been possibly changed: master_library, multi_playlist, star_store, p_force_queue, theme, prefs, gui, gen_codes, radio_playlists """ - from t_modules.t_main import show_message, uid_gen + from tauon.t_modules.t_main import show_message, uid_gen if db_version <= 0: logging.error("Called database_migrate with db_version equal to or below 0!") diff --git a/t_modules/t_dbus.py b/src/tauon/t_modules/t_dbus.py similarity index 99% rename from t_modules/t_dbus.py rename to src/tauon/t_modules/t_dbus.py index 6e0497597..7711779b4 100644 --- a/t_modules/t_dbus.py +++ b/src/tauon/t_modules/t_dbus.py @@ -29,12 +29,12 @@ gi.require_version("Gdk", "4.0") from gi.repository import Gdk, GLib -from t_modules.t_extra import filename_to_metadata, star_count2 +from tauon.t_modules.t_extra import filename_to_metadata, star_count2 if TYPE_CHECKING: from gi.repository import AppIndicator3 - from t_modules.t_main import Tauon + from tauon.t_modules.t_main import Tauon class Gnome: diff --git a/t_modules/t_draw.py b/src/tauon/t_modules/t_draw.py similarity index 99% rename from t_modules/t_draw.py rename to src/tauon/t_modules/t_draw.py index 9fb71c8c4..feb234933 100644 --- a/t_modules/t_draw.py +++ b/src/tauon/t_modules/t_draw.py @@ -55,7 +55,7 @@ ) from sdl2.sdlimage import IMG_Load_RW -from t_modules.t_extra import Timer, alpha_blend, coll_rect +from tauon.t_modules.t_extra import Timer, alpha_blend, coll_rect if TYPE_CHECKING: from sdl2 import SDL_Renderer diff --git a/t_modules/t_extra.py b/src/tauon/t_modules/t_extra.py similarity index 99% rename from t_modules/t_extra.py rename to src/tauon/t_modules/t_extra.py index f4b14706b..9a3304756 100644 --- a/t_modules/t_extra.py +++ b/src/tauon/t_modules/t_extra.py @@ -39,7 +39,7 @@ if TYPE_CHECKING: from collections.abc import Callable - from t_modules.t_main import TrackClass + from tauon.t_modules.t_main import TrackClass def tmp_cache_dir() -> str: tmp_dir = GLib.get_tmp_dir() diff --git a/t_modules/t_jellyfin.py b/src/tauon/t_modules/t_jellyfin.py similarity index 99% rename from t_modules/t_jellyfin.py rename to src/tauon/t_modules/t_jellyfin.py index beb658aaf..7458c6548 100644 --- a/t_modules/t_jellyfin.py +++ b/src/tauon/t_modules/t_jellyfin.py @@ -30,12 +30,12 @@ import requests -from t_modules.t_extra import Timer +from tauon.t_modules.t_extra import Timer if TYPE_CHECKING: from io import BytesIO - from t_modules.t_main import Tauon, TauonPlaylist, TrackClass + from tauon.t_modules.t_main import Tauon, TauonPlaylist, TrackClass class Jellyfin: diff --git a/t_modules/t_launch.py b/src/tauon/t_modules/t_launch.py similarity index 81% rename from t_modules/t_launch.py rename to src/tauon/t_modules/t_launch.py index 7f3655dd6..76ea8f714 100644 --- a/t_modules/t_launch.py +++ b/src/tauon/t_modules/t_launch.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from t_modules.t_main import GuiVar, PlayerCtl, Tauon, TDraw + from tauon.t_modules.t_main import GuiVar, PlayerCtl, Tauon, TDraw class Launch: def __init__(self, tauon: Tauon, pctl: PlayerCtl, gui: GuiVar, ddt: TDraw) -> None: diff --git a/t_modules/t_lyrics.py b/src/tauon/t_modules/t_lyrics.py similarity index 100% rename from t_modules/t_lyrics.py rename to src/tauon/t_modules/t_lyrics.py diff --git a/t_modules/t_main.py b/src/tauon/t_modules/t_main.py similarity index 99% rename from t_modules/t_main.py rename to src/tauon/t_modules/t_main.py index bba9f220a..df8ba26fe 100644 --- a/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -228,25 +228,25 @@ from send2trash import send2trash from unidecode import unidecode -from t_modules import t_bootstrap -from t_modules.t_config import Config -from t_modules.t_extra import * -from t_modules.t_db_migrate import database_migrate -from t_modules.t_draw import TDraw, QuickThumbnail -from t_modules.t_jellyfin import Jellyfin -from t_modules.t_launch import Launch -from t_modules.t_lyrics import * -from t_modules.t_phazor import phazor_exists, player4 -from t_modules.t_search import * -from t_modules.t_spot import SpotCtl -from t_modules.t_stream import StreamEnc -from t_modules.t_tagscan import Ape, Flac, M4a, Opus, Wav, parse_picture_block -from t_modules.t_themeload import * -from t_modules.t_tidal import Tidal -from t_modules.t_webserve import authserve, controller, stream_proxy, webserve, webserve2 +from tauon.t_modules import t_bootstrap +from tauon.t_modules.t_config import Config +from tauon.t_modules.t_extra import * +from tauon.t_modules.t_db_migrate import database_migrate +from tauon.t_modules.t_draw import TDraw, QuickThumbnail +from tauon.t_modules.t_jellyfin import Jellyfin +from tauon.t_modules.t_launch import Launch +from tauon.t_modules.t_lyrics import * +from tauon.t_modules.t_phazor import phazor_exists, player4 +from tauon.t_modules.t_search import * +from tauon.t_modules.t_spot import SpotCtl +from tauon.t_modules.t_stream import StreamEnc +from tauon.t_modules.t_tagscan import Ape, Flac, M4a, Opus, Wav, parse_picture_block +from tauon.t_modules.t_themeload import * +from tauon.t_modules.t_tidal import Tidal +from tauon.t_modules.t_webserve import authserve, controller, stream_proxy, webserve, webserve2 if TYPE_CHECKING: - from t_modules.t_phazor import Cachement, LibreSpot + from tauon.t_modules.t_phazor import Cachement, LibreSpot try: from jxlpy import JXLImagePlugin @@ -317,10 +317,10 @@ import atexit if system == "linux": - from t_modules import t_topchart + from tauon.t_modules import t_topchart if system == "linux" and not macos and not msys: - from t_modules.t_dbus import Gnome + from tauon.t_modules.t_dbus import Gnome h = t_bootstrap.holder t_window = h.w @@ -4231,7 +4231,7 @@ def scale_assets(scale_want, force=False): if scale_want != 1: if os.path.isdir(scaled_asset_directory) and scaled_asset_directory != asset_directory: shutil.rmtree(scaled_asset_directory) - from t_modules.t_svgout import render_icons + from tauon.t_modules.t_svgout import render_icons if scaled_asset_directory != asset_directory: logging.info("Rendering icons...") @@ -8402,7 +8402,7 @@ def wake(self): chrome = None try: - from t_modules.t_chrome import Chrome + from tauon.t_modules.t_chrome import Chrome chrome = Chrome(tauon) except Exception: @@ -13023,7 +13023,7 @@ def clear_cache(self): colours.last_album = "" -# from t_modules.t_art_render import AlbumArt +# from tauon.t_modules.t_art_render import AlbumArt album_art_gen = AlbumArt() @@ -42112,7 +42112,7 @@ def ready_playback(self): if prefs.backend == 4: self.playback = threading.Thread(target=player4, args=[tauon]) # elif prefs.backend == 2: - # from t_modules.t_gstreamer import player3 + # from tauon.t_modules.t_gstreamer import player3 # self.playback = threading.Thread(target=player3, args=[tauon]) self.playback.daemon = True self.playback.start() diff --git a/t_modules/t_phazor.py b/src/tauon/t_modules/t_phazor.py similarity index 99% rename from t_modules/t_phazor.py rename to src/tauon/t_modules/t_phazor.py index 07e062608..ef3b2228f 100644 --- a/t_modules/t_phazor.py +++ b/src/tauon/t_modules/t_phazor.py @@ -42,10 +42,10 @@ import requests from requests.models import PreparedRequest -from t_modules.t_extra import Timer, shooter, tmp_cache_dir +from tauon.t_modules.t_extra import Timer, shooter, tmp_cache_dir if TYPE_CHECKING: - from t_modules.t_main import PlayerCtl, Tauon, TrackClass + from tauon.t_modules.t_main import PlayerCtl, Tauon, TrackClass def find_library(libname: str) -> Path | None: """Search for 'libname.so'. diff --git a/t_modules/t_search.py b/src/tauon/t_modules/t_search.py similarity index 100% rename from t_modules/t_search.py rename to src/tauon/t_modules/t_search.py diff --git a/t_modules/t_spot.py b/src/tauon/t_modules/t_spot.py similarity index 99% rename from t_modules/t_spot.py rename to src/tauon/t_modules/t_spot.py index 8df331464..be4605aa2 100644 --- a/t_modules/t_spot.py +++ b/src/tauon/t_modules/t_spot.py @@ -30,10 +30,10 @@ import requests -from t_modules.t_extra import Timer +from tauon.t_modules.t_extra import Timer if TYPE_CHECKING: - from t_modules.t_main import Tauon, TrackClass + from tauon.t_modules.t_main import Tauon, TrackClass try: import tekore as tk diff --git a/t_modules/t_stream.py b/src/tauon/t_modules/t_stream.py similarity index 99% rename from t_modules/t_stream.py rename to src/tauon/t_modules/t_stream.py index 9babe4e71..cb11ed71f 100644 --- a/t_modules/t_stream.py +++ b/src/tauon/t_modules/t_stream.py @@ -32,8 +32,8 @@ import mutagen -from t_modules.t_extra import filename_safe -from t_modules.t_webserve import vb +from tauon.t_modules.t_extra import filename_safe +from tauon.t_modules.t_webserve import vb if sys.platform != "win32": import fcntl @@ -43,7 +43,7 @@ from subprocess import Popen from urllib.request import _UrlopenRet - from t_modules.t_main import Tauon + from tauon.t_modules.t_main import Tauon class StreamEnc: diff --git a/t_modules/t_svgout.py b/src/tauon/t_modules/t_svgout.py similarity index 100% rename from t_modules/t_svgout.py rename to src/tauon/t_modules/t_svgout.py diff --git a/t_modules/t_tagscan.py b/src/tauon/t_modules/t_tagscan.py similarity index 99% rename from t_modules/t_tagscan.py rename to src/tauon/t_modules/t_tagscan.py index 0ace09642..18ec62946 100644 --- a/t_modules/t_tagscan.py +++ b/src/tauon/t_modules/t_tagscan.py @@ -28,7 +28,7 @@ import struct import wave -from t_modules.t_extra import process_odat +from tauon.t_modules.t_extra import process_odat def parse_mbids_from_vorbis(object, key, value): diff --git a/t_modules/t_themeload.py b/src/tauon/t_modules/t_themeload.py similarity index 98% rename from t_modules/t_themeload.py rename to src/tauon/t_modules/t_themeload.py index d252b6cc4..16ec14620 100644 --- a/t_modules/t_themeload.py +++ b/src/tauon/t_modules/t_themeload.py @@ -36,11 +36,11 @@ ) from sdl2.sdlimage import IMG_Load_RW -from t_modules.t_extra import rgb_add_hls, test_lumi +from tauon.t_modules.t_extra import rgb_add_hls, test_lumi if TYPE_CHECKING: - from t_modules.t_draw import TDraw - from t_modules.t_main import GuiVar, Tauon + from tauon.t_modules.t_draw import TDraw + from tauon.t_modules.t_main import GuiVar, Tauon def get_colour_from_line(cline: str) -> list[int]: diff --git a/t_modules/t_tidal.py b/src/tauon/t_modules/t_tidal.py similarity index 99% rename from t_modules/t_tidal.py rename to src/tauon/t_modules/t_tidal.py index 8acc7a33f..72c9ab654 100644 --- a/t_modules/t_tidal.py +++ b/src/tauon/t_modules/t_tidal.py @@ -17,7 +17,7 @@ logging.exception("Tidalapi not found") if TYPE_CHECKING: - from t_modules.t_main import Tauon, TrackClass + from tauon.t_modules.t_main import Tauon, TrackClass class Tidal: diff --git a/t_modules/t_topchart.py b/src/tauon/t_modules/t_topchart.py similarity index 99% rename from t_modules/t_topchart.py rename to src/tauon/t_modules/t_topchart.py index 6bd89a163..fb96ba466 100644 --- a/t_modules/t_topchart.py +++ b/src/tauon/t_modules/t_topchart.py @@ -33,7 +33,7 @@ from PIL import Image if TYPE_CHECKING: - from t_modules.t_main import AlbumArt, Tauon, TrackClass + from tauon.t_modules.t_main import AlbumArt, Tauon, TrackClass class TopChart: diff --git a/t_modules/t_webserve.py b/src/tauon/t_modules/t_webserve.py similarity index 99% rename from t_modules/t_webserve.py rename to src/tauon/t_modules/t_webserve.py index 9707922c2..a82331391 100644 --- a/t_modules/t_webserve.py +++ b/src/tauon/t_modules/t_webserve.py @@ -31,10 +31,10 @@ from socketserver import ThreadingMixIn from typing import TYPE_CHECKING -from t_modules.t_extra import Timer +from tauon.t_modules.t_extra import Timer if TYPE_CHECKING: - from t_modules.t_main import AlbumArt, GuiVar, PlayerCtl, Tauon, TrackClass + from tauon.t_modules.t_main import AlbumArt, GuiVar, PlayerCtl, Tauon, TrackClass def send_file(path: str, mime: str, server) -> None: range_req = False diff --git a/src/tauon/tauon.py b/src/tauon/tauon.py index 89290804d..ee09251d0 100755 --- a/src/tauon/tauon.py +++ b/src/tauon/tauon.py @@ -62,7 +62,7 @@ ) from sdl2.sdlimage import IMG_Load -from t_modules import t_bootstrap +from tauon.t_modules import t_bootstrap # DEBUG+ to file and std_err logging.basicConfig( @@ -367,7 +367,7 @@ def transfer_args_and_exit() -> None: img_path = img_path2 del img_path2 -raw_image = IMG_Load(img_path.encode()) +raw_image = IMG_Load(str(img_path).encode()) sdl_texture = SDL_CreateTextureFromSurface(renderer, raw_image) w = raw_image.contents.w h = raw_image.contents.h @@ -414,7 +414,7 @@ def transfer_args_and_exit() -> None: del img_path if pyinstaller_mode or sys.platform == "darwin" or install_mode: - from t_modules import t_main + from tauon.t_modules import t_main else: # Using the above import method breaks previous pickles. Could be fixed # but yet to decide what best method is. From 20a128a7cfeec7afcdc5a8836ff7a066994c9a44 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 21:57:50 +0100 Subject: [PATCH 22/63] t_main: Add missing SDL_Rect import --- src/tauon/t_modules/t_main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index df8ba26fe..2e985d0fb 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -191,6 +191,7 @@ SDL_QueryTexture, SDL_Quit, SDL_QuitSubSystem, + SDL_Rect, SDL_RenderClear, SDL_RenderFillRect, SDL_RenderPresent, From 085cf71d7cc2b764b601bcf32d32885e9683b96c Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 22:05:47 +0100 Subject: [PATCH 23/63] t_main/reqs: Make natsort, opencc and setproctitle truly optional --- requirements.txt | 3 --- requirements_optional.txt | 3 +++ src/tauon/t_modules/t_main.py | 37 +++++++++++++++++++++++------------ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/requirements.txt b/requirements.txt index 47e2acc61..c7e87b862 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,6 @@ beautifulsoup4 dbus-python musicbrainzngs mutagen -natsort -opencc Pillow PlexAPI PyGObject @@ -11,5 +9,4 @@ pylast>=3.1.0 PySDL2 requests Send2Trash -setproctitle unidecode diff --git a/requirements_optional.txt b/requirements_optional.txt index 53a353e38..01f27b774 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,8 +1,11 @@ jxlpy #librespot - https://github.com/kokarare1212/librespot-python/pull/286 +natsort +opencc #picard - picard 2.12.3 requires charset-normalizer~=3.3.2, but you have charset-normalizer 3.4.0 which is incompatible. plexapi PyChromecast pypresence +setproctitle tekore tidalapi diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 2e985d0fb..aeb368f5b 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -252,45 +252,56 @@ try: from jxlpy import JXLImagePlugin logging.info("Found jxlpy for JPEG XL support") +except ModuleNotFoundError: + logging.warning("Unable to import jxlpy, JPEG XL support will be disabled.") except Exception: - logging.exception("Unable to import jxlpy") + logging.exception("Unkown error trying to import jxlpy, JPEG XL support will be disabled.") try: import setproctitle - setproctitle.setproctitle("tauonmb") +except ModuleNotFoundError: + logging.warning("Unable to import setproctitle, won't be setting process title.") except Exception: - logging.exception("Could not set process title.") + logging.exception("Unkown error trying to import setproctitle, JPEG XL support will be disabled.") +else: + setproctitle.setproctitle("tauonmb") # try: # import rpc # discord_allow = True # except Exception: # logging.exception("Unable to import rpc, Discord Rich Presence will be disabled.") +discord_allow = False try: from pypresence import Presence +except ModuleNotFoundError: + logging.warning("Unable to import pypresence, Discord Rich Presence will be disabled.") +except Exception: + logging.exception("Unkown error trying to import pypresence, Discord Rich Presence will be disabled.") +else: import asyncio - discord_allow = True -except Exception: - logging.exception("Unable to import python-pypresence, Discord Rich Presence will be disabled.") - discord_allow = False - use_cc = False try: import opencc +except ModuleNotFoundError: + logging.warning("Unable to import opencc, TODO(Martin): <what is lost?>.") +except Exception: + logging.exception("Unkown error trying to import opencc, TODO(Martin): <what is lost?>.") +else: s2t = opencc.OpenCC("s2t") t2s = opencc.OpenCC("t2s") use_cc = True -except Exception: - logging.exception("OpenCC not found.") use_natsort = False try: import natsort - - use_natsort = True +except ModuleNotFoundError: + logging.warning("Unable to import natsort, TODO(Martin): <what is lost?>.") except Exception: - logging.exception("Python module natsort not found") + logging.exception("Unknown error trying to import natsort, TODO(Martin): <what is lost?>.") +else: + use_natsort = True # Detect platform windows_native = False From 72f7b1c343643c5e15a9d2eac240fe3412ea82f6 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 22:28:13 +0100 Subject: [PATCH 24/63] t_main: Add hopefully all missing SDL imports --- src/tauon/t_modules/t_main.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index aeb368f5b..6c9264ea3 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -78,8 +78,8 @@ import requests from PIL import Image, ImageDraw, ImageEnhance, ImageFilter from sdl2 import ( - SDL_BLENDMODE_NONE, SDL_BLENDMODE_BLEND, + SDL_BLENDMODE_NONE, SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE, SDL_BUTTON_RIGHT, @@ -104,8 +104,16 @@ SDL_CONTROLLERDEVICEADDED, SDL_DROPFILE, SDL_DROPTEXT, + SDL_FALSE, SDL_HITTEST_DRAGGABLE, SDL_HITTEST_NORMAL, + SDL_HITTEST_RESIZE_BOTTOM, + SDL_HITTEST_RESIZE_BOTTOMLEFT, + SDL_HITTEST_RESIZE_BOTTOMRIGHT, + SDL_HITTEST_RESIZE_LEFT, + SDL_HITTEST_RESIZE_RIGHT, + SDL_HITTEST_RESIZE_TOPLEFT, + SDL_HITTEST_RESIZE_TOPRIGHT, SDL_INIT_EVERYTHING, SDL_INIT_GAMECONTROLLER, SDL_KEYDOWN, @@ -125,13 +133,18 @@ SDL_SYSTEM_CURSOR_ARROW, SDL_SYSTEM_CURSOR_HAND, SDL_SYSTEM_CURSOR_IBEAM, + SDL_SYSTEM_CURSOR_SIZENS, + SDL_SYSTEM_CURSOR_SIZENWSE, SDL_SYSTEM_CURSOR_SIZEWE, SDL_SYSWM_COCOA, SDL_SYSWM_UNKNOWN, SDL_SYSWM_WAYLAND, + SDL_SYSWM_X11, SDL_TEXTEDITING, SDL_TEXTINPUT, SDL_TEXTUREACCESS_TARGET, + SDL_TRUE, + SDL_WINDOW_FULLSCREEN_DESKTOP, SDL_WINDOW_INPUT_FOCUS, SDL_WINDOWEVENT, SDL_WINDOWEVENT_DISPLAY_CHANGED, @@ -164,15 +177,21 @@ SDLK_RSHIFT, SDLK_TAB, SDLK_UP, + SDL_CaptureMouse, + SDL_CreateColorCursor, SDL_CreateRGBSurfaceWithFormatFrom, SDL_CreateSystemCursor, SDL_CreateTexture, SDL_CreateTextureFromSurface, SDL_Delay, + SDL_DestroyTexture, SDL_DestroyWindow, SDL_Event, SDL_FreeSurface, + SDL_GameControllerNameForIndex, + SDL_GameControllerOpen, SDL_GetClipboardText, + SDL_GetCurrentVideoDriver, SDL_GetGlobalMouseState, SDL_GetKeyFromName, SDL_GetMouseState, @@ -180,10 +199,15 @@ SDL_GetVersion, SDL_GetWindowFlags, SDL_GetWindowPosition, + SDL_GetWindowSize, SDL_GetWindowWMInfo, + SDL_GL_GetDrawableSize, SDL_HasClipboardText, + SDL_HideWindow, SDL_HitTest, SDL_InitSubSystem, + SDL_IsGameController, + SDL_MaximizeWindow, SDL_MinimizeWindow, SDL_PollEvent, SDL_PumpEvents, @@ -191,8 +215,10 @@ SDL_QueryTexture, SDL_Quit, SDL_QuitSubSystem, + SDL_RaiseWindow, SDL_Rect, SDL_RenderClear, + SDL_RenderCopy, SDL_RenderFillRect, SDL_RenderPresent, SDL_RestoreWindow, @@ -201,6 +227,7 @@ SDL_SetRenderDrawBlendMode, SDL_SetRenderDrawColor, SDL_SetRenderTarget, + SDL_SetTextInputRect, SDL_SetTextureAlphaMod, SDL_SetTextureBlendMode, SDL_SetTextureColorMod, @@ -210,9 +237,12 @@ SDL_SetWindowHitTest, SDL_SetWindowIcon, SDL_SetWindowMinimumSize, + SDL_SetWindowOpacity, SDL_SetWindowPosition, SDL_SetWindowResizable, SDL_SetWindowSize, + SDL_SetWindowTitle, + SDL_ShowWindow, SDL_StartTextInput, SDL_SysWMinfo, SDL_version, @@ -851,7 +881,7 @@ def no_padding(info): return 0 wayland = True -if not os.environ.get('SDL_VIDEODRIVER') == "wayland": +if os.environ.get('SDL_VIDEODRIVER') != "wayland": wayland = False os.environ['GDK_BACKEND'] = "x11" From d19b34b9821a06466ae2e2b1d958f14590022bcc Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 23:07:41 +0100 Subject: [PATCH 25/63] t_main: Remove all star imports --- src/tauon/t_modules/t_main.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 6c9264ea3..f37aa6085 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -63,7 +63,7 @@ import zipfile from collections import OrderedDict from collections.abc import Callable -from ctypes import c_char_p, c_double, c_int, c_uint32, c_void_p, pointer, Structure +from ctypes import byref, c_char_p, c_double, c_int, c_uint32, c_void_p, pointer, Structure from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING @@ -261,23 +261,24 @@ from tauon.t_modules import t_bootstrap from tauon.t_modules.t_config import Config -from tauon.t_modules.t_extra import * +from tauon.t_modules.t_extra import FunctionStore, Timer, rgb_add_hls, alpha_blend, alpha_mod, colour_value, test_lumi, shooter, ColourGenCache, year_search, get_display_time, point_proximity_test, is_light, clean_string, mac_styles, tmp_cache_dir, TestTimer, filename_to_metadata, get_artist_strip_feat, get_split_artists, get_artist_safe, filename_safe, sleep_timeout, fit_box, contrast_ratio, rgb_to_hls, process_odat, commonprefix, check_equal, search_magic, search_magic_any, get_hms_time, hms_to_seconds, is_grey, hls_to_rgb, get_filesize_string, get_filesize_string_rounded, uri_parse, reduce_paths, j_chars, star_count, star_count3, genre_correct, hsl_to_rgb, grow_rect, point_distance, seconds_to_day_hms, d_date_display, d_date_display2, colour_slide, archive_file_scan, subtract_rect, folder_file_scan, get_folder_size, get_year_from_string from tauon.t_modules.t_db_migrate import database_migrate from tauon.t_modules.t_draw import TDraw, QuickThumbnail from tauon.t_modules.t_jellyfin import Jellyfin from tauon.t_modules.t_launch import Launch -from tauon.t_modules.t_lyrics import * +from tauon.t_modules.t_lyrics import lyric_sources, genius, uses_scraping from tauon.t_modules.t_phazor import phazor_exists, player4 -from tauon.t_modules.t_search import * +from tauon.t_modules.t_search import bandcamp_search from tauon.t_modules.t_spot import SpotCtl from tauon.t_modules.t_stream import StreamEnc from tauon.t_modules.t_tagscan import Ape, Flac, M4a, Opus, Wav, parse_picture_block -from tauon.t_modules.t_themeload import * +from tauon.t_modules.t_themeload import Deco, load_theme from tauon.t_modules.t_tidal import Tidal from tauon.t_modules.t_webserve import authserve, controller, stream_proxy, webserve, webserve2 if TYPE_CHECKING: from tauon.t_modules.t_phazor import Cachement, LibreSpot + from ctypes import CDLL try: from jxlpy import JXLImagePlugin From a449af82f8858ab684e5f3808c9a9031d8321483 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 23:09:16 +0100 Subject: [PATCH 26/63] run.sh: Remove tauon_music_box.egg-info on start --- run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.sh b/run.sh index b596636b3..b1c13f6e7 100755 --- a/run.sh +++ b/run.sh @@ -6,7 +6,7 @@ cd "$(dirname "$0")" export PYTHONPATH=".":"${PYTHONPATH-}" -rm -rf .env build dist ./src/phazor/kissfft/* ./src/phazor/miniaudio/* +rm -rf .env build dist tauon_music_box.egg-info ./src/phazor/kissfft/* ./src/phazor/miniaudio/* _kissfftver=131.1.0 _miniaudiocommit=4a5b74bef029b3592c54b6048650ee5f972c1a48 From 3eff5105f6b77e37c68463450c3c2480e6537a9a Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 23:12:56 +0100 Subject: [PATCH 27/63] t_main: Delete macOS "tap.stop()" which seemed completely useless as tap isn't defined anywhere --- src/tauon/t_modules/t_main.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index f37aa6085..90ccd46c1 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -48382,12 +48382,6 @@ def drop_file(target): except Exception: logging.exception("uninit notification error") -if macos: - try: - tap.stop() - except Exception: - logging.exception("Failed to stop tap") - try: instance_lock.close() except Exception: From 7ee323bbf4d776dbbd78dd7f389975abd7e58e7d Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 23:16:06 +0100 Subject: [PATCH 28/63] t_main: Fix transfer-playtime-to not copying flags --- src/tauon/t_modules/t_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 90ccd46c1..8f7136498 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -44301,7 +44301,7 @@ def drop_file(target): new[0] = fr_s[0] + to_s[0] # playtime new[1] = fr_s[1] # flags if to_s[1]: - new[1] = so_s[1] # keep target flags + new[1] = to_s[1] # keep target flags new[2] = fr_s[2] # raiting if to_s[2] > 0 and fr_s[2] == 0: new[2] = to_s[2] # keep target rating From 75a1d02b4bab3240c9916dbb07a358e612ae7a5f Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 23:30:23 +0100 Subject: [PATCH 29/63] t_main: Fix Windows version check accidentally running on other platforms --- src/tauon/t_modules/t_main.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 8f7136498..0878d0d9c 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -840,13 +840,14 @@ def asset_loader(name, mod=False): musicbrainzngs.set_useragent("TauonMusicBox", n_version, "https://github.com/Taiko2k/Tauon") arch = platform.machine() -win_ver = platform.release() +platform_release = platform.release() platform_system = platform.system() -try: - win_ver = int(win_ver) -except Exception: - logging.exception("Failed getting Windows version from platform.release()") - win_ver = 0 +win_ver = 0 +if platform.system() == 'Windows': + try: + win_ver = int(platform_release) + except Exception: + logging.exception("Failed getting Windows version from platform.release()") # logging.info(arch) From 7a721a8b67984dec68908b78ae2316398a9f1d57 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 23:41:16 +0100 Subject: [PATCH 30/63] t_extra: Stop spamming a 2021 line in the logs --- src/tauon/t_modules/t_extra.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tauon/t_modules/t_extra.py b/src/tauon/t_modules/t_extra.py index 9a3304756..f18a2edb7 100644 --- a/src/tauon/t_modules/t_extra.py +++ b/src/tauon/t_modules/t_extra.py @@ -386,6 +386,13 @@ def is_ignorable_file(string: str) -> bool: date_pattern = re.compile(r'\b(?:\d{2}([/. -])\d{2}\1(\d{4})|\b(\d{4})([/. -])\d{2}\4\d{2}).*') def get_year_from_string(s: str) -> str: + """Gets year in form of YYYY from a string + + Example usage: + example_string = "Event date: 2021-12-31." + print(get_year_from_string(example_string)) + > "2021" + """ # Search for the pattern in the string match = date_pattern.search(s) @@ -395,11 +402,6 @@ def get_year_from_string(s: str) -> str: return "" - -# Example usage -example_string = "Event date: 2021-12-31." -print(get_year_from_string(example_string)) # Output: "2021" - def is_music_related(string: str) -> bool: for s in [ "Folder.jpg", From 6417a049d92e2f0e7833a83e6c61bfdc53372914 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Mon, 18 Nov 2024 23:58:24 +0100 Subject: [PATCH 31/63] t_extra: Use logging --- src/tauon/t_modules/t_extra.py | 49 +++++++++++++++++----------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/tauon/t_modules/t_extra.py b/src/tauon/t_modules/t_extra.py index f18a2edb7..f24720d28 100644 --- a/src/tauon/t_modules/t_extra.py +++ b/src/tauon/t_modules/t_extra.py @@ -21,6 +21,7 @@ import colorsys import glob import locale +import logging import math import os import random @@ -422,8 +423,8 @@ def is_music_related(string: str) -> bool: def archive_file_scan(path: str, extensions: str, launch_prefix: str="") -> float: """Get ratio of given file extensions in archive""" ext = os.path.splitext(path)[1][1:].lower() - # print(path) - # print(ext) + #logging.info(path) + #logging.info(ext) try: if ext == "rar": matches = 0 @@ -431,7 +432,7 @@ def archive_file_scan(path: str, extensions: str, launch_prefix: str="") -> floa line = launch_prefix + "unrar lb -p- " + shlex.quote(path) + " " + shlex.quote(os.path.dirname(path)) + os.sep result = subprocess.run(shlex.split(line), stdout=subprocess.PIPE) file_list = result.stdout.decode("utf-8", "ignore").split("\n") - # print(file_list) + #logging.info(file_list) for fi in file_list: for ty in extensions: if fi[len(ty) * -1:].lower() == ty: @@ -444,16 +445,16 @@ def archive_file_scan(path: str, extensions: str, launch_prefix: str="") -> floa matches += 5 count += 1 if count > 200: - #print("RAR archive has many files") - #print(" --- " + path) + #logging.info("RAR archive has many files") + #logging.info(" --- " + path) return 0 if matches == 0: - #print("RAR archive does not appear to contain audio files") - #print(" --- " + path) + #logging.info("RAR archive does not appear to contain audio files") + #logging.info(" --- " + path) return 0 if count == 0: - #print("Archive has no files") - #print(" --- " + path) + #logging.info("Archive has no files") + #logging.info(" --- " + path) return 0 elif ext == "7z": @@ -462,7 +463,7 @@ def archive_file_scan(path: str, extensions: str, launch_prefix: str="") -> floa line = launch_prefix + "7z l " + shlex.quote(path) # + " " + shlex.quote(os.path.dirname(path)) + os.sep result = subprocess.run(shlex.split(line), stdout=subprocess.PIPE) file_list = result.stdout.decode("utf-8", "ignore").split("\n") - # print(file_list) + #logging.info(file_list) for fi in file_list: @@ -480,16 +481,16 @@ def archive_file_scan(path: str, extensions: str, launch_prefix: str="") -> floa count += 1 if count > 200: - #print("7z archive has many files") - #print(" --- " + path) + #logging.info("7z archive has many files") + #logging.info(" --- " + path) return 0 if matches == 0: - #print("7z archive does not appear to contain audio files") - #print(" --- " + path) + #logging.info("7z archive does not appear to contain audio files") + #logging.info(" --- " + path) return 0 if count == 0: - #print("7z archive has no files") - #print(" --- " + path) + #logging.info("7z archive has no files") + #logging.info(" --- " + path) return 0 elif ext == "zip": @@ -497,7 +498,7 @@ def archive_file_scan(path: str, extensions: str, launch_prefix: str="") -> floa zip_ref = zipfile.ZipFile(path, "r") matches = 0 count = 0 - #print(zip_ref.namelist()) + #logging.info(zip_ref.namelist()) for fi in zip_ref.namelist(): for ty in extensions: if fi[len(ty) * -1:].lower() == ty: @@ -510,22 +511,22 @@ def archive_file_scan(path: str, extensions: str, launch_prefix: str="") -> floa matches += 5 count += 1 if count == 0: - #print("Archive has no files") - #print(" --- " + path) + #logging.info("Archive has no files") + #logging.info(" --- " + path) return 0 if count > 300: - #print("Zip archive has many files") - #print(" --- " + path) + #logging.info("Zip archive has many files") + #logging.info(" --- " + path) return 0 if matches == 0: - #print("Zip archive does not appear to contain audio files") - #print(" --- " + path) + #logging.info("Zip archive does not appear to contain audio files") + #logging.info(" --- " + path) return 0 else: return 0 except Exception: - print("Archive test error") + logging.exception("Archive test error") return 0 From ea5c94c7763aa314002a432e101160a2e158ed67 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 01:01:27 +0100 Subject: [PATCH 32/63] t_main: Add missing bs4 import --- src/tauon/t_modules/t_main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 0878d0d9c..878ff3333 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -68,6 +68,7 @@ from pathlib import Path from typing import TYPE_CHECKING from xml.sax.saxutils import escape, unescape +from bs4 import BeautifulSoup import musicbrainzngs import mutagen From 2cda8899d361c0638a0dee3125ca72b2b73867f1 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 01:03:29 +0100 Subject: [PATCH 33/63] t_main: Add colored_traceback to optdepends --- requirements_optional.txt | 1 + src/tauon/t_modules/t_main.py | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/requirements_optional.txt b/requirements_optional.txt index 01f27b774..c8233eb16 100644 --- a/requirements_optional.txt +++ b/requirements_optional.txt @@ -1,3 +1,4 @@ +colored_traceback jxlpy #librespot - https://github.com/kokarare1212/librespot-python/pull/286 natsort diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 878ff3333..272d3ac0c 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -281,6 +281,15 @@ from tauon.t_modules.t_phazor import Cachement, LibreSpot from ctypes import CDLL +# Log to debug as we don't care at all when user does not have this +try: + import colored_traceback.always + logging.debug("Found colored_traceback for colored crash tracebacks") +except ModuleNotFoundError: + logging.debug("Unable to import colored_traceback, tracebacks will be dull.") +except Exception: + logging.exception("Unkown error trying to import colored_traceback, tracebacks will be dull.") + try: from jxlpy import JXLImagePlugin logging.info("Found jxlpy for JPEG XL support") @@ -793,7 +802,7 @@ def render(self, x, y, colour): loaded_asset_dc = {} -def asset_loader(name, mod=False): +def asset_loader(name: str, mod: bool = False) -> WhiteModImageAsset | LoadImageAsset: if name in loaded_asset_dc: return loaded_asset_dc[name] @@ -4260,7 +4269,7 @@ def auto_scale(): auto_scale() -def scale_assets(scale_want, force=False): +def scale_assets(scale_want: int, force: bool = False) -> None: global scaled_asset_directory if scale_want != 1: scaled_asset_directory = os.path.join(user_directory, "scaled-icons") @@ -4344,8 +4353,7 @@ def get_window_position(): # Access functions from libopenmpt for scanning tracker files class MOD(Structure): - _fields_ = [('ctl', c_char_p), - ('value', c_char_p)] + _fields_ = [('ctl', c_char_p), ('value', c_char_p)] mpt = None @@ -4399,7 +4407,7 @@ class GMETrackInfo(Structure): ("s12", c_char_p), ("s13", c_char_p), ("s14", c_char_p), - ("s15", c_char_p) + ("s15", c_char_p), ] @@ -4421,7 +4429,7 @@ class GMETrackInfo(Structure): gme.gme_open_file.restype = ctypes.c_char_p except Exception: - logging.exception("Cannont find libgme") + logging.exception("Cannot find libgme") def use_id3(tags, nt): def natural_get(tag, track, frame, attr): From 9013a2a5c66be58e2dc619782ddf514d9987cb0e Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 01:13:20 +0100 Subject: [PATCH 34/63] t_main: Define current_date and current_title --- src/tauon/t_modules/t_main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 272d3ac0c..208dae119 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -27075,6 +27075,8 @@ def reload_albums(quiet=False, return_playlist=-1, custom_list=None): dex = [] current_folder = "" current_album = "" + current_date = "" + current_title = "" if custom_list is not None: playlist = custom_list From ff1b96852137887e0c53bd20fd67d34e2dd2816c Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 01:37:37 +0100 Subject: [PATCH 35/63] t_main: Also add current_artist to reload_albums() --- src/tauon/t_modules/t_main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 208dae119..42034bc22 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -322,6 +322,7 @@ else: import asyncio discord_allow = True + use_cc = False try: import opencc @@ -27075,6 +27076,7 @@ def reload_albums(quiet=False, return_playlist=-1, custom_list=None): dex = [] current_folder = "" current_album = "" + current_artist = "" current_date = "" current_title = "" From 67cce7bfe0c11da207be84e58bf93c55ee771327 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 01:39:48 +0100 Subject: [PATCH 36/63] t_main: Add nicer warnings to module import errors --- src/tauon/t_modules/t_main.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 42034bc22..507fb7dfc 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -327,9 +327,9 @@ try: import opencc except ModuleNotFoundError: - logging.warning("Unable to import opencc, TODO(Martin): <what is lost?>.") + logging.warning("Unable to import opencc, Traditional and Simplified Chinese searches will not be usable interchangeably.") except Exception: - logging.exception("Unkown error trying to import opencc, TODO(Martin): <what is lost?>.") + logging.exception("Unkown error trying to import opencc, Traditional and Simplified Chinese searches will not be usable interchangeably.") else: s2t = opencc.OpenCC("s2t") t2s = opencc.OpenCC("t2s") @@ -339,9 +339,9 @@ try: import natsort except ModuleNotFoundError: - logging.warning("Unable to import natsort, TODO(Martin): <what is lost?>.") + logging.warning("Unable to import natsort, playlists may not sort as intended!") except Exception: - logging.exception("Unknown error trying to import natsort, TODO(Martin): <what is lost?>.") + logging.exception("Unknown error trying to import natsort, playlists may not sort as intended!") else: use_natsort = True From 150b709d947c16ef7680c122f33a99ec9d47bef1 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 01:40:13 +0100 Subject: [PATCH 37/63] t_draw: Add the same import improvements from t_main --- src/tauon/t_modules/t_draw.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tauon/t_modules/t_draw.py b/src/tauon/t_modules/t_draw.py index feb234933..58d3a7498 100644 --- a/src/tauon/t_modules/t_draw.py +++ b/src/tauon/t_modules/t_draw.py @@ -63,8 +63,10 @@ try: from jxlpy import JXLImagePlugin logging.info("Found jxlpy for JPEG XL support") +except ModuleNotFoundError: + logging.warning("Unable to import jxlpy, JPEG XL support will be disabled.") except Exception: - logging.exception("Unable to import jxlpy") + logging.exception("Unkown error trying to import jxlpy, JPEG XL support will be disabled.") system = "linux" if sys.platform == "win32": From ca5ed98a5e89237f4ba8b3ea50a3314a0642c10b Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 01:54:28 +0100 Subject: [PATCH 38/63] t_main: Improve logging for pychromecast import --- src/tauon/t_modules/t_main.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 507fb7dfc..f3657abb9 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -8456,11 +8456,14 @@ def wake(self): chrome = None try: - from tauon.t_modules.t_chrome import Chrome - - chrome = Chrome(tauon) + from tauon.t_modules.t_chrome import Chrome + chrome = Chrome(tauon) + logging.debug("Found import Chrome(pychromecast) for chromecast support") +except ModuleNotFoundError: + logging.debug("Unable to import Chrome(pychromecast), chromecast support will be disabled.") except Exception: - print("Pychromecast not found") + logging.exception("Unkown error trying to import Chrome(pychromecast), chromecast support will be disabled.") + tauon.chrome = chrome class PlexService: From c5e12f501fd180b1169b2e602aaea2109462dab9 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 01:57:10 +0100 Subject: [PATCH 39/63] t_main: Logging improvements --- src/tauon/t_modules/t_main.py | 69 +++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index f3657abb9..bbeda1e96 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -4602,8 +4602,9 @@ def scan_ffprobe(nt): logging.exception("FFPROBE couldn't supply a track") -# This function takes a track object and scans metadata for it. (Filepath needs to be set) + def tag_scan(nt): + """This function takes a track object and scans metadata for it. (Filepath needs to be set)""" if nt.is_embed_cue: return nt if nt.is_network or not nt.fullpath: @@ -4613,6 +4614,11 @@ def tag_scan(nt): nt.modified_time = os.path.getmtime(nt.fullpath) nt.found = True except FileNotFoundError: + logging.debug("File not found when executing getmtime!") + nt.found = False + return nt + except Exception: + logging.exception("Unknown error executing getmtime!") nt.found = False return nt @@ -5246,7 +5252,6 @@ def radio_progress(self): try: get_radio_art() except Exception: - # raise logging.exception("Get art error") pctl.notify_update(mpris=False) @@ -5384,21 +5389,25 @@ def show_selected(self): return 0 - # Get track object by id def g(self, id): + """Get track object by id""" return self.master_library[id] - # Get track object by playlist and index + def sg(self, i, pl): + """Get track object by playlist and index""" if pl == -1: pl = self.active_playlist_viewing try: playlist = self.multi_playlist[pl][2] return self.g(playlist[i]) except IndexError: - pass + logging.exception("Failed getting track object by playlist and index!") + except Exception: + logging.exception("Unknown error getting track object by playlist and index!") return None - def show_object(self): # The track to show in the metadata side panel + def show_object(self): + """The track to show in the metadata side panel""" target_track = None @@ -7155,8 +7164,8 @@ def last_fm_only_connect(self): return True except Exception as e: - show_message(_("Error communicating with Last.fm network"), str(e), mode='warning') logging.exception("Error communicating with Last.fm network") + show_message(_("Error communicating with Last.fm network"), str(e), mode='warning') return False def no_user_connect(self): @@ -7164,12 +7173,12 @@ def no_user_connect(self): return False try: self.network = self.get_network()(api_key=self.API_KEY, api_secret=self.API_SECRET) - print('Connection appears successful') + logging.info('Connection appears successful') return True except Exception as e: - show_message(_("Error communicating with Last.fm network"), str(e), mode='warning') logging.exception("Error communicating with Last.fm network") + show_message(_("Error communicating with Last.fm network"), str(e), mode='warning') return False def get_all_scrobbles_estimate_time(self): @@ -7697,7 +7706,7 @@ def listen_playing(self, track_object): try: additional = str(int(track_object.track_number)) except Exception: - pass + logging.exception("Error trying to get track_number") if track_object.length: additional["duration"] = str(track_object.length) @@ -7713,9 +7722,9 @@ def listen_playing(self, track_object): r = requests.post(self.url(), headers={"Authorization": "Token " + prefs.lb_token}, data=json.dumps(data)) if r.status_code != 200: show_message(_("There was an error submitting data to ListenBrainz"), r.text, mode='warning') - print("error") - print(r.status_code) - print(r.json()) + logging.error("There was an error submitting data to ListenBrainz") + logging.error(r.status_code) + logging.error(r.json()) def paste_key(self): @@ -7824,6 +7833,7 @@ def love(set=True, track_id=None, no_delay=False, notify=False, sync=True): try: lastfm.love(pctl.master_library[track_id].artist, pctl.master_library[track_id].title) except Exception: + logging.exception("Failed updating last.fm love status") show_message(_("Failed updating last.fm love status"), mode='warning') star[1] = star[1].replace("L", "") # = [star[0], star[1].strip("L"), star[2]] star_store.insert(track_id, star) @@ -7844,6 +7854,7 @@ def love(set=True, track_id=None, no_delay=False, notify=False, sync=True): try: lastfm.unlove(pctl.master_library[track_id].artist, pctl.master_library[track_id].title) except Exception: + logging.exception("Failed updating last.fm love status") show_message(_("Failed updating last.fm love status"), mode='warning') star[1] = star[1] + "L" star_store.insert(track_id, star) @@ -7873,6 +7884,7 @@ def maloja_get_scrobble_counts(): lastfm.scanning_scrobbles = False return except Exception: + logging.exception("There was an error reaching the Maloja server") show_message(_("There was an error reaching the Maloja server"), mode='warning') lastfm.scanning_scrobbles = False return @@ -7907,6 +7919,7 @@ def maloja_get_scrobble_counts(): show_message(_("Scanning scrobbles complete"), mode="done") except Exception: + logging.exception("There was an error parsing the data") show_message(_("There was an error parsing the data"), mode="warning") gui.pl_update += 1 @@ -7936,6 +7949,7 @@ def maloja_scrobble(track): show_message(_("There was an error submitting data to Maloja server"), r.text, mode='warning') return False except Exception: + logging.exception("There was an error submitting data to Maloja server") show_message(_("There was an error submitting data to Maloja server"), mode='warning') return False return True @@ -7968,7 +7982,7 @@ def process_queue(self): tr = self.queue.pop() gui.pl_update = 1 - print("Submit Scrobble " + tr[0].artist + " - " + tr[0].title) + logging.info("Submit Scrobble " + tr[0].artist + " - " + tr[0].title) success = True @@ -7984,14 +7998,13 @@ def process_queue(self): success = koel.listen(tr[0], submit=True) if not success: - print("Re-queue scrobble") + logging.info("Re-queue scrobble") self.queue.append(tr) time.sleep(10) break except Exception: - print("SCROBBLE QUEUE ERROR") - # raise + logging.exception("SCROBBLE QUEUE ERROR") if not self.queue: scrobble_warning_timer.force_set(1000) @@ -8001,7 +8014,7 @@ def process_queue(self): def update(self, add_time): if pctl.queue_step > len(pctl.track_queue) - 1: - print("Queue step error 1") + logging.info("Queue step error 1") return if self.a_index != pctl.track_queue[pctl.queue_step]: @@ -8011,7 +8024,7 @@ def update(self, add_time): self.a_pt = False self.a_sc = False if pctl.playing_time == 0 and self.a_sc is True: - print("Reset scrobble timer") + logging.info("Reset scrobble timer") pctl.a_time = 0 pctl.b_time = 0 self.a_pt = False @@ -8339,6 +8352,7 @@ def go(): show_message(_("Downloading... {N}/80MB").format(N=mb)) except Exception as e: + logging.exception("Download failed") show_message(_("Download failed"), str(e), mode="error") f.seek(0) @@ -8505,7 +8519,7 @@ def connect(self): self.connected = True def resolve_stream(self, location): - print("Get plex stream") + logging.info("Get plex stream") if not self.connected: self.connect() @@ -8552,8 +8566,7 @@ def get_albums(self, return_list=False): for track in album.tracks(): if not track.duration: - print( - "Warning: Skipping track with invalid duration - " + track.title + " - " + track.grandparentTitle) + logging.warning("Skipping track with invalid duration - " + track.title + " - " + track.grandparentTitle) continue id = pctl.master_count @@ -8657,11 +8670,11 @@ def r(self, point, p=None, binary=False, get_url=False): return response.content d = json.loads(response.text) - # print(d) + # logging.info(d) if d["subsonic-response"]["status"] != "ok": show_message(_("Subsonic Error: ") + response.text, mode="warning") - print("Subsonic Error: " + response.text) + logging.error("Subsonic Error: " + response.text) return d @@ -8676,14 +8689,14 @@ def resolve_stream(self, key): p['maxBitRate'] = prefs.network_stream_bitrate return self.r("stream", p={"id": key}, get_url=True) - # print(responce.content) + # logging.info(response.content) def listen(self, track_object, submit=False): try: a = self.r("scrobble", p={"id": track_object.url_key, "submission": submit}) except Exception: - print("Error connect for scrobble on airsonic") + logging.exception("Error connect for scrobble on airsonic") return True def set_rating(self, track_object, rating): @@ -8691,7 +8704,7 @@ def set_rating(self, track_object, rating): try: a = self.r("setRating", p={"id": track_object.url_key, "rating": math.ceil(rating / 2)}) except Exception: - print("Error connect for set rating on airsonic") + logging.exception("Error connect for set rating on airsonic") return True def set_album_rating(self, track_object, rating): @@ -8700,7 +8713,7 @@ def set_album_rating(self, track_object, rating): try: a = self.r("setRating", p={"id": id, "rating": math.ceil(rating / 2)}) except Exception: - print("Error connect for set rating on airsonic") + logging.exception("Error connect for set rating on airsonic") return True def get_music3(self, return_list=False): From 2f024aabb720488cd35dfbcd651263deebe42d2c Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 02:11:18 +0100 Subject: [PATCH 40/63] t_main+migrate: Don't return None, raise a ValueError instead --- src/tauon/t_modules/t_db_migrate.py | 4 +-- src/tauon/t_modules/t_main.py | 42 ++++++++++++++++------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/tauon/t_modules/t_db_migrate.py b/src/tauon/t_modules/t_db_migrate.py index 9667827da..b35330192 100644 --- a/src/tauon/t_modules/t_db_migrate.py +++ b/src/tauon/t_modules/t_db_migrate.py @@ -28,7 +28,7 @@ def database_migrate( radio_playlists: list[TauonPlaylist], p_force_queue: list, theme: int, -) -> tuple[dict, list[TauonPlaylist], StarStore, list, int, Prefs, GuiVar, dict, list[TauonPlaylist]] | None: +) -> tuple[dict, list[TauonPlaylist], StarStore, list, int, Prefs, GuiVar, dict, list[TauonPlaylist]]: """Migrate database to a newer version if we're behind Returns all the objects that could've been possibly changed: @@ -38,7 +38,7 @@ def database_migrate( if db_version <= 0: logging.error("Called database_migrate with db_version equal to or below 0!") - return None + raise ValueError logging.warning(f"Running migrations as DB version was {db_version}!") if db_version <= 0.8: diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index bbeda1e96..3660e02cc 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -3501,24 +3501,30 @@ def get_theme_name(number): # Run upgrades if we're behind the current DB standard if db_version < latest_db_version: - master_library, multi_playlist, star_store, p_force_queue, theme, prefs, gui, gen_codes, radio_playlists = database_migrate( - db_version=db_version, - master_library=master_library, - install_mode=install_mode, - multi_playlist=multi_playlist, - star_store=star_store, - install_directory=install_directory, - a_cache_dir=a_cache_dir, - cache_directory=cache_directory, - config_directory=config_directory, - user_directory=user_directory, - gui=gui, - gen_codes=gen_codes, - prefs=prefs, - radio_playlists=radio_playlists, - theme=theme, - p_force_queue=p_force_queue, - ) + logging.warning(f"Current DB version {db_version} was lower than latest {latest_db_version}, running migrations!") + try: + master_library, multi_playlist, star_store, p_force_queue, theme, prefs, gui, gen_codes, radio_playlists = database_migrate( + db_version=db_version, + master_library=master_library, + install_mode=install_mode, + multi_playlist=multi_playlist, + star_store=star_store, + install_directory=install_directory, + a_cache_dir=a_cache_dir, + cache_directory=cache_directory, + config_directory=config_directory, + user_directory=user_directory, + gui=gui, + gen_codes=gen_codes, + prefs=prefs, + radio_playlists=radio_playlists, + theme=theme, + p_force_queue=p_force_queue, + ) + except ValueError: + logging.exception("That should not happen") + except Exception: + logging.exception("Unknown error running database migration!") if playing_in_queue > len(QUE) - 1: playing_in_queue = len(QUE) - 1 From 0caed0b299b2ada33c5fa6e27a8ee293dedb8f52 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 12:38:55 +0100 Subject: [PATCH 41/63] Migrate theme directory under src/tauon --- {theme => src/tauon/theme}/Ash.ttheme | 0 {theme => src/tauon/theme}/Astro.ttheme | 0 {theme => src/tauon/theme}/Carbon.ttheme | 0 {theme => src/tauon/theme}/Cucumber Splash.ttheme | 0 {theme => src/tauon/theme}/High Contrast Dark.ttheme | 0 {theme => src/tauon/theme}/Lavender Light.ttheme | 0 {theme => src/tauon/theme}/Lime.ttheme | 0 {theme => src/tauon/theme}/Neon Love.ttheme | 0 {theme => src/tauon/theme}/Rose.ttheme | 0 {theme => src/tauon/theme}/Sky.ttheme | 0 {theme => src/tauon/theme}/Sunken.ttheme | 0 {theme => src/tauon/theme}/Turbo.ttheme | 0 {theme => src/tauon/theme}/Vape.ttheme | 0 {theme => src/tauon/theme}/Wasp.ttheme | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename {theme => src/tauon/theme}/Ash.ttheme (100%) rename {theme => src/tauon/theme}/Astro.ttheme (100%) rename {theme => src/tauon/theme}/Carbon.ttheme (100%) rename {theme => src/tauon/theme}/Cucumber Splash.ttheme (100%) rename {theme => src/tauon/theme}/High Contrast Dark.ttheme (100%) rename {theme => src/tauon/theme}/Lavender Light.ttheme (100%) rename {theme => src/tauon/theme}/Lime.ttheme (100%) rename {theme => src/tauon/theme}/Neon Love.ttheme (100%) rename {theme => src/tauon/theme}/Rose.ttheme (100%) rename {theme => src/tauon/theme}/Sky.ttheme (100%) rename {theme => src/tauon/theme}/Sunken.ttheme (100%) rename {theme => src/tauon/theme}/Turbo.ttheme (100%) rename {theme => src/tauon/theme}/Vape.ttheme (100%) rename {theme => src/tauon/theme}/Wasp.ttheme (100%) diff --git a/theme/Ash.ttheme b/src/tauon/theme/Ash.ttheme similarity index 100% rename from theme/Ash.ttheme rename to src/tauon/theme/Ash.ttheme diff --git a/theme/Astro.ttheme b/src/tauon/theme/Astro.ttheme similarity index 100% rename from theme/Astro.ttheme rename to src/tauon/theme/Astro.ttheme diff --git a/theme/Carbon.ttheme b/src/tauon/theme/Carbon.ttheme similarity index 100% rename from theme/Carbon.ttheme rename to src/tauon/theme/Carbon.ttheme diff --git a/theme/Cucumber Splash.ttheme b/src/tauon/theme/Cucumber Splash.ttheme similarity index 100% rename from theme/Cucumber Splash.ttheme rename to src/tauon/theme/Cucumber Splash.ttheme diff --git a/theme/High Contrast Dark.ttheme b/src/tauon/theme/High Contrast Dark.ttheme similarity index 100% rename from theme/High Contrast Dark.ttheme rename to src/tauon/theme/High Contrast Dark.ttheme diff --git a/theme/Lavender Light.ttheme b/src/tauon/theme/Lavender Light.ttheme similarity index 100% rename from theme/Lavender Light.ttheme rename to src/tauon/theme/Lavender Light.ttheme diff --git a/theme/Lime.ttheme b/src/tauon/theme/Lime.ttheme similarity index 100% rename from theme/Lime.ttheme rename to src/tauon/theme/Lime.ttheme diff --git a/theme/Neon Love.ttheme b/src/tauon/theme/Neon Love.ttheme similarity index 100% rename from theme/Neon Love.ttheme rename to src/tauon/theme/Neon Love.ttheme diff --git a/theme/Rose.ttheme b/src/tauon/theme/Rose.ttheme similarity index 100% rename from theme/Rose.ttheme rename to src/tauon/theme/Rose.ttheme diff --git a/theme/Sky.ttheme b/src/tauon/theme/Sky.ttheme similarity index 100% rename from theme/Sky.ttheme rename to src/tauon/theme/Sky.ttheme diff --git a/theme/Sunken.ttheme b/src/tauon/theme/Sunken.ttheme similarity index 100% rename from theme/Sunken.ttheme rename to src/tauon/theme/Sunken.ttheme diff --git a/theme/Turbo.ttheme b/src/tauon/theme/Turbo.ttheme similarity index 100% rename from theme/Turbo.ttheme rename to src/tauon/theme/Turbo.ttheme diff --git a/theme/Vape.ttheme b/src/tauon/theme/Vape.ttheme similarity index 100% rename from theme/Vape.ttheme rename to src/tauon/theme/Vape.ttheme diff --git a/theme/Wasp.ttheme b/src/tauon/theme/Wasp.ttheme similarity index 100% rename from theme/Wasp.ttheme rename to src/tauon/theme/Wasp.ttheme From 56c18e948cee9247b850aac776eacc700fb6810e Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Tue, 19 Nov 2024 18:58:22 +0100 Subject: [PATCH 42/63] t_main: Only run migrations when version isn't 0 too --- src/tauon/t_modules/t_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 3660e02cc..a02799942 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -3500,7 +3500,7 @@ def get_theme_name(number): return "" # Run upgrades if we're behind the current DB standard -if db_version < latest_db_version: +if db_version > 0 and db_version < latest_db_version: logging.warning(f"Current DB version {db_version} was lower than latest {latest_db_version}, running migrations!") try: master_library, multi_playlist, star_store, p_force_queue, theme, prefs, gui, gen_codes, radio_playlists = database_migrate( From 9427a66c145955625e99b824eef46d58e115fc68 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 15:45:53 +0100 Subject: [PATCH 43/63] t_main: Remove duplicated mutagen import --- src/tauon/t_modules/t_main.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index a02799942..1283e4b29 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -14998,11 +14998,6 @@ def field_edit(x, y, label, field_number, names, text_box): if changed: show_message(_("Press enter on fields to apply your changes first!")) return - try: - import mutagen - except Exception: - show_message(_("Please install package python-mutagen for this feature")) - return if gui.write_tag_in_progress: return From 8b8d5b3c3996e7fbe7ce1e4541be66b99e459fcf Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 16:06:43 +0100 Subject: [PATCH 44/63] t_main: Log all exceptions --- src/tauon/t_modules/t_main.py | 172 ++++++++++++++++++++-------------- 1 file changed, 103 insertions(+), 69 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 1283e4b29..7a417aa23 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -4559,7 +4559,7 @@ def natural_get(tag, track, frame, attr): nt.misc['replaygain_album_peak'] = float(item.text[0]) except Exception: logging.exception("Tag Scan: Read Replay Gain MP3 error") - logging.exception(nt.fullpath) + logging.debug(nt.fullpath) if item.desc == "FMPS_RATING": nt.misc['FMPS_Rating'] = float(item.text[0]) @@ -4620,7 +4620,7 @@ def tag_scan(nt): nt.modified_time = os.path.getmtime(nt.fullpath) nt.found = True except FileNotFoundError: - logging.debug("File not found when executing getmtime!") + logging.error("File not found when executing getmtime!") nt.found = False return nt except Exception: @@ -8480,7 +8480,7 @@ def wake(self): chrome = Chrome(tauon) logging.debug("Found import Chrome(pychromecast) for chromecast support") except ModuleNotFoundError: - logging.debug("Unable to import Chrome(pychromecast), chromecast support will be disabled.") + logging.warning("Unable to import Chrome(pychromecast), chromecast support will be disabled.") except Exception: logging.exception("Unkown error trying to import Chrome(pychromecast), chromecast support will be disabled.") @@ -8502,7 +8502,10 @@ def connect(self): try: from plexapi.myplex import MyPlexAccount + except ModuleNotFoundError: + logging.warning("Unable to import python-plexapi, plex support will be disabled.") except Exception: + logging.exception("Unknown error to import python-plexapi, plex support will be disabled.") show_message(_("Error importing python-plexapi"), mode='error') self.scanning = False return @@ -8511,8 +8514,9 @@ def connect(self): account = MyPlexAccount(prefs.plex_username, prefs.plex_password) self.resource = account.resource(prefs.plex_servername).connect() # returns a PlexServer instance except Exception: + logging.exception("Error connecting to PLEX server, check login credentials and server accessibility.") show_message(_("Error connecting to PLEX server"), - _("Try check login credentials and that server is accessible."), mode='error') + _("Try checking login credentials and that the server is accessible."), mode='error') self.scanning = False return @@ -8702,7 +8706,7 @@ def listen(self, track_object, submit=False): try: a = self.r("scrobble", p={"id": track_object.url_key, "submission": submit}) except Exception: - logging.exception("Error connect for scrobble on airsonic") + logging.exception("Error connecting for scrobble on airsonic") return True def set_rating(self, track_object, rating): @@ -8736,6 +8740,7 @@ def get_music3(self, return_list=False): try: a = self.r("getIndexes") except Exception: + logging.exception("Error connecting to Airsonic server") show_message(_("Error connecting to Airsonic server"), mode="error") self.scanning = False return [] @@ -8770,11 +8775,13 @@ def getsongs(index, folder_id, name, inner=False, parent=None): return except json.decoder.JSONDecodeError: - print("Error reading Airsonic directory") + logging.exception("Error reading Airsonic directory") if not inner: statuses[index] = 2 show_message(_("Error reading Airsonic directory!"), mode="warning") return + except Exception: + logging.exception("Unknown Error reading Airsonic directory") items = d["subsonic-response"]["directory"]["child"] @@ -9042,19 +9049,19 @@ def connect(self): try: r = requests.post(target, json=body, headers=headers) except Exception: + logging.exception("Could not establish connection") gui.show_message(_("Could not establish connection"), mode="error") - print("Could not establish connection") return if r.status_code == 200: # print(r.json()) self.token = r.json()["token"] if self.token: - print("GOT KOEL TOKEN") + logging.info("GOT KOEL TOKEN") self.connected = True else: - print("AUTH ERROR") + logging.info("AUTH ERROR") else: error = "" @@ -9086,8 +9093,8 @@ def resolve_stream(self, id): #target = f"{self.server}/api/download/songs" #params["songs"] = [id,] - print(target) - print(urllib.parse.urlencode(params)) + logging.info(target) + logging.info(urllib.parse.urlencode(params)) return target, params @@ -9105,7 +9112,7 @@ def listen(self, track_object, submit=False): # print(r.status_code) # print(r.text) except Exception: - print("error submitting listen to koel") + logging.exception("error submitting listen to koel") def get_albums(self, return_list=False): @@ -9226,7 +9233,7 @@ def get(self, point): r = requests.get(url + point) data = r.json() except Exception as e: - print("Error") + logging.exception("Network error") show_message(_("Network error"), str(e), mode="error") return data @@ -9259,7 +9266,7 @@ def get_playlist(self, playlist_name=None, return_list=False): try: t = self.get("tracklist/" + id) except Exception: - print("error getting tracklist") + logging.exception("error getting tracklist") return [] at = t["tracks"] @@ -9480,7 +9487,7 @@ def stop(self): gnomeThread.daemon = True gnomeThread.start() except Exception: - print("ERROR: Could not start Dbus thread") + logging.exception("Could not start Dbus thread") if (system == "windows" or msys): @@ -10099,7 +10106,7 @@ def bass_player_thread(player): try: player(pctl, gui, prefs, lfm_scrobbler, star_store, tauon) except Exception: - # logging.exception('Exception on player thread') + logging.exception('Exception on player thread') show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode='error') time.sleep(1) show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode='error') @@ -10514,7 +10521,7 @@ def find_synced_lyric_data(track): else: return None except Exception: - print("Read lyrics file error") + logging.exception("Read lyrics file error") return None return data @@ -10626,6 +10633,7 @@ def generate(self, track): if len(t) < 10: break except Exception: + logging.exception("Failed generating timed lyrics") continue self.data = sorted(self.data, key=lambda x: x[0]) @@ -11730,7 +11738,7 @@ def worker_render(self): # key = self.queue[0] key = self.queue.pop(0) except Exception: - print("thumb queue empty") + logging.exception("thumb queue empty") break if key not in self.gall: @@ -11788,7 +11796,7 @@ def worker_render(self): # response = urllib.request.urlopen(url) # source_image = response # except Exception: - # print("IMAGE NETWORK LOAD ERROR") + # logging.exception("IMAGE NETWORK LOAD ERROR") # else: # source_image = open(source[1], 'rb') source_image = album_art_gen.get_source_raw(0, 0, key[0], subsource=source) @@ -11808,6 +11816,7 @@ def worker_render(self): im = im.convert("RGB") im.thumbnail((size, size), Image.Resampling.LANCZOS) except Exception: + logging.exception("Failed to work with thumbnail") im = album_art_gen.get_error_img(size) error = True @@ -11830,8 +11839,7 @@ def worker_render(self): time.sleep(0.001) except Exception: - # raise - # print('ERROR: Image load failed on track: ' + key[0].fullpath) + logging.exception('Image load failed on track: ' + key[0].fullpath) console.print('ERROR: Image load failed on track: ') console.print("- " + key[0].fullpath) order = [0, None, None, None] @@ -11939,6 +11947,7 @@ def render(self, track, location, size=None, force_offset=None): try: self.lock.release() except Exception: + logging.exception("Failed to release lock") pass return False @@ -12171,7 +12180,7 @@ def get_sources(self, tr): direc = os.path.dirname(filepath) items_in_dir = os.listdir(direc) except Exception: - print(f"Error loading directory: {direc}") + logging.exception(f"Error loading directory: {direc}") return [] # Check for embedded image @@ -12180,6 +12189,7 @@ def get_sources(self, tr): if pic: source_list.append([1, filepath]) except Exception: + logging.exception("Failed to get embedded image") pass if not tr.is_network: @@ -12377,8 +12387,8 @@ def get_embed(self, track): tag = mutagen.id3.ID3(filepath) frame = tag.getall("APIC") pic = frame[0].data - except Exception as e: - pass + except Exception: + logging.exception("Failed to get tags") if len(pic) < 30: pic = None @@ -12451,7 +12461,7 @@ def get_source_raw(self, offset, sources, track, subsource=None): source_image.seek(0) except Exception: - pass + logging.exception("Failed to get source") else: source_image = open(subsource[1], 'rb') @@ -12534,7 +12544,7 @@ def get_background(self, track): s = musicbrainzngs.search_artists(artist, limit=1) artist_id = s['artist-list'][0]['id'] except Exception: - print("Failed to find artist MBID for: {artist}".format(artist=artist)) + logging.exception("Failed to find artist MBID for: {artist}".format(artist=artist)) prefs.failed_background_artists.append(artist) return None @@ -12568,13 +12578,12 @@ def get_background(self, track): return t except Exception: - #raise - print("Failed to find fanart background for: {artist}".format(artist=artist)) + logging.exception("Failed to find fanart background for: {artist}".format(artist=artist)) if not gui.artist_info_panel: artist_info_box.get_data(artist) path = artist_info_box.get_data(artist, get_img_path=True) if os.path.isfile(path): - print("Downloaded background lfm") + logging.debug("Downloaded background lfm") return open(path, "rb") @@ -12793,7 +12802,7 @@ def display(self, track, location, box, fast=False, theme_only=False): except Exception: - print("IMAGE NETWORK LOAD ERROR") + logging.exception("IMAGE NETWORK LOAD ERROR") raise else: @@ -12815,6 +12824,7 @@ def display(self, track, location, box, fast=False, theme_only=False): if im.mode != "RGB": im = im.convert("RGB") except Exception: + logging.exception("Failed to convert image") if theme_only: return im = Image.open(os.path.join(install_directory, "assets", "load-error.png")) @@ -12828,6 +12838,7 @@ def display(self, track, location, box, fast=False, theme_only=False): try: im = im.resize(new_size, Image.Resampling.LANCZOS) except Exception: + logging.exception("Failed to resize image") im = Image.open(os.path.join(install_directory, "assets", "load-error.png")) o_size = im.size new_size = fit_box(o_size, box) @@ -12836,6 +12847,7 @@ def display(self, track, location, box, fast=False, theme_only=False): try: im.thumbnail((box[0], box[1]), Image.Resampling.LANCZOS) except Exception: + logging.exception("Failed to convert image to thumbnail") im = Image.open(os.path.join(install_directory, "assets", "load-error.png")) o_size = im.size im.thumbnail((box[0], box[1]), Image.Resampling.LANCZOS) @@ -12849,7 +12861,7 @@ def display(self, track, location, box, fast=False, theme_only=False): try: im.thumbnail((50, 50), Image.Resampling.LANCZOS) except Exception: - print("theme gen error") + logging.exception("theme gen error") return pixels = im.getcolors(maxcolors=2500) pixels = sorted(pixels, key=lambda x: x[0], reverse=True)[:] @@ -13047,8 +13059,7 @@ def display(self, track, location, box, fast=False, theme_only=False): playlist_hold = False except Exception as error: - # raise - # print("Image processing error: " + str(error)) + logging.exception("Image processing error") console.print("Image load error") console.print("-- Associated track: " + track.fullpath) console.print("-- Exception: " + str(error)) @@ -13057,7 +13068,7 @@ def display(self, track, location, box, fast=False, theme_only=False): try: del self.source_cache[index][offset] except Exception: - print(" -- Error, no source cache?") + logging.exception(" -- Error, no source cache?") return 1 @@ -13161,11 +13172,10 @@ def worker(self): try: self.im = album_art_gen.get_blur_im(track) - except Exception as e: - print("Blur blackground error") - print(str(e)) + except Exception: + logging.exception("Blur blackground error") raise - #print(track.fullpath) + #logging.debug(track.fullpath) if self.im is None or self.im is False: if self.a_texture: @@ -13659,12 +13669,12 @@ def read_pls(lines, path, followed=False): if ".pls" in radio["stream_url"]: if not followed: try: - print("Download .pls") + logging.info("Download .pls") response = requests.get(radio["stream_url"], stream=True) if int(response.headers["Content-Length"]) < 2000: read_pls(response.content.decode().splitlines(), path, followed=True) except Exception: - print("Failed to retrieve .pls") + logging.exception("Failed to retrieve .pls") else: stations.append(radio) if gui.auto_play_import: @@ -13733,6 +13743,7 @@ def load_xspf(path): b = {} except Exception: + logging.exception("Error importing/parsing XSPF playlist") show_message(_("Error importing XSPF playlist."), _("Sorry about that."), mode='warning') # tauon.log("-- Error parsing XSPF file") console.print("-- Error parsing XSPF file") @@ -14809,10 +14820,11 @@ def render(self): star_store.insert(item, star) except Exception: + logging.exception("Rendering error") total_todo -= 1 rename_track_box.active = False - print('Done') + logging.info('Done') if pre_state == 1: pctl.revert() @@ -15985,6 +15997,7 @@ def get_lyric_fire(track_object, silent=False): found = True break except Exception as e: + logging.exception("Failed to find lyrics") console.print(str(e)) if not found: @@ -16229,6 +16242,7 @@ def save_embed_img(track_object): open_folder(track_object.index) except Exception: + logging.exception("Unknown error trying to save an image") show_message(_("Image save error."), _("A mysterious error occurred"), mode='error') @@ -16434,7 +16448,7 @@ def download_art1(tr): clear_track_image_cache(pctl.g(track_id)) return except Exception: - print("Failed to get from fanart.tv") + logging.exception("Failed to get from fanart.tv") show_message(_("Searching MusicBrainz for cover art...")) t = io.BytesIO(musicbrainzngs.get_release_group_image_front(album_id, size=None)) @@ -16459,6 +16473,7 @@ def download_art1(tr): return except Exception: + logging.exception("Matching cover art or ID could not be found.") show_message(_("Matching cover art or ID could not be found.")) @@ -16515,8 +16530,8 @@ def remove_embed_picture(track_object, dry=True): remove = True tag.save(padding=no_padding) removed += 1 - except Exception as e: - print("No APIC found") + except Exception: + logging.exception("No MP3 APIC found") if tr.file_ext == "M4A": try: @@ -16525,7 +16540,7 @@ def remove_embed_picture(track_object, dry=True): tag.save(padding=no_padding) removed += 1 except Exception: - pass + logging.exception("No m4A covr tag found") if tr.file_ext in ("OGA", "OPUS", "OGG"): show_message(_("Removing vorbis image not implemented")) @@ -16543,11 +16558,12 @@ def remove_embed_picture(track_object, dry=True): tag.save(padding=no_padding) removed += 1 except Exception: - pass + logging.exception("Failed to save tags on FLAC") clear_track_image_cache(tr) except Exception as e: + logging.exception("Image remove error") show_message(_("Image remove error"), mode='error') return @@ -16579,6 +16595,7 @@ def delete_file_image(track_object): clear_track_image_cache(track_object) print("Deleted file: " + source) except Exception: + logging.exception("Failed to delete file") show_message(_("Something went wrong"), mode='error') @@ -17164,7 +17181,7 @@ def move_radio_playlist(source, dest): pctl.radio_playlists.remove("old") pctl.radio_playlist_viewing = pctl.radio_playlists.index(temp) except Exception: - print("Warning: Playlist move error") + logging.exception("Playlist move error") def move_playlist(source, dest): @@ -17184,7 +17201,7 @@ def move_playlist(source, dest): pctl.active_playlist_viewing = pctl.multi_playlist.index(view) default_playlist = default_playlist = pctl.multi_playlist[pctl.active_playlist_viewing][2] except Exception: - print("Warning: Playlist move error") + logging.exception("Playlist move error") def delete_playlist(index, force=False, check_lock=False): @@ -17385,6 +17402,7 @@ def tryint(s): try: return int(s) except Exception: + logging.exception("Failed to parse as int") return s @@ -17404,6 +17422,7 @@ def index_key(index): dd = 1 d = str(dd) except Exception: + logging.exception("Failed to parse as index as int") d = "" @@ -17427,6 +17446,7 @@ def index_key(index): try: return [tryint(c) for c in re.split('([0-9]+)', s)] except Exception: + logging.exception("Failed to parse as int, returning 'a'") return "a" @@ -18270,9 +18290,8 @@ def rat_key(track_id): temp.append(item) playlist = temp except Exception: + logging.exception("Failed to get rating") errors = True - pass - # raise elif cm[:4] == "rat<": value = cm[4:] @@ -18284,8 +18303,8 @@ def rat_key(track_id): temp.append(item) playlist = temp except Exception: + logging.exception("Failed to get rating") errors = True - pass elif cm[:4] == "rat>": value = cm[4:] @@ -18297,8 +18316,8 @@ def rat_key(track_id): temp.append(item) playlist = temp except Exception: + logging.exception("Failed to get rating") errors = True - pass elif cm == "rat": temp = [] @@ -18481,7 +18500,7 @@ def rat_key(track_id): try: worker2_lock.release() except Exception: - pass + logging.exception("Failed to release worker2 lock") while search_over.sip: time.sleep(0.01) @@ -18492,7 +18511,7 @@ def rat_key(track_id): found_name = result[1] break else: - print("No folder search result found") + logging.info("No folder search result found") continue search_over.clear() @@ -18516,7 +18535,7 @@ def rat_key(track_id): try: worker2_lock.release() except Exception: - pass + logging.exception("Failed to release worker2 lock") while search_over.sip: time.sleep(0.01) @@ -18560,7 +18579,7 @@ def rat_key(track_id): try: worker2_lock.release() except Exception: - pass + logging.exception("Failed to release worker2 lock") while search_over.sip: time.sleep(0.01) @@ -20412,6 +20431,7 @@ def del_selected(force_delete=False): send2trash(tr.fullpath) show_message(_("Tracks sent to trash")) except Exception: + logging.exception("One or more tracks could not be sent to trash") show_message(_("One or more tracks could not be sent to trash")) if force_delete: @@ -20419,6 +20439,7 @@ def del_selected(force_delete=False): os.remove(tr.fullpath) show_message(_("Files deleted"), mode='info') except Exception: + logging.exception("Error deleting one or more files") show_message(_("Error deleting one or more files"), mode='error') else: @@ -20685,6 +20706,7 @@ def delete_track(track_ref): os.remove(fullpath) show_message(_("File deleted"), fullpath, mode='info') except Exception: + logging.exception("Error deleting file") show_message(_("Error deleting file"), fullpath, mode='error') else: show_message(_("File moved to trash")) @@ -20694,6 +20716,7 @@ def delete_track(track_ref): os.remove(fullpath) show_message(_("File deleted"), fullpath, mode='info') except Exception: + logging.exception("Error deleting file") show_message(_("Error deleting file"), fullpath, mode='error') reload() @@ -20789,8 +20812,10 @@ def delete_folder(index, force=False): except Exception: if force: - show_message(_("Unable to comply."), _("Could not delete folder. Try check permissions."), mode='error') + logging.exception("Unable to comply, could not delete folder. Try checking permissions.") + show_message(_("Unable to comply."), _("Could not delete folder. Try checking permissions."), mode='error') else: + logging.exception("Folder could not be trashed, try again while holding shift to force delete.") show_message(_("Folder could not be trashed."), _("Try again while holding shift to force delete."), mode='error') @@ -20882,7 +20907,7 @@ def rename_parent(index, template): os.rename(old, new_parent_path) print(new_parent_path) except Exception: - + logging.exception("Rename failed, something went wrong!") show_message(_("Rename Failed!"), _("Something went wrong, sorry."), mode='error') return @@ -20966,6 +20991,7 @@ def move_folder_up(index, do=False): os.rename(os.path.join(upper_folder, "RMTEMP000"), os.path.join(upper_folder, folder_name)) except Exception as e: + logging.exception("System Error!") show_message(_("System Error!"), str(e), mode='error') # Fix any other tracks paths that contain the old path @@ -21028,8 +21054,8 @@ def clean_folder(index, do=False): if pctl.g(track_id).parent_folder_path == folder: clear_track_image_cache(pctl.g(track_id)) - except Exception as e: - # show_message(str(e)) + except Exception: + logging.exception("Error deleting files, may not have permission or file may be set to read-only") show_message(_("Error deleting files."), _("May not have permission or file may be set to read-only"), mode='warning') return 0 @@ -21373,6 +21399,7 @@ def intel_moji(index): detect = enc break except Exception: + logging.exception("Error decoding artist") continue if detect is None and track.album not in track.parent_folder_path: @@ -21383,6 +21410,7 @@ def intel_moji(index): detect = enc break except Exception: + logging.exception("Error decoding album") continue for item in lot: @@ -22683,7 +22711,7 @@ def check_auto_update_okay(code, pl=None): try: cmds = shlex.split(code) except Exception: - print("Malformed generator code!") + logging.exception("Malformed generator code!") return False return "auto" in cmds or (prefs.always_auto_update_playlists and pctl.active_playlist_playing != pl and @@ -23932,7 +23960,7 @@ def get_album_art_url(tr): tr.misc['musicbrainz_releasegroupid'] = release_group_id #print("got release group id") except Exception: - #logging.info("Error lookup mbid for discord") + logging.exception("Error lookup mbid for discord") pctl.album_mbid_release_group_cache[(artist, tr.album)] = None if not release_id: @@ -23985,6 +24013,8 @@ def get_album_art_url(tr): except (requests.RequestException, ValueError): logging.exception("No image found for album id") pctl.album_mbid_release_cache[(artist, tr.album)] = None + except Exception: + logging.exception("Unknown error getting image found for album id") if image_data: for image in image_data["images"]: @@ -26267,7 +26297,7 @@ def add_file(path, force_scan=False): target_dir = os.path.join(music_directory, os.path.basename(target_dir)) # print(os.path.getsize(path)) if os.path.getsize(path) > 4e+9: - print("Archive file is large!") + logging.warning("Archive file is large!") show_message(_("Skipping oversize zip file (>4GB)")) return 1 if not os.path.isdir(target_dir) and not os.path.isfile(target_dir): @@ -26281,8 +26311,8 @@ def add_file(path, force_scan=False): zip_ref.extractall(target_dir) zip_ref.close() except RuntimeError as e: + logging.exception("Zip error") to_got = b - print("Zip error") if 'encrypted' in e: show_message(_("Failed to extract zip archive."), _("The archive is encrypted. You'll need to extract it manually with the password."), @@ -26293,7 +26323,7 @@ def add_file(path, force_scan=False): mode='warning') return 1 except Exception: - print("Zip error 2") + logging.exception("Zip error 2") to_got = b show_message(_("Failed to extract zip archive."), _("Maybe archive is corrupted? Does disk have enough space and have write permission?"), @@ -26310,6 +26340,7 @@ def add_file(path, force_scan=False): result = subprocess.run(shlex.split(line)) print(result) except Exception: + logging.exception("Failed to extract rar archive.") to_got = b show_message(_("Failed to extract rar archive."), mode='warning') @@ -26325,6 +26356,7 @@ def add_file(path, force_scan=False): result = subprocess.run(shlex.split(line)) print(result) except Exception: + logging.exception("Failed to extract 7z archive.") to_got = b show_message(_("Failed to extract 7z archive."), mode='warning') @@ -26340,18 +26372,20 @@ def add_file(path, force_scan=False): try: shutil.move(new + "/" + cont[0], upper) except Exception: + logging.exception("Could not move file") error = True shutil.rmtree(new) - print(new) + logging.info(new) target_dir = upper + "/" + cont[0] if not os.path.isdir(target_dir): - print("Extract error, expected directory not found") + logging.error("Extract error, expected directory not found") if True and not error and prefs.auto_del_zip: - print("Moving archive file to trash: " + path) + logging.info("Moving archive file to trash: " + path) try: send2trash(path) except Exception: + logging.exception("Could not move archive to trash") show_message(_("Could not move archive to trash"), path, mode='info') to_got = b @@ -40546,7 +40580,7 @@ def loader(self): if r.status_code != 200 or int(r.headers.get('Content-Length', 0)) > 2000000: raise Exception("Error get radio thumb") except Exception: - print("error get radio thumb") + logging.exception("error get radio thumb") self.cache[key] = [0, ] if station.get("icon") and station.get("icon") not in prefs.radio_thumb_bans: prefs.radio_thumb_bans.append(station.get("icon")) From 167e67db4b28e59cad9c414bbb81209a4938a06e Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 16:08:29 +0100 Subject: [PATCH 45/63] Move templates to src/tauon --- {templates => src/tauon/templates}/logo-bg.png | Bin {templates => src/tauon/templates}/pause.svg | 0 {templates => src/tauon/templates}/play.svg | 0 {templates => src/tauon/templates}/radio.html | 0 {templates => src/tauon/templates}/radio.js | 0 {templates => src/tauon/templates}/stop.svg | 0 {templates => src/tauon/templates}/theme.css | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {templates => src/tauon/templates}/logo-bg.png (100%) rename {templates => src/tauon/templates}/pause.svg (100%) rename {templates => src/tauon/templates}/play.svg (100%) rename {templates => src/tauon/templates}/radio.html (100%) rename {templates => src/tauon/templates}/radio.js (100%) rename {templates => src/tauon/templates}/stop.svg (100%) rename {templates => src/tauon/templates}/theme.css (100%) diff --git a/templates/logo-bg.png b/src/tauon/templates/logo-bg.png similarity index 100% rename from templates/logo-bg.png rename to src/tauon/templates/logo-bg.png diff --git a/templates/pause.svg b/src/tauon/templates/pause.svg similarity index 100% rename from templates/pause.svg rename to src/tauon/templates/pause.svg diff --git a/templates/play.svg b/src/tauon/templates/play.svg similarity index 100% rename from templates/play.svg rename to src/tauon/templates/play.svg diff --git a/templates/radio.html b/src/tauon/templates/radio.html similarity index 100% rename from templates/radio.html rename to src/tauon/templates/radio.html diff --git a/templates/radio.js b/src/tauon/templates/radio.js similarity index 100% rename from templates/radio.js rename to src/tauon/templates/radio.js diff --git a/templates/stop.svg b/src/tauon/templates/stop.svg similarity index 100% rename from templates/stop.svg rename to src/tauon/templates/stop.svg diff --git a/templates/theme.css b/src/tauon/templates/theme.css similarity index 100% rename from templates/theme.css rename to src/tauon/templates/theme.css From d4d61b7d5a54b592ae072197ee836b96a5615463 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 17:12:28 +0100 Subject: [PATCH 46/63] tauon.py: Upgrade logs, now with colors, on UNIX systems anyway --- src/tauon/tauon.py | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/tauon/tauon.py b/src/tauon/tauon.py index ee09251d0..2f8b5d469 100755 --- a/src/tauon/tauon.py +++ b/src/tauon/tauon.py @@ -64,12 +64,41 @@ from tauon.t_modules import t_bootstrap + +class CustomLoggingFormatter(logging.Formatter): + """Nicely format logging.loglevel logs""" + + grey = "\x1b[38;20m" + grey_bold = "\x1b[38;1m" + yellow = "\x1b[33;20m" + yellow_bold = "\x1b[33;1m" + red = "\x1b[31;20m" + bold_red = "\x1b[31;1m" + reset = "\x1b[0m" + format = "%(asctime)s [%(levelname)s] [%(module)s] %(message)s" + format_verbose = "%(asctime)s [%(levelname)s] [%(module)s] %(message)s (%(filename)s:%(lineno)d)" + + FORMATS = { + logging.DEBUG: grey_bold + format_verbose + reset, + logging.INFO: yellow + format + reset, + logging.WARNING: yellow_bold + format + reset, + logging.ERROR: red + format + reset, + logging.CRITICAL: bold_red + format_verbose + reset, + } + + def format(self, record: dict) -> str: + log_fmt = self.FORMATS.get(record.levelno) + # Remove the miliseconds(%f) from the default string + date_fmt = "%Y-%m-%d %H:%M:%S" + formatter = logging.Formatter(log_fmt, date_fmt) + # Center align + min length things to prevent logs jumping around when switching between different values + record.levelname = f"{record.levelname:^7}" + record.module = f"{record.module:^10}" + return formatter.format(record) + # DEBUG+ to file and std_err logging.basicConfig( level=logging.DEBUG, -# filename=user_directory + '/crash.log', -# format='%(asctime)s %(levelname)s %(name)s %(message)s') - format="%(asctime)s [%(levelname)s] [%(module)s] %(message)s", handlers=[ logging.StreamHandler(), # logging.FileHandler('/tmp/tauon.log'), @@ -77,6 +106,7 @@ ) # INFO+ to std_err logging.getLogger().handlers[0].setLevel(logging.INFO) +logging.getLogger().handlers[0].setFormatter(CustomLoggingFormatter()) if sys.platform != "win32": import fcntl From 6570a0f5d39c6ad1c43a1310e1fc46c5d64aa91b Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 17:40:09 +0100 Subject: [PATCH 47/63] Convert all remaining bare print statements into logging --- src/tauon/t_modules/t_jellyfin.py | 7 +- src/tauon/t_modules/t_main.py | 615 +++++++++++++++-------------- src/tauon/t_modules/t_phazor.py | 2 +- src/tauon/t_modules/t_spot.py | 18 +- src/tauon/t_modules/t_stream.py | 1 - src/tauon/t_modules/t_themeload.py | 3 +- src/tauon/t_modules/t_tidal.py | 2 +- src/tauon/t_modules/t_webserve.py | 1 - 8 files changed, 325 insertions(+), 324 deletions(-) diff --git a/src/tauon/t_modules/t_jellyfin.py b/src/tauon/t_modules/t_jellyfin.py index 7458c6548..4d2860235 100644 --- a/src/tauon/t_modules/t_jellyfin.py +++ b/src/tauon/t_modules/t_jellyfin.py @@ -83,6 +83,7 @@ def _authenticate(self, debug: bool = False) -> None: data=json.dumps({ "username": username, "Pw": password }), timeout=(5, 10), ) except Exception: + logging.exception("Could not establish connection to server. Check server is running and URL is correct.") self.gui.show_message(_("Could not establish connection to server."), _("Check server is running and URL is correct."), mode="error") return @@ -411,7 +412,7 @@ def ingest_library(self, return_list: bool = False) -> list | None: ) except Exception: - logging.exception("ERROR") + logging.exception("Error connecting to Jellyfin for Import") self.gui.show_message(_("Error connecting to Jellyfin for Import"), mode="error") self.scanning = False return None @@ -428,7 +429,7 @@ def ingest_library(self, return_list: bool = False) -> list | None: # group by parent grouped_items = itertools.groupby(sorted_items, lambda item: (item.get("AlbumArtist", "") + " - " + item.get("Album", "")).strip("- ")) else: - logging.error("ERROR") + logging.error("Error accessing Jellyfin") self.scanning = False self.tauon.gui.show_message(_("Error accessing Jellyfin"), mode="warning") return None @@ -439,7 +440,7 @@ def ingest_library(self, return_list: bool = False) -> list | None: track_id = self.pctl.master_count # id here is tauons track_id for the track existing_track = existing.get(track.get("Id")) replace_existing = existing_track is not None - #print(track.items()) + #logging.info(track.items()) if replace_existing: track_id = existing_track nt = self.pctl.g(track_id) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 7a417aa23..3741d5967 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -2963,7 +2963,6 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" ggc = 2 try: - sp1 = user_directory + "/star.p" sp2 = user_directory + "/star.p.backup" @@ -2980,22 +2979,26 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" to_load = sp2 star_store.db = pickle.load(open(to_load, "rb")) - +except FileNotFoundError: + logging.error('No existing star.p file') except Exception: - logging.exception('No existing star.p file') + logging.exception('Unknown error loading star.p file') try: album_star_store.db = pickle.load(open(user_directory + "/album-star.p", "rb")) - +except FileNotFoundError: + logging.error('No existing album-star.p file') except Exception: - logging.exception('No existing album-star.p file') + logging.exception('Unknown error loading album-star.p file') try: if os.path.isfile(user_directory + "/lyrics_substitutions.json"): with open(user_directory + "/lyrics_substitutions.json", 'r') as f: prefs.lyrics_subs = json.load(f) +except FileNotFoundError: + logging.error('No existing lyrics_substitutions.json file') except Exception: - logging.exception("Error loading lyrics_substitutions.json") + logging.exception("Unknown error loading lyrics_substitutions.json") perf_timer.set() @@ -3078,7 +3081,7 @@ def pumper(): save = pickle.load(state_file) if t == 1: - logging.info("Using backup state") + logging.warning("Using backup state") if save[63] is not None: prefs.ui_scale = save[63] @@ -5602,7 +5605,7 @@ def show_current(self, select=True, playing=True, quiet=False, this_only=False, pctl.playlist_view_position = 0 # if pctl.playlist_view_position > len(self.multi_playlist[self.active_playlist_viewing][2]) - 1: - # print("Run Over") + # logging.info("Run Over") if select: shift_selection = [] @@ -5669,7 +5672,7 @@ def revert(self): self.decode_time = 0 if not len(self.track_queue) > self.queue_step >= 0: - print("ERROR - there is no previous track?") + logging.error("There is no previous track?") return self.target_open = pctl.master_library[self.track_queue[self.queue_step]].fullpath @@ -5740,7 +5743,7 @@ def play_target(self, gapless=False, jump=False): tm.ready_playback() - # print(self.track_queue) + #logging.info(self.track_queue) self.playing_time = 0 self.decode_time = 0 target = pctl.master_library[self.track_queue[self.queue_step]] @@ -5998,7 +6001,7 @@ def seek_decimal(self, decimal): elif decimal < 0: decimal = 0 self.new_time = pctl.playing_length * decimal - # print('seek to:' + str(pctl.new_time)) + #logging.info('seek to:' + str(pctl.new_time)) self.playerCommand = 'seek' self.playerCommandReady = True self.playing_time = self.new_time @@ -6229,7 +6232,7 @@ def test_progress(self): pctl.selected_in_playlist] != self.playing_object().index \ and -1 < pctl.selected_in_playlist < len(default_playlist): - print("Repeat follow cursor") + logging.info("Repeat follow cursor") self.playing_time = 0 self.decode_time = 0 @@ -6275,7 +6278,7 @@ def test_progress(self): if not self.playing_time + 0.1 >= self.playing_length: return - print("Do transition CUE") + logging.info("Do transition CUE") self.playlist_playing_position += 1 self.queue_step += 1 self.track_queue.append(pp[self.playlist_playing_position]) @@ -6298,7 +6301,7 @@ def test_progress(self): id = self.advance(quiet=True, end=True, dry=True) if id is not None and not spot_ctl.playing: - #print("Commit") + #logging.info("Commit") self.start_commit(id) return @@ -6351,7 +6354,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, if not dry: if self.playing_state == 1 and 1 < self.left_time < 45: pctl.master_library[self.left_index].skips += 1 - # print('skip registered') + #logging.info('skip registered') if not dry: pctl.playing_time = 0 @@ -6460,7 +6463,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, if len(pl) <= self.playlist_playing_position: if dry: return None - print("END OF PLAYLIST!") + logging.info("END OF PLAYLIST!") del self.force_queue[0] self.advance() return @@ -6479,7 +6482,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, if dry: return None - print("Remove expired album from queue") + logging.info("Remove expired album from queue") del self.force_queue[0] if q[6]: @@ -6566,7 +6569,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, if ti.index not in pp: if dry: return None - print("No tracks to repeat!") + logging.info("No tracks to repeat!") return 0 matches = [] @@ -6603,7 +6606,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, # pool.remove(ref) if ref[1] not in pp: # Check track still in the live playlist - print("Track not in pool") + logging.info("Track not in pool") continue i, p = ref # Find position of reference in playlist @@ -6614,7 +6617,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, random.shuffle(matches) pctl.shuffle_pools[id] = matches - print("Refill folder shuffle pool") + logging.info("Refill folder shuffle pool") self.playlist_playing_position = i self.track_queue.append(p) @@ -6760,7 +6763,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, self.playlist_playing_position += 1 self.track_queue.append(self.playing_playlist()[self.playlist_playing_position]) - # print("standand advance") + # logging.info("standand advance") # self.queue_target = len(self.track_queue) - 1 # if end: # self.play_target_gapless(jump= not end) @@ -6774,7 +6777,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, if self.random_mode and (self.album_shuffle_mode or prefs.album_shuffle_lock_mode): # Album shuffle mode - print("Album shuffle mode") + logging.info("Album shuffle mode") po = self.playing_object() @@ -6839,11 +6842,11 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, self.queue_step = len(self.track_queue) - 1 if play: self.play_target(jump=not end) - # print("THERS ONLY ONE ALBUM IN THE PLAYLIST") + # logging.info("THERE IS ONLY ONE ALBUM IN THE PLAYLIST") # self.stop() else: - print("ADVANCE ERROR - NO CASE!") + logging.error("ADVANCE ERROR - NO CASE!") if dry: return None @@ -7133,7 +7136,7 @@ def connect(self, m_notify=True): show_message(_("No Last.Fm account registered"), _("Authorise an account in settings"), mode='info') return - print('Attempting to connect to Last.fm network') + logging.info('Attempting to connect to Last.fm network') try: @@ -7144,7 +7147,7 @@ def connect(self, m_notify=True): if m_notify: show_message(_("Connection to Last.fm was successful."), mode='done') - print('Connection to lastfm appears successful') + logging.info('Connection to lastfm appears successful') return True except Exception as e: @@ -7166,7 +7169,7 @@ def last_fm_only_connect(self): return False try: self.lastfm_network = pylast.LastFMNetwork(api_key=self.API_KEY, api_secret=self.API_SECRET) - print('Connection appears successful') + logging.info('Connection appears successful') return True except Exception as e: @@ -7391,7 +7394,6 @@ def scrobble(self, track_object, timestamp=None): gui.update += 1 gui.delay_frame(5) - # print(e) return False return True @@ -7403,11 +7405,11 @@ def get_bio(self, artist): artist_object = pylast.Artist(artist, self.lastfm_network) bio = artist_object.get_bio_summary(language="en") - # print(artist_object.get_cover_image()) - # print("\n\n") - # print(bio) - # print("\n\n") - # print(artist_object.get_bio_content()) + # logging.info(artist_object.get_cover_image()) + # logging.info("\n\n") + # logging.info(bio) + # logging.info("\n\n") + # logging.info(artist_object.get_bio_content()) return bio # else: # return "" @@ -7567,7 +7569,7 @@ def update(self, track_object): else: return 0 - # print('Updating Now Playing') + # logging.info('Updating Now Playing') title = track_object.title album = track_object.album @@ -7585,7 +7587,6 @@ def update(self, track_object): logging.exception("Error connecting to last.fm.") console.print("Error connecting to last.fm.", level=3) console.print("-- " + str(e), level=3) - # print(e) if 'retry' in str(e): return 2 # show_message(_("Could not update Last.fm. ", str(e), mode='warning') @@ -7663,7 +7664,7 @@ def listen_full(self, track_object, time): if additional: metadata['additional_info'] = additional - # print(additional) + # logging.info(additional) data["payload"].append({"track_metadata": metadata}) data["payload"][0]["listened_at"] = time @@ -8069,7 +8070,7 @@ def update(self, add_time): self.scrob_full_track(pctl.master_library[self.a_index]) def listen_track(self, track_object): - # print("LISTEN") + # logging.info("LISTEN") if track_object.is_network: if track_object.file_ext == "SUB": @@ -8087,7 +8088,7 @@ def listen_track(self, track_object): mini_t.start() def scrob_full_track(self, track_object): - # print("SCROBBLE") + # logging.info("SCROBBLE") track_object.lfm_scrobbles += 1 gui.pl_update += 1 @@ -8439,7 +8440,7 @@ def bg_save(self): tm.ready("worker") def exit(self, reason): - print("Shutting down. Reason: " + reason) + logging.info("Shutting down. Reason: " + reason) pctl.running = False self.wake() @@ -8927,7 +8928,7 @@ def getsongs(index, folder_id, name, inner=False, parent=None): # return # # except json.decoder.JSONDecodeError: - # print("Error reading Airsonic directory") + # logging.error("Error reading Airsonic directory") # show_message(_("Error reading Airsonic directory!)", mode="warning") # return # @@ -9019,7 +9020,7 @@ def __init__(self): def connect(self): - print("Connect to koel...") + logging.info("Connect to koel...") if not prefs.koel_username or not prefs.koel_password or not prefs.koel_server_url: show_message(_("Missing username, password and/or server URL"), mode='warning') self.scanning = False @@ -9027,7 +9028,7 @@ def connect(self): if self.token: self.connected = True - print("Already authorised") + logging.info("Already authorised") return password = prefs.koel_password @@ -9054,7 +9055,7 @@ def connect(self): return if r.status_code == 200: - # print(r.json()) + # logging.info(r.json()) self.token = r.json()["token"] if self.token: logging.info("GOT KOEL TOKEN") @@ -9109,8 +9110,8 @@ def listen(self, track_object, submit=False): } r = requests.post(target, headers=headers, json={"song": track_object.url_key}) - # print(r.status_code) - # print(r.text) + # logging.info(r.status_code) + # logging.info(r.text) except Exception: logging.exception("error submitting listen to koel") @@ -9638,7 +9639,7 @@ def update(self, playlist): self.genre_list = copy.deepcopy(sorted_list) self.genre_dict = genre_dict - # print('\n-----------------------\n') + # logging.info('\n-----------------------\n') g_albums = {} @@ -10014,14 +10015,14 @@ def get_xcursor(name): if not maximized and gui.maximized: SDL_MaximizeWindow(t_window) -# print(SDL_GetError()) +# logging.error(SDL_GetError()) # t_window = SDL_CreateShapedWindow(window_title, # SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, # window_size[0], window_size[1], # flags) -# print(SDL_GetError()) +# logging.error(SDL_GetError()) if system == 'windows' or msys: gui.window_id = sss.info.win.window @@ -10031,7 +10032,7 @@ def get_xcursor(name): # SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, b"1") # # except Exception: -# print("old version of SDL detected") +# logging.exception("old version of SDL detected") # get window surface and set up renderer # renderer = SDL_CreateRenderer(t_window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC) @@ -10164,12 +10165,12 @@ def update(self, force=False): if os.path.isfile(install_directory + "/TaskbarLib.tlb"): - print("Taskbar progress enabled") + logging.info("Taskbar progress enabled") pctl.windows_progress = WinTask() else: pctl.taskbar_progress = False - print("Could not find TaskbarLib.tlb") + logging.warning("Could not find TaskbarLib.tlb") # --------------------------------------------------------------------------------------------- @@ -10637,7 +10638,7 @@ def generate(self, track): continue self.data = sorted(self.data, key=lambda x: x[0]) - # print(self.data) + # logging.info(self.data) self.ready = True return True @@ -11563,9 +11564,9 @@ def d(): self.selection = 0 a = ddt.get_text_w(self.text[0: len(self.text) - self.cursor_position], font) - # print("") - # print(self.selection) - # print(self.cursor_position) + # logging.info("") + # logging.info(self.selection) + # logging.info(self.cursor_position) b = ddt.get_text_w(self.text[0: len(self.text) - self.selection], font) @@ -11762,7 +11763,7 @@ def worker_render(self): img_name = str(key[2]) + "-" + str(size) + '-' + str(key[0].index) + "-" + str(offset) if prefs.cache_gallery and os.path.isfile(os.path.join(g_cache_dir, img_name + '.jpg')): source_image = open(os.path.join(g_cache_dir, img_name + '.jpg'), 'rb') - # print('load from cache') + # logging.info('load from cache') cache_load = True else: slow_load = True @@ -11783,11 +11784,11 @@ def worker_render(self): if prefs.cache_gallery and os.path.isfile(os.path.join(g_cache_dir, img_name + '.jpg')): source_image = open(os.path.join(g_cache_dir, img_name + '.jpg'), 'rb') - print("slow load image") + logging.info("slow load image") cache_load = True # elif source[0] == 1: - # # print('tag') + # #logging.info('tag') # source_image = io.BytesIO(album_art_gen.get_embed(key[0])) # # elif source[0] == 2: @@ -11882,7 +11883,7 @@ def render(self, track, location, size=None, force_offset=None): key = (track, size, offset) if key in self.gall: - # print("old") + #logging.info("old") order = self.gall[key] @@ -12062,7 +12063,7 @@ def clear_track_image_cache(track): n = item.split("-") if len(n) > 2 and n[2] == str(track.index): os.remove(os.path.join(direc, item)) - print("Cleared cache thumbnail: " + os.path.join(direc, item)) + logging.info("Cleared cache thumbnail: " + os.path.join(direc, item)) keys = set() for key, value in gall_ren.gall.items(): @@ -12369,7 +12370,7 @@ def get_embed(self, track): # cached = self.embed_cached # if cached[0] == track: - # # print("used cached") + # #logging.info("used cached") # return cached[1] filepath = track.fullpath @@ -12516,7 +12517,7 @@ def get_base64(self, track, size): return sss def get_background(self, track): - #print("Find background...") + #logging.info("Find background...") # Determine artist name to use artist = get_artist_safe(track) if not artist: @@ -12525,14 +12526,14 @@ def get_background(self, track): # Check cache for existing image path = os.path.join(b_cache_dir, artist) if os.path.isfile(path): - print("Load cached background") + logging.info("Load cached background") return open(path, "rb") else: # Try last.fm background path = artist_info_box.get_data(artist, get_img_path=True) if os.path.isfile(path): - print("Load cached background lfm") + logging.info("Load cached background lfm") return open(path, "rb") # Check we've not already attempted a search for this artist @@ -12622,7 +12623,7 @@ def get_blur_im(self, track): if im.format == "JPEG": format = "JPG" - # print(im.size) + #logging.info(im.size) if im.mode != "RGB": im = im.convert("RGB") @@ -12630,7 +12631,7 @@ def get_blur_im(self, track): ratio += 0.2 if (oy_size * ratio) - ((oy_size * ratio) // 4) < window_size[1]: - print("Adjust bg vertical") + logging.info("Adjust bg vertical") ratio = window_size[1] / (oy_size - (oy_size // 4)) ratio += 0.2 @@ -12654,7 +12655,7 @@ def get_blur_im(self, track): enhancer = ImageEnhance.Brightness(im) deduct = 1 - ((pixel_sum - 0.6) * 1.5) im = enhancer.enhance(deduct) - print(deduct) + logging.info(deduct) gui.center_blur_pixel = im.getpixel((new_x // 2, new_y // 4 * 3)) @@ -12682,7 +12683,7 @@ def save_thumb(self, track_object, size, save_path, png=False, zoom=False): sources = self.get_sources(track_object) if len(sources) == 0: - print("Error thumbnailing; no source images found") + logging.error("Error thumbnailing; no source images found") return False offset = self.get_offset(filepath, sources) @@ -12898,9 +12899,9 @@ def display(self, track, location, box, fast=False, theme_only=False): im.thumbnail((50, 50), Image.Resampling.LANCZOS) pixels = im.getcolors(maxcolors=2500) - # print(pixels) + #logging.info(pixels) pixels = sorted(pixels, key=lambda x: x[0], reverse=True)[:] - # print(pixels) + #logging.info(pixels) min_colour_varience = 75 @@ -12915,7 +12916,7 @@ def display(self, track, location, box, fast=False, theme_only=False): else: x_colours.append(colour) - # print(x_colours) + #logging.info(x_colours) colours.playlist_panel_bg = colours.side_panel_background colours.playlist_box_background = colours.side_panel_background @@ -13011,7 +13012,7 @@ def display(self, track, location, box, fast=False, theme_only=False): wop = rw_from_object(g) s_image = IMG_Load_RW(wop, 0) - # print(IMG_GetError()) + #logging.error(IMG_GetError()) c = SDL_CreateTextureFromSurface(renderer, s_image) @@ -13603,10 +13604,10 @@ def load_m3u(path): titles[value.artist + " - " + value.title] = value # Is file path already imported? - print(line) + logging.info(line) if line in location_dict: playlist.append(location_dict[line].index) - print("found imported") + logging.info("found imported") # Or... does the file exist? Then import it elif os.path.isfile(line): nt = TrackClass() @@ -13616,13 +13617,13 @@ def load_m3u(path): pctl.master_library[pctl.master_count] = nt playlist.append(pctl.master_count) pctl.master_count += 1 - print("found file") + logging.info("found file") # Last resort, guess based on title elif line_title in titles: playlist.append(titles[line_title].index) - print("found title") + logging.info("found title") else: - print("not found") + logging.info("not found") if playlist: pctl.multi_playlist.append(pl_gen(title=name, @@ -13717,8 +13718,8 @@ def load_xspf(path): for track in top: if track.tag.endswith("track"): for field in track: - print(field.tag) - print(field.text) + logging.info(field.tag) + logging.info(field.text) if 'title' in field.tag and field.text: b['title'] = field.text if 'location' in field.tag and field.text: @@ -13879,7 +13880,7 @@ def load_xspf(path): if missing > 0: show_message(_('Failed to locate {N} out of {T} tracks.') .format(N=str(missing), T=str(len(a)))) - # print(playlist) + #logging.info(playlist) if playlist: pctl.multi_playlist.append(pl_gen(title=name, playlist=playlist)) @@ -14235,7 +14236,7 @@ def render(self): x_run = self.pos[0] for i in range(len(self.items)): - # print(self.items[i]) + #logging.info(self.items[i]) # Draw menu break if self.items[i] is None: @@ -14784,7 +14785,7 @@ def render(self): oldname = pctl.master_library[item].filename oldpath = pctl.master_library[item].fullpath - print('Renaming...') + logging.info('Renaming...') star = star_store.full_get(item) star_store.remove(item) @@ -14794,17 +14795,17 @@ def render(self): oldsplit = os.path.split(oldpath) if os.path.exists(os.path.join(oldsplit[0], afterline)): - print("A file with that name already exists") + logging.error("A file with that name already exists") total_todo -= 1 continue if not afterline: - print("Rename Error") + logging.error("Rename Error") total_todo -= 1 continue if "." in afterline and not afterline.split(".")[0]: - print("A file does not have a target filename") + logging.error("A file does not have a target filename") total_todo -= 1 continue @@ -14880,9 +14881,9 @@ def render(self): albums = [pctl.g(default_playlist[s]).album for s in select] album_artists = [pctl.g(default_playlist[s]).album_artist for s in select] - # print(select) + #logging.info(select) if select != self.selected or pctl.active_playlist_viewing != self.playlist: - # print("reset") + #logging.info("reset") self.selected = select self.playlist = pctl.active_playlist_viewing edit_album.clear() @@ -15259,7 +15260,7 @@ def render(self): self.run_export(current, self.id, warnings=True) def run_export(self, current, id, warnings=True): - print("Export playlist") + logging.info("Export playlist") path = current["path"] if not os.path.isdir(path): if warnings: @@ -15636,14 +15637,14 @@ def move_playing_folder_to_stem(path, pl_id=None): if pctl.g(item).fullpath.startswith(artist_folder): insert = i - print("The folder to be moved is: " + move_folder) + logging.info("The folder to be moved is: " + move_folder) load_order = LoadClass() load_order.target = os.path.join(artist_folder, track.parent_folder_name) load_order.playlist = pl_id load_order.playlist_position = insert - print(artist_folder) - print(os.path.join(artist_folder, track.parent_folder_name)) + logging.info(artist_folder) + logging.info(os.path.join(artist_folder, track.parent_folder_name)) move_jobs.append((move_folder, os.path.join(artist_folder, track.parent_folder_name), True, track.parent_folder_name, load_order)) tm.ready("worker") @@ -15950,9 +15951,9 @@ def get_lyric_fire(track_object, silent=False): return t = lyrics_fetch_timer.get() - print("Lyric rate limit timer is: " + str(t) + " / -60") + logging.info("Lyric rate limit timer is: " + str(t) + " / -60") if t < -40: - print("Lets try again later") + logging.info("Lets try again later") if not silent: show_message(_("Let's be polite and try later.")) @@ -16024,11 +16025,11 @@ def get_lyric_wiki(track_object): shoot_dl.daemon = True shoot_dl.start() - print("..Done") + logging.info("..Done") def get_lyric_wiki_silent(track_object): - print("Searching for lyrics...") + logging.info("Searching for lyrics...") if track_object.artist == "" or track_object.title == "": return @@ -16037,7 +16038,7 @@ def get_lyric_wiki_silent(track_object): shoot_dl.daemon = True shoot_dl.start() - print("..Done") + logging.info("..Done") def test_auto_lyrics(track_object): @@ -16118,11 +16119,11 @@ def paste_lyrics_deco(): def paste_lyrics(track_object): if SDL_HasClipboardText(): clip = SDL_GetClipboardText() - # print(clip) + #logging.info(clip) track_object.lyrics = clip.decode('utf-8') else: - print('NO TEXT TO PASTE') + logging.warning('NO TEXT TO PASTE') def paste_chord_lyrics(track_object): @@ -16383,7 +16384,7 @@ def download_art1(tr): if 'musicbrainz_releasegroupid' not in tr.misc or 'musicbrainz_artistids' not in tr.misc or not tr.misc[ 'musicbrainz_artistids']: - print("MusicBrainz ID lookup...") + logging.info("MusicBrainz ID lookup...") artist = tr.album_artist if not tr.album: @@ -16396,16 +16397,16 @@ def download_art1(tr): album_id = s['release-group-list'][0]['id'] artist_id = s['release-group-list'][0]['artist-credit'][0]['artist']['id'] - print("Found release group ID: " + album_id) - print("Found artist ID: " + artist_id) + logging.info("Found release group ID: " + album_id) + logging.info("Found artist ID: " + artist_id) else: album_id = tr.misc['musicbrainz_releasegroupid'] artist_id = tr.misc['musicbrainz_artistids'][0] - print("Using tagged release group ID: " + album_id) - print("Using tagged artist ID: " + artist_id) + logging.info("Using tagged release group ID: " + album_id) + logging.info("Using tagged artist ID: " + artist_id) if prefs.enable_fanart_cover: try: @@ -16546,10 +16547,10 @@ def remove_embed_picture(track_object, dry=True): show_message(_("Removing vorbis image not implemented")) # try: # tag = mutagen.File(tr.fullpath).tags - # print(tag) + # logging.info(tag) # removed += 1 # except Exception: - # pass + # logging.exception("Failed to manipulate tags") if "FLAC" == tr.file_ext: try: @@ -16593,7 +16594,7 @@ def delete_file_image(track_object): os.remove(source) # clear_img_cache() clear_track_image_cache(track_object) - print("Deleted file: " + source) + logging.info("Deleted file: " + source) except Exception: logging.exception("Failed to delete file") show_message(_("Something went wrong"), mode='error') @@ -17098,7 +17099,7 @@ def clear_playlist(index): pctl.multi_playlist[index][7].clear() # clear import folder list if not pctl.multi_playlist[index][2]: - print("Playlist is already empty") + logging.info("Playlist is already empty") return li = [] @@ -17265,7 +17266,7 @@ def delete_playlist(index, force=False, check_lock=False): pctl.active_playlist_viewing = i break else: - # print("Lost the viewed playlist!") + # logging.info("Lost the viewed playlist!") # Try find the playing playlist and make it the viewed playlist for i, pl in enumerate(pctl.multi_playlist): if pl[6] == old_playing_id: @@ -17295,7 +17296,7 @@ def delete_playlist(index, force=False, check_lock=False): pctl.active_playlist_playing = i break else: - print("Lost the playing playlist!") + logging.info("Lost the playing playlist!") pctl.active_playlist_playing = pctl.active_playlist_viewing pctl.playlist_playing_position = -1 @@ -17833,7 +17834,7 @@ def year_sort(pl, custom_list=None): plt.append((album, date, artist + " " + get_object(playlist[p]).album)) p += len(album) - # print(album) + #logging.info(album) if plt: pl2 += year_s(plt) @@ -18097,8 +18098,8 @@ def is_source_type(code): code.startswith("sal") # - # print(cmds) - # print(quotes) + #logging.info(cmds) + #logging.info(quotes) pctl.regen_in_progress = True @@ -18558,7 +18559,7 @@ def rat_key(track_id): break if not found_name: - print("No genre search result found") + logging.warning("No genre search result found") continue search_over.clear() @@ -18590,7 +18591,7 @@ def rat_key(track_id): found_name = result[1] break else: - print("No artist search result found") + logging.warning("No artist search result found") continue search_over.clear() @@ -18675,14 +18676,14 @@ def rat_key(track_id): break else: for p in pctl.multi_playlist: - # print(p[0].lower()) - # print(pl_name.lower()) + #logging.info(p[0].lower()) + #logging.info(pl_name.lower()) if p[0].lower().startswith(pl_name.lower()): target = p[2] break if target is None: - print(f"not found: {pl_name}") - print("Target playlist not found") + logging.warning(f"not found: {pl_name}") + logging.warning("Target playlist not found") if cm.startswith("s\""): selections_searched += 1 errors = "playlist" @@ -18712,7 +18713,7 @@ def rat_key(track_id): reload() pctl.notify_change() - # print(cmds) + #logging.info(cmds) def make_auto_sorting(pl): @@ -18905,7 +18906,7 @@ def auto_sync_thread(pl): break if prefs.bypass_transcode or (prefs.smart_bypass and 0 < pctl.g(folder_dict[item][0]).bitrate <= 128): - print("Smart bypass...") + logging.info("Smart bypass...") source_parent = pctl.g(folder_dict[item][0]).parent_folder_path if os.path.exists(source_parent): @@ -19187,14 +19188,14 @@ def gen_folder_top(pl, get_sets=False, custom_list=None): sets.append(copy.deepcopy(se)) def best(folder): - # print(folder) + #logging.info(folder) total_star = 0 for item in folder: # key = pctl.master_library[item].title + pctl.master_library[item].filename # if key in pctl.star_library: # total_star += int(pctl.star_library[key]) total_star += int(star_store.get(item)) - # print(total_star) + #logging.info(total_star) return total_star if get_sets: @@ -19983,8 +19984,8 @@ def convert_folder(index): if item not in folder: folder.append(item) - # print(prefs.transcode_codec) - # print(track_object.file_ext) + #logging.info(prefs.transcode_codec) + #logging.info(track_object.file_ext) if prefs.transcode_codec == 'flac' and track_object.file_ext.lower() in ('mp3', 'opus', 'mp4', 'ogg', 'aac'): @@ -19993,7 +19994,7 @@ def convert_folder(index): return - # print(folder) + #logging.info(folder) transcode_list.append(folder) tm.ready("worker") @@ -20158,9 +20159,9 @@ def lightning_paste(): if (len(t_artist) > 0 and t_artist in level) or \ (len(ta_artist) > 0 and ta_artist in level): - print("found target artist level") - print(t_artist) - print("Upper folder is: " + upper) + logging.info("found target artist level") + logging.info(t_artist) + logging.info("Upper folder is: " + upper) if len(move_path) < 4: show_message(_("Safety interupt! The source path seems oddly short."), move_path, mode='error') @@ -20201,15 +20202,15 @@ def lightning_paste(): artist_folder = os.path.join(upper, artist) - print("Target will be: " + artist_folder) + logging.info("Target will be: " + artist_folder) if os.path.isdir(artist_folder): - print("The target artist folder already exists") + logging.info("The target artist folder already exists") else: - print("Need to make artist folder") + logging.info("Need to make artist folder") os.makedirs(artist_folder) - print("The folder to be moved is: " + move_path) + logging.info("The folder to be moved is: " + move_path) load_order = LoadClass() load_order.target = os.path.join(artist_folder, move_track.parent_folder_name) load_order.playlist = pctl.multi_playlist[pctl.active_playlist_viewing][6] @@ -20251,35 +20252,35 @@ def lightning_paste(): def paste(playlist_no=None, track_id=None): clip = copy_from_clipboard() - print(clip) + logging.info(clip) if "tidal.com/album/" in clip: - print(clip) + logging.info(clip) num = clip.split("/")[-1].split("?")[0] if num and num.isnumeric(): - print(num) + logging.info(num) tidal.append_album(num) clip = False elif "tidal.com/playlist/" in clip: - print(clip) + logging.info(clip) num = clip.split("/")[-1].split("?")[0] tidal.playlist(num) clip = False elif "tidal.com/mix/" in clip: - print(clip) + logging.info(clip) num = clip.split("/")[-1].split("?")[0] tidal.mix(num) clip = False elif "tidal.com/browse/track/" in clip: - print(clip) + logging.info(clip) num = clip.split("/")[-1].split("?")[0] tidal.track(num) clip = False elif "tidal.com/browse/artist/" in clip: - print(clip) + logging.info(clip) num = clip.split("/")[-1].split("?")[0] tidal.artist(num) clip = False @@ -20287,7 +20288,7 @@ def paste(playlist_no=None, track_id=None): elif "spotify" in clip: cargo.clear() for link in clip.split("\n"): - print(link) + logging.info(link) link = link.strip() if clip.startswith("https://open.spotify.com/track/") or clip.startswith("spotify:track:"): spot_ctl.append_track(link) @@ -20834,7 +20835,7 @@ def rename_parent(index, template): return old = track.parent_folder_path - # print(old) + #logging.info(old) new = parse_template2(template, track) @@ -20857,11 +20858,11 @@ def rename_parent(index, template): show_message(_("Woah, careful there!"), _("I don't think we should rename that folder."), mode='warning') return - print(track.parent_folder_path) + logging.info(track.parent_folder_path) re = os.path.dirname(track.parent_folder_path.rstrip("/\\")) - print(re) + logging.info(re) new_parent_path = os.path.join(re, new) - print(new_parent_path) + logging.info(new_parent_path) pre_state = 0 @@ -20905,7 +20906,7 @@ def rename_parent(index, template): if new_parent_path is not None: try: os.rename(old, new_parent_path) - print(new_parent_path) + logging.info(new_parent_path) except Exception: logging.exception("Rename failed, something went wrong!") show_message(_("Rename Failed!"), _("Something went wrong, sorry."), mode='error') @@ -21008,8 +21009,8 @@ def move_folder_up(index, do=False): search_string_cache.pop(object.index, None) search_dia_string_cache.pop(object.index, None) - print(object.fullpath) - print(object.parent_folder_path) + logging.info(object.fullpath) + logging.info(object.parent_folder_path) if pre_state == 1: pctl.revert() @@ -21040,13 +21041,13 @@ def clean_folder(index, do=False): found += 1 found += 1 if do: - print("Deleting Folder: " + os.path.join(folder, item)) + logging.info("Deleting Folder: " + os.path.join(folder, item)) shutil.rmtree(os.path.join(folder, item)) if do: for item in to_purge: if os.path.isfile(os.path.join(folder, item)): - print('Deleting File: ' + os.path.join(folder, item)) + logging.info('Deleting File: ' + os.path.join(folder, item)) os.remove(os.path.join(folder, item)) # clear_img_cache() @@ -21098,10 +21099,10 @@ def vacuum_playtimes(index): key = star_store.object_key(tr) value = [total_playtime, flags, 0] if key not in star_store.db: - print("Saving value") + logging.info("Saving value") star_store.db[key] = value else: - print("ERROR KEY ALREADY HERE?") + logging.error("ERROR KEY ALREADY HERE?") def reload_metadata(input, keep_star=True): @@ -21128,7 +21129,7 @@ def reload_metadata(input, keep_star=True): search_string_cache.pop(track.index, None) search_dia_string_cache.pop(track.index, None) - #print('Reloading Metadata for ' + track.filename) + #logging.info('Reloading Metadata for ' + track.filename) if keep_star: to_scan.append(track.index) else: @@ -21219,7 +21220,7 @@ def editor(index): else: if not os.path.isfile(prefs.tag_editor_target.strip('"')): - print(prefs.tag_editor_target) + logging.info(prefs.tag_editor_target) show_message(_("Application not found"), prefs.tag_editor_target, mode='info') return @@ -21258,12 +21259,12 @@ def editor(index): if pctl.master_library[track].fullpath == a: pctl.master_library[track].fullpath = b pctl.master_library[track].filename = os.path.basename(b) - print("External Edit: File rename detected.") - print(" Renaming: " + a) - print(" To: " + b) + logging.info("External Edit: File rename detected.") + logging.info(" Renaming: " + a) + logging.info(" To: " + b) break else: - print("External Edit: A file rename was detected but track was not found.") + logging.warning("External Edit: A file rename was detected but track was not found.") gui.message_box = False reload_metadata(obs, keep_star=False) @@ -21422,7 +21423,7 @@ def intel_moji(index): for cha in test: if cha in j_chars: detect = enc - print("This looks like Japanese: " + test) + logging.info("This looks like Japanese: " + test) break if detect is not None: break @@ -21433,7 +21434,7 @@ def intel_moji(index): for cha in test: if cha in j_chars: detect = enc - print("This looks like Japanese: " + test) + logging.info("This looks like Japanese: " + test) break if detect is not None: break @@ -21441,7 +21442,7 @@ def intel_moji(index): break if detect is not None: - print("Fix Mojibake: Detected encoding as: " + detect) + logging.info("Fix Mojibake: Detected encoding as: " + detect) for item in lot: track = pctl.master_library[item] # key = pctl.master_library[item].title + pctl.master_library[item].filename @@ -21642,7 +21643,7 @@ def add_to_spotify_library2(album_url): for i, p in enumerate(pctl.multi_playlist): code = pctl.gen_codes.get(p[6]) if code and code.startswith("sal"): - print("Fetching Spotify Library...") + logging.info("Fetching Spotify Library...") regenerate_playlist(i, silent=True) @@ -23116,7 +23117,7 @@ def import_popm(): star_store.set_rating(tr.index, t_rating) unique.add(tr.index) else: - print("Won't import POPM because track is already rated") + logging.info("Won't import POPM because track is already rated") skipped.add(tr.index) s = str(len(unique)) + " ratings imported" @@ -23450,7 +23451,7 @@ def toggle_spotify_like_active2(tr): for i, p in enumerate(pctl.multi_playlist): code = pctl.gen_codes.get(p[6]) if code and code.startswith("slt"): - print("Fetching Spotify likes...") + logging.info("Fetching Spotify likes...") regenerate_playlist(i, silent=True) gui.pl_update += 1 @@ -23954,11 +23955,11 @@ def get_album_art_url(tr): if not release_group_id: try: - #print("lookup release group id") + #logging.info("lookup release group id") s = musicbrainzngs.search_release_groups(tr.album, artist=artist, limit=1) release_group_id = s['release-group-list'][0]['id'] tr.misc['musicbrainz_releasegroupid'] = release_group_id - #print("got release group id") + #logging.info("got release group id") except Exception: logging.exception("Error lookup mbid for discord") pctl.album_mbid_release_group_cache[(artist, tr.album)] = None @@ -23985,7 +23986,7 @@ def get_album_art_url(tr): url = f"{base_url}{release_group_id}" try: - #print("lookup image url from release group") + #logging.info("lookup image url from release group") response = requests.get(url) response.raise_for_status() image_data = response.json() @@ -24027,7 +24028,7 @@ def get_album_art_url(tr): url = image["thumbnails"].get("small") if url: - print("got mb image url for discord") + logging.info("got mb image url for discord") pctl.mbid_image_url_cache[final_id] = url return url @@ -24044,12 +24045,12 @@ def discord_loop(): if not pctl.playing_ready(): return asyncio.set_event_loop(asyncio.new_event_loop()) - # print("Attempting to connect to Discord...") + # logging.info("Attempting to connect to Discord...") client_id = '954253873160286278' RPC = Presence(client_id) RPC.connect() - print("Discord RPC connection successful.") + logging.info("Discord RPC connection successful.") time.sleep(1) start_time = time.time() idle_time = Timer() @@ -24083,7 +24084,7 @@ def discord_loop(): break if current_state == 0 and idle_time.get() > 13: - print("Pause discord RPC...") + logging.info("Pause discord RPC...") gui.discord_status = "Idle" RPC.clear(pid) # RPC.close() @@ -24092,7 +24093,7 @@ def discord_loop(): if prefs.disconnect_discord: break if pctl.playing_state == 1: - print("Reconnect discord...") + logging.info("Reconnect discord...") RPC.connect() gui.discord_status = "Connected" break @@ -24132,8 +24133,8 @@ def discord_loop(): album += " " if state == 1: - # print("PLAYING: " + title) - # print(start_time) + #logging.info("PLAYING: " + title) + #logging.info(start_time) url = get_album_art_url(pctl.playing_object()) large_image = "tauon-standard" @@ -24149,7 +24150,7 @@ def discord_loop(): small_image=small_image,) else: - # print("Discord RPC - Stop") + #logging.info("Discord RPC - Stop") RPC.update(pid=pid, state="Idle", large_image="tauon-standard", ) @@ -24488,7 +24489,7 @@ def cue_scan(content, tn): content = content.replace("\r", "") content = content.split("\n") - # print(content) + #logging.info(content) global added @@ -25088,7 +25089,7 @@ def render(self): if self.force_select > -1: selected = self.force_select - # print(selected) + #logging.info(selected) if selected != p: fade = 0.8 @@ -25560,7 +25561,7 @@ def worker2(): if t < 1: time.sleep(1 - t) spot_search_rate_timer.set() - print("Spotify search") + logging.info("Spotify search") search_over.results.clear() results = spot_ctl.search(search_over.search_text.text) if results is not None: @@ -25636,7 +25637,7 @@ def worker2(): for playlist in pctl.multi_playlist: # if "<" in playlist[0]: - # # print("Skipping search on derivative playlist: " + playlist[0]) + # #logging.info("Skipping search on derivative playlist: " + playlist[0]) # continue for track in playlist[2]: @@ -25927,7 +25928,7 @@ def worker2(): temp_results[:] = [item for item in temp_results if item is not None] search_over.results = sorted(temp_results, key=lambda x: x[4], reverse=True) - # print(search_over.results) + #logging.info(search_over.results) i = 0 for playlist in pctl.multi_playlist: @@ -25940,7 +25941,7 @@ def worker2(): search_over.on = 0 search_over.force_select = 0 - # print(perf_timer.get()) + #logging.info(perf_timer.get()) def worker1(): @@ -26295,7 +26296,7 @@ def add_file(path, force_scan=False): target_dir = split[0] if prefs.extract_to_music and music_directory is not None: target_dir = os.path.join(music_directory, os.path.basename(target_dir)) - # print(os.path.getsize(path)) + #logging.info(os.path.getsize(path)) if os.path.getsize(path) > 4e+9: logging.warning("Archive file is large!") show_message(_("Skipping oversize zip file (>4GB)")) @@ -26338,7 +26339,7 @@ def add_file(path, force_scan=False): line = launch_prefix + "unrar x -y -p- " + shlex.quote(path) + " " + shlex.quote( target_dir) + os.sep result = subprocess.run(shlex.split(line)) - print(result) + logging.info(result) except Exception: logging.exception("Failed to extract rar archive.") to_got = b @@ -26354,7 +26355,7 @@ def add_file(path, force_scan=False): line = launch_prefix + "7z x -y " + shlex.quote(path) + " -o" + shlex.quote( target_dir) + os.sep result = subprocess.run(shlex.split(line)) - print(result) + logging.info(result) except Exception: logging.exception("Failed to extract 7z archive.") to_got = b @@ -26367,7 +26368,7 @@ def add_file(path, force_scan=False): new = upper + "/temporaryfolderd" error = False if len(cont) == 1 and os.path.isdir(split[0] + "/" + cont[0]): - print("one thing") + logging.info("one thing") os.rename(target_dir, new) try: shutil.move(new + "/" + cont[0], upper) @@ -26404,7 +26405,7 @@ def add_file(path, force_scan=False): de = loaded_pathes_cache[path] if pctl.master_library[de].fullpath in cue_list: - print("File has an associated .cue file... Skipping") + logging.info("File has an associated .cue file... Skipping") return if pctl.master_library[de].file_ext.lower() in GME_Formats: @@ -26542,7 +26543,7 @@ def cache_paths(): return dic, dic2 - # print(pctl.master_library) + #logging.info(pctl.master_library) global transcode_list global transcode_state @@ -26758,7 +26759,7 @@ def cache_paths(): folder_name = ref_track_object.parent_folder_name break - print("Transcoding folder: " + folder_name) + logging.info("Transcoding folder: " + folder_name) # Remove any existing matching folder if os.path.isdir(prefs.encoder_output + folder_name): @@ -26823,7 +26824,7 @@ def cache_paths(): else: album_art_gen.save_thumb(pctl.g(folder_items[0]), (1080, 1080), output_dir + "cover") - # print(transcode_list[0]) + #logging.info(transcode_list[0]) del transcode_list[0] transcode_state = "" @@ -26894,7 +26895,7 @@ def cache_paths(): break loaderCommand = LC_Done - # print("LOAD ORDER") + #logging.info("LOAD ORDER") order.tracks = added # Double check for cue dupes @@ -26906,7 +26907,7 @@ def cache_paths(): added = [] order.stage = 2 loaderCommandReady = False - # print("DONE LOADING") + #logging.info("DONE LOADING") break @@ -27077,7 +27078,7 @@ def key(tag): break if noise > len(album_dex) / 2: - # print("Playlist is too noisy for power bar.") + #logging.info("Playlist is too noisy for power bar.") return [] tag_list_sort = sorted(tag_list, key=key, reverse=True) @@ -28119,7 +28120,7 @@ def rg(self, x0, y0, w0, h0): if prefs.replay_preamp == 0: colour = colours.box_text_label ddt.text((x + sw + round(14 * gui.scale), y - round(8 * gui.scale)), text, colour, 11) - # print(prefs.replay_preamp) + #logging.info(prefs.replay_preamp) y += round(18 * gui.scale) ddt.text((x, y, 4, 310 * gui.scale, 300 * gui.scale), @@ -29603,7 +29604,7 @@ def get_friend_love(self): return if not lastfm.scanning_friends and not lastfm.scanning_scrobbles and not lastfm.scanning_loves: - print("Launch friend love thread") + logging.info("Launch friend love thread") shoot_dl = threading.Thread(target=lastfm.get_friends_love) shoot_dl.daemon = True shoot_dl.start() @@ -30854,7 +30855,7 @@ def test(self): return True self.last_id = self.id - # print(len(self.id)) + #logging.info(len(self.id)) self.id = [] for f in self.field_array: @@ -31159,7 +31160,7 @@ def render(self): gui.update_on_drag = True # List all tabs eligible to be shown - # print("-------------") + #logging.info("-------------") ready_tabs = [] show_tabs = [] @@ -31235,8 +31236,8 @@ def render(self): break # for tab in show_tabs: - # print(pctl.multi_playlist[tab][0]) - # print("---") + # logging.info(pctl.multi_playlist[tab][0]) + #logging.info("---") left_overflow = [x for x in left_tabs if x not in show_tabs] right_overflow = [x for x in right_tabs if x not in show_tabs] self.shown_tabs = show_tabs @@ -32075,7 +32076,7 @@ def render(self): seek = bargetX / self.seek_bar_size[0] pctl.seek_decimal(seek) - # print(seek) + #logging.info(seek) self.seek_time = pctl.playing_time @@ -33896,7 +33897,7 @@ def set_mini_mode(): def restore_full_mode(): - print("RESTORE FULL") + logging.info("RESTORE FULL") i_y = pointer(c_int(0)) i_x = pointer(c_int(0)) SDL_GetWindowPosition(t_window, i_x, i_y) @@ -33938,7 +33939,7 @@ def restore_full_mode(): logical_size[0] = i_x.contents.value logical_size[1] = i_y.contents.value - # print(window_size) + #logging.info(window_size) SDL_PumpEvents() SDL_GL_GetDrawableSize(t_window, i_x, i_y) @@ -34887,12 +34888,12 @@ def full_render(self): (highlight_width, gui.playlist_row_height), colours.row_select_highlight) - # print(d_date) # date of album release / release year - # print(tr.parent_folder_name) # folder name - # print(tr.album) - # print(tr.artist) - # print(tr.album_artist) - # print(tr.genre) + #logging.info(d_date) # date of album release / release year + #logging.info(tr.parent_folder_name) # folder name + #logging.info(tr.album) + #logging.info(tr.artist) + #logging.info(tr.album_artist) + #logging.info(tr.genre) @@ -35333,7 +35334,7 @@ def full_render(self): max_w=wid) if ddt.was_truncated: - # print(text) + #logging.info(text) rect = (run, y, wid - 1, gui.playlist_row_height - 1) gui.heart_fields.append(rect) @@ -35843,7 +35844,7 @@ def start2(self, url): self.load_failed = True self.load_connecting = False gui.update += 1 - print("Start radio failed") + logging.error("Starting radio failed") # show_message(_("Failed to establish a connection"), mode="error") return @@ -35873,18 +35874,18 @@ def start2(self, url): if url == "https://listen.moe/stream": wss = "wss://listen.moe/gateway_v2" if wss: - print("Connecting to Listen.moe") + logging.info("Connecting to Listen.moe") import websocket import _thread as th def send_heartbeat(ws): - # print(self.ws_interval) + #logging.info(self.ws_interval) time.sleep(self.ws_interval) ws.send("{\"op\":9}") - print("Send heatbeat") + logging.info("Send heatbeat") def on_message(ws, message): - print(message) + logging.info(message) d = json.loads(message) if d["op"] == 10: shoot = threading.Thread(target=send_heartbeat, args=[ws]) @@ -35914,9 +35915,9 @@ def on_message(ws, message): filename = d["d"]["song"]["albums"][0]["image"] fulllink = "https://cdn.listen.moe/covers/" + filename - # print(fulllink) + #logging.info(fulllink) art_response = requests.get(fulllink) - # print(art_response.status_code) + #logging.info(art_response.status_code) if art_response.status_code == 200: if pctl.radio_image_bin: @@ -35952,12 +35953,12 @@ def run(*args): # ws.send("{\"op\":9}") # time.sleep(10) # ws.close() - # print("thread terminating...") + #logging.info("thread terminating...") th.start_new_thread(run, ()) # websocket.enableTrace(True) - # print(wss) + #logging.info(wss) ws = websocket.WebSocketApp(wss, on_message=on_message, on_error=on_error) @@ -36142,7 +36143,7 @@ def parse_data(self, data): for station in data: radio = {} - # print(station) + #logging.info(station) radio["title"] = station["name"] radio["stream_url_unresolved"] = station["url"] radio["stream_url"] = station["url_resolved"] @@ -37234,7 +37235,7 @@ def create_artist_pl(artist, replace=False): tr = pctl.playing_object() if new is not None and tr and pctl.active_playlist_playing == this_pl: if tr.index not in pctl.multi_playlist[this_pl][2] and tr.index in pctl.multi_playlist[source_pl][2]: - print("Transfer back playing") + logging.info("Transfer back playing") pctl.active_playlist_playing = source_pl pctl.playlist_playing_position = pctl.multi_playlist[source_pl][2].index(tr.index) @@ -37309,7 +37310,7 @@ def verify_discogs(): def save_discogs_artist_thumb(artist, filepath): - print("Searching discogs for artist image...") + logging.info("Searching discogs for artist image...") # Make artist name url safe artist = artist.replace("/", "").replace("\\", "").replace(":", "") @@ -37333,7 +37334,7 @@ def save_discogs_artist_thumb(artist, filepath): # Find a square image in list of images for image in images: if image['height'] == image['width']: - print("Found square") + logging.info("Found square") url = image['uri'] break else: @@ -37359,15 +37360,15 @@ def save_discogs_artist_thumb(artist, filepath): im = im.crop((left, upper, right, lower)) im.save(filepath, 'JPEG', quality=90) im.close() - print("Found artist image from Discogs") + logging.info("Found artist image from Discogs") def save_fanart_artist_thumb(mbid, filepath, preview=False): - print("Searching fanart.tv for image...") - # print("mbid is " + mbid) + logging.info("Searching fanart.tv for image...") + #logging.info("mbid is " + mbid) r = requests.get("http://webservice.fanart.tv/v3/music/" \ + mbid + "?api_key=" + prefs.fatvap, timeout=5) - # print(r.json()) + #logging.info(r.json()) thumblink = r.json()['artistthumb'][0]['url'] if preview: thumblink = thumblink.replace("/fanart/music", "/preview/music") @@ -37959,7 +37960,7 @@ def draw_card(self, artist, x, y, w): blocks.append(current_block) current_block = [] - # print(blocks) + #logging.info(blocks) # return # block_starts = [] @@ -37977,7 +37978,7 @@ def draw_card(self, artist, x, y, w): # current = False # # if not block_starts: - # print("No matching artists found in playlist") + # logging.info("No matching artists found in playlist") # return if not blocks: @@ -38015,7 +38016,7 @@ def draw_card(self, artist, x, y, w): next = False track = pctl.sg(c, -1) if track is None: - print("Index out of range!") + logging.error("Index out of range!") pctl.selected_in_playlist = 0 return if track.artist.casefold != artist.casefold: @@ -38684,7 +38685,7 @@ def render(self, x, y, w, h): playlist_hold = True self.dragging_name = self.click_drag_source[0] - print(self.dragging_name) + logging.info(self.dragging_name) if "/" in self.dragging_name: self.dragging_name = os.path.basename(self.dragging_name) @@ -38870,7 +38871,7 @@ def make_as_playlist(self): pl = id_to_pl(item[2]) if pl is None: - print("Lost the target playlist") + logging.info("Lost the target playlist") continue pp = pctl.multi_playlist[pl][2] @@ -39775,7 +39776,7 @@ def __init__(self): def load(self, path, box_size=None): if not os.path.isfile(path): - print("NO PICTURE FILE TO LOAD") + logging.warning("NO PICTURE FILE TO LOAD") return g = io.BytesIO() @@ -39788,7 +39789,7 @@ def load(self, path, box_size=None): im.save(g, 'BMP') g.seek(0) self.image_data = g - print("Save BMP to memory") + logging.info("Save BMP to memory") self.size = im.size[0], im.size[1] def draw(self, x, y): @@ -39801,7 +39802,7 @@ def draw(self, x, y): SDL_DestroyTexture(self.texture) # Convert raw image to sdl texture - # print("Create Texture") + #logging.info("Create Texture") wop = rw_from_object(self.image_data) s_image = IMG_Load_RW(wop, 0) self.texture = SDL_CreateTextureFromSurface(renderer, s_image) @@ -40169,17 +40170,17 @@ def get_data(self, artist, get_img_path=False, force_dl=False): # if cover_link and 'http' in cover_link: # # Fetch cover_link # try: - # # print("Fetching artist image...") + # #logging.info("Fetching artist image...") # response = urllib.request.urlopen(cover_link) # info = response.info() - # # print("got response") + # #logging.info("got response") # if info.get_content_maintype() == 'image': # # f = open(filepath, 'wb') # f.write(response.read()) # f.close() # - # # print("written file, now loading...") + # #logging.info("written file, now loading...") # # artist_picture_render.load(filepath, round(gui.artist_panel_height - 20 * gui.scale)) # artist_picture_render.show = True @@ -40457,7 +40458,7 @@ def parse(self, lines): final.append(("".join(lyrics), chords)) - print(final) + logging.info(final) self.data = final def get_cache_title(self, track): @@ -40573,7 +40574,7 @@ def loader(self): if src: pass - # print("found cached") + #logging.info("found cached") elif station.get("icon") and station["icon"] not in prefs.radio_thumb_bans: try: r = requests.get(station.get("icon"), headers={'User-Agent': t_agent}, timeout=5, stream=True) @@ -40718,7 +40719,7 @@ def render(self): # box = min(window_size[0] // 2, box) bg = colours.playlist_panel_background ddt.rect((0, gui.panelY, window_size[0], window_size[1] - gui.panelY), bg) - # print(prefs.radio_urls) + #logging.info(prefs.radio_urls) # Add station button x = window_size[0] - round(60 * gui.scale) @@ -41591,7 +41592,7 @@ def render(self): # low = (0, 0.5, 0) # ---- - # print(hls_to_rgb(.55, .6, .75)) + #logging.info(hls_to_rgb(.55, .6, .75)) high = [76, 183, 229, 255] # (.55, .6, .75) if colours.lm: # high = (.55, .75, .75) @@ -41761,12 +41762,12 @@ def scan(self): if min_age < 240 and os.path.isfile(path) and ext in Archive_Formats: size = os.path.getsize(path) - # print("Check: " + path) + #logging.info("Check: " + path) if path in self.watching: # Check if size is stable, then scan for audio files - # print("watching...") + #logging.info("watching...") if size == self.watching[path] and size != 0: - # print("scan") + #logging.info("scan") del self.watching[path] # Check if folder to extract to exists @@ -41777,22 +41778,22 @@ def scan(self): if os.path.exists(target_dir): pass - # print("Target folder for archive already exists") + #logging.info("Target folder for archive already exists") elif archive_file_scan(path, DA_Formats, launch_prefix) >= 0.4: self.ready.add(path) gui.update += 1 - # print("Archive detected as music") + #logging.info("Archive detected as music") else: pass - # print("Archive rejected as music") + #logging.info("Archive rejected as music") self.done.add(path) else: - # print("update.") + #logging.info("update.") self.watching[path] = size else: self.watching[path] = size - # print("add.") + #logging.info("add.") elif min_age < 60 and os.path.isdir( path) and path not in quick_import_done and "encode-output" not in path: @@ -41834,14 +41835,14 @@ def scan(self): if len(self.ready) > 0: temp = set() - # print(quick_import_done) - # print(self.ready) + #logging.info(quick_import_done) + #logging.info(self.ready) for item in self.ready: if item not in quick_import_done: if os.path.exists(path): temp.add(item) # else: - # print("FILE IMPORTED") + # logging.info("FILE IMPORTED") self.ready = temp if len(self.watching) > 0: @@ -42292,11 +42293,11 @@ def check_playback_running(self): sv = SDL_version() SDL_GetVersion(sv) sdl_version = sv.major * 100 + sv.minor * 10 + sv.patch -print("Using SDL version: " + str(sv.major) + "." + str(sv.minor) + "." + str(sv.patch)) +logging.info("Using SDL version: " + str(sv.major) + "." + str(sv.minor) + "." + str(sv.patch)) # C-ML # if prefs.backend == 2: -# print("Using GStreamer as fallback. Some functions disabled") +# logging.warning("Using GStreamer as fallback. Some functions disabled") if prefs.backend == 0: show_message(_("ERROR: No backend found"), mode='error') @@ -42329,13 +42330,13 @@ def undo(self): switch_playlist(i) break else: - print("No matching playlist ID to restore tracks to") + logging.info("No matching playlist ID to restore tracks to") return for i, ref in reversed(li): if i > len(pl): - print("restore track error - playlist not correct length") + logging.error("restore track error - playlist not correct length") continue pl.insert(i, ref) @@ -42412,7 +42413,7 @@ def update_layout_do(): gui.reload_theme = True global theme theme = get_theme_number(prefs.theme_name) - # print("Config reload theme...") + #logging.info("Config reload theme...") # Restore in case of error if gui.rspw < 30 * gui.scale: @@ -42524,12 +42525,12 @@ def update_layout_do(): # prefs.art_bg_blur = 15 # # if w / h == 16 / 9: - # print("YEP") + # logging.info("YEP") # elif w / h < 16 / 9: - # print("too low") + # logging.info("too low") # else: - # print("too high") - # print((w, h)) + # logging.info("too high") + #logging.info((w, h)) # input.mouse_click = False @@ -42678,7 +42679,7 @@ def update_layout_do(): gui.art_max_ratio_lock = gui.art_aspect_ratio - # print("Avaliabe: " + str(box_r)) + #logging.info("Avaliabe: " + str(box_r)) elif box_r <= 1: gui.art_unlock_ratio = False gui.art_max_ratio_lock = 1 @@ -43273,8 +43274,8 @@ def is_level_zero(include_menus=True): ww = test_width if ww > item.sub_menu_width: - # print("extend") - # print(item) + #logging.info("extend") + #logging.info(item) item.sub_menu_width = ww if w > menu.w: @@ -43307,9 +43308,9 @@ def drop_file(target): i_y = i_y.contents.value / logical_size[0] * window_size[0] i_x = i_x.contents.value / logical_size[0] * window_size[0] - # print((i_x, i_y)) + #logging.info((i_x, i_y)) gui.drop_playlist_target = 0 - # print(event.drop) + #logging.info(event.drop) if i_y < gui.panelY and not new_playlist_cooldown and gui.mode == 1: x = top_panel.tabs_left_x @@ -43321,12 +43322,12 @@ def drop_file(target): tab_pulse.pulse() gui.update += 1 gui.pl_pulse = True - print("Direct drop") + logging.info("Direct drop") break x += wid else: - print("MISS") + logging.info("MISS") if new_playlist_cooldown: gui.drop_playlist_target = pctl.active_playlist_viewing else: @@ -43346,7 +43347,7 @@ def drop_file(target): tab_pulse.pulse() gui.update += 1 gui.pl_pulse = True - print("Direct drop") + logging.info("Direct drop") break y += playlist_box.tab_h + playlist_box.gap else: @@ -43379,7 +43380,7 @@ def drop_file(target): load_order.playlist = pctl.multi_playlist[gui.drop_playlist_target][6] load_orders.append(copy.deepcopy(load_order)) - # print('dropped: ' + str(dropped_file)) + #logging.info('dropped: ' + str(dropped_file)) gui.update += 1 mouse_down = False drag_mode = False @@ -43496,7 +43497,7 @@ def drop_file(target): while SDL_PollEvent(ctypes.byref(event)) != 0: # if event.type == SDL_SYSWMEVENT: - # print(event.syswm.msg.contents) # Not implemented by pysdl2 + # logging.info(event.syswm.msg.contents) # Not implemented by pysdl2 if event.type == SDL_CONTROLLERDEVICEADDED and prefs.use_gamepad: if SDL_IsGameController(event.cdevice.which): @@ -43614,7 +43615,7 @@ def drop_file(target): power += 5 link = event.drop.file.decode() - # print(link) + #logging.info(link) if pctl.playing_ready() and link.startswith('http'): if system != 'windows' and sdl_version >= 204: @@ -43639,8 +43640,8 @@ def drop_file(target): i_x = i_x.contents.value / logical_size[0] * window_size[0] if coll_point((i_x, i_y), gui.main_art_box): - print('Drop picture...') - # print(link) + logging.info('Drop picture...') + #logging.info(link) gui.image_downloading = True track = pctl.playing_object() target_dir = track.parent_folder_path @@ -43661,10 +43662,10 @@ def drop_file(target): power += 5 dropped_file_sdl = event.drop.file - # print(dropped_file_sdl) + #logging.info(dropped_file_sdl) target = str(urllib.parse.unquote(dropped_file_sdl.decode("utf-8", errors='surrogateescape'))).replace("file:///", "/").replace("\r", "") - # print(target) + #logging.info(target) drop_file(target) @@ -43682,9 +43683,9 @@ def drop_file(target): break elif event.type == SDL_TEXTEDITING: power += 5 - # print("edit text") + #logging.info("edit text") editline = event.edit.text - # print(editline) + #logging.info(editline) editline = editline.decode("utf-8", 'ignore') k_input = True gui.update += 1 @@ -43709,9 +43710,9 @@ def drop_file(target): if event.button.button == SDL_BUTTON_RIGHT: right_click = True right_down = True - # print("RIGHT DOWN") + #logging.info("RIGHT DOWN") elif event.button.button == SDL_BUTTON_LEFT: - # print("LEFT DOWN") + #logging.info("LEFT DOWN") # if mouse_position[1] > 1 and mouse_position[0] > 1: # mouse_down = True @@ -43847,7 +43848,7 @@ def drop_file(target): input_text += event.text.text.decode('utf-8') gui.update += 1 - # print(input_text) + #logging.info(input_text) elif event.type == SDL_MOUSEWHEEL: k_input = True @@ -43857,10 +43858,10 @@ def drop_file(target): elif event.type == SDL_WINDOWEVENT: power += 5 - # print(event.window.event) + #logging.info(event.window.event) if event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED: - #print("SDL_WINDOWEVENT_FOCUS_GAINED") + #logging.info("SDL_WINDOWEVENT_FOCUS_GAINED") if system == "linux" and not macos and not msys: gnome.focus() @@ -43882,7 +43883,7 @@ def drop_file(target): elif event.window.event == SDL_WINDOWEVENT_RESIZED or event.window.event == SDL_WINDOWEVENT_DISPLAY_CHANGED: if event.window.data1 < 500: - print("Grrr why this happen, stupid bug - reproducible when moving window from one screen to another in Plasma") + logging.error("Grrr why this happen, stupid bug - reproducible when moving window from one screen to another in Plasma") SDL_SetWindowSize(t_window, logical_size[0], logical_size[1]) elif restore_ignore_timer.get() > 1 or event.window.event == SDL_WINDOWEVENT_DISPLAY_CHANGED: # Hacky gui.update = 2 @@ -43905,7 +43906,7 @@ def drop_file(target): elif event.window.event == SDL_WINDOWEVENT_ENTER: - # print("ENTER") + #logging.info("ENTER") mouse_enter_window = True gui.mouse_in_window = True gui.update += 1 @@ -43913,7 +43914,7 @@ def drop_file(target): # elif event.window.event == SDL_WINDOWEVENT_HIDDEN: # elif event.window.event == SDL_WINDOWEVENT_EXPOSED: - # print("expose") + #logging.info("expose") gui.lowered = False elif event.window.event == SDL_WINDOWEVENT_MINIMIZED: @@ -43931,7 +43932,7 @@ def drop_file(target): if update_title: update_title_do() - # print("restore") + #logging.info("restore") elif event.window.event == SDL_WINDOWEVENT_SHOWN: focused = True @@ -43939,7 +43940,7 @@ def drop_file(target): gui.update += 1 # elif event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED: - # print("FOCUS GAINED") + # logging.info("FOCUS GAINED") # # input.mouse_enter_event = True # # gui.update += 1 # # k_input = True @@ -43962,7 +43963,7 @@ def drop_file(target): if gui.request_raise: gui.request_raise = False - print("Raise") + logging.info("Raise") SDL_ShowWindow(t_window) SDL_RestoreWindow(t_window) SDL_RaiseWindow(t_window) @@ -44073,17 +44074,17 @@ def drop_file(target): dl_mon.scan() if mouse_down and not coll((2, 2, window_size[0] - 4, window_size[1] - 4)): - # print(SDL_GetMouseState(None, None)) + #logging.info(SDL_GetMouseState(None, None)) if SDL_GetGlobalMouseState(None, None) == 0: mouse_down = False mouse_up = True quick_drag = False - # print(window_size) + #logging.info(window_size) # if window_size[0] / window_size[1] == 16 / 9: - # print('OK') + # logging.info('OK') # if window_size[0] / window_size[1] > 16 / 9: - # print("A") + # logging.info("A") if key_meta: input_text = "" @@ -44379,7 +44380,7 @@ def drop_file(target): tauon.copied_track = None gui.pl_update += 1 - print("Transferred track stats!") + logging.info("Transferred track stats!") elif tauon.copied_track is None: show_message(_("First select a source track by copying it into clipboard")) @@ -44868,7 +44869,7 @@ def drop_file(target): if theme == 0: gui.theme_name = "Mindaro" - print("Applying default theme: Mindaro") + logging.info("Applying default theme: Mindaro") colours.lm = False colours.__init__() colours.post_config() @@ -44876,14 +44877,14 @@ def drop_file(target): prefs.theme_name = gui.theme_name - # print("Theme number: " + str(theme)) + #logging.info("Theme number: " + str(theme)) gui.reload_theme = False ddt.text_background_colour = colours.playlist_panel_background # --------------------------------------------------------------------------------------------------------- # GUI DRAWING------ - # print(gui.update) - # print(gui.lowered) + #logging.info(gui.update) + #logging.info(gui.lowered) if gui.mode == 3: gui.pl_update = 0 @@ -44895,7 +44896,7 @@ def drop_file(target): gui.update = 2 if reset_render: - print("Reset render targets!") + logging.info("Reset render targets!") clear_img_cache(delete_disk=False) ddt.clear_text_cache() for item in WhiteModImageAsset.assets: @@ -44953,7 +44954,7 @@ def drop_file(target): elif ggc == 1: ggc = 0 gbc.enable() - # print("Enabling garbage collecting") + #logging.info("Enabling garbage collecting") if gui.mode == 4: launch.render() @@ -45114,7 +45115,7 @@ def drop_file(target): row_len = int((area_x - album_h_gap) / (album_mode_art_size + album_h_gap)) - # print(row_len) + #logging.info(row_len) compact = 40 * gui.scale a_offset = 7 * gui.scale @@ -45915,7 +45916,7 @@ def drop_file(target): break else: del load_orders[i] - print("Error: Target playlist lost") + logging.error("Target playlist lost") break if order.replace_stem: @@ -45927,9 +45928,9 @@ def drop_file(target): len(order.target.rstrip("/\\"))] in ("/", "\\")): del pctl.multi_playlist[target_pl][2][ii] - # print(order.tracks) + #logging.info(order.tracks) if order.playlist_position is not None: - # print(order.playlist_position) + #logging.info(order.playlist_position) pctl.multi_playlist[target_pl][2][ order.playlist_position:order.playlist_position] = order.tracks # else: @@ -45985,7 +45986,7 @@ def drop_file(target): if pctl.multi_playlist[target_pl][9]: show_message(_("Auto sort skipped because playlist is locked.")) else: - print("Auto sorting") + logging.info("Auto sorting") standard_sort(target_pl) year_sort(target_pl) @@ -46095,7 +46096,7 @@ def drop_file(target): gui.pl_update = 1 gui.set_label_hold = -1 - # print("MOVE") + #logging.info("MOVE") break gui.set_label_hold = -1 @@ -46135,7 +46136,7 @@ def drop_file(target): if not mouse_down: gui.set_label_hold = -1 - # print(in_grip) + #logging.info(in_grip) if gui.set_label_hold == -1: if in_grip and not x_menu.active and not view_menu.active and not tab_menu.active and not set_menu.active: gui.cursor_want = 1 @@ -46673,7 +46674,7 @@ def drop_file(target): pctl.playlist_view_position = 0 # if playlist_position == len(default_playlist): - # print("END") + # logging.info("END") # elif mouse_position[1] < sbp: # pctl.playlist_view_position -= 2 @@ -47118,7 +47119,7 @@ def drop_file(target): x -= int(170 * gui.scale) y1 += int(15 * gui.scale) - # print(tc.size) + #logging.info(tc.size) if tc.is_cue and tc.misc.get("parent-length", 0) > 0 and tc.misc.get("parent-size", 0) > 0: ddt.text((x1, y1), _("File size"), key_colour_off, 212, max_w=70 * gui.scale) estimate = (tc.length / tc.misc.get("parent-length")) * tc.misc.get("parent-size") diff --git a/src/tauon/t_modules/t_phazor.py b/src/tauon/t_modules/t_phazor.py index ef3b2228f..add2bf1da 100644 --- a/src/tauon/t_modules/t_phazor.py +++ b/src/tauon/t_modules/t_phazor.py @@ -952,8 +952,8 @@ def start_librespot() -> None: pctl.playerCommandReady = False except Exception: - #tauon.spot_ctl.preparing_spotify = False logging.exception("Failed to start Spotify track") + #tauon.spot_ctl.preparing_spotify = False pctl.playerCommand = "stop" pctl.playerCommandReady = True continue diff --git a/src/tauon/t_modules/t_spot.py b/src/tauon/t_modules/t_spot.py index be4605aa2..d9f8817e5 100644 --- a/src/tauon/t_modules/t_spot.py +++ b/src/tauon/t_modules/t_spot.py @@ -96,7 +96,7 @@ def connect(self) -> None: if self.token is None: self.load_token() if self.token: - print("Init spotify support") + logging.info("Init spotify support") self.sender = tk.RetryingSender(retries=3) self.spotify = tk.Spotify(self.token, sender=self.sender) self.country = self.spotify.current_user().country @@ -212,7 +212,7 @@ def control(self, command: str, param: int | None = None) -> None: except Exception as e: logging.exception("Control failure") - #print(repr(e)) + #logging.info(repr(e)) if "No active device found" in repr(e): try: tr = self.tauon.pctl.playing_object() @@ -628,7 +628,7 @@ def play_target(self, id: int, force_new_device: bool = False, start_time: int = self.tauon.gui.update += 1 elif not done: - #print(d_id) + #logging.info(d_id) logging.info("A ready device is present...") try: self.progress_timer.set() @@ -636,7 +636,7 @@ def play_target(self, id: int, force_new_device: bool = False, start_time: int = # Check conditions for a proper transition if self.playing: - #print("already playing") + #logging.info("already playing") result = self.spotify.playback_currently_playing() if result and result.item and result.is_playing: remain = result.item.duration_ms - result.progress_ms @@ -776,7 +776,7 @@ def playlist(self, url: str, return_list: bool = False, silent: bool = False) -> id = url if len(id) != 22: - print("ID Error") + logging.error("ID Error") if return_list: return [] return None @@ -915,7 +915,7 @@ def load_album(self, album: str, playlist: list[int] | None): id = album.id parent = (album_artist + " - " + album_name).strip("- ") - # print(a.release_date, a.name) + # logging.info(a.release_date, a.name) for track in album.tracks.items: pr = None @@ -1121,12 +1121,12 @@ def monitor(self) -> None: p = result.progress_ms if p is not None: #if abs(self.tauon.pctl.playing_time - (p / 1000)) > 0.4: - # print("DESYNC") - # print(abs(self.tauon.pctl.playing_time - (p / 1000))) + # logging.info("DESYNC") + # logging.info(abs(self.tauon.pctl.playing_time - (p / 1000))) self.tauon.pctl.playing_time = p / 1000 self.tauon.pctl.decode_time = self.tauon.pctl.playing_time # else: - # print("SYNCED") + # logging.info("SYNCED") def update(self, start: bool = False) -> None: diff --git a/src/tauon/t_modules/t_stream.py b/src/tauon/t_modules/t_stream.py index cb11ed71f..1f6a46437 100644 --- a/src/tauon/t_modules/t_stream.py +++ b/src/tauon/t_modules/t_stream.py @@ -404,7 +404,6 @@ def save_track(): except Exception: logging.exception("Encoder thread crashed!") - #raise self.encode_running = False return diff --git a/src/tauon/t_modules/t_themeload.py b/src/tauon/t_modules/t_themeload.py index 16ec14620..fedbf4d2c 100644 --- a/src/tauon/t_modules/t_themeload.py +++ b/src/tauon/t_modules/t_themeload.py @@ -21,6 +21,7 @@ import base64 import io import json +import logging import os from typing import TYPE_CHECKING @@ -363,7 +364,7 @@ def load(self, name: str) -> None: decos = self.get_themes(deco=True) if name not in decos: - print("Missing deco file") + logging.error("Missing deco file") return target = decos[name] diff --git a/src/tauon/t_modules/t_tidal.py b/src/tauon/t_modules/t_tidal.py index 72c9ab654..738e20d54 100644 --- a/src/tauon/t_modules/t_tidal.py +++ b/src/tauon/t_modules/t_tidal.py @@ -354,7 +354,7 @@ def append_album(self, id: int) -> None: tracks = album.tracks() for track in tracks: - print("{}: '{}' by '{}'".format(track.id, track.name, track.artist.name)) + logging.info("{}: '{}' by '{}'".format(track.id, track.name, track.artist.name)) nt = self.new_track(track) self.tauon.pctl.multi_playlist[self.tauon.pctl.active_playlist_viewing][2].append(nt.index) diff --git a/src/tauon/t_modules/t_webserve.py b/src/tauon/t_modules/t_webserve.py index a82331391..817b32c25 100644 --- a/src/tauon/t_modules/t_webserve.py +++ b/src/tauon/t_modules/t_webserve.py @@ -195,7 +195,6 @@ def do_GET(self) -> None: data = {"image_data": base64} except Exception: logging.exception("No image data") - #raise data = {"image_data": "None"} lyrics = tauon.synced_to_static_lyrics.get(track) From aab878d27d54b42fc19d190b3bdeb6f141da0a26 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 17:53:38 +0100 Subject: [PATCH 48/63] t_main: Move input.txt template to templates directory --- pyproject.toml | 2 +- src/tauon/t_modules/t_main.py | 12 +++++------- src/tauon/{ => templates}/input.txt | 0 3 files changed, 6 insertions(+), 8 deletions(-) rename src/tauon/{ => templates}/input.txt (100%) diff --git a/pyproject.toml b/pyproject.toml index 005ae0cfc..56b4541b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ dependencies = {file = "requirements.txt"} [tool.setuptools.package-data] -"tauon" = ["assets/*", "templates/*", "theme/*", "input.txt"] +"tauon" = ["assets/*", "templates/*", "theme/*"] # https://github.com/microsoft/pyright/blob/main/docs/configuration.md#pyright-configuration [tool.pyright] diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 3741d5967..eb621aee9 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -834,13 +834,11 @@ def asset_loader(name: str, mod: bool = False) -> WhiteModImageAsset | LoadImage # loading_image.render(window_size[0] // 2 - loading_image.w // 2, window_size[1] // 2 - loading_image.h // 2) # SDL_RenderPresent(renderer) -# if install_directory != config_directory and not os.path.isfile(os.path.join(config_directory, "config.txt")): -# logging.info("Config file is missing... copying template from program files") -# shutil.copy(os.path.join(install_directory, "config.txt"), config_directory) - -if install_directory != config_directory and not os.path.isfile(os.path.join(config_directory, "input.txt")): - logging.info("Input config file is missing... copying template from program files") - shutil.copy(os.path.join(install_directory, "input.txt"), config_directory) +if install_directory != config_directory and not Path(Path(config_directory) / "input.txt").is_file(): + logging.warning("Input config file is missing, first run? Copying input.txt template from templates directory") + #logging.warning(install_directory) + #logging.warning(config_directory) + shutil.copy(Path(install_directory) / "templates" / "input.txt", config_directory) last_fm_enable = False diff --git a/src/tauon/input.txt b/src/tauon/templates/input.txt similarity index 100% rename from src/tauon/input.txt rename to src/tauon/templates/input.txt From 5787ad97344123c69bd357f4c2c94625082f1c67 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 18:24:30 +0100 Subject: [PATCH 49/63] t_main: Spaces to tabs til 7k & remove one else indent --- src/tauon/t_modules/t_main.py | 4325 +++++++++++++++++---------------- 1 file changed, 2167 insertions(+), 2158 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index eb621aee9..29421ecd1 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -4567,2310 +4567,2319 @@ def natural_get(tag, track, frame, attr): def scan_ffprobe(nt): - startupinfo = None - if system == 'windows' or msys: - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - try: - result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format=duration", "-of", - "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) - nt.length = float(result.stdout.decode()) - except Exception: - logging.exception("FFPROBE couldn't supply a duration") - try: - result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=title", "-of", - "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) - nt.title = str(result.stdout.decode()) - except Exception: - logging.exception("FFPROBE couldn't supply a title") - try: - result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=artist", "-of", - "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) - nt.artist = str(result.stdout.decode()) - except Exception: - logging.exception("FFPROBE couldn't supply a artist") - try: - result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=album", "-of", - "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) - nt.album = str(result.stdout.decode()) - except Exception: - logging.exception("FFPROBE couldn't supply a album") - try: - result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=date", "-of", - "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) - nt.date = str(result.stdout.decode()) - except Exception: - logging.exception("FFPROBE couldn't supply a date") - try: - result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=track", "-of", - "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) - nt.track_number = str(result.stdout.decode()) - except Exception: - logging.exception("FFPROBE couldn't supply a track") + startupinfo = None + if system == 'windows' or msys: + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + try: + result = subprocess.run( + [tauon.get_ffprobe(), "-v", "error", "-show_entries", "format=duration", "-of", + "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) + nt.length = float(result.stdout.decode()) + except Exception: + logging.exception("FFPROBE couldn't supply a duration") + try: + result = subprocess.run( + [tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=title", "-of", + "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) + nt.title = str(result.stdout.decode()) + except Exception: + logging.exception("FFPROBE couldn't supply a title") + try: + result = subprocess.run( + [tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=artist", "-of", + "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) + nt.artist = str(result.stdout.decode()) + except Exception: + logging.exception("FFPROBE couldn't supply a artist") + try: + result = subprocess.run( + [tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=album", "-of", + "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) + nt.album = str(result.stdout.decode()) + except Exception: + logging.exception("FFPROBE couldn't supply a album") + try: + result = subprocess.run( + [tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=date", "-of", + "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) + nt.date = str(result.stdout.decode()) + except Exception: + logging.exception("FFPROBE couldn't supply a date") + try: + result = subprocess.run( + [tauon.get_ffprobe(), "-v", "error", "-show_entries", "format_tags=track", "-of", + "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) + nt.track_number = str(result.stdout.decode()) + except Exception: + logging.exception("FFPROBE couldn't supply a track") def tag_scan(nt): - """This function takes a track object and scans metadata for it. (Filepath needs to be set)""" - if nt.is_embed_cue: - return nt - if nt.is_network or not nt.fullpath: - return - try: - try: - nt.modified_time = os.path.getmtime(nt.fullpath) - nt.found = True - except FileNotFoundError: - logging.error("File not found when executing getmtime!") - nt.found = False - return nt - except Exception: - logging.exception("Unknown error executing getmtime!") - nt.found = False - return nt - - nt.misc.clear() - - nt.file_ext = os.path.splitext(os.path.basename(nt.fullpath))[1][1:].upper() - - if nt.file_ext.lower() in GME_Formats and gme: - - emu = ctypes.c_void_p() - track_info = ctypes.POINTER(GMETrackInfo)() - err = gme.gme_open_file(nt.fullpath.encode("utf-8"), ctypes.byref(emu), -1) - #logging.error(err) - if not err: - n = nt.subtrack - err = gme.gme_track_info(emu, byref(track_info), n) - #logging.error(err) - if not err: - nt.length = track_info.contents.play_length / 1000 - nt.title = track_info.contents.song.decode("utf-8") - nt.artist = track_info.contents.author.decode("utf-8") - nt.album = track_info.contents.game.decode("utf-8") - nt.comment = track_info.contents.comment.decode("utf-8") - gme.gme_free_info(track_info) - gme.gme_delete(emu) - - filepath = nt.fullpath # this is the full file path - filename = nt.filename # this is the name of the file - - # Get the directory of the file - dir_path = os.path.dirname(filepath) - - # Loop through all files in the directory to find any matching M3U - for file in os.listdir(dir_path): - if file.endswith('.m3u'): - with open(os.path.join(dir_path, file), encoding='utf-8', errors='replace') as f: - content = f.read() - if '�' in content: # Check for replacement marker - with open(os.path.join(dir_path, file), encoding='windows-1252') as b: - content = b.read() - if "::" in content: - a, b = content.split("::") - if a == filename: - s = re.split(r'(?<!\\),', b) - try: - st = int(s[1]) - except Exception: - logging.exception("Failed to assign st to int") - continue - if st == n: - nt.title = s[2].split(' - ')[0].replace("\\", "") - nt.artist = s[2].split(' - ')[1].replace("\\", "") - nt.album = s[2].split(' - ')[2].replace("\\", "") - nt.length = hms_to_seconds(s[3]) - break - if not nt.title: - nt.title = "Track " + str(nt.subtrack + 1) - - elif nt.file_ext in ("MOD", "IT", "XM", "S3M", "MPTM") and mpt: - f = open(nt.fullpath, "rb") - data = f.read() - f.close() - MOD1 = MOD.from_address( - mpt.openmpt_module_create_from_memory(ctypes.c_char_p(data), ctypes.c_size_t(len(data)), None, None, - None)) - nt.length = mpt.openmpt_module_get_duration_seconds(byref(MOD1)) - nt.title = mpt.openmpt_module_get_metadata(byref(MOD1), ctypes.c_char_p(b"title")).decode() - nt.artist = mpt.openmpt_module_get_metadata(byref(MOD1), ctypes.c_char_p(b"artist")).decode() - nt.comment = mpt.openmpt_module_get_metadata(byref(MOD1), ctypes.c_char_p(b"message_raw")).decode() - - mpt.openmpt_module_destroy(byref(MOD1)) - del MOD1 - - elif nt.file_ext == "FLAC": - - audio = Flac(nt.fullpath) - audio.read() - - nt.length = audio.length - nt.title = audio.title - nt.artist = audio.artist - nt.album = audio.album - nt.composer = audio.composer - nt.date = audio.date - nt.samplerate = audio.sample_rate - nt.bit_depth = audio.bit_depth - nt.size = os.path.getsize(nt.fullpath) - nt.track_number = audio.track_number - nt.genre = audio.genre - nt.album_artist = audio.album_artist - nt.disc_number = audio.disc_number - nt.lyrics = audio.lyrics - if nt.length: - nt.bitrate = int(nt.size / nt.length * 8 / 1024) - nt.track_total = audio.track_total - nt.disc_total = audio.disc_total - nt.comment = audio.comment - nt.cue_sheet = audio.cue_sheet - nt.misc = audio.misc - - elif nt.file_ext == "WAV": - - try: - audio = Wav(nt.fullpath) - audio.read() - - nt.samplerate = audio.sample_rate - nt.length = audio.length - nt.title = audio.title - nt.artist = audio.artist - nt.album = audio.album - nt.track_number = audio.track_number - - except Exception: - logging.exception("Failed saving WAV file as a Track, will try again differently") - audio = mutagen.File(nt.fullpath) - nt.samplerate = audio.info.sample_rate - nt.bitrate = audio.info.bitrate // 1000 - nt.length = audio.info.length - nt.size = os.path.getsize(nt.fullpath) - audio = mutagen.File(nt.fullpath) - if audio.tags and type(audio.tags) == mutagen.wave._WaveID3: - use_id3(audio.tags, nt) - - elif nt.file_ext == "OPUS" or nt.file_ext == "OGG" or nt.file_ext == "OGA": - - #logging.info("get opus") - audio = Opus(nt.fullpath) - audio.read() - - #logging.info(audio.title) - - nt.length = audio.length - nt.title = audio.title - nt.artist = audio.artist - nt.album = audio.album - nt.composer = audio.composer - nt.date = audio.date - nt.samplerate = audio.sample_rate - nt.size = os.path.getsize(nt.fullpath) - nt.track_number = audio.track_number - nt.genre = audio.genre - nt.album_artist = audio.album_artist - nt.bitrate = audio.bit_rate - nt.lyrics = audio.lyrics - nt.disc_number = audio.disc_number - nt.track_total = audio.track_total - nt.disc_total = audio.disc_total - nt.comment = audio.comment - nt.misc = audio.misc - if nt.bitrate == 0 and nt.length > 0: - nt.bitrate = int(nt.size / nt.length * 8 / 1024) - - elif nt.file_ext == "APE": - - audio = mutagen.File(nt.fullpath) - nt.length = audio.info.length - nt.bit_depth = audio.info.bits_per_sample - nt.samplerate = audio.info.sample_rate - nt.size = os.path.getsize(nt.fullpath) - if nt.length > 0: - nt.bitrate = int(nt.size / nt.length * 8 / 1024) - - # # def getter(audio, key, type): - # # if - # t = audio.tags - # logging.info(t.keys()) - # nt.size = os.path.getsize(nt.fullpath) - # nt.title = str(t.get("title", "")) - # nt.album = str(t.get("album", "")) - # nt.date = str(t.get("year", "")) - # nt.disc_number = str(t.get("discnumber", "")) - # nt.comment = str(t.get("comment", "")) - # nt.artist = str(t.get("artist", "")) - # nt.composer = str(t.get("composer", "")) - # nt.composer = str(t.get("composer", "")) - - audio = Ape(nt.fullpath) - audio.read() - - # logging.info(audio.title) - - # nt.length = audio.length - nt.title = audio.title - nt.artist = audio.artist - nt.album = audio.album - nt.date = audio.date - nt.composer = audio.composer - # nt.bit_depth = audio.bit_depth - nt.track_number = audio.track_number - nt.genre = audio.genre - nt.album_artist = audio.album_artist - nt.disc_number = audio.disc_number - nt.lyrics = audio.lyrics - nt.track_total = audio.track_total - nt.disc_total = audio.disc_total - nt.comment = audio.comment - nt.misc = audio.misc - - elif nt.file_ext == "WV" or nt.file_ext == "TTA": - - audio = Ape(nt.fullpath) - audio.read() - - # logging.info(audio.title) - - nt.length = audio.length - nt.title = audio.title - nt.artist = audio.artist - nt.album = audio.album - nt.date = audio.date - nt.composer = audio.composer - nt.samplerate = audio.sample_rate - nt.bit_depth = audio.bit_depth - nt.size = os.path.getsize(nt.fullpath) - nt.track_number = audio.track_number - nt.genre = audio.genre - nt.album_artist = audio.album_artist - nt.disc_number = audio.disc_number - nt.lyrics = audio.lyrics - if nt.length > 0: - nt.bitrate = int(nt.size / nt.length * 8 / 1024) - nt.track_total = audio.track_total - nt.disc_total = audio.disc_total - nt.comment = audio.comment - nt.misc = audio.misc + """This function takes a track object and scans metadata for it. (Filepath needs to be set)""" + if nt.is_embed_cue: + return nt + if nt.is_network or not nt.fullpath: + return + try: + try: + nt.modified_time = os.path.getmtime(nt.fullpath) + nt.found = True + except FileNotFoundError: + logging.error("File not found when executing getmtime!") + nt.found = False + return nt + except Exception: + logging.exception("Unknown error executing getmtime!") + nt.found = False + return nt + + nt.misc.clear() + + nt.file_ext = os.path.splitext(os.path.basename(nt.fullpath))[1][1:].upper() + + if nt.file_ext.lower() in GME_Formats and gme: + + emu = ctypes.c_void_p() + track_info = ctypes.POINTER(GMETrackInfo)() + err = gme.gme_open_file(nt.fullpath.encode("utf-8"), ctypes.byref(emu), -1) + #logging.error(err) + if not err: + n = nt.subtrack + err = gme.gme_track_info(emu, byref(track_info), n) + #logging.error(err) + if not err: + nt.length = track_info.contents.play_length / 1000 + nt.title = track_info.contents.song.decode("utf-8") + nt.artist = track_info.contents.author.decode("utf-8") + nt.album = track_info.contents.game.decode("utf-8") + nt.comment = track_info.contents.comment.decode("utf-8") + gme.gme_free_info(track_info) + gme.gme_delete(emu) + + filepath = nt.fullpath # this is the full file path + filename = nt.filename # this is the name of the file + + # Get the directory of the file + dir_path = os.path.dirname(filepath) + + # Loop through all files in the directory to find any matching M3U + for file in os.listdir(dir_path): + if file.endswith('.m3u'): + with open(os.path.join(dir_path, file), encoding='utf-8', errors='replace') as f: + content = f.read() + if '�' in content: # Check for replacement marker + with open(os.path.join(dir_path, file), encoding='windows-1252') as b: + content = b.read() + if "::" in content: + a, b = content.split("::") + if a == filename: + s = re.split(r'(?<!\\),', b) + try: + st = int(s[1]) + except Exception: + logging.exception("Failed to assign st to int") + continue + if st == n: + nt.title = s[2].split(' - ')[0].replace("\\", "") + nt.artist = s[2].split(' - ')[1].replace("\\", "") + nt.album = s[2].split(' - ')[2].replace("\\", "") + nt.length = hms_to_seconds(s[3]) + break + if not nt.title: + nt.title = "Track " + str(nt.subtrack + 1) + + elif nt.file_ext in ("MOD", "IT", "XM", "S3M", "MPTM") and mpt: + f = open(nt.fullpath, "rb") + data = f.read() + f.close() + MOD1 = MOD.from_address( + mpt.openmpt_module_create_from_memory( + ctypes.c_char_p(data), ctypes.c_size_t(len(data)), None, None, None)) + nt.length = mpt.openmpt_module_get_duration_seconds(byref(MOD1)) + nt.title = mpt.openmpt_module_get_metadata(byref(MOD1), ctypes.c_char_p(b"title")).decode() + nt.artist = mpt.openmpt_module_get_metadata(byref(MOD1), ctypes.c_char_p(b"artist")).decode() + nt.comment = mpt.openmpt_module_get_metadata(byref(MOD1), ctypes.c_char_p(b"message_raw")).decode() + + mpt.openmpt_module_destroy(byref(MOD1)) + del MOD1 + + elif nt.file_ext == "FLAC": + + audio = Flac(nt.fullpath) + audio.read() + + nt.length = audio.length + nt.title = audio.title + nt.artist = audio.artist + nt.album = audio.album + nt.composer = audio.composer + nt.date = audio.date + nt.samplerate = audio.sample_rate + nt.bit_depth = audio.bit_depth + nt.size = os.path.getsize(nt.fullpath) + nt.track_number = audio.track_number + nt.genre = audio.genre + nt.album_artist = audio.album_artist + nt.disc_number = audio.disc_number + nt.lyrics = audio.lyrics + if nt.length: + nt.bitrate = int(nt.size / nt.length * 8 / 1024) + nt.track_total = audio.track_total + nt.disc_total = audio.disc_total + nt.comment = audio.comment + nt.cue_sheet = audio.cue_sheet + nt.misc = audio.misc + + elif nt.file_ext == "WAV": - else: + try: + audio = Wav(nt.fullpath) + audio.read() - # Use MUTAGEN - try: - if nt.file_ext.lower() in VID_Formats: - scan_ffprobe(nt) - return nt + nt.samplerate = audio.sample_rate + nt.length = audio.length + nt.title = audio.title + nt.artist = audio.artist + nt.album = audio.album + nt.track_number = audio.track_number - try: - audio = mutagen.File(nt.fullpath) - except Exception: - logging.exception("Mutagen scan failed, falling back to FFPROBE") - scan_ffprobe(nt) - return nt + except Exception: + logging.exception("Failed saving WAV file as a Track, will try again differently") + audio = mutagen.File(nt.fullpath) + nt.samplerate = audio.info.sample_rate + nt.bitrate = audio.info.bitrate // 1000 + nt.length = audio.info.length + nt.size = os.path.getsize(nt.fullpath) + audio = mutagen.File(nt.fullpath) + if audio.tags and type(audio.tags) == mutagen.wave._WaveID3: + use_id3(audio.tags, nt) + + elif nt.file_ext == "OPUS" or nt.file_ext == "OGG" or nt.file_ext == "OGA": + + #logging.info("get opus") + audio = Opus(nt.fullpath) + audio.read() + + #logging.info(audio.title) + + nt.length = audio.length + nt.title = audio.title + nt.artist = audio.artist + nt.album = audio.album + nt.composer = audio.composer + nt.date = audio.date + nt.samplerate = audio.sample_rate + nt.size = os.path.getsize(nt.fullpath) + nt.track_number = audio.track_number + nt.genre = audio.genre + nt.album_artist = audio.album_artist + nt.bitrate = audio.bit_rate + nt.lyrics = audio.lyrics + nt.disc_number = audio.disc_number + nt.track_total = audio.track_total + nt.disc_total = audio.disc_total + nt.comment = audio.comment + nt.misc = audio.misc + if nt.bitrate == 0 and nt.length > 0: + nt.bitrate = int(nt.size / nt.length * 8 / 1024) + + elif nt.file_ext == "APE": + + audio = mutagen.File(nt.fullpath) + nt.length = audio.info.length + nt.bit_depth = audio.info.bits_per_sample + nt.samplerate = audio.info.sample_rate + nt.size = os.path.getsize(nt.fullpath) + if nt.length > 0: + nt.bitrate = int(nt.size / nt.length * 8 / 1024) + + # # def getter(audio, key, type): + # # if + # t = audio.tags + # logging.info(t.keys()) + # nt.size = os.path.getsize(nt.fullpath) + # nt.title = str(t.get("title", "")) + # nt.album = str(t.get("album", "")) + # nt.date = str(t.get("year", "")) + # nt.disc_number = str(t.get("discnumber", "")) + # nt.comment = str(t.get("comment", "")) + # nt.artist = str(t.get("artist", "")) + # nt.composer = str(t.get("composer", "")) + # nt.composer = str(t.get("composer", "")) + + audio = Ape(nt.fullpath) + audio.read() + + # logging.info(audio.title) + + # nt.length = audio.length + nt.title = audio.title + nt.artist = audio.artist + nt.album = audio.album + nt.date = audio.date + nt.composer = audio.composer + # nt.bit_depth = audio.bit_depth + nt.track_number = audio.track_number + nt.genre = audio.genre + nt.album_artist = audio.album_artist + nt.disc_number = audio.disc_number + nt.lyrics = audio.lyrics + nt.track_total = audio.track_total + nt.disc_total = audio.disc_total + nt.comment = audio.comment + nt.misc = audio.misc + + elif nt.file_ext == "WV" or nt.file_ext == "TTA": + + audio = Ape(nt.fullpath) + audio.read() + + # logging.info(audio.title) + + nt.length = audio.length + nt.title = audio.title + nt.artist = audio.artist + nt.album = audio.album + nt.date = audio.date + nt.composer = audio.composer + nt.samplerate = audio.sample_rate + nt.bit_depth = audio.bit_depth + nt.size = os.path.getsize(nt.fullpath) + nt.track_number = audio.track_number + nt.genre = audio.genre + nt.album_artist = audio.album_artist + nt.disc_number = audio.disc_number + nt.lyrics = audio.lyrics + if nt.length > 0: + nt.bitrate = int(nt.size / nt.length * 8 / 1024) + nt.track_total = audio.track_total + nt.disc_total = audio.disc_total + nt.comment = audio.comment + nt.misc = audio.misc - nt.samplerate = audio.info.sample_rate - nt.bitrate = audio.info.bitrate // 1000 - nt.length = audio.info.length - nt.size = os.path.getsize(nt.fullpath) + else: - if not nt.length: - try: - startupinfo = None - if system == 'windows' or msys: - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) - nt.length = float(result.stdout.decode()) - except Exception: - logging.exception("FFPROBE couldn't supply a duration") - - if type(audio.tags) == mutagen.mp4.MP4Tags: - tags = audio.tags - - def in_get(key, tags): - if key in tags: - return tags[key][0] - return "" - - nt.title = in_get("\xa9nam", tags) - nt.album = in_get("\xa9alb", tags) - nt.artist = in_get("\xa9ART", tags) - nt.album_artist = in_get("aART", tags) - nt.composer = in_get("\xa9wrt", tags) - nt.date = in_get("\xa9day", tags) - nt.comment = in_get("\xa9cmt", tags) - nt.genre = in_get("\xa9gen", tags) - if "\xa9lyr" in tags: - nt.lyrics = in_get("\xa9lyr", tags) - nt.track_total = "" - nt.track_number = "" - t = in_get("trkn", tags) - if t: - nt.track_number = str(t[0]) - if t[1]: - nt.track_total = str(t[1]) - - nt.disc_total = "" - nt.disc_number = "" - t = in_get("disk", tags) - if t: - nt.disc_number = str(t[0]) - if t[1]: - nt.disc_total = str(t[1]) - - if '----:com.apple.iTunes:MusicBrainz Track Id' in tags: - nt.misc['musicbrainz_recordingid'] = in_get("----:com.apple.iTunes:MusicBrainz Track Id", - tags).decode() - if '----:com.apple.iTunes:MusicBrainz Release Track Id' in tags: - nt.misc['musicbrainz_trackid'] = in_get("----:com.apple.iTunes:MusicBrainz Release Track Id", - tags).decode() - if '----:com.apple.iTunes:MusicBrainz Album Id' in tags: - nt.misc['musicbrainz_albumid'] = in_get("----:com.apple.iTunes:MusicBrainz Album Id", - tags).decode() - if '----:com.apple.iTunes:MusicBrainz Release Group Id' in tags: - nt.misc['musicbrainz_releasegroupid'] = in_get( - "----:com.apple.iTunes:MusicBrainz Release Group Id", tags).decode() - if '----:com.apple.iTunes:MusicBrainz Artist Id' in tags: - nt.misc['musicbrainz_artistids'] = [x.decode() for x in - tags.get("----:com.apple.iTunes:MusicBrainz Artist Id")] - - - elif type(audio.tags) == mutagen.id3.ID3: - use_id3(audio.tags, nt) + # Use MUTAGEN + try: + if nt.file_ext.lower() in VID_Formats: + scan_ffprobe(nt) + return nt + + try: + audio = mutagen.File(nt.fullpath) + except Exception: + logging.exception("Mutagen scan failed, falling back to FFPROBE") + scan_ffprobe(nt) + return nt + + nt.samplerate = audio.info.sample_rate + nt.bitrate = audio.info.bitrate // 1000 + nt.length = audio.info.length + nt.size = os.path.getsize(nt.fullpath) + + if not nt.length: + try: + startupinfo = None + if system == 'windows' or msys: + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) + nt.length = float(result.stdout.decode()) + except Exception: + logging.exception("FFPROBE couldn't supply a duration") + + if type(audio.tags) == mutagen.mp4.MP4Tags: + tags = audio.tags + + def in_get(key, tags): + if key in tags: + return tags[key][0] + return "" + + nt.title = in_get("\xa9nam", tags) + nt.album = in_get("\xa9alb", tags) + nt.artist = in_get("\xa9ART", tags) + nt.album_artist = in_get("aART", tags) + nt.composer = in_get("\xa9wrt", tags) + nt.date = in_get("\xa9day", tags) + nt.comment = in_get("\xa9cmt", tags) + nt.genre = in_get("\xa9gen", tags) + if "\xa9lyr" in tags: + nt.lyrics = in_get("\xa9lyr", tags) + nt.track_total = "" + nt.track_number = "" + t = in_get("trkn", tags) + if t: + nt.track_number = str(t[0]) + if t[1]: + nt.track_total = str(t[1]) + + nt.disc_total = "" + nt.disc_number = "" + t = in_get("disk", tags) + if t: + nt.disc_number = str(t[0]) + if t[1]: + nt.disc_total = str(t[1]) + + if '----:com.apple.iTunes:MusicBrainz Track Id' in tags: + nt.misc['musicbrainz_recordingid'] = in_get( + "----:com.apple.iTunes:MusicBrainz Track Id", + tags).decode() + if '----:com.apple.iTunes:MusicBrainz Release Track Id' in tags: + nt.misc['musicbrainz_trackid'] = in_get( + "----:com.apple.iTunes:MusicBrainz Release Track Id", + tags).decode() + if '----:com.apple.iTunes:MusicBrainz Album Id' in tags: + nt.misc['musicbrainz_albumid'] = in_get( + "----:com.apple.iTunes:MusicBrainz Album Id", + tags).decode() + if '----:com.apple.iTunes:MusicBrainz Release Group Id' in tags: + nt.misc['musicbrainz_releasegroupid'] = in_get( + "----:com.apple.iTunes:MusicBrainz Release Group Id", + tags).decode() + if '----:com.apple.iTunes:MusicBrainz Artist Id' in tags: + nt.misc['musicbrainz_artistids'] = [x.decode() for x in + tags.get("----:com.apple.iTunes:MusicBrainz Artist Id")] + + + elif type(audio.tags) == mutagen.id3.ID3: + use_id3(audio.tags, nt) - except Exception: - logging.exception("Failed loading file through Mutagen") - raise + except Exception: + logging.exception("Failed loading file through Mutagen") + raise - # Parse any multiple artists into list - artists = nt.artist.split(";") - if len(artists) > 1: - for a in artists: - a = a.strip() - if a: - if "artists" not in nt.misc: - nt.misc["artists"] = [] - if a not in nt.misc["artists"]: - nt.misc["artists"].append(a) + # Parse any multiple artists into list + artists = nt.artist.split(";") + if len(artists) > 1: + for a in artists: + a = a.strip() + if a: + if "artists" not in nt.misc: + nt.misc["artists"] = [] + if a not in nt.misc["artists"]: + nt.misc["artists"].append(a) - except Exception: - try: - if Exception is UnicodeDecodeError: - logging.exception("Unicode decode error on file:", nt.fullpath, "\n") - else: - logging.exception("Error: Tag read failed on file:", nt.fullpath, "\n") - except Exception: - logging.exception("Error printing error. Non utf8 not allowed:", nt.fullpath.encode('utf-8', 'surrogateescape').decode('utf-8', 'replace'), "\n") - return nt + except Exception: + try: + if Exception is UnicodeDecodeError: + logging.exception("Unicode decode error on file:", nt.fullpath, "\n") + else: + logging.exception("Error: Tag read failed on file:", nt.fullpath, "\n") + except Exception: + logging.exception("Error printing error. Non utf8 not allowed:", nt.fullpath.encode('utf-8', 'surrogateescape').decode('utf-8', 'replace'), "\n") + return nt - return nt + return nt def get_radio_art(): - if radiobox.loaded_url in radiobox.websocket_source_urls: - return - elif "ggdrasil" in radiobox.playing_title: - time.sleep(3) - url = "https://yggdrasilradio.net/data.php?" - response = requests.get(url) - if response.status_code == 200: - lines = response.content.decode().split("|") - if len(lines) > 11 and lines[11]: - art_id = lines[11].strip().strip("*") - art_url = "https://yggdrasilradio.net/images/albumart/" + art_id - art_response = requests.get(art_url) - if art_response.status_code == 200: - if pctl.radio_image_bin: - pctl.radio_image_bin.close() - pctl.radio_image_bin = None - pctl.radio_image_bin = io.BytesIO(art_response.content) - pctl.radio_image_bin.seek(0) - radiobox.dummy_track.art_url_key = "ok" - pctl.update_tag_history() - - elif "gensokyoradio.net" in radiobox.loaded_url: - - response = requests.get("https://gensokyoradio.net/api/station/playing/") - - if response.status_code == 200: - d = json.loads(response.text) - song_info = d.get("SONGINFO") - if song_info: - radiobox.dummy_track.artist = song_info.get("ARTIST", "") - radiobox.dummy_track.title = song_info.get("TITLE", "") - radiobox.dummy_track.album = song_info.get("ALBUM", "") - - misc = d.get("MISC") - if misc: - art = misc.get("ALBUMART") - if art: - art_url = "https://gensokyoradio.net/images/albums/500/" + art - art_response = requests.get(art_url) - if art_response.status_code == 200: - if pctl.radio_image_bin: - pctl.radio_image_bin.close() - pctl.radio_image_bin = None - pctl.radio_image_bin = io.BytesIO(art_response.content) - pctl.radio_image_bin.seek(0) - radiobox.dummy_track.art_url_key = "ok" - pctl.update_tag_history() - - elif "radio.plaza.one" in radiobox.loaded_url: - time.sleep(3) - console.print("Fetching plaza art") - response = requests.get("https://api.plaza.one/status") - if response.status_code == 200: - d = json.loads(response.text) - if "song" in d: - tr = d["song"]["length"] - d["song"]["position"] - tr += 1 - if tr < 10: - tr = 10 - pctl.radio_poll_timer.force_set(tr * -1) - - if "artist" in d["song"]: - radiobox.dummy_track.artist = d["song"]["artist"] - if "title" in d["song"]: - radiobox.dummy_track.title = d["song"]["title"] - if "album" in d["song"]: - radiobox.dummy_track.album = d["song"]["album"] - if "artwork_src" in d["song"]: - art_url = d["song"]["artwork_src"] - art_response = requests.get(art_url) - if art_response.status_code == 200: - if pctl.radio_image_bin: - pctl.radio_image_bin.close() - pctl.radio_image_bin = None - pctl.radio_image_bin = io.BytesIO(art_response.content) - pctl.radio_image_bin.seek(0) - radiobox.dummy_track.art_url_key = "ok" - pctl.update_tag_history() - - # Failure - elif pctl.radio_image_bin: - pctl.radio_image_bin.close() - pctl.radio_image_bin = None - - gui.clear_image_cache_next += 1 + if radiobox.loaded_url in radiobox.websocket_source_urls: + return + elif "ggdrasil" in radiobox.playing_title: + time.sleep(3) + url = "https://yggdrasilradio.net/data.php?" + response = requests.get(url) + if response.status_code == 200: + lines = response.content.decode().split("|") + if len(lines) > 11 and lines[11]: + art_id = lines[11].strip().strip("*") + art_url = "https://yggdrasilradio.net/images/albumart/" + art_id + art_response = requests.get(art_url) + if art_response.status_code == 200: + if pctl.radio_image_bin: + pctl.radio_image_bin.close() + pctl.radio_image_bin = None + pctl.radio_image_bin = io.BytesIO(art_response.content) + pctl.radio_image_bin.seek(0) + radiobox.dummy_track.art_url_key = "ok" + pctl.update_tag_history() + + elif "gensokyoradio.net" in radiobox.loaded_url: + + response = requests.get("https://gensokyoradio.net/api/station/playing/") + + if response.status_code == 200: + d = json.loads(response.text) + song_info = d.get("SONGINFO") + if song_info: + radiobox.dummy_track.artist = song_info.get("ARTIST", "") + radiobox.dummy_track.title = song_info.get("TITLE", "") + radiobox.dummy_track.album = song_info.get("ALBUM", "") + + misc = d.get("MISC") + if misc: + art = misc.get("ALBUMART") + if art: + art_url = "https://gensokyoradio.net/images/albums/500/" + art + art_response = requests.get(art_url) + if art_response.status_code == 200: + if pctl.radio_image_bin: + pctl.radio_image_bin.close() + pctl.radio_image_bin = None + pctl.radio_image_bin = io.BytesIO(art_response.content) + pctl.radio_image_bin.seek(0) + radiobox.dummy_track.art_url_key = "ok" + pctl.update_tag_history() + + elif "radio.plaza.one" in radiobox.loaded_url: + time.sleep(3) + console.print("Fetching plaza art") + response = requests.get("https://api.plaza.one/status") + if response.status_code == 200: + d = json.loads(response.text) + if "song" in d: + tr = d["song"]["length"] - d["song"]["position"] + tr += 1 + if tr < 10: + tr = 10 + pctl.radio_poll_timer.force_set(tr * -1) + + if "artist" in d["song"]: + radiobox.dummy_track.artist = d["song"]["artist"] + if "title" in d["song"]: + radiobox.dummy_track.title = d["song"]["title"] + if "album" in d["song"]: + radiobox.dummy_track.album = d["song"]["album"] + if "artwork_src" in d["song"]: + art_url = d["song"]["artwork_src"] + art_response = requests.get(art_url) + if art_response.status_code == 200: + if pctl.radio_image_bin: + pctl.radio_image_bin.close() + pctl.radio_image_bin = None + pctl.radio_image_bin = io.BytesIO(art_response.content) + pctl.radio_image_bin.seek(0) + radiobox.dummy_track.art_url_key = "ok" + pctl.update_tag_history() + + # Failure + elif pctl.radio_image_bin: + pctl.radio_image_bin.close() + pctl.radio_image_bin = None + + gui.clear_image_cache_next += 1 # Main class that controls playback (play, pause, stepping, playlists, queue etc). Sends commands to backend. class PlayerCtl: - # C-PC - def __init__(self): - - self.running = True - self.system = system - self.macos = macos - self.windows_native = windows_native - self.install_directory = install_directory - self.user_directory = user_directory - self.config_directory = config_directory - self.prefs = prefs - - # Database - - self.master_count = master_count - self.total_playtime: float = 0 - self.master_library = master_library - self.db_inc = random.randint(0, 10000) - # self.star_library = star_library - self.LoadClass = LoadClass - - self.gen_codes = gen_codes - - self.shuffle_pools = {} - self.after_import_flag = False - self.quick_add_target = None - - self.album_mbid_release_cache = {} - self.album_mbid_release_group_cache = {} - self.mbid_image_url_cache = {} - - # Misc player control - - self.url = "" - # self.save_urls = url_saves - self.tag_meta = "" - self.found_tags = {} - self.encoder_pause = 0 - - # Playback - - self.track_queue = QUE - self.queue_step = playing_in_queue - self.playing_time = 0 - self.playlist_playing_position = playlist_playing # track in playlist that is playing - if self.playlist_playing_position == None: - self.playlist_playing_position = -1 - self.playlist_view_position = playlist_view_position - self.selected_in_playlist = selected_in_playlist - self.target_open = "" - self.target_object = None - self.start_time = 0 - self.b_start_time = 0 - self.playerCommand = "" - self.playerSubCommand = "" - self.playerCommandReady = False - self.playing_state = 0 - self.playing_length = 0 - self.jump_time = 0 - self.random_mode = prefs.random_mode - self.repeat_mode = prefs.repeat_mode - self.album_repeat_mode = prefs.album_repeat_mode - self.album_shuffle_mode = prefs.album_shuffle_mode - # self.album_shuffle_pool = [] - # self.album_shuffle_id = "" - self.last_playing_time = 0 - self.multi_playlist = multi_playlist - self.active_playlist_viewing = playlist_active # the playlist index that is being viewed - self.active_playlist_playing = playlist_active # the playlist index that is playing from - self.force_queue = p_force_queue # [] - self.pause_queue = False - self.left_time = 0 - self.left_index = 0 - self.player_volume = volume - self.new_time = 0 - self.time_to_get = [] - self.a_time = 0 - self.b_time = 0 - # self.playlist_backup = [] - self.active_replaygain = 0 - self.auto_stop = False - - self.record_stream = False - self.record_title = "" - - # Bass - - self.bass_devices = [] - self.set_device = 0 - - self.gst_devices = [] # Display names - self.gst_outputs = {} # Display name : (sink, device) - - self.mpris = None - self.tray_update = None - self.eq = [0] * 2 # not used - self.enable_eq = True # not used - - self.playing_time_int = 0 # playing time but with no decimel - - self.windows_progress = None - - self.finish_transition = False - # self.queue_target = 0 - self.start_time_target = 0 - - self.decode_time = 0 - self.download_time = 0 - - self.radio_meta_on = "" - - self.radio_scrobble_trip = True - self.radio_scrobble_timer = Timer() - - self.radio_image_bin = None - self.radio_rate_timer = Timer(2) - self.radio_poll_timer = Timer(2) - - self.volume_update_timer = Timer() - self.wake_past_time = 0 - - self.regen_in_progress = False - self.notify_in_progress = False - - self.radio_playlists = radio_playlists - self.radio_playlist_viewing = radio_playlist_viewing - self.tag_history = {} - - self.commit = None - self.spot_playing = False - - self.buffering_percent = 0 - - def notify_change(self): - self.db_inc += 1 - tauon.bg_save() - - def update_tag_history(self): - if prefs.auto_rec: - self.tag_history[radiobox.song_key] = { - "title": radiobox.dummy_track.title, - "artist": radiobox.dummy_track.artist, - "album": radiobox.dummy_track.album, - # "image": pctl.radio_image_bin - } - - def radio_progress(self): - if radiobox.loaded_url and "radio.plaza.one" in radiobox.loaded_url and self.radio_poll_timer.get() > 0: - self.radio_poll_timer.force_set(-10) - response = requests.get("https://api.plaza.one/status") - - if response.status_code == 200: - d = json.loads(response.text) - if "song" in d: - if "artist" in d["song"] and "title" in d["song"]: - self.tag_meta = d["song"]["artist"] + " - " + d["song"]["title"] - - if self.tag_meta: - if self.radio_rate_timer.get() > 7 and self.radio_meta_on != self.tag_meta: - self.radio_rate_timer.set() - self.radio_scrobble_trip = False - self.radio_meta_on = self.tag_meta - - radiobox.dummy_track.art_url_key = "" - radiobox.dummy_track.title = "" - radiobox.dummy_track.date = "" - radiobox.dummy_track.artist = "" - radiobox.dummy_track.album = "" - radiobox.dummy_track.lyrics = "" - radiobox.dummy_track.date = "" - - tags = pctl.found_tags - if "title" in tags: - radiobox.dummy_track.title = tags["title"] - if "artist" in tags: - radiobox.dummy_track.artist = tags["artist"] - if "year" in tags: - radiobox.dummy_track.date = tags["year"] - if "album" in tags: - radiobox.dummy_track.album = tags["album"] - - elif self.tag_meta.count( - "-") == 1 and not ":" in self.tag_meta and not "advert" in self.tag_meta.lower(): - artist, title = self.tag_meta.split("-") - radiobox.dummy_track.title = title.strip() - radiobox.dummy_track.artist = artist.strip() - - if self.tag_meta: - radiobox.song_key = self.tag_meta - else: - radiobox.song_key = radiobox.dummy_track.artist + " - " + radiobox.dummy_track.title - - self.update_tag_history() - if radiobox.loaded_url not in radiobox.websocket_source_urls: - pctl.radio_image_bin = None - logging.info("NEXT RADIO TRACK") - - try: - get_radio_art() - except Exception: - logging.exception("Get art error") - - pctl.notify_update(mpris=False) - if pctl.mpris: - pctl.mpris.update(force=True) - - lfm_scrobbler.listen_track(radiobox.dummy_track) - lfm_scrobbler.start_queue() - - if self.radio_scrobble_trip is False and self.radio_scrobble_timer.get() > 45: - self.radio_scrobble_trip = True - lfm_scrobbler.scrob_full_track(copy.deepcopy(radiobox.dummy_track)) - - def update_shuffle_pool(self, pl_id): - - new_pool = copy.deepcopy(self.multi_playlist[id_to_pl(pl_id)][2]) - random.shuffle(new_pool) - self.shuffle_pools[pl_id] = new_pool - console.print("Refill shuffle pool") - - def notify_update_fire(self): - if self.mpris is not None: - self.mpris.update() - if tauon.update_play_lock is not None: - tauon.update_play_lock() - # if self.tray_update is not None: - # self.tray_update() - self.notify_in_progress = False - - def notify_update(self, mpris=True): - tauon.tray_releases += 1 - try: - tauon.tray_lock.release() - except Exception: - logging.exception("Failed to release tray_lock") - - if mpris and smtc: - tr = pctl.playing_object() - if tr: - state = 0 - if pctl.playing_state == 1: - state = 1 - if pctl.playing_state == 2: - state = 2 - image_path = "" - try: - image_path = tauon.thumb_tracks.path(tr) - except Exception: - logging.exception("Failed to set image_path from thumb_tracks.path") - - if image_path is None: - image_path = "" - - image_path = image_path.replace("/", "\\") - #logging.info(image_path) - - sm.update(state, tr.title.encode("utf-16"), len(tr.title), tr.artist.encode("utf-16"), len(tr.artist), - image_path.encode("utf-16"), len(image_path)) - - - if self.mpris is not None and mpris is True: - while self.notify_in_progress: - time.sleep(0.01) - self.notify_in_progress = True - shoot = threading.Thread(target=self.notify_update_fire) - shoot.daemon = True - shoot.start() - if prefs.art_bg or (gui.mode == 3 and prefs.mini_mode_mode == 5): - tm.ready("style") - - def get_url(self, track_object): - - if track_object.file_ext == "TIDAL": - return tidal.resolve_stream(track_object), None - if track_object.file_ext == "PLEX": - return plex.resolve_stream(track_object.url_key), None - - if track_object.file_ext == "JELY": - return jellyfin.resolve_stream(track_object.url_key) - - if track_object.file_ext == "KOEL": - return koel.resolve_stream(track_object.url_key) - - if track_object.file_ext == "SUB": - return subsonic.resolve_stream(track_object.url_key) - - if track_object.file_ext == "TAU": - return tau.resolve_stream(track_object.url_key), None - - return None, None - - def playing_playlist(self): - return self.multi_playlist[self.active_playlist_playing][2] - - def playing_ready(self): - return len(self.track_queue) > 0 - - def selected_ready(self): - return default_playlist and pctl.selected_in_playlist < len(default_playlist) - - def render_playlist(self): - - if taskbar_progress and msys and self.windows_progress: - self.windows_progress.update(True) - gui.pl_update = 1 - - def show_selected(self): - - if gui.playlist_view_length < 1: - return 0 - - global shift_selection - - for i in range(len(self.multi_playlist[self.active_playlist_viewing][2])): - - if i == pctl.selected_in_playlist: - - if i < pctl.playlist_view_position: - pctl.playlist_view_position = i - random.randint(2, int((gui.playlist_view_length / 3) * 2) + int( - gui.playlist_view_length / 6)) - console.print("DEBUG: Position changed show selected (a)") - elif abs(pctl.playlist_view_position - i) > gui.playlist_view_length: - pctl.playlist_view_position = i - console.print("DEBUG: Position changed show selected (b)") - if i > 6: - pctl.playlist_view_position -= 5 - console.print("DEBUG: Position changed show selected (c)") - if i > gui.playlist_view_length * 1 and i + (gui.playlist_view_length * 2) < len( - self.multi_playlist[self.active_playlist_viewing][2]) and i > 10: - pctl.playlist_view_position = i - random.randint(2, int(gui.playlist_view_length / 3) * 2) - console.print("DEBUG: Position changed show selected (d)") - break - - self.render_playlist() - - return 0 - - def g(self, id): - """Get track object by id""" - return self.master_library[id] - - def sg(self, i, pl): - """Get track object by playlist and index""" - if pl == -1: - pl = self.active_playlist_viewing - try: - playlist = self.multi_playlist[pl][2] - return self.g(playlist[i]) - except IndexError: - logging.exception("Failed getting track object by playlist and index!") - except Exception: - logging.exception("Unknown error getting track object by playlist and index!") - return None - - def show_object(self): - """The track to show in the metadata side panel""" - - target_track = None - - if self.playing_state == 3: - return radiobox.dummy_track - - if 3 > self.playing_state > 0: - target_track = self.playing_object() - - elif self.playing_state == 0 and prefs.meta_shows_selected: - if -1 < pctl.selected_in_playlist < len(self.multi_playlist[self.active_playlist_viewing][2]): - target_track = self.g(self.multi_playlist[self.active_playlist_viewing][2][pctl.selected_in_playlist]) - - elif self.playing_state == 0 and prefs.meta_persists_stop: - target_track = self.master_library[self.track_queue[self.queue_step]] - - if prefs.meta_shows_selected_always: - if -1 < pctl.selected_in_playlist < len(self.multi_playlist[self.active_playlist_viewing][2]): - target_track = self.g(self.multi_playlist[self.active_playlist_viewing][2][pctl.selected_in_playlist]) - - return target_track - - def playing_object(self) -> TrackClass | None: - - if self.playing_state == 3: - return radiobox.dummy_track - - if len(self.track_queue) > 0: - return self.master_library[self.track_queue[self.queue_step]] - else: - return None - - def title_text(self): - - line = "" - track = pctl.playing_object() - if track: - title = track.title - artist = track.artist - - if not title: - line = clean_string(track.filename) - else: - if artist != "": - line += artist - if title != "": - if line != "": - line += " - " - line += title - - if pctl.playing_state == 3 and not title and not artist: - return pctl.tag_meta - - return line - - def show(self): - - global shift_selection - - if not self.track_queue: - return 0 - - def show_current(self, select=True, playing=True, quiet=False, this_only=False, highlight=False, index=None, - no_switch=False, folder_list=True): - - # logging.info("show------") - # logging.info(select) - # logging.info(playing) - # logging.info(quiet) - # logging.info(this_only) - # logging.info(highlight) - # logging.info("--------") - console.print("DEBUG: Position set by show playing") - - global shift_selection - - if spot_ctl.coasting: - sptr = tauon.dummy_track.misc.get("spotify-track-url") - if sptr: - - for p in default_playlist: - tr = pctl.g(p) - if tr.misc.get("spotify-track-url") == sptr: - index = tr.index - break - else: - for i, pl in enumerate(pctl.multi_playlist): - for p in pl[2]: - tr = pctl.g(p) - if tr.misc.get("spotify-track-url") == sptr: - index = tr.index - switch_playlist(i) - break - else: - continue - break - else: - return - - if not self.track_queue: - return 0 - - track_index = self.track_queue[self.queue_step] - if index is not None: - track_index = index - - # Switch to source playlist - if not no_switch: - if self.active_playlist_viewing != self.active_playlist_playing and ( - track_index not in self.multi_playlist[self.active_playlist_viewing][2]): - switch_playlist(self.active_playlist_playing) - - if gui.playlist_view_length < 1: - return 0 - - for i in range(len(self.multi_playlist[self.active_playlist_viewing][2])): - if self.multi_playlist[self.active_playlist_viewing][2][i] == track_index: - - if self.playlist_playing_position < len(self.multi_playlist[self.active_playlist_viewing][2]) and \ - self.active_playlist_viewing == self.active_playlist_playing and track_index == \ - self.multi_playlist[self.active_playlist_viewing][2][self.playlist_playing_position] and \ - i != self.playlist_playing_position: - # continue - i = self.playlist_playing_position - - if select: - pctl.selected_in_playlist = i + # C-PC + def __init__(self): - if playing: - # Make the found track the playing track - self.playlist_playing_position = i - self.active_playlist_playing = self.active_playlist_viewing + self.running = True + self.system = system + self.macos = macos + self.windows_native = windows_native + self.install_directory = install_directory + self.user_directory = user_directory + self.config_directory = config_directory + self.prefs = prefs + + # Database + + self.master_count = master_count + self.total_playtime: float = 0 + self.master_library = master_library + self.db_inc = random.randint(0, 10000) + # self.star_library = star_library + self.LoadClass = LoadClass + + self.gen_codes = gen_codes + + self.shuffle_pools = {} + self.after_import_flag = False + self.quick_add_target = None + + self.album_mbid_release_cache = {} + self.album_mbid_release_group_cache = {} + self.mbid_image_url_cache = {} + + # Misc player control + + self.url = "" + # self.save_urls = url_saves + self.tag_meta = "" + self.found_tags = {} + self.encoder_pause = 0 + + # Playback + + self.track_queue = QUE + self.queue_step = playing_in_queue + self.playing_time = 0 + self.playlist_playing_position = playlist_playing # track in playlist that is playing + if self.playlist_playing_position == None: + self.playlist_playing_position = -1 + self.playlist_view_position = playlist_view_position + self.selected_in_playlist = selected_in_playlist + self.target_open = "" + self.target_object = None + self.start_time = 0 + self.b_start_time = 0 + self.playerCommand = "" + self.playerSubCommand = "" + self.playerCommandReady = False + self.playing_state = 0 + self.playing_length = 0 + self.jump_time = 0 + self.random_mode = prefs.random_mode + self.repeat_mode = prefs.repeat_mode + self.album_repeat_mode = prefs.album_repeat_mode + self.album_shuffle_mode = prefs.album_shuffle_mode + # self.album_shuffle_pool = [] + # self.album_shuffle_id = "" + self.last_playing_time = 0 + self.multi_playlist = multi_playlist + self.active_playlist_viewing = playlist_active # the playlist index that is being viewed + self.active_playlist_playing = playlist_active # the playlist index that is playing from + self.force_queue = p_force_queue # [] + self.pause_queue = False + self.left_time = 0 + self.left_index = 0 + self.player_volume = volume + self.new_time = 0 + self.time_to_get = [] + self.a_time = 0 + self.b_time = 0 + # self.playlist_backup = [] + self.active_replaygain = 0 + self.auto_stop = False + + self.record_stream = False + self.record_title = "" + + # Bass + + self.bass_devices = [] + self.set_device = 0 + + self.gst_devices = [] # Display names + self.gst_outputs = {} # Display name : (sink, device) + + self.mpris = None + self.tray_update = None + self.eq = [0] * 2 # not used + self.enable_eq = True # not used + + self.playing_time_int = 0 # playing time but with no decimel + + self.windows_progress = None + + self.finish_transition = False + # self.queue_target = 0 + self.start_time_target = 0 + + self.decode_time = 0 + self.download_time = 0 + + self.radio_meta_on = "" + + self.radio_scrobble_trip = True + self.radio_scrobble_timer = Timer() + + self.radio_image_bin = None + self.radio_rate_timer = Timer(2) + self.radio_poll_timer = Timer(2) + + self.volume_update_timer = Timer() + self.wake_past_time = 0 + + self.regen_in_progress = False + self.notify_in_progress = False + + self.radio_playlists = radio_playlists + self.radio_playlist_viewing = radio_playlist_viewing + self.tag_history = {} + + self.commit = None + self.spot_playing = False + + self.buffering_percent = 0 + + def notify_change(self): + self.db_inc += 1 + tauon.bg_save() + + def update_tag_history(self): + if prefs.auto_rec: + self.tag_history[radiobox.song_key] = { + "title": radiobox.dummy_track.title, + "artist": radiobox.dummy_track.artist, + "album": radiobox.dummy_track.album, + # "image": pctl.radio_image_bin + } + + def radio_progress(self): + if radiobox.loaded_url and "radio.plaza.one" in radiobox.loaded_url and self.radio_poll_timer.get() > 0: + self.radio_poll_timer.force_set(-10) + response = requests.get("https://api.plaza.one/status") + + if response.status_code == 200: + d = json.loads(response.text) + if "song" in d: + if "artist" in d["song"] and "title" in d["song"]: + self.tag_meta = d["song"]["artist"] + " - " + d["song"]["title"] + + if self.tag_meta: + if self.radio_rate_timer.get() > 7 and self.radio_meta_on != self.tag_meta: + self.radio_rate_timer.set() + self.radio_scrobble_trip = False + self.radio_meta_on = self.tag_meta + + radiobox.dummy_track.art_url_key = "" + radiobox.dummy_track.title = "" + radiobox.dummy_track.date = "" + radiobox.dummy_track.artist = "" + radiobox.dummy_track.album = "" + radiobox.dummy_track.lyrics = "" + radiobox.dummy_track.date = "" + + tags = pctl.found_tags + if "title" in tags: + radiobox.dummy_track.title = tags["title"] + if "artist" in tags: + radiobox.dummy_track.artist = tags["artist"] + if "year" in tags: + radiobox.dummy_track.date = tags["year"] + if "album" in tags: + radiobox.dummy_track.album = tags["album"] + + elif self.tag_meta.count( + "-") == 1 and not ":" in self.tag_meta and not "advert" in self.tag_meta.lower(): + artist, title = self.tag_meta.split("-") + radiobox.dummy_track.title = title.strip() + radiobox.dummy_track.artist = artist.strip() + + if self.tag_meta: + radiobox.song_key = self.tag_meta + else: + radiobox.song_key = radiobox.dummy_track.artist + " - " + radiobox.dummy_track.title + + self.update_tag_history() + if radiobox.loaded_url not in radiobox.websocket_source_urls: + pctl.radio_image_bin = None + logging.info("NEXT RADIO TRACK") + + try: + get_radio_art() + except Exception: + logging.exception("Get art error") + + pctl.notify_update(mpris=False) + if pctl.mpris: + pctl.mpris.update(force=True) + + lfm_scrobbler.listen_track(radiobox.dummy_track) + lfm_scrobbler.start_queue() + + if self.radio_scrobble_trip is False and self.radio_scrobble_timer.get() > 45: + self.radio_scrobble_trip = True + lfm_scrobbler.scrob_full_track(copy.deepcopy(radiobox.dummy_track)) + + def update_shuffle_pool(self, pl_id): + + new_pool = copy.deepcopy(self.multi_playlist[id_to_pl(pl_id)][2]) + random.shuffle(new_pool) + self.shuffle_pools[pl_id] = new_pool + console.print("Refill shuffle pool") + + def notify_update_fire(self): + if self.mpris is not None: + self.mpris.update() + if tauon.update_play_lock is not None: + tauon.update_play_lock() + # if self.tray_update is not None: + # self.tray_update() + self.notify_in_progress = False + + def notify_update(self, mpris=True): + tauon.tray_releases += 1 + try: + tauon.tray_lock.release() + except Exception: + logging.exception("Failed to release tray_lock") + + if mpris and smtc: + tr = pctl.playing_object() + if tr: + state = 0 + if pctl.playing_state == 1: + state = 1 + if pctl.playing_state == 2: + state = 2 + image_path = "" + try: + image_path = tauon.thumb_tracks.path(tr) + except Exception: + logging.exception("Failed to set image_path from thumb_tracks.path") + + if image_path is None: + image_path = "" + + image_path = image_path.replace("/", "\\") + #logging.info(image_path) + + sm.update( + state, tr.title.encode("utf-16"), len(tr.title), tr.artist.encode("utf-16"), len(tr.artist), + image_path.encode("utf-16"), len(image_path)) + + + if self.mpris is not None and mpris is True: + while self.notify_in_progress: + time.sleep(0.01) + self.notify_in_progress = True + shoot = threading.Thread(target=self.notify_update_fire) + shoot.daemon = True + shoot.start() + if prefs.art_bg or (gui.mode == 3 and prefs.mini_mode_mode == 5): + tm.ready("style") + + def get_url(self, track_object): + + if track_object.file_ext == "TIDAL": + return tidal.resolve_stream(track_object), None + if track_object.file_ext == "PLEX": + return plex.resolve_stream(track_object.url_key), None + + if track_object.file_ext == "JELY": + return jellyfin.resolve_stream(track_object.url_key) + + if track_object.file_ext == "KOEL": + return koel.resolve_stream(track_object.url_key) - vl = gui.playlist_view_length - if pctl.multi_playlist[pctl.active_playlist_viewing][6] == gui.playlist_current_visible_tracks_id: - vl = gui.playlist_current_visible_tracks + if track_object.file_ext == "SUB": + return subsonic.resolve_stream(track_object.url_key) - if not ( - quiet and self.playing_object().length < 15): # or (abs(pctl.playlist_view_position - i) < vl - 1)): + if track_object.file_ext == "TAU": + return tau.resolve_stream(track_object.url_key), None - # Align to album if in view range (and folder titles are active) - ap = get_album_info(i)[1][0] + return None, None - if not (quiet and pctl.playlist_view_position <= i <= pctl.playlist_view_position + vl) and ( - not abs(i - ap) > vl - 2) and not pctl.multi_playlist[pctl.active_playlist_viewing][4]: - pctl.playlist_view_position = ap + def playing_playlist(self): + return self.multi_playlist[self.active_playlist_playing][2] - else: - # Move to a random offset --- - - if i == pctl.playlist_view_position - 1 and pctl.playlist_view_position > 1: - pctl.playlist_view_position -= 1 - - # Move a bit if its just out of range - elif pctl.playlist_view_position + vl - 2 == i and i < len( - self.multi_playlist[self.active_playlist_viewing][2]) - 5: - pctl.playlist_view_position += 3 - - # We know its out of range if above view postion - elif i < pctl.playlist_view_position: - pctl.playlist_view_position = i - random.randint(2, int(( - gui.playlist_view_length / 3) * 2) + int( - gui.playlist_view_length / 6)) - - # If its below we need to test if its in view. If playing track in view, don't jump. - elif abs(pctl.playlist_view_position - i) >= vl: - pctl.playlist_view_position = i - if i > 6: - pctl.playlist_view_position -= 5 - if i > gui.playlist_view_length and i + (gui.playlist_view_length * 2) < len( - self.multi_playlist[self.active_playlist_viewing][2]) and i > 10: - pctl.playlist_view_position = i - random.randint(2, - int(gui.playlist_view_length / 3) * 2) + def playing_ready(self): + return len(self.track_queue) > 0 - break + def selected_ready(self): + return default_playlist and pctl.selected_in_playlist < len(default_playlist) - else: # Search other all other playlists - if not this_only: - for i, playlist in enumerate(self.multi_playlist): - if track_index in playlist[2]: - switch_playlist(i, quiet=True) - self.show_current(select, playing, quiet, this_only=True, index=track_index) - break + def render_playlist(self): - if pctl.playlist_view_position < 0: - pctl.playlist_view_position = 0 + if taskbar_progress and msys and self.windows_progress: + self.windows_progress.update(True) + gui.pl_update = 1 - # if pctl.playlist_view_position > len(self.multi_playlist[self.active_playlist_viewing][2]) - 1: - # logging.info("Run Over") + def show_selected(self): - if select: - shift_selection = [] + if gui.playlist_view_length < 1: + return 0 - self.render_playlist() + global shift_selection - if album_mode and not quiet: - if highlight: - gui.gallery_animate_highlight_on = goto_album(pctl.selected_in_playlist) - gallery_select_animate_timer.set() - else: - goto_album(pctl.selected_in_playlist) + for i in range(len(self.multi_playlist[self.active_playlist_viewing][2])): - if prefs.left_panel_mode == "artist list" and gui.lsp and not quiet: - artist_list_box.locate_artist(pctl.playing_object()) + if i == pctl.selected_in_playlist: - if folder_list and prefs.left_panel_mode == "folder view" and gui.lsp and not quiet and not tree_view_box.lock_pl: - tree_view_box.show_track(pctl.playing_object()) + if i < pctl.playlist_view_position: + pctl.playlist_view_position = i - random.randint(2, int((gui.playlist_view_length / 3) * 2) + int( + gui.playlist_view_length / 6)) + console.print("DEBUG: Position changed show selected (a)") + elif abs(pctl.playlist_view_position - i) > gui.playlist_view_length: + pctl.playlist_view_position = i + console.print("DEBUG: Position changed show selected (b)") + if i > 6: + pctl.playlist_view_position -= 5 + console.print("DEBUG: Position changed show selected (c)") + if i > gui.playlist_view_length * 1 and i + (gui.playlist_view_length * 2) < len( + self.multi_playlist[self.active_playlist_viewing][2]) and i > 10: + pctl.playlist_view_position = i - random.randint(2, int(gui.playlist_view_length / 3) * 2) + console.print("DEBUG: Position changed show selected (d)") + break - return 0 + self.render_playlist() - def toggle_mute(self): - global volume_store - if pctl.player_volume > 0: - volume_store = pctl.player_volume - pctl.player_volume = 0 - else: - pctl.player_volume = volume_store + return 0 - pctl.set_volume() + def g(self, id): + """Get track object by id""" + return self.master_library[id] - def set_volume(self, notify=True): + def sg(self, i, pl): + """Get track object by playlist and index""" + if pl == -1: + pl = self.active_playlist_viewing + try: + playlist = self.multi_playlist[pl][2] + return self.g(playlist[i]) + except IndexError: + logging.exception("Failed getting track object by playlist and index!") + except Exception: + logging.exception("Unknown error getting track object by playlist and index!") + return None - if (spot_ctl.coasting or spot_ctl.playing) and not spot_ctl.local and mouse_down: - # Rate limit network volume change - t = self.volume_update_timer.get() - if t < 0.3: - return + def show_object(self): + """The track to show in the metadata side panel""" - self.volume_update_timer.set() - self.playerCommand = 'volume' - self.playerCommandReady = True - if notify: - self.notify_update() + target_track = None - def revert(self): + if self.playing_state == 3: + return radiobox.dummy_track - if self.queue_step == 0: - return + if 3 > self.playing_state > 0: + target_track = self.playing_object() - prev = 0 - while len(self.track_queue) > prev + 1 and prev < 5: - if self.track_queue[len(self.track_queue) - 1 - prev] == self.left_index: - self.queue_step = len(self.track_queue) - 1 - prev - self.jump_time = self.left_time - self.playing_time = self.left_time - self.decode_time = self.left_time - break - prev += 1 - else: - self.queue_step -= 1 - self.jump_time = 0 - self.playing_time = 0 - self.decode_time = 0 + elif self.playing_state == 0 and prefs.meta_shows_selected: + if -1 < pctl.selected_in_playlist < len(self.multi_playlist[self.active_playlist_viewing][2]): + target_track = self.g(self.multi_playlist[self.active_playlist_viewing][2][pctl.selected_in_playlist]) - if not len(self.track_queue) > self.queue_step >= 0: - logging.error("There is no previous track?") - return + elif self.playing_state == 0 and prefs.meta_persists_stop: + target_track = self.master_library[self.track_queue[self.queue_step]] - self.target_open = pctl.master_library[self.track_queue[self.queue_step]].fullpath - self.target_object = pctl.master_library[self.track_queue[self.queue_step]] - self.start_time = pctl.master_library[self.track_queue[self.queue_step]].start_time - self.start_time_target = self.start_time - self.playing_length = pctl.master_library[self.track_queue[self.queue_step]].length - self.playerCommand = 'open' - self.playerCommandReady = True - self.playing_state = 1 + if prefs.meta_shows_selected_always: + if -1 < pctl.selected_in_playlist < len(self.multi_playlist[self.active_playlist_viewing][2]): + target_track = self.g(self.multi_playlist[self.active_playlist_viewing][2][pctl.selected_in_playlist]) - if tauon.stream_proxy.download_running: - tauon.stream_proxy.stop() + return target_track - self.show_current() - self.render_playlist() + def playing_object(self) -> TrackClass | None: - def deduct_shuffle(self, track_id): - if pctl.multi_playlist and self.random_mode: - pl = pctl.multi_playlist[pctl.active_playlist_playing] - id = pl[6] + if self.playing_state == 3: + return radiobox.dummy_track - if id not in pctl.shuffle_pools: - self.update_shuffle_pool(pl[6]) + if len(self.track_queue) > 0: + return self.master_library[self.track_queue[self.queue_step]] + else: + return None - pool = pctl.shuffle_pools[id] - if not pool: - del pctl.shuffle_pools[id] - self.update_shuffle_pool(pl[6]) - pool = pctl.shuffle_pools[id] + def title_text(self): - if track_id in pool: - pool.remove(track_id) + line = "" + track = pctl.playing_object() + if track: + title = track.title + artist = track.artist + if not title: + line = clean_string(track.filename) + else: + if artist != "": + line += artist + if title != "": + if line != "": + line += " - " + line += title - def play_target_rr(self): - tm.ready_playback() - self.playing_length = pctl.master_library[self.track_queue[self.queue_step]].length + if pctl.playing_state == 3 and not title and not artist: + return pctl.tag_meta - if self.playing_length > 2: - random_start = random.randrange(1, int(self.playing_length) - 45 if self.playing_length > 50 else int( - self.playing_length)) - else: - random_start = 0 - - self.playing_time = random_start - self.target_open = pctl.master_library[self.track_queue[self.queue_step]].fullpath - self.target_object = pctl.master_library[self.track_queue[self.queue_step]] - self.start_time = pctl.master_library[self.track_queue[self.queue_step]].start_time - self.start_time_target = self.start_time - self.jump_time = random_start - self.playerCommand = 'open' - if not prefs.use_jump_crossfade: - self.playerSubCommand = 'now' - self.playerCommandReady = True - self.playing_state = 1 - radiobox.loaded_station = None + return line - if tauon.stream_proxy.download_running: - tauon.stream_proxy.stop() + def show(self): - if update_title: - update_title_do() + global shift_selection - self.deduct_shuffle(self.target_object.index) + if not self.track_queue: + return 0 - def play_target(self, gapless=False, jump=False): + def show_current( + self, select=True, playing=True, quiet=False, this_only=False, highlight=False, index=None, + no_switch=False, folder_list=True): + + # logging.info("show------") + # logging.info(select) + # logging.info(playing) + # logging.info(quiet) + # logging.info(this_only) + # logging.info(highlight) + # logging.info("--------") + console.print("DEBUG: Position set by show playing") + + global shift_selection + + if spot_ctl.coasting: + sptr = tauon.dummy_track.misc.get("spotify-track-url") + if sptr: + + for p in default_playlist: + tr = pctl.g(p) + if tr.misc.get("spotify-track-url") == sptr: + index = tr.index + break + else: + for i, pl in enumerate(pctl.multi_playlist): + for p in pl[2]: + tr = pctl.g(p) + if tr.misc.get("spotify-track-url") == sptr: + index = tr.index + switch_playlist(i) + break + else: + continue + break + else: + return - tm.ready_playback() + if not self.track_queue: + return 0 - #logging.info(self.track_queue) - self.playing_time = 0 - self.decode_time = 0 - target = pctl.master_library[self.track_queue[self.queue_step]] - self.target_open = target.fullpath - self.target_object = target - self.start_time = target.start_time - self.start_time_target = self.start_time - self.playing_length = target.length - self.last_playing_time = 0 - self.commit = None - radiobox.loaded_station = None - - if tauon.stream_proxy and tauon.stream_proxy.download_running: - tauon.stream_proxy.stop() - - if pctl.multi_playlist[pctl.active_playlist_playing][11]: - t = target.misc.get("position", 0) - if t: - self.playing_time = 0 - self.decode_time = 0 - self.jump_time = t - - self.playerCommand = 'open' - if jump: # and not prefs.use_jump_crossfade: - self.playerSubCommand = 'now' - - self.playerCommandReady = True - - self.playing_state = 1 - self.update_change() - self.deduct_shuffle(target.index) - - def update_change(self): - if update_title: - update_title_do() - self.notify_update() - hit_discord() - self.render_playlist() + track_index = self.track_queue[self.queue_step] + if index is not None: + track_index = index - if lfm_scrobbler.a_sc: - lfm_scrobbler.a_sc = False - self.a_time = 0 + # Switch to source playlist + if not no_switch: + if self.active_playlist_viewing != self.active_playlist_playing and ( + track_index not in self.multi_playlist[self.active_playlist_viewing][2]): + switch_playlist(self.active_playlist_playing) - lfm_scrobbler.start_queue() + if gui.playlist_view_length < 1: + return 0 - if (album_mode or not gui.rsp) and (gui.theme_name == "Carbon" or prefs.colour_from_image): - target = self.playing_object() - if target and prefs.colour_from_image and target.parent_folder_path == colours.last_album: - return + for i in range(len(self.multi_playlist[self.active_playlist_viewing][2])): + if self.multi_playlist[self.active_playlist_viewing][2][i] == track_index: - album_art_gen.display(target, (0, 0), (50, 50), theme_only=True) + if self.playlist_playing_position < len(self.multi_playlist[self.active_playlist_viewing][2]) and \ + self.active_playlist_viewing == self.active_playlist_playing and track_index == \ + self.multi_playlist[self.active_playlist_viewing][2][self.playlist_playing_position] and \ + i != self.playlist_playing_position: + # continue + i = self.playlist_playing_position - def jump(self, index, pl_position=None, jump=True): + if select: + pctl.selected_in_playlist = i - lfm_scrobbler.start_queue() - pctl.auto_stop = False + if playing: + # Make the found track the playing track + self.playlist_playing_position = i + self.active_playlist_playing = self.active_playlist_viewing - if self.force_queue and not pctl.pause_queue: - if self.force_queue[0][4] == 1: - if pctl.g(self.force_queue[0][0]).parent_folder_path != pctl.g(index).parent_folder_path: - del self.force_queue[0] + vl = gui.playlist_view_length + if pctl.multi_playlist[pctl.active_playlist_viewing][6] == gui.playlist_current_visible_tracks_id: + vl = gui.playlist_current_visible_tracks - if len(self.track_queue) > 0: - self.left_time = self.playing_time - self.left_index = self.track_queue[self.queue_step] + if not ( + quiet and self.playing_object().length < 15): # or (abs(pctl.playlist_view_position - i) < vl - 1)): - if self.playing_state == 1 and self.left_time > 5 and self.playing_length - self.left_time > 15: - pctl.master_library[self.left_index].skips += 1 + # Align to album if in view range (and folder titles are active) + ap = get_album_info(i)[1][0] - global playlist_hold - gui.update_spec = 0 - self.active_playlist_playing = self.active_playlist_viewing - self.track_queue.append(index) - self.queue_step = len(self.track_queue) - 1 - playlist_hold = False - self.play_target(jump=jump) + if not (quiet and pctl.playlist_view_position <= i <= pctl.playlist_view_position + vl) and ( + not abs(i - ap) > vl - 2) and not pctl.multi_playlist[pctl.active_playlist_viewing][4]: + pctl.playlist_view_position = ap - if pl_position is not None: - self.playlist_playing_position = pl_position + else: + # Move to a random offset --- + + if i == pctl.playlist_view_position - 1 and pctl.playlist_view_position > 1: + pctl.playlist_view_position -= 1 + + # Move a bit if its just out of range + elif pctl.playlist_view_position + vl - 2 == i and i < len( + self.multi_playlist[self.active_playlist_viewing][2]) - 5: + pctl.playlist_view_position += 3 + + # We know its out of range if above view postion + elif i < pctl.playlist_view_position: + pctl.playlist_view_position = i - random.randint(2, int(( + gui.playlist_view_length / 3) * 2) + int(gui.playlist_view_length / 6)) + + # If its below we need to test if its in view. If playing track in view, don't jump. + elif abs(pctl.playlist_view_position - i) >= vl: + pctl.playlist_view_position = i + if i > 6: + pctl.playlist_view_position -= 5 + if i > gui.playlist_view_length and i + (gui.playlist_view_length * 2) < len( + self.multi_playlist[self.active_playlist_viewing][2]) and i > 10: + pctl.playlist_view_position = i - random.randint(2, + int(gui.playlist_view_length / 3) * 2) + + break + + else: # Search other all other playlists + if not this_only: + for i, playlist in enumerate(self.multi_playlist): + if track_index in playlist[2]: + switch_playlist(i, quiet=True) + self.show_current(select, playing, quiet, this_only=True, index=track_index) + break + + if pctl.playlist_view_position < 0: + pctl.playlist_view_position = 0 + + # if pctl.playlist_view_position > len(self.multi_playlist[self.active_playlist_viewing][2]) - 1: + # logging.info("Run Over") + + if select: + shift_selection = [] + + self.render_playlist() + + if album_mode and not quiet: + if highlight: + gui.gallery_animate_highlight_on = goto_album(pctl.selected_in_playlist) + gallery_select_animate_timer.set() + else: + goto_album(pctl.selected_in_playlist) - gui.pl_update = 1 + if prefs.left_panel_mode == "artist list" and gui.lsp and not quiet: + artist_list_box.locate_artist(pctl.playing_object()) - def back(self): + if folder_list and prefs.left_panel_mode == "folder view" and gui.lsp and not quiet and not tree_view_box.lock_pl: + tree_view_box.show_track(pctl.playing_object()) - if self.playing_state < 3 and prefs.back_restarts and pctl.playing_time > 6: - self.seek_time(0) - self.render_playlist() - return + return 0 - if spot_ctl.coasting: - spot_ctl.control("previous") - spot_ctl.update_timer.set() - self.playing_time = -2 - self.decode_time = -2 - return + def toggle_mute(self): + global volume_store + if pctl.player_volume > 0: + volume_store = pctl.player_volume + pctl.player_volume = 0 + else: + pctl.player_volume = volume_store - if len(self.track_queue) > 0: - self.left_time = self.playing_time - self.left_index = self.track_queue[self.queue_step] + pctl.set_volume() - gui.update_spec = 0 - # Move up - if self.random_mode is False and len(self.playing_playlist()) > self.playlist_playing_position > 0: + def set_volume(self, notify=True): - if len(self.track_queue) > 0 and self.playing_playlist()[self.playlist_playing_position] != \ - self.track_queue[ - self.queue_step]: + if (spot_ctl.coasting or spot_ctl.playing) and not spot_ctl.local and mouse_down: + # Rate limit network volume change + t = self.volume_update_timer.get() + if t < 0.3: + return - try: - p = self.playing_playlist().index(self.track_queue[self.queue_step]) - except Exception: - logging.exception("Failed to change playing_playlist") - p = random.randrange(len(self.playing_playlist())) - if p is not None: - self.playlist_playing_position = p - - self.playlist_playing_position -= 1 - self.track_queue.append(self.playing_playlist()[self.playlist_playing_position]) - self.queue_step = len(self.track_queue) - 1 - self.play_target(jump=True) - - elif self.random_mode is True and self.queue_step > 0: - self.queue_step -= 1 - self.play_target(jump=True) - else: - logging.info("BACK: NO CASE!") - self.show_current() + self.volume_update_timer.set() + self.playerCommand = 'volume' + self.playerCommandReady = True + if notify: + self.notify_update() - if self.active_playlist_viewing == self.active_playlist_playing: - self.show_current(False, True) + def revert(self): - if album_mode: - goto_album(self.playlist_playing_position) - if gui.combo_mode and self.active_playlist_viewing == self.active_playlist_playing: - self.show_current() - - self.render_playlist() - self.notify_update() - notify_song() - lfm_scrobbler.start_queue() - gui.pl_update += 1 + if self.queue_step == 0: + return - def stop(self, block=False, run=False): + prev = 0 + while len(self.track_queue) > prev + 1 and prev < 5: + if self.track_queue[len(self.track_queue) - 1 - prev] == self.left_index: + self.queue_step = len(self.track_queue) - 1 - prev + self.jump_time = self.left_time + self.playing_time = self.left_time + self.decode_time = self.left_time + break + prev += 1 + else: + self.queue_step -= 1 + self.jump_time = 0 + self.playing_time = 0 + self.decode_time = 0 - self.playerCommand = 'stop' - if run: - self.playerCommand = 'runstop' - if block: - self.playerSubCommand = "return" + if not len(self.track_queue) > self.queue_step >= 0: + logging.error("There is no previous track?") + return - self.playerCommandReady = True + self.target_open = pctl.master_library[self.track_queue[self.queue_step]].fullpath + self.target_object = pctl.master_library[self.track_queue[self.queue_step]] + self.start_time = pctl.master_library[self.track_queue[self.queue_step]].start_time + self.start_time_target = self.start_time + self.playing_length = pctl.master_library[self.track_queue[self.queue_step]].length + self.playerCommand = 'open' + self.playerCommandReady = True + self.playing_state = 1 - try: - tm.player_lock.release() - except Exception: - logging.exception("Failed to release player_lock") - - self.record_stream = False - if len(self.track_queue) > 0: - self.left_time = self.playing_time - self.left_index = self.track_queue[self.queue_step] - previous_state = self.playing_state - self.playing_time = 0 - self.decode_time = 0 - self.playing_state = 0 - self.render_playlist() - - gui.update_spec = 0 - # gui.update_level = True # Allows visualiser to enter decay sequence - gui.update = True - if update_title: - update_title_do() # Update title bar text - - if tauon.stream_proxy and tauon.stream_proxy.download_running: - tauon.stream_proxy.stop() - - if block: - loop = 0 - sleep_timeout(lambda: self.playerSubCommand != "stopped", 2) - if tauon.stream_proxy.download_running: - sleep_timeout(lambda: tauon.stream_proxy.download_running, 2) + if tauon.stream_proxy.download_running: + tauon.stream_proxy.stop() - if spot_ctl.playing or spot_ctl.coasting: - logging.info("Spotify stop") - spot_ctl.control("stop") + self.show_current() + self.render_playlist() - self.notify_update() - lfm_scrobbler.start_queue() - return previous_state + def deduct_shuffle(self, track_id): + if pctl.multi_playlist and self.random_mode: + pl = pctl.multi_playlist[pctl.active_playlist_playing] + id = pl[6] - def pause(self): + if id not in pctl.shuffle_pools: + self.update_shuffle_pool(pl[6]) - if tauon.spotc and tauon.spotc.running and spot_ctl.playing: - if self.playing_state == 1: - self.playerCommand = 'pauseon' - self.playerCommandReady = True - elif self.playing_state == 2: - self.playerCommand = 'pauseoff' - self.playerCommandReady = True + pool = pctl.shuffle_pools[id] + if not pool: + del pctl.shuffle_pools[id] + self.update_shuffle_pool(pl[6]) + pool = pctl.shuffle_pools[id] - if self.playing_state == 3: - if spot_ctl.coasting: - if spot_ctl.paused: - spot_ctl.control("resume") - else: - spot_ctl.control("pause") - return + if track_id in pool: + pool.remove(track_id) - if spot_ctl.playing: - if self.playing_state == 2: - spot_ctl.control("resume") - self.playing_state = 1 - elif self.playing_state == 1: - spot_ctl.control("pause") - self.playing_state = 2 - self.render_playlist() - return - if self.playing_state == 1: - self.playerCommand = 'pauseon' - self.playing_state = 2 - elif self.playing_state == 2: - self.playerCommand = 'pauseoff' - self.playing_state = 1 - notify_song() - - self.playerCommandReady = True - - self.render_playlist() - self.notify_update() - - def pause_only(self): - if self.playing_state == 1: - self.playerCommand = 'pauseon' - self.playing_state = 2 - - self.playerCommandReady = True - self.render_playlist() - self.notify_update() - - def play_pause(self): - if self.playing_state == 3: - self.stop() - elif self.playing_state > 0: - self.pause() - else: - self.play() + def play_target_rr(self): + tm.ready_playback() + self.playing_length = pctl.master_library[self.track_queue[self.queue_step]].length - def seek_decimal(self, decimal): - # if self.commit: - # return - if self.playing_state == 1 or self.playing_state == 2 or (self.playing_state == 3 and spot_ctl.coasting): - if decimal > 1: - decimal = 1 - elif decimal < 0: - decimal = 0 - self.new_time = pctl.playing_length * decimal - #logging.info('seek to:' + str(pctl.new_time)) - self.playerCommand = 'seek' - self.playerCommandReady = True - self.playing_time = self.new_time - - if msys and taskbar_progress and self.windows_progress: - self.windows_progress.update(True) - - if self.mpris is not None: - self.mpris.seek_do(self.playing_time) - - def seek_time(self, new): - # if self.commit: - # return - if self.playing_state == 1 or self.playing_state == 2 or (self.playing_state == 3 and spot_ctl.coasting): + if self.playing_length > 2: + random_start = random.randrange(1, int(self.playing_length) - 45 if self.playing_length > 50 else int( + self.playing_length)) + else: + random_start = 0 + + self.playing_time = random_start + self.target_open = pctl.master_library[self.track_queue[self.queue_step]].fullpath + self.target_object = pctl.master_library[self.track_queue[self.queue_step]] + self.start_time = pctl.master_library[self.track_queue[self.queue_step]].start_time + self.start_time_target = self.start_time + self.jump_time = random_start + self.playerCommand = 'open' + if not prefs.use_jump_crossfade: + self.playerSubCommand = 'now' + self.playerCommandReady = True + self.playing_state = 1 + radiobox.loaded_station = None + + if tauon.stream_proxy.download_running: + tauon.stream_proxy.stop() + + if update_title: + update_title_do() + + self.deduct_shuffle(self.target_object.index) + + def play_target(self, gapless=False, jump=False): + + tm.ready_playback() + + #logging.info(self.track_queue) + self.playing_time = 0 + self.decode_time = 0 + target = pctl.master_library[self.track_queue[self.queue_step]] + self.target_open = target.fullpath + self.target_object = target + self.start_time = target.start_time + self.start_time_target = self.start_time + self.playing_length = target.length + self.last_playing_time = 0 + self.commit = None + radiobox.loaded_station = None + + if tauon.stream_proxy and tauon.stream_proxy.download_running: + tauon.stream_proxy.stop() + + if pctl.multi_playlist[pctl.active_playlist_playing][11]: + t = target.misc.get("position", 0) + if t: + self.playing_time = 0 + self.decode_time = 0 + self.jump_time = t + + self.playerCommand = 'open' + if jump: # and not prefs.use_jump_crossfade: + self.playerSubCommand = 'now' + + self.playerCommandReady = True + + self.playing_state = 1 + self.update_change() + self.deduct_shuffle(target.index) + + def update_change(self): + if update_title: + update_title_do() + self.notify_update() + hit_discord() + self.render_playlist() + + if lfm_scrobbler.a_sc: + lfm_scrobbler.a_sc = False + self.a_time = 0 + + lfm_scrobbler.start_queue() + + if (album_mode or not gui.rsp) and (gui.theme_name == "Carbon" or prefs.colour_from_image): + target = self.playing_object() + if target and prefs.colour_from_image and target.parent_folder_path == colours.last_album: + return - if new > self.playing_length - 0.5: - self.advance() - return + album_art_gen.display(target, (0, 0), (50, 50), theme_only=True) - if new < 0.4: - new = 0 + def jump(self, index, pl_position=None, jump=True): - self.new_time = new - self.playing_time = new + lfm_scrobbler.start_queue() + pctl.auto_stop = False - self.playerCommand = 'seek' - self.playerCommandReady = True + if self.force_queue and not pctl.pause_queue: + if self.force_queue[0][4] == 1: + if pctl.g(self.force_queue[0][0]).parent_folder_path != pctl.g(index).parent_folder_path: + del self.force_queue[0] - if self.mpris is not None: - self.mpris.seek_do(self.playing_time) + if len(self.track_queue) > 0: + self.left_time = self.playing_time + self.left_index = self.track_queue[self.queue_step] - def play(self): + if self.playing_state == 1 and self.left_time > 5 and self.playing_length - self.left_time > 15: + pctl.master_library[self.left_index].skips += 1 - if spot_ctl.playing: - if self.playing_state == 2: - self.play_pause() - return + global playlist_hold + gui.update_spec = 0 + self.active_playlist_playing = self.active_playlist_viewing + self.track_queue.append(index) + self.queue_step = len(self.track_queue) - 1 + playlist_hold = False + self.play_target(jump=jump) - # Unpause if paused - if self.playing_state == 2: - self.playerCommand = 'pauseoff' - self.playerCommandReady = True - self.playing_state = 1 - self.notify_update() + if pl_position is not None: + self.playlist_playing_position = pl_position - # If stopped... - elif pctl.playing_state == 0: + gui.pl_update = 1 - if radiobox.loaded_station: - radiobox.start(radiobox.loaded_station) - return + def back(self): - # If the queue is empty - if self.track_queue == [] and len(self.multi_playlist[self.active_playlist_playing][2]) > 0: - self.track_queue.append(self.multi_playlist[self.active_playlist_playing][2][0]) - self.queue_step = 0 - self.playlist_playing_position = 0 - self.active_playlist_playing = 0 + if self.playing_state < 3 and prefs.back_restarts and pctl.playing_time > 6: + self.seek_time(0) + self.render_playlist() + return - self.play_target() + if spot_ctl.coasting: + spot_ctl.control("previous") + spot_ctl.update_timer.set() + self.playing_time = -2 + self.decode_time = -2 + return - # If the queue is not empty, play? - elif len(self.track_queue) > 0: - self.play_target() + if len(self.track_queue) > 0: + self.left_time = self.playing_time + self.left_index = self.track_queue[self.queue_step] + + gui.update_spec = 0 + # Move up + if self.random_mode is False and len(self.playing_playlist()) > self.playlist_playing_position > 0: + + if len(self.track_queue) > 0 and self.playing_playlist()[self.playlist_playing_position] != \ + self.track_queue[ + self.queue_step]: + + try: + p = self.playing_playlist().index(self.track_queue[self.queue_step]) + except Exception: + logging.exception("Failed to change playing_playlist") + p = random.randrange(len(self.playing_playlist())) + if p is not None: + self.playlist_playing_position = p + + self.playlist_playing_position -= 1 + self.track_queue.append(self.playing_playlist()[self.playlist_playing_position]) + self.queue_step = len(self.track_queue) - 1 + self.play_target(jump=True) + + elif self.random_mode is True and self.queue_step > 0: + self.queue_step -= 1 + self.play_target(jump=True) + else: + logging.info("BACK: NO CASE!") + self.show_current() + + if self.active_playlist_viewing == self.active_playlist_playing: + self.show_current(False, True) + + if album_mode: + goto_album(self.playlist_playing_position) + if gui.combo_mode and self.active_playlist_viewing == self.active_playlist_playing: + self.show_current() + + self.render_playlist() + self.notify_update() + notify_song() + lfm_scrobbler.start_queue() + gui.pl_update += 1 + + def stop(self, block=False, run=False): + + self.playerCommand = 'stop' + if run: + self.playerCommand = 'runstop' + if block: + self.playerSubCommand = "return" + + self.playerCommandReady = True + + try: + tm.player_lock.release() + except Exception: + logging.exception("Failed to release player_lock") + + self.record_stream = False + if len(self.track_queue) > 0: + self.left_time = self.playing_time + self.left_index = self.track_queue[self.queue_step] + previous_state = self.playing_state + self.playing_time = 0 + self.decode_time = 0 + self.playing_state = 0 + self.render_playlist() + + gui.update_spec = 0 + # gui.update_level = True # Allows visualiser to enter decay sequence + gui.update = True + if update_title: + update_title_do() # Update title bar text + + if tauon.stream_proxy and tauon.stream_proxy.download_running: + tauon.stream_proxy.stop() + + if block: + loop = 0 + sleep_timeout(lambda: self.playerSubCommand != "stopped", 2) + if tauon.stream_proxy.download_running: + sleep_timeout(lambda: tauon.stream_proxy.download_running, 2) + + if spot_ctl.playing or spot_ctl.coasting: + logging.info("Spotify stop") + spot_ctl.control("stop") + + self.notify_update() + lfm_scrobbler.start_queue() + return previous_state + + def pause(self): + + if tauon.spotc and tauon.spotc.running and spot_ctl.playing: + if self.playing_state == 1: + self.playerCommand = 'pauseon' + self.playerCommandReady = True + elif self.playing_state == 2: + self.playerCommand = 'pauseoff' + self.playerCommandReady = True + + if self.playing_state == 3: + if spot_ctl.coasting: + if spot_ctl.paused: + spot_ctl.control("resume") + else: + spot_ctl.control("pause") + return - self.render_playlist() + if spot_ctl.playing: + if self.playing_state == 2: + spot_ctl.control("resume") + self.playing_state = 1 + elif self.playing_state == 1: + spot_ctl.control("pause") + self.playing_state = 2 + self.render_playlist() + return - def spot_test_progress(self): + if self.playing_state == 1: + self.playerCommand = 'pauseon' + self.playing_state = 2 + elif self.playing_state == 2: + self.playerCommand = 'pauseoff' + self.playing_state = 1 + notify_song() + + self.playerCommandReady = True + + self.render_playlist() + self.notify_update() + + def pause_only(self): + if self.playing_state == 1: + self.playerCommand = 'pauseon' + self.playing_state = 2 + + self.playerCommandReady = True + self.render_playlist() + self.notify_update() + + def play_pause(self): + if self.playing_state == 3: + self.stop() + elif self.playing_state > 0: + self.pause() + else: + self.play() + + def seek_decimal(self, decimal): + # if self.commit: + # return + if self.playing_state == 1 or self.playing_state == 2 or (self.playing_state == 3 and spot_ctl.coasting): + if decimal > 1: + decimal = 1 + elif decimal < 0: + decimal = 0 + self.new_time = pctl.playing_length * decimal + #logging.info('seek to:' + str(pctl.new_time)) + self.playerCommand = 'seek' + self.playerCommandReady = True + self.playing_time = self.new_time + + if msys and taskbar_progress and self.windows_progress: + self.windows_progress.update(True) + + if self.mpris is not None: + self.mpris.seek_do(self.playing_time) + + def seek_time(self, new): + # if self.commit: + # return + if self.playing_state == 1 or self.playing_state == 2 or (self.playing_state == 3 and spot_ctl.coasting): + + if new > self.playing_length - 0.5: + self.advance() + return - if (self.playing_state == 1 or self.playing_state == 2) and spot_ctl.playing: - th = 5 # the rate to poll the spotify API - if self.playing_time > self.playing_length: - th = 1 - if not spot_ctl.paused: - if spot_ctl.start_timer.get() < 0.5: - spot_ctl.progress_timer.set() - return - add_time = spot_ctl.progress_timer.get() - if add_time > 5: - add_time = 0 - self.playing_time += add_time - self.decode_time = self.playing_time - # self.test_progress() - spot_ctl.progress_timer.set() - if len(self.track_queue) > 0 and 2 > add_time > 0: - star_store.add(self.track_queue[self.queue_step], add_time) - if spot_ctl.update_timer.get() > th: - spot_ctl.update_timer.set() - shooter(spot_ctl.monitor) - else: - self.test_progress() - - elif self.playing_state == 3 and spot_ctl.coasting: - th = 7 - if self.playing_time > self.playing_length or self.playing_time < 2.5: - th = 1 - if spot_ctl.update_timer.get() < th: - if not spot_ctl.paused: - self.playing_time += spot_ctl.progress_timer.get() - self.decode_time = self.playing_time - spot_ctl.progress_timer.set() + if new < 0.4: + new = 0 - else: - tauon.spot_ctl.update_timer.set() - tauon.spot_ctl.update() - - def purge_track(self, track_id, fast=False): # Remove a track from the database - # Remove from all playlists - if not fast: - for playlist in self.multi_playlist: - while track_id in playlist[2]: - album_dex.clear() - playlist[2].remove(track_id) - # Stop if track is playing track - if self.track_queue and self.track_queue[self.queue_step] == track_id and self.playing_state != 0: - self.stop(block=True) - # Remove from playback history - while track_id in self.track_queue: - self.track_queue.remove(track_id) - self.queue_step -= 1 - # Remove track from force queue - for i in reversed(range(len(self.force_queue))): - if self.force_queue[i][0] == track_id: - del self.force_queue[i] - del self.master_library[track_id] - - def test_progress(self): - - # Fuzzy reload lastfm for rescrobble - if lfm_scrobbler.a_sc and self.playing_time < 1: - lfm_scrobbler.a_sc = False - self.a_time = 0 - - # Update the UI if playing time changes a whole number - # next_round = int(pctl.playing_time) - # if self.playing_time_int != next_round: - # #if not prefs.power_save: - # #gui.update += 1 - # self.playing_time_int = next_round - - gap_extra = 2 # 2 - - if spot_ctl.playing or tauon.chrome_mode: - gap_extra = 3 - - if msys and taskbar_progress and self.windows_progress: - self.windows_progress.update(True) - - if self.commit is not None: - return + self.new_time = new + self.playing_time = new - if self.playing_state == 1 and pctl.multi_playlist[pctl.active_playlist_playing][11]: - tr = pctl.playing_object() - if tr: - tr.misc["position"] = pctl.decode_time + self.playerCommand = 'seek' + self.playerCommandReady = True - if self.playing_state == 1 and self.decode_time + gap_extra >= self.playing_length and self.decode_time > 0.2: + if self.mpris is not None: + self.mpris.seek_do(self.playing_time) - # Allow some time for spotify playing time to update? - if spot_ctl.playing and spot_ctl.start_timer.get() < 3: - return + def play(self): - # Allow some time for backend to provide a length - if self.playing_time < 6 and self.playing_length == 0: - return - if not spot_ctl.playing and pctl.a_time < 2: - return + if spot_ctl.playing: + if self.playing_state == 2: + self.play_pause() + return - self.decode_time = 0 + # Unpause if paused + if self.playing_state == 2: + self.playerCommand = 'pauseoff' + self.playerCommandReady = True + self.playing_state = 1 + self.notify_update() - pp = self.playing_playlist() + # If stopped... + elif pctl.playing_state == 0: - if pctl.auto_stop: # and not pctl.force_queue and not (pctl.force_queue and pctl.pause_queue): - self.stop(run=True) - if pctl.force_queue or (not pctl.force_queue and not pctl.random_mode and not pctl.repeat_mode): - self.advance(play=False) - gui.update += 2 - pctl.auto_stop = False + if radiobox.loaded_station: + radiobox.start(radiobox.loaded_station) + return - elif self.force_queue and not self.pause_queue: - id = self.advance(end=True, quiet=True, dry=True) - if id is not None: - self.start_commit(id) - return - else: - self.advance(end=True, quiet=True) + # If the queue is empty + if self.track_queue == [] and len(self.multi_playlist[self.active_playlist_playing][2]) > 0: + self.track_queue.append(self.multi_playlist[self.active_playlist_playing][2][0]) + self.queue_step = 0 + self.playlist_playing_position = 0 + self.active_playlist_playing = 0 + + self.play_target() + + # If the queue is not empty, play? + elif len(self.track_queue) > 0: + self.play_target() + + self.render_playlist() + + def spot_test_progress(self): + + if (self.playing_state == 1 or self.playing_state == 2) and spot_ctl.playing: + th = 5 # the rate to poll the spotify API + if self.playing_time > self.playing_length: + th = 1 + if not spot_ctl.paused: + if spot_ctl.start_timer.get() < 0.5: + spot_ctl.progress_timer.set() + return + add_time = spot_ctl.progress_timer.get() + if add_time > 5: + add_time = 0 + self.playing_time += add_time + self.decode_time = self.playing_time + # self.test_progress() + spot_ctl.progress_timer.set() + if len(self.track_queue) > 0 and 2 > add_time > 0: + star_store.add(self.track_queue[self.queue_step], add_time) + if spot_ctl.update_timer.get() > th: + spot_ctl.update_timer.set() + shooter(spot_ctl.monitor) + else: + self.test_progress() + + elif self.playing_state == 3 and spot_ctl.coasting: + th = 7 + if self.playing_time > self.playing_length or self.playing_time < 2.5: + th = 1 + if spot_ctl.update_timer.get() < th: + if not spot_ctl.paused: + self.playing_time += spot_ctl.progress_timer.get() + self.decode_time = self.playing_time + spot_ctl.progress_timer.set() + else: + tauon.spot_ctl.update_timer.set() + tauon.spot_ctl.update() + + def purge_track(self, track_id, fast=False): # Remove a track from the database + # Remove from all playlists + if not fast: + for playlist in self.multi_playlist: + while track_id in playlist[2]: + album_dex.clear() + playlist[2].remove(track_id) + # Stop if track is playing track + if self.track_queue and self.track_queue[self.queue_step] == track_id and self.playing_state != 0: + self.stop(block=True) + # Remove from playback history + while track_id in self.track_queue: + self.track_queue.remove(track_id) + self.queue_step -= 1 + # Remove track from force queue + for i in reversed(range(len(self.force_queue))): + if self.force_queue[i][0] == track_id: + del self.force_queue[i] + del self.master_library[track_id] + + def test_progress(self): + + # Fuzzy reload lastfm for rescrobble + if lfm_scrobbler.a_sc and self.playing_time < 1: + lfm_scrobbler.a_sc = False + self.a_time = 0 + + # Update the UI if playing time changes a whole number + # next_round = int(pctl.playing_time) + # if self.playing_time_int != next_round: + # #if not prefs.power_save: + # #gui.update += 1 + # self.playing_time_int = next_round + + gap_extra = 2 # 2 + + if spot_ctl.playing or tauon.chrome_mode: + gap_extra = 3 + + if msys and taskbar_progress and self.windows_progress: + self.windows_progress.update(True) + + if self.commit is not None: + return + if self.playing_state == 1 and pctl.multi_playlist[pctl.active_playlist_playing][11]: + tr = pctl.playing_object() + if tr: + tr.misc["position"] = pctl.decode_time - elif self.repeat_mode is True: + if self.playing_state == 1 and self.decode_time + gap_extra >= self.playing_length and self.decode_time > 0.2: - if self.album_repeat_mode: + # Allow some time for spotify playing time to update? + if spot_ctl.playing and spot_ctl.start_timer.get() < 3: + return - if self.playlist_playing_position > len(pp) - 1: - self.playlist_playing_position = 0 # Hack fix, race condition bug? + # Allow some time for backend to provide a length + if self.playing_time < 6 and self.playing_length == 0: + return + if not spot_ctl.playing and pctl.a_time < 2: + return - ti = self.g(pp[self.playlist_playing_position]) + self.decode_time = 0 - i = self.playlist_playing_position + pp = self.playing_playlist() - # Test if next track is in same folder - if i + 1 < len(pp): - nt = self.g(pp[i + 1]) - if ti.parent_folder_path == nt.parent_folder_path: - # The next track is in the same folder - # so advance normally - self.advance(quiet=True, end=True) - return + if pctl.auto_stop: # and not pctl.force_queue and not (pctl.force_queue and pctl.pause_queue): + self.stop(run=True) + if pctl.force_queue or (not pctl.force_queue and not pctl.random_mode and not pctl.repeat_mode): + self.advance(play=False) + gui.update += 2 + pctl.auto_stop = False - # We need to backtrack to see where the folder begins - i -= 1 - while i >= 0: - nt = self.g(pp[i]) - if ti.parent_folder_path != nt.parent_folder_path: - i += 1 - break - i -= 1 - if i < 0: - i = 0 + elif self.force_queue and not self.pause_queue: + id = self.advance(end=True, quiet=True, dry=True) + if id is not None: + self.start_commit(id) + return + else: + self.advance(end=True, quiet=True) - pctl.selected_in_playlist = i - shift_selection = [i] - self.jump(pp[i], i, jump=False) - elif prefs.playback_follow_cursor and self.playing_ready() \ - and self.multi_playlist[pctl.active_playlist_viewing][2][ - pctl.selected_in_playlist] != self.playing_object().index \ - and -1 < pctl.selected_in_playlist < len(default_playlist): + elif self.repeat_mode is True: - logging.info("Repeat follow cursor") + if self.album_repeat_mode: - self.playing_time = 0 - self.decode_time = 0 - self.active_playlist_playing = self.active_playlist_viewing - self.playlist_playing_position = pctl.selected_in_playlist + if self.playlist_playing_position > len(pp) - 1: + self.playlist_playing_position = 0 # Hack fix, race condition bug? - self.track_queue.append(default_playlist[pctl.selected_in_playlist]) - self.queue_step = len(self.track_queue) - 1 - self.play_target(jump=False) - self.render_playlist() - lfm_scrobbler.start_queue() + ti = self.g(pp[self.playlist_playing_position]) - else: - id = self.track_queue[self.queue_step] - self.commit = id - target = self.g(id) - self.target_open = target.fullpath - self.target_object = target - self.start_time = target.start_time - self.start_time_target = self.start_time - self.playerCommand = 'open' - self.playerSubCommand = 'repeat' - self.playerCommandReady = True - - #self.render_playlist() - lfm_scrobbler.start_queue() - - # Reload lastfm for rescrobble - if lfm_scrobbler.a_sc: - lfm_scrobbler.a_sc = False - self.a_time = 0 - - elif self.random_mode is False and len(pp) > self.playlist_playing_position + 1 and \ - self.master_library[pp[self.playlist_playing_position]].is_cue is True \ - and self.master_library[pp[self.playlist_playing_position + 1]].filename == \ - self.master_library[pp[self.playlist_playing_position]].filename and int( - self.master_library[pp[self.playlist_playing_position]].track_number) == int( - self.master_library[pp[self.playlist_playing_position + 1]].track_number) - 1: - - # not (self.force_queue and not self.pause_queue) and \ - - # We can shave it closer - if not self.playing_time + 0.1 >= self.playing_length: - return + i = self.playlist_playing_position - logging.info("Do transition CUE") - self.playlist_playing_position += 1 - self.queue_step += 1 - self.track_queue.append(pp[self.playlist_playing_position]) - self.playing_state = 1 - self.playing_time = 0 - self.decode_time = 0 - self.playing_length = self.master_library[self.track_queue[self.queue_step]].length - self.start_time = self.master_library[self.track_queue[self.queue_step]].start_time - self.start_time_target = self.start_time - lfm_scrobbler.start_queue() + # Test if next track is in same folder + if i + 1 < len(pp): + nt = self.g(pp[i + 1]) + if ti.parent_folder_path == nt.parent_folder_path: + # The next track is in the same folder + # so advance normally + self.advance(quiet=True, end=True) + return - gui.update += 1 - gui.pl_update = 1 + # We need to backtrack to see where the folder begins + i -= 1 + while i >= 0: + nt = self.g(pp[i]) + if ti.parent_folder_path != nt.parent_folder_path: + i += 1 + break + i -= 1 + if i < 0: + i = 0 - if update_title: - update_title_do() - self.notify_update() - else: - # self.advance(quiet=True, end=True) + pctl.selected_in_playlist = i + shift_selection = [i] - id = self.advance(quiet=True, end=True, dry=True) - if id is not None and not spot_ctl.playing: - #logging.info("Commit") - self.start_commit(id) - return + self.jump(pp[i], i, jump=False) - self.advance(quiet=True, end=True) - self.playing_time = 0 - self.decode_time = 0 - - def start_commit(self, id, repeat=False): - self.commit = id - target = self.g(id) - self.target_open = target.fullpath - self.target_object = target - self.start_time = target.start_time - self.start_time_target = self.start_time - self.playerCommand = 'open' - if repeat: - self.playerSubCommand = 'repeat' - self.playerCommandReady = True - - def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, play=True, dry=False): - - # Spotify remote control mode - if not dry: - if spot_ctl.coasting: - spot_ctl.control("next") - spot_ctl.update_timer.set() - self.playing_time = -2 - self.decode_time = -2 - return + elif prefs.playback_follow_cursor and self.playing_ready() \ + and self.multi_playlist[pctl.active_playlist_viewing][2][ + pctl.selected_in_playlist] != self.playing_object().index \ + and -1 < pctl.selected_in_playlist < len(default_playlist): - # Temporary Workaround for UI block causing unwanted dragging - if not dry: - quick_d_timer.set() + logging.info("Repeat follow cursor") - if prefs.show_current_on_transition: - quiet = False + self.playing_time = 0 + self.decode_time = 0 + self.active_playlist_playing = self.active_playlist_viewing + self.playlist_playing_position = pctl.selected_in_playlist - # Trim the history if it gets too long - while len(self.track_queue) > 250: - self.queue_step -= 1 - del self.track_queue[0] + self.track_queue.append(default_playlist[pctl.selected_in_playlist]) + self.queue_step = len(self.track_queue) - 1 + self.play_target(jump=False) + self.render_playlist() + lfm_scrobbler.start_queue() - # Save info about the track we are leaving - if not dry: - if len(self.track_queue) > 0: - self.left_time = self.playing_time - self.left_index = self.track_queue[self.queue_step] + else: + id = self.track_queue[self.queue_step] + self.commit = id + target = self.g(id) + self.target_open = target.fullpath + self.target_object = target + self.start_time = target.start_time + self.start_time_target = self.start_time + self.playerCommand = 'open' + self.playerSubCommand = 'repeat' + self.playerCommandReady = True + + #self.render_playlist() + lfm_scrobbler.start_queue() + + # Reload lastfm for rescrobble + if lfm_scrobbler.a_sc: + lfm_scrobbler.a_sc = False + self.a_time = 0 + + elif self.random_mode is False and len(pp) > self.playlist_playing_position + 1 and \ + self.master_library[pp[self.playlist_playing_position]].is_cue is True \ + and self.master_library[pp[self.playlist_playing_position + 1]].filename == \ + self.master_library[pp[self.playlist_playing_position]].filename and int( + self.master_library[pp[self.playlist_playing_position]].track_number) == int( + self.master_library[pp[self.playlist_playing_position + 1]].track_number) - 1: + + # not (self.force_queue and not self.pause_queue) and \ + + # We can shave it closer + if not self.playing_time + 0.1 >= self.playing_length: + return + + logging.info("Do transition CUE") + self.playlist_playing_position += 1 + self.queue_step += 1 + self.track_queue.append(pp[self.playlist_playing_position]) + self.playing_state = 1 + self.playing_time = 0 + self.decode_time = 0 + self.playing_length = self.master_library[self.track_queue[self.queue_step]].length + self.start_time = self.master_library[self.track_queue[self.queue_step]].start_time + self.start_time_target = self.start_time + lfm_scrobbler.start_queue() + + gui.update += 1 + gui.pl_update = 1 + + if update_title: + update_title_do() + self.notify_update() + else: + # self.advance(quiet=True, end=True) + + id = self.advance(quiet=True, end=True, dry=True) + if id is not None and not spot_ctl.playing: + #logging.info("Commit") + self.start_commit(id) + return + + self.advance(quiet=True, end=True) + self.playing_time = 0 + self.decode_time = 0 + + def start_commit(self, id, repeat=False): + self.commit = id + target = self.g(id) + self.target_open = target.fullpath + self.target_object = target + self.start_time = target.start_time + self.start_time_target = self.start_time + self.playerCommand = 'open' + if repeat: + self.playerSubCommand = 'repeat' + self.playerCommandReady = True + + def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, play=True, dry=False): + + # Spotify remote control mode + if not dry: + if spot_ctl.coasting: + spot_ctl.control("next") + spot_ctl.update_timer.set() + self.playing_time = -2 + self.decode_time = -2 + return - # Test to register skip (not currently used for anything) - if not dry: - if self.playing_state == 1 and 1 < self.left_time < 45: - pctl.master_library[self.left_index].skips += 1 - #logging.info('skip registered') + # Temporary Workaround for UI block causing unwanted dragging + if not dry: + quick_d_timer.set() - if not dry: - pctl.playing_time = 0 - pctl.decode_time = 0 - pctl.playing_length = 100 - gui.update_spec = 0 + if prefs.show_current_on_transition: + quiet = False - old = self.queue_step - end_of_playlist = False + # Trim the history if it gets too long + while len(self.track_queue) > 250: + self.queue_step -= 1 + del self.track_queue[0] - # Force queue (middle click on track) - if len(self.force_queue) > 0 and not self.pause_queue: + # Save info about the track we are leaving + if not dry: + if len(self.track_queue) > 0: + self.left_time = self.playing_time + self.left_index = self.track_queue[self.queue_step] - q = self.force_queue[0] - target_index = q[0] + # Test to register skip (not currently used for anything) + if not dry: + if self.playing_state == 1 and 1 < self.left_time < 45: + pctl.master_library[self.left_index].skips += 1 + #logging.info('skip registered') - if q[3] == 1: - # This is an album type + if not dry: + pctl.playing_time = 0 + pctl.decode_time = 0 + pctl.playing_length = 100 + gui.update_spec = 0 - if q[4] == 0: - # We have not started playing the album yet - # So we go to that track - # (This is a copy of the track code, but we don't delete the item) + old = self.queue_step + end_of_playlist = False - if not dry: + # Force queue (middle click on track) + if len(self.force_queue) > 0 and not self.pause_queue: - pl = id_to_pl(q[2]) - if pl is not None: - self.active_playlist_playing = pl + q = self.force_queue[0] + target_index = q[0] - if target_index not in self.playing_playlist(): - del self.force_queue[0] - self.advance() - return + if q[3] == 1: + # This is an album type - if dry: - return target_index + if q[4] == 0: + # We have not started playing the album yet + # So we go to that track + # (This is a copy of the track code, but we don't delete the item) - self.playlist_playing_position = q[1] - self.track_queue.append(target_index) - self.queue_step = len(self.track_queue) - 1 - # self.queue_target = len(self.track_queue) - 1 - if play: - self.play_target(jump=not end) + if not dry: - # Set the flag that we have entered the album - self.force_queue[0][4] = 1 + pl = id_to_pl(q[2]) + if pl is not None: + self.active_playlist_playing = pl - # This code is mirrored below ------- - ok_continue = True + if target_index not in self.playing_playlist(): + del self.force_queue[0] + self.advance() + return - # Check if we are at end of playlist - pl = pctl.multi_playlist[pctl.active_playlist_playing][2] - if self.playlist_playing_position > len(pl) - 3: - ok_continue = False + if dry: + return target_index - # Check next song is in album - if ok_continue: - if self.g(pl[self.playlist_playing_position + 1]).parent_folder_path != pctl.g( - target_index).parent_folder_path: - ok_continue = False + self.playlist_playing_position = q[1] + self.track_queue.append(target_index) + self.queue_step = len(self.track_queue) - 1 + # self.queue_target = len(self.track_queue) - 1 + if play: + self.play_target(jump=not end) - # ----------- + # Set the flag that we have entered the album + self.force_queue[0][4] = 1 + # This code is mirrored below ------- + ok_continue = True - elif q[4] == 1: - # We have previously started playing this album + # Check if we are at end of playlist + pl = pctl.multi_playlist[pctl.active_playlist_playing][2] + if self.playlist_playing_position > len(pl) - 3: + ok_continue = False - # Check to see if we still are: - ok_continue = True + # Check next song is in album + if ok_continue: + if self.g(pl[self.playlist_playing_position + 1]).parent_folder_path != pctl.g( + target_index).parent_folder_path: + ok_continue = False - if pctl.g(target_index).parent_folder_path != pctl.playing_object().parent_folder_path: - # Remember to set jumper check this too (leave album if we jump to some other track, i.e. double click)) - ok_continue = False + # ----------- - pl = pctl.multi_playlist[pctl.active_playlist_playing][2] - # Check next song is in album - if ok_continue: + elif q[4] == 1: + # We have previously started playing this album - # Check if we are at end of playlist, or already at end of album - if self.playlist_playing_position >= len(pl) - 1 or self.playlist_playing_position < len( - pl) - 1 and \ - self.g(pl[self.playlist_playing_position + 1]).parent_folder_path != pctl.g( - target_index).parent_folder_path: + # Check to see if we still are: + ok_continue = True - if dry: - return None + if pctl.g(target_index).parent_folder_path != pctl.playing_object().parent_folder_path: + # Remember to set jumper check this too (leave album if we jump to some other track, i.e. double click)) + ok_continue = False - del self.force_queue[0] - self.advance() - return + pl = pctl.multi_playlist[pctl.active_playlist_playing][2] + # Check next song is in album + if ok_continue: - # Check if 2 songs down is in album, remove entry in queue if not - elif self.playlist_playing_position < len(pl) - 2 and \ - self.g(pl[self.playlist_playing_position + 2]).parent_folder_path != pctl.g( - target_index).parent_folder_path: - ok_continue = False + # Check if we are at end of playlist, or already at end of album + if self.playlist_playing_position >= len(pl) - 1 or self.playlist_playing_position < len( + pl) - 1 and \ + self.g(pl[self.playlist_playing_position + 1]).parent_folder_path != pctl.g( + target_index).parent_folder_path: - # if ok_continue: - # We seem to be still in the album. Step down one and play - if not dry: - self.playlist_playing_position += 1 + if dry: + return None - if len(pl) <= self.playlist_playing_position: - if dry: - return None - logging.info("END OF PLAYLIST!") - del self.force_queue[0] - self.advance() - return + del self.force_queue[0] + self.advance() + return - if dry: - return pl[self.playlist_playing_position + 1] - self.track_queue.append(pl[self.playlist_playing_position]) - self.queue_step = len(self.track_queue) - 1 - # self.queue_target = len(self.track_queue) - 1 - if play: - self.play_target(jump=not end) - if not ok_continue: - # It seems this item has expired, remove it and call advance again + # Check if 2 songs down is in album, remove entry in queue if not + elif self.playlist_playing_position < len(pl) - 2 and \ + self.g(pl[self.playlist_playing_position + 2]).parent_folder_path != pctl.g( + target_index).parent_folder_path: + ok_continue = False - if dry: - return None + # if ok_continue: + # We seem to be still in the album. Step down one and play + if not dry: + self.playlist_playing_position += 1 - logging.info("Remove expired album from queue") - del self.force_queue[0] + if len(pl) <= self.playlist_playing_position: + if dry: + return None + logging.info("END OF PLAYLIST!") + del self.force_queue[0] + self.advance() + return - if q[6]: - pctl.auto_stop = True - if prefs.stop_end_queue and not self.force_queue: - pctl.auto_stop = True + if dry: + return pl[self.playlist_playing_position + 1] + self.track_queue.append(pl[self.playlist_playing_position]) + self.queue_step = len(self.track_queue) - 1 + # self.queue_target = len(self.track_queue) - 1 + if play: + self.play_target(jump=not end) - if queue_box.scroll_position > 0: - queue_box.scroll_position -= 1 + if not ok_continue: + # It seems this item has expired, remove it and call advance again - # self.advance() - # return + if dry: + return None - else: - # This is track type - pl = id_to_pl(q[2]) - if not dry: - if pl is not None: - self.active_playlist_playing = pl + logging.info("Remove expired album from queue") + del self.force_queue[0] - if target_index not in self.playing_playlist(): - if dry: - return None - del self.force_queue[0] - self.advance() - return + if q[6]: + pctl.auto_stop = True + if prefs.stop_end_queue and not self.force_queue: + pctl.auto_stop = True - if dry: - return target_index - - self.playlist_playing_position = q[1] - self.track_queue.append(target_index) - self.queue_step = len(self.track_queue) - 1 - # self.queue_target = len(self.track_queue) - 1 - if play: - self.play_target(jump=not end) - del self.force_queue[0] - if q[6]: - pctl.auto_stop = True - if prefs.stop_end_queue and not self.force_queue: - pctl.auto_stop = True - if queue_box.scroll_position > 0: - queue_box.scroll_position -= 1 - - # Stop if playlist is empty - elif len(self.playing_playlist()) == 0: - if dry: - return None - self.stop() - return 0 + if queue_box.scroll_position > 0: + queue_box.scroll_position -= 1 - # Playback follow cursor - elif prefs.playback_follow_cursor and self.playing_ready() \ - and self.multi_playlist[pctl.active_playlist_viewing][2][ - pctl.selected_in_playlist] != self.playing_object().index \ - and -1 < pctl.selected_in_playlist < len(default_playlist): + # self.advance() + # return - if dry: - return default_playlist[pctl.selected_in_playlist] + else: + # This is track type + pl = id_to_pl(q[2]) + if not dry: + if pl is not None: + self.active_playlist_playing = pl + + if target_index not in self.playing_playlist(): + if dry: + return None + del self.force_queue[0] + self.advance() + return + + if dry: + return target_index + + self.playlist_playing_position = q[1] + self.track_queue.append(target_index) + self.queue_step = len(self.track_queue) - 1 + # self.queue_target = len(self.track_queue) - 1 + if play: + self.play_target(jump=not end) + del self.force_queue[0] + if q[6]: + pctl.auto_stop = True + if prefs.stop_end_queue and not self.force_queue: + pctl.auto_stop = True + if queue_box.scroll_position > 0: + queue_box.scroll_position -= 1 + + # Stop if playlist is empty + elif len(self.playing_playlist()) == 0: + if dry: + return None + self.stop() + return 0 - self.active_playlist_playing = self.active_playlist_viewing - self.playlist_playing_position = pctl.selected_in_playlist + # Playback follow cursor + elif prefs.playback_follow_cursor and self.playing_ready() \ + and self.multi_playlist[pctl.active_playlist_viewing][2][ + pctl.selected_in_playlist] != self.playing_object().index \ + and -1 < pctl.selected_in_playlist < len(default_playlist): - self.track_queue.append(default_playlist[pctl.selected_in_playlist]) - self.queue_step = len(self.track_queue) - 1 - if play: - self.play_target(jump=not end) + if dry: + return default_playlist[pctl.selected_in_playlist] - # If random, jump to random track - elif (self.random_mode or rr) and len(self.playing_playlist()) > 0 and not ( - self.album_shuffle_mode or prefs.album_shuffle_lock_mode): - # self.queue_step += 1 - new_step = self.queue_step + 1 + self.active_playlist_playing = self.active_playlist_viewing + self.playlist_playing_position = pctl.selected_in_playlist - if new_step == len(self.track_queue): + self.track_queue.append(default_playlist[pctl.selected_in_playlist]) + self.queue_step = len(self.track_queue) - 1 + if play: + self.play_target(jump=not end) - if self.album_repeat_mode and self.repeat_mode: - # Album shuffle mode - pp = self.playing_playlist() - k = self.playlist_playing_position - # ti = self.g(pp[k]) - ti = self.master_library[self.track_queue[self.queue_step]] + # If random, jump to random track + elif (self.random_mode or rr) and len(self.playing_playlist()) > 0 and not ( + self.album_shuffle_mode or prefs.album_shuffle_lock_mode): + # self.queue_step += 1 + new_step = self.queue_step + 1 - if ti.index not in pp: - if dry: - return None - logging.info("No tracks to repeat!") - return 0 + if new_step == len(self.track_queue): - matches = [] - for i, p in enumerate(pp): + if self.album_repeat_mode and self.repeat_mode: + # Album shuffle mode + pp = self.playing_playlist() + k = self.playlist_playing_position + # ti = self.g(pp[k]) + ti = self.master_library[self.track_queue[self.queue_step]] - if self.g(p).parent_folder_path == ti.parent_folder_path: - matches.append((i, p)) + if ti.index not in pp: + if dry: + return None + logging.info("No tracks to repeat!") + return 0 - if matches: - # Avoid a repeat of same track - if len(matches) > 1 and (k, ti.index) in matches: - matches.remove((k, ti.index)) + matches = [] + for i, p in enumerate(pp): - i, p = random.choice(matches) # not used + if self.g(p).parent_folder_path == ti.parent_folder_path: + matches.append((i, p)) - if prefs.true_shuffle: + if matches: + # Avoid a repeat of same track + if len(matches) > 1 and (k, ti.index) in matches: + matches.remove((k, ti.index)) - id = ti.parent_folder_path + i, p = random.choice(matches) # not used - while True: - if id in pctl.shuffle_pools: + if prefs.true_shuffle: - pool = pctl.shuffle_pools[id] + id = ti.parent_folder_path - if not pool: - del pctl.shuffle_pools[id] # Trigger a refill - continue + while True: + if id in pctl.shuffle_pools: - ref = pool.pop() - if dry: - pool.append(ref) - return ref[1] - # ref = random.choice(pool) - # pool.remove(ref) + pool = pctl.shuffle_pools[id] - if ref[1] not in pp: # Check track still in the live playlist - logging.info("Track not in pool") - continue + if not pool: + del pctl.shuffle_pools[id] # Trigger a refill + continue - i, p = ref # Find position of reference in playlist - break + ref = pool.pop() + if dry: + pool.append(ref) + return ref[1] + # ref = random.choice(pool) + # pool.remove(ref) - else: - # Refill the pool - random.shuffle(matches) - pctl.shuffle_pools[id] = matches + if ref[1] not in pp: # Check track still in the live playlist + logging.info("Track not in pool") + continue - logging.info("Refill folder shuffle pool") + i, p = ref # Find position of reference in playlist + break - self.playlist_playing_position = i - self.track_queue.append(p) + else: + # Refill the pool + random.shuffle(matches) + pctl.shuffle_pools[id] = matches - else: - # Normal select from playlist + logging.info("Refill folder shuffle pool") - if prefs.true_shuffle: - # True shuffle avoids repeats by using a pool + self.playlist_playing_position = i + self.track_queue.append(p) - pl = pctl.multi_playlist[pctl.active_playlist_playing] - id = pl[6] + else: + # Normal select from playlist - while True: + if prefs.true_shuffle: + # True shuffle avoids repeats by using a pool - if id in pctl.shuffle_pools: + pl = pctl.multi_playlist[pctl.active_playlist_playing] + id = pl[6] - pool = pctl.shuffle_pools[id] + while True: - if not pool: - del pctl.shuffle_pools[id] # Trigger a refill - continue + if id in pctl.shuffle_pools: - ref = pool.pop() - if dry: - pool.append(ref) - return ref - # ref = random.choice(pool) - # pool.remove(ref) + pool = pctl.shuffle_pools[id] - if ref not in pl[2]: # Check track still in the live playlist - continue + if not pool: + del pctl.shuffle_pools[id] # Trigger a refill + continue - random_jump = pl[2].index(ref) # Find position of reference in playlist - break + ref = pool.pop() + if dry: + pool.append(ref) + return ref + # ref = random.choice(pool) + # pool.remove(ref) - else: - # Refill the pool - self.update_shuffle_pool(pl[6]) + if ref not in pl[2]: # Check track still in the live playlist + continue - else: - random_jump = random.randrange(len(self.playing_playlist())) # not used + random_jump = pl[2].index(ref) # Find position of reference in playlist + break - self.playlist_playing_position = random_jump - self.track_queue.append(self.playing_playlist()[random_jump]) + else: + # Refill the pool + self.update_shuffle_pool(pl[6]) - if inplace and self.queue_step > 1: - del self.track_queue[self.queue_step] - else: - if dry: - return self.track_queue[new_step] - self.queue_step = new_step + else: + random_jump = random.randrange(len(self.playing_playlist())) # not used - if rr: - if dry: - return None - self.play_target_rr() - else: - if play: - self.play_target(jump=not end) + self.playlist_playing_position = random_jump + self.track_queue.append(self.playing_playlist()[random_jump]) + if inplace and self.queue_step > 1: + del self.track_queue[self.queue_step] + else: + if dry: + return self.track_queue[new_step] + self.queue_step = new_step + + if rr: + if dry: + return None + self.play_target_rr() + else: + if play: + self.play_target(jump=not end) - # If not random mode, Step down 1 on the playlist - elif self.random_mode is False and len(self.playing_playlist()) > 0: - # Stop at end of playlist - if self.playlist_playing_position == len(self.playing_playlist()) - 1: - if dry: - return None - if prefs.end_setting == 'stop': - self.playing_state = 0 - self.playerCommand = 'runstop' - self.playerCommandReady = True - end_of_playlist = True - - elif prefs.end_setting == 'advance' or prefs.end_setting == 'cycle': - - # If at end playlist and not cycle mode, stop playback - if pctl.active_playlist_playing == len( - pctl.multi_playlist) - 1 and not prefs.end_setting == 'cycle': - self.playing_state = 0 - self.playerCommand = 'runstop' - self.playerCommandReady = True - end_of_playlist = True + # If not random mode, Step down 1 on the playlist + elif self.random_mode is False and len(self.playing_playlist()) > 0: - else: + # Stop at end of playlist + if self.playlist_playing_position == len(self.playing_playlist()) - 1: + if dry: + return None + if prefs.end_setting == 'stop': + self.playing_state = 0 + self.playerCommand = 'runstop' + self.playerCommandReady = True + end_of_playlist = True - p = pctl.active_playlist_playing - for i in range(len(pctl.multi_playlist)): + elif prefs.end_setting == 'advance' or prefs.end_setting == 'cycle': - k = (p + i + 1) % len(pctl.multi_playlist) + # If at end playlist and not cycle mode, stop playback + if pctl.active_playlist_playing == len( + pctl.multi_playlist) - 1 and not prefs.end_setting == 'cycle': + self.playing_state = 0 + self.playerCommand = 'runstop' + self.playerCommandReady = True + end_of_playlist = True - # Skip a playlist if empty - if not (pctl.multi_playlist[k][2]): - continue + else: - # Skip a playlist if hidden - if pctl.multi_playlist[k][8] and prefs.tabs_on_top: - continue + p = pctl.active_playlist_playing + for i in range(len(pctl.multi_playlist)): - # Set found playlist as playing the first track - pctl.active_playlist_playing = k - pctl.playlist_playing_position = -1 - pctl.advance(end=end, force=True, play=play) - break + k = (p + i + 1) % len(pctl.multi_playlist) - else: - # Restart current if no other eligible playlist found - pctl.playlist_playing_position = -1 - pctl.advance(end=end, force=True, play=play) + # Skip a playlist if empty + if not (pctl.multi_playlist[k][2]): + continue - return + # Skip a playlist if hidden + if pctl.multi_playlist[k][8] and prefs.tabs_on_top: + continue - elif prefs.end_setting == 'repeat': - pctl.playlist_playing_position = -1 - pctl.advance(end=end, force=True, play=play) - return + # Set found playlist as playing the first track + pctl.active_playlist_playing = k + pctl.playlist_playing_position = -1 + pctl.advance(end=end, force=True, play=play) + break - gui.update += 3 + else: + # Restart current if no other eligible playlist found + pctl.playlist_playing_position = -1 + pctl.advance(end=end, force=True, play=play) - else: - if self.playlist_playing_position > len(self.playing_playlist()) - 1: - if dry: - return None - self.playlist_playing_position = 0 - - elif not force and len(self.track_queue) > 0 and self.playing_playlist()[ - self.playlist_playing_position] != self.track_queue[ - self.queue_step]: - try: - if dry: - return None - self.playlist_playing_position = self.playing_playlist().index( - self.track_queue[self.queue_step]) - except Exception: - logging.exception("Failed to set playlist_playing_position") + return - if len(self.playing_playlist()) == self.playlist_playing_position + 1: - return + elif prefs.end_setting == 'repeat': + pctl.playlist_playing_position = -1 + pctl.advance(end=end, force=True, play=play) + return - if dry: - return self.playing_playlist()[self.playlist_playing_position + 1] - self.playlist_playing_position += 1 - self.track_queue.append(self.playing_playlist()[self.playlist_playing_position]) + gui.update += 3 - # logging.info("standand advance") - # self.queue_target = len(self.track_queue) - 1 - # if end: - # self.play_target_gapless(jump= not end) - # else: - self.queue_step = len(self.track_queue) - 1 - if play: - self.play_target(jump=not end) + else: + if self.playlist_playing_position > len(self.playing_playlist()) - 1: + if dry: + return None + self.playlist_playing_position = 0 + + elif not force and len(self.track_queue) > 0 and self.playing_playlist()[ + self.playlist_playing_position] != self.track_queue[ + self.queue_step]: + try: + if dry: + return None + self.playlist_playing_position = self.playing_playlist().index( + self.track_queue[self.queue_step]) + except Exception: + logging.exception("Failed to set playlist_playing_position") + + if len(self.playing_playlist()) == self.playlist_playing_position + 1: + return + + if dry: + return self.playing_playlist()[self.playlist_playing_position + 1] + self.playlist_playing_position += 1 + self.track_queue.append(self.playing_playlist()[self.playlist_playing_position]) + + # logging.info("standand advance") + # self.queue_target = len(self.track_queue) - 1 + # if end: + # self.play_target_gapless(jump= not end) + # else: + self.queue_step = len(self.track_queue) - 1 + if play: + self.play_target(jump=not end) - else: + else: - if self.random_mode and (self.album_shuffle_mode or prefs.album_shuffle_lock_mode): + if self.random_mode and (self.album_shuffle_mode or prefs.album_shuffle_lock_mode): - # Album shuffle mode - logging.info("Album shuffle mode") + # Album shuffle mode + logging.info("Album shuffle mode") - po = self.playing_object() + po = self.playing_object() - redraw = False + redraw = False - # Checks - if po is not None and len(self.playing_playlist()) > 0: + # Checks + if po is not None and len(self.playing_playlist()) > 0: - # If we at end of playlist, we'll go to a new album - if len(self.playing_playlist()) == self.playlist_playing_position + 1: - redraw = True - # If the next track is a new album, go to a new album - elif po.parent_folder_path != pctl.g( - self.playing_playlist()[self.playlist_playing_position + 1]).parent_folder_path: - redraw = True - # Always redraw on press in album shuffle lockdown - if prefs.album_shuffle_lock_mode and not end: - redraw = True + # If we at end of playlist, we'll go to a new album + if len(self.playing_playlist()) == self.playlist_playing_position + 1: + redraw = True + # If the next track is a new album, go to a new album + elif po.parent_folder_path != pctl.g( + self.playing_playlist()[self.playlist_playing_position + 1]).parent_folder_path: + redraw = True + # Always redraw on press in album shuffle lockdown + if prefs.album_shuffle_lock_mode and not end: + redraw = True - if not redraw: - if dry: - return self.playing_playlist()[self.playlist_playing_position + 1] - self.playlist_playing_position += 1 - self.track_queue.append(self.playing_playlist()[self.playlist_playing_position]) - self.queue_step = len(self.track_queue) - 1 - # self.queue_target = len(self.track_queue) - 1 - if play: - self.play_target(jump=not end) + if not redraw: + if dry: + return self.playing_playlist()[self.playlist_playing_position + 1] + self.playlist_playing_position += 1 + self.track_queue.append(self.playing_playlist()[self.playlist_playing_position]) + self.queue_step = len(self.track_queue) - 1 + # self.queue_target = len(self.track_queue) - 1 + if play: + self.play_target(jump=not end) - else: + else: - if dry: - return None - albums = [] - current_folder = "" - for i in range(len(self.playing_playlist())): - if i == 0: - albums.append(i) - current_folder = self.master_library[self.playing_playlist()[i]].parent_folder_path - else: - if pctl.master_library[self.playing_playlist()[i]].parent_folder_path != current_folder: - current_folder = self.master_library[self.playing_playlist()[i]].parent_folder_path - albums.append(i) - - random.shuffle(albums) - - for a in albums: - - if self.g(self.playing_playlist()[ - a]).parent_folder_path != self.playing_object().parent_folder_path: - self.playlist_playing_position = a - self.track_queue.append(self.playing_playlist()[a]) - self.queue_step = len(self.track_queue) - 1 - # self.queue_target = len(self.track_queue) - 1 - if play: - self.play_target(jump=not end) - break - else: - a = 0 - self.playlist_playing_position = a - self.track_queue.append(self.playing_playlist()[a]) - self.queue_step = len(self.track_queue) - 1 - if play: - self.play_target(jump=not end) - # logging.info("THERE IS ONLY ONE ALBUM IN THE PLAYLIST") - # self.stop() + if dry: + return None + albums = [] + current_folder = "" + for i in range(len(self.playing_playlist())): + if i == 0: + albums.append(i) + current_folder = self.master_library[self.playing_playlist()[i]].parent_folder_path + else: + if pctl.master_library[self.playing_playlist()[i]].parent_folder_path != current_folder: + current_folder = self.master_library[self.playing_playlist()[i]].parent_folder_path + albums.append(i) + + random.shuffle(albums) + + for a in albums: + + if self.g(self.playing_playlist()[a]).parent_folder_path != self.playing_object().parent_folder_path: + self.playlist_playing_position = a + self.track_queue.append(self.playing_playlist()[a]) + self.queue_step = len(self.track_queue) - 1 + # self.queue_target = len(self.track_queue) - 1 + if play: + self.play_target(jump=not end) + break + a = 0 + self.playlist_playing_position = a + self.track_queue.append(self.playing_playlist()[a]) + self.queue_step = len(self.track_queue) - 1 + if play: + self.play_target(jump=not end) + # logging.info("THERE IS ONLY ONE ALBUM IN THE PLAYLIST") + # self.stop() - else: - logging.error("ADVANCE ERROR - NO CASE!") + else: + logging.error("ADVANCE ERROR - NO CASE!") - if dry: - return None + if dry: + return None - if self.active_playlist_viewing == self.active_playlist_playing: - self.show_current(quiet=quiet) - elif prefs.auto_goto_playing: - self.show_current(quiet=quiet, this_only=True, playing=False, highlight=True, no_switch=True) + if self.active_playlist_viewing == self.active_playlist_playing: + self.show_current(quiet=quiet) + elif prefs.auto_goto_playing: + self.show_current(quiet=quiet, this_only=True, playing=False, highlight=True, no_switch=True) - # if album_mode: - # goto_album(self.playlist_playing) + # if album_mode: + # goto_album(self.playlist_playing) - self.render_playlist() + self.render_playlist() - if spot_ctl.playing and end_of_playlist: - spot_ctl.control("stop") + if spot_ctl.playing and end_of_playlist: + spot_ctl.control("stop") - self.notify_update() - lfm_scrobbler.start_queue() - if play: - notify_song(end_of_playlist, delay=1.3) + self.notify_update() + lfm_scrobbler.start_queue() + if play: + notify_song(end_of_playlist, delay=1.3) - def reset_missing_flags(self): - for value in self.master_library.values(): - value.found = True - gui.pl_update += 1 + def reset_missing_flags(self): + for value in self.master_library.values(): + value.found = True + gui.pl_update += 1 pctl = PlayerCtl() @@ -6879,169 +6888,169 @@ def reset_missing_flags(self): def auto_name_pl(target_pl): - if not pctl.multi_playlist[target_pl][2]: - return + if not pctl.multi_playlist[target_pl][2]: + return - albums = [] - artists = [] - parents = [] + albums = [] + artists = [] + parents = [] - track = None + track = None - for index in pctl.multi_playlist[target_pl][2]: - track = pctl.g(index) - albums.append(track.album) - if track.album_artist: - artists.append(track.album_artist) - else: - artists.append(track.artist) - parents.append(track.parent_folder_path) + for index in pctl.multi_playlist[target_pl][2]: + track = pctl.g(index) + albums.append(track.album) + if track.album_artist: + artists.append(track.album_artist) + else: + artists.append(track.artist) + parents.append(track.parent_folder_path) - nt = "" - artist = "" + nt = "" + artist = "" - if track: - artist = track.artist - if track.album_artist: - artist = track.album_artist + if track: + artist = track.artist + if track.album_artist: + artist = track.album_artist - if track and albums and albums[0] and albums.count(albums[0]) == len(albums): - nt = artist + " - " + track.album + if track and albums and albums[0] and albums.count(albums[0]) == len(albums): + nt = artist + " - " + track.album - elif track and artists and artists[0] and artists.count(artists[0]) == len(artists): - nt = artists[0] + elif track and artists and artists[0] and artists.count(artists[0]) == len(artists): + nt = artists[0] - else: - nt = os.path.basename(commonprefix(parents)) + else: + nt = os.path.basename(commonprefix(parents)) - pctl.multi_playlist[target_pl][0] = nt + pctl.multi_playlist[target_pl][0] = nt def get_object(index): - return pctl.master_library[index] + return pctl.master_library[index] def update_title_do(): - if pctl.playing_state > 0: - if len(pctl.track_queue) > 0: - line = pctl.master_library[pctl.track_queue[pctl.queue_step]].artist + " - " + \ - pctl.master_library[pctl.track_queue[pctl.queue_step]].title - # line += " : : Tauon Music Box" - line = line.encode('utf-8') - SDL_SetWindowTitle(t_window, line) - else: - line = "Tauon Music Box" - line = line.encode('utf-8') - SDL_SetWindowTitle(t_window, line) + if pctl.playing_state > 0: + if len(pctl.track_queue) > 0: + line = pctl.master_library[pctl.track_queue[pctl.queue_step]].artist + " - " + \ + pctl.master_library[pctl.track_queue[pctl.queue_step]].title + # line += " : : Tauon Music Box" + line = line.encode('utf-8') + SDL_SetWindowTitle(t_window, line) + else: + line = "Tauon Music Box" + line = line.encode('utf-8') + SDL_SetWindowTitle(t_window, line) def open_encode_out(): - if system == 'windows' or msys: - line = r'explorer ' + prefs.encoder_output.replace("/", "\\") - subprocess.Popen(line) - else: - line = prefs.encoder_output - line += "/" - if macos: - subprocess.Popen(['open', line]) - else: - subprocess.Popen(['xdg-open', line]) + if system == 'windows' or msys: + line = r'explorer ' + prefs.encoder_output.replace("/", "\\") + subprocess.Popen(line) + else: + line = prefs.encoder_output + line += "/" + if macos: + subprocess.Popen(['open', line]) + else: + subprocess.Popen(['xdg-open', line]) def g_open_encode_out(a, b, c): - open_encode_out() + open_encode_out() # if system == 'linux' and not macos and not msys: - try: - Notify.init("Tauon Music Box") - g_tc_notify = Notify.Notification.new("Tauon Music Box", - "Transcoding has finished.") - value = GLib.Variant("s", t_id) - g_tc_notify.set_hint("desktop-entry", value) - - g_tc_notify.add_action( - "action_click", - "Open Output Folder", - g_open_encode_out, - None - ) + try: + Notify.init("Tauon Music Box") + g_tc_notify = Notify.Notification.new("Tauon Music Box", + "Transcoding has finished.") + value = GLib.Variant("s", t_id) + g_tc_notify.set_hint("desktop-entry", value) + + g_tc_notify.add_action( + "action_click", + "Open Output Folder", + g_open_encode_out, + None + ) - de_notify_support = True + de_notify_support = True - except Exception: - logging.exception("Failed init notifications") + except Exception: + logging.exception("Failed init notifications") - if de_notify_support: - song_notification = Notify.Notification.new("Next track notification") - value = GLib.Variant("s", t_id) - song_notification.set_hint("desktop-entry", value) + if de_notify_support: + song_notification = Notify.Notification.new("Next track notification") + value = GLib.Variant("s", t_id) + song_notification.set_hint("desktop-entry", value) def notify_song_fire(notification, delay, id): - time.sleep(delay) - notification.show() - if id is None: - return + time.sleep(delay) + notification.show() + if id is None: + return - time.sleep(8) - if id == gui.notify_main_id: - notification.close() + time.sleep(8) + if id == gui.notify_main_id: + notification.close() def notify_song(notify_of_end=False, delay=0.0): - if not de_notify_support: - return + if not de_notify_support: + return - if notify_of_end and prefs.end_setting != "stop": - return + if notify_of_end and prefs.end_setting != "stop": + return - if prefs.show_notifications and pctl.playing_object() is not None and not window_is_focused(): - if prefs.stop_notifications_mini_mode and gui.mode == 3: - return + if prefs.show_notifications and pctl.playing_object() is not None and not window_is_focused(): + if prefs.stop_notifications_mini_mode and gui.mode == 3: + return - track = pctl.playing_object() + track = pctl.playing_object() - if not track or not (track.title or track.artist or track.album or track.filename): - return # only display if we have at least one piece of metadata avaliable + if not track or not (track.title or track.artist or track.album or track.filename): + return # only display if we have at least one piece of metadata avaliable - i_path = "" - try: - if not notify_of_end: - i_path = thumb_tracks.path(track) - except Exception: - logging.exception(track.fullpath.encode('utf-8', 'replace').decode("utf-8")) - logging.error("Thumbnail error") + i_path = "" + try: + if not notify_of_end: + i_path = thumb_tracks.path(track) + except Exception: + logging.exception(track.fullpath.encode('utf-8', 'replace').decode("utf-8")) + logging.error("Thumbnail error") - top_line = track.title + top_line = track.title - if prefs.notify_include_album: - bottom_line = (track.artist + " | " + track.album).strip("| ") - else: - bottom_line = track.artist + if prefs.notify_include_album: + bottom_line = (track.artist + " | " + track.album).strip("| ") + else: + bottom_line = track.artist - if not track.title: - a, t = filename_to_metadata(clean_string(track.filename)) - if not track.artist: - bottom_line = a - top_line = t + if not track.title: + a, t = filename_to_metadata(clean_string(track.filename)) + if not track.artist: + bottom_line = a + top_line = t - gui.notify_main_id = uid_gen() - id = gui.notify_main_id + gui.notify_main_id = uid_gen() + id = gui.notify_main_id - if notify_of_end: - bottom_line = "Tauon Music Box" - top_line = (_("End of playlist")) - id = None + if notify_of_end: + bottom_line = "Tauon Music Box" + top_line = (_("End of playlist")) + id = None - song_notification.update(top_line, bottom_line, i_path) + song_notification.update(top_line, bottom_line, i_path) - shoot_dl = threading.Thread(target=notify_song_fire, args=([song_notification, delay, id])) - shoot_dl.daemon = True - shoot_dl.start() + shoot_dl = threading.Thread(target=notify_song_fire, args=([song_notification, delay, id])) + shoot_dl.daemon = True + shoot_dl.start() # Last.FM ----------------------------------------------------------------- From 0f967f7ac2c5b03c4a4f11ceae5d6c3b053b0025 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 18:29:05 +0100 Subject: [PATCH 50/63] t_main: Add a docstring to PlayerCtl and do not attempt to close nonexistent radio_server --- src/tauon/t_modules/t_main.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 29421ecd1..686e228c9 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -5067,8 +5067,8 @@ def get_radio_art(): gui.clear_image_cache_next += 1 -# Main class that controls playback (play, pause, stepping, playlists, queue etc). Sends commands to backend. class PlayerCtl: + """Main class that controls playback (play, pause, stepping, playlists, queue etc). Sends commands to backend.""" # C-PC def __init__(self): @@ -48433,14 +48433,15 @@ def drop_file(target): time.sleep(2) try: - tm.player_lock.release() + tm.player_lock.release() except Exception: - logging.exception("Failed to release player_lock") + logging.exception("Failed to release player_lock") -try: - tauon.radio_server.server_close() -except Exception: - logging.exception("Failed to close radio server") +if tauon.radio_server is not None: + try: + tauon.radio_server.server_close() + except Exception: + logging.exception("Failed to close radio server") if system == "windows" or msys: tray.stop() From 874da2c26db99ae0e7c9e6386510869e621ee028 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 18:39:55 +0100 Subject: [PATCH 51/63] t_spot: Improve tekore module load --- src/tauon/t_modules/t_spot.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tauon/t_modules/t_spot.py b/src/tauon/t_modules/t_spot.py index d9f8817e5..46e75547f 100644 --- a/src/tauon/t_modules/t_spot.py +++ b/src/tauon/t_modules/t_spot.py @@ -35,12 +35,15 @@ if TYPE_CHECKING: from tauon.t_modules.t_main import Tauon, TrackClass +tekore_imported = False try: import tekore as tk - tekore_imported = True +except ModuleNotFoundError: + logging.warning("Unable to import Tekore, Spotify support will be disabled..") except Exception: - logging.exception("Failed to load Tekore") - tekore_imported = False + logging.exception("Unkown error trying to import Tekore, Spotify support will be disabled.") +else: + tekore_imported = True class SpotCtl: From ddace2cbea3247a0ffe204981b70b1e133a644c5 Mon Sep 17 00:00:00 2001 From: Martin Rys <martin@rys.rs> Date: Wed, 20 Nov 2024 19:07:53 +0100 Subject: [PATCH 52/63] t_main + t_extra: Unify quotes t_spot: Fix an extra dot --- src/tauon/t_modules/t_extra.py | 2 +- src/tauon/t_modules/t_main.py | 2168 ++++++++++++++++---------------- src/tauon/t_modules/t_spot.py | 2 +- 3 files changed, 1086 insertions(+), 1086 deletions(-) diff --git a/src/tauon/t_modules/t_extra.py b/src/tauon/t_modules/t_extra.py index f24720d28..c486c0b03 100644 --- a/src/tauon/t_modules/t_extra.py +++ b/src/tauon/t_modules/t_extra.py @@ -384,7 +384,7 @@ def is_ignorable_file(string: str) -> bool: # Pre-compile the regular expression pattern for dates starting with the year -date_pattern = re.compile(r'\b(?:\d{2}([/. -])\d{2}\1(\d{4})|\b(\d{4})([/. -])\d{2}\4\d{2}).*') +date_pattern = re.compile(r"\b(?:\d{2}([/. -])\d{2}\1(\d{4})|\b(\d{4})([/. -])\d{2}\4\d{2}).*") def get_year_from_string(s: str) -> str: """Gets year in form of YYYY from a string diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 686e228c9..405fa8ef4 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -430,7 +430,7 @@ fc.FcConfigAppFontAddDir(config.value, font_folder.encode()) # Detect what desktop environment we are in to enable specific features -desktop = os.environ.get('XDG_CURRENT_DESKTOP') +desktop = os.environ.get("XDG_CURRENT_DESKTOP") # de_notify_support = desktop == 'GNOME' or desktop == 'KDE' de_notify_support = False draw_min_button = True @@ -479,17 +479,17 @@ user_directory = install_directory config_directory = user_directory cache_directory = os.path.join(user_directory, "cache") -home_directory = os.path.join(os.path.expanduser('~')) +home_directory = os.path.join(os.path.expanduser("~")) asset_directory = os.path.join(install_directory, "assets") svg_directory = os.path.join(install_directory, "assets/svg") scaled_asset_directory = asset_directory -music_directory = os.path.join(os.path.expanduser('~'), "Music") +music_directory = os.path.join(os.path.expanduser("~"), "Music") if not os.path.isdir(music_directory): - music_directory = os.path.join(os.path.expanduser('~'), "music") + music_directory = os.path.join(os.path.expanduser("~"), "music") -download_directory = os.path.join(os.path.expanduser('~'), "Downloads") +download_directory = os.path.join(os.path.expanduser("~"), "Downloads") # Detect if we are installed or running portable install_mode = False @@ -527,7 +527,7 @@ flatpak_mode = True # If we're installed, use home data locations -if (install_mode and system == 'linux') or macos or msys: +if (install_mode and system == "linux") or macos or msys: cache_directory = os.path.join(GLib.get_user_cache_dir(), "TauonMusicBox") user_directory = os.path.join(GLib.get_user_data_dir(), "TauonMusicBox") @@ -607,9 +607,9 @@ os.makedirs(os.path.join(user_directory, "theme")) -if system == 'linux': +if system == "linux": system_config_directory = GLib.get_user_config_dir() - xdg_dir_file = os.path.join(system_config_directory, 'user-dirs.dirs') + xdg_dir_file = os.path.join(system_config_directory, "user-dirs.dirs") if os.path.isfile(xdg_dir_file): with open(xdg_dir_file) as f: @@ -625,12 +625,12 @@ logging.info(f"Found XDG-Downloads: {download_directory}") -if os.getenv('XDG_MUSIC_DIR'): - music_directory = os.getenv('XDG_MUSIC_DIR') +if os.getenv("XDG_MUSIC_DIR"): + music_directory = os.getenv("XDG_MUSIC_DIR") logging.info("Override music to: " + music_directory) -if os.getenv('XDG_DOWNLOAD_DIR'): - download_directory = os.getenv('XDG_DOWNLOAD_DIR') +if os.getenv("XDG_DOWNLOAD_DIR"): + download_directory = os.getenv("XDG_DOWNLOAD_DIR") logging.info("Override downloads to: " + download_directory) if music_directory: @@ -641,7 +641,7 @@ if not os.path.isdir(music_directory): music_directory = None -logging.info('Install directory: ' + install_directory) +logging.info("Install directory: " + install_directory) old_backend = 2 @@ -852,7 +852,7 @@ def asset_loader(name: str, mod: bool = False) -> WhiteModImageAsset | LoadImage platform_release = platform.release() platform_system = platform.system() win_ver = 0 -if platform.system() == 'Windows': +if platform.system() == "Windows": try: win_ver = int(platform_release) except Exception: @@ -868,7 +868,7 @@ def _(message): try: - py_locale.setlocale(py_locale.LC_ALL, '') + py_locale.setlocale(py_locale.LC_ALL, "") except Exception: logging.exception("SET LOCALE ERROR") @@ -892,9 +892,9 @@ def no_padding(info): return 0 wayland = True -if os.environ.get('SDL_VIDEODRIVER') != "wayland": +if os.environ.get("SDL_VIDEODRIVER") != "wayland": wayland = False - os.environ['GDK_BACKEND'] = "x11" + os.environ["GDK_BACKEND"] = "x11" # Setting various timers @@ -1092,25 +1092,25 @@ def print(self, message: str, level: int = 0): # These will be the extensions of files to be added when importing DA_Formats = { - 'mp3', 'wav', 'opus', 'flac', 'ape', 'aiff', - 'm4a', 'ogg', 'oga', 'aac', 'tta', 'wv', 'wma' + "mp3", "wav", "opus", "flac", "ape", "aiff", + "m4a", "ogg", "oga", "aac", "tta", "wv", "wma", } -VID_Formats = {'mp4', "webm"} +VID_Formats = {"mp4", "webm"} -MOD_Formats = {'xm', 'mod', 's3m', 'it', 'mptm', "umx", "okt", "mtm", "669", "far", "wow", "dmf", "med", "mt2", "ult"} +MOD_Formats = {"xm", "mod", "s3m", "it", "mptm", "umx", "okt", "mtm", "669", "far", "wow", "dmf", "med", "mt2", "ult"} -GME_Formats = {'ay', 'gbs', 'gym', 'hes', 'kss', 'nsf', 'nsfe', 'sap', 'spc', 'vgm', 'vgz'} +GME_Formats = {"ay", "gbs", "gym", "hes", "kss", "nsf", "nsfe", "sap", "spc", "vgm", "vgz"} DA_Formats |= MOD_Formats DA_Formats |= GME_Formats -Archive_Formats = {'zip'} +Archive_Formats = {"zip"} -if whicher('unrar'): +if whicher("unrar"): Archive_Formats.add("rar") -if whicher('7z'): +if whicher("7z"): Archive_Formats.add("7z") cargo = [] @@ -1121,7 +1121,7 @@ def print(self, message: str, level: int = 0): # pl_follow = False # List of encodings to check for with the fix mojibake function -encodings = ['cp932', 'utf-8', 'big5hkscs', 'gbk'] # These seem to be the most common for Japanese +encodings = ["cp932", "utf-8", "big5hkscs", "gbk"] # These seem to be the most common for Japanese track_box = False @@ -1254,9 +1254,9 @@ def __init__(self): self.change_volume_fade_time = 400 self.cross_fade_time = 700 # 700 self.volume_wheel_increment = 2 - self.encoder_output = user_directory + '/encoder/' + self.encoder_output = user_directory + "/encoder/" if music_directory is not None: - self.encoder_output = music_directory + '/encode-output/' + self.encoder_output = music_directory + "/encode-output/" self.rename_folder_template = "<albumartist> - <album>" self.rename_tracks_template = "<tn>. <artist> - <title>.<ext>" @@ -1273,8 +1273,8 @@ def __init__(self): self.prefer_bottom_title = True self.append_date = True - self.transcode_codec = 'opus' - self.transcode_mode = 'single' + self.transcode_codec = "opus" + self.transcode_mode = "single" self.transcode_bitrate = 64 # self.line_style = 1 @@ -1311,7 +1311,7 @@ def __init__(self): self.spec2_base = [10, 10, 100] self.spec2_multiply = [0.5, 1, 1] - self.spec2_colour_setting = 'custom' + self.spec2_colour_setting = "custom" self.auto_lfm = False self.scrobble_mark = False @@ -1504,7 +1504,7 @@ def __init__(self): self.always_art_header = False # self.center_bg = True - self.ui_lang = 'auto' + self.ui_lang = "auto" self.side_panel_layout = 0 self.use_absolute_track_index = False @@ -1775,7 +1775,7 @@ def __init__(self): self.message_box = False self.message_text = "" - self.message_mode = 'info' + self.message_mode = "info" self.message_subtext = "" self.message_subtext2 = "" self.message_box_confirm_reference = None @@ -1834,9 +1834,9 @@ def __init__(self): self.set_point = 0 self.set_old = 0 self.pl_st = [ - ['Artist', 156, False], ['Title', 188, False], ['T', 40, True], ['Album', 153, False], - ['P', 28, True], ['Starline', 86, True], ['Date', 48, True], ['Codec', 55, True], - ['Time', 53, True]] + ["Artist", 156, False], ["Title", 188, False], ["T", 40, True], ["Album", 153, False], + ["P", 28, True], ["Starline", 86, True], ["Date", 48, True], ["Codec", 55, True], + ["Time", 53, True]] for item in self.pl_st: item[1] = item[1] * self.scale @@ -2134,7 +2134,7 @@ def get_artist_preview(artist, x, y): if not path: show_message(_("No artist image found.")) if not prefs.enable_fanart_artist and not verify_discogs(): - show_message(_("No artist image found."), _("No providers are enabled in settings!"), mode='warning') + show_message(_("No artist image found."), _("No providers are enabled in settings!"), mode="warning") gui.preview_artist_loading = "" return set_artist_preview(path, artist, x, y) @@ -2219,7 +2219,7 @@ def set_rating(self, index, value, write=False): del tag["FMPS_RATING"] tag.save() else: - tag["FMPS_RATING"] = ['{:.2f}'.format(value / 10)] + tag["FMPS_RATING"] = ["{:.2f}".format(value / 10)] tag.save() elif tr.file_ext == "MP3": @@ -2247,12 +2247,12 @@ def set_rating(self, index, value, write=False): frames = tag.getall("TXXX") for i in reversed(range(len(frames))): if frames[i].desc.lower() == "fmps_rating": - frames[i].text = '{:.2f}'.format(value / 10) + frames[i].text = "{:.2f}".format(value / 10) changed = True if not changed: tag.add( mutagen.id3.TXXX( - encoding=mutagen.id3.Encoding.UTF8, text='{:.2f}'.format(value / 10), + encoding=mutagen.id3.Encoding.UTF8, text="{:.2f}".format(value / 10), desc="FMPS_RATING")) tag.save() @@ -2264,7 +2264,7 @@ def set_rating(self, index, value, write=False): del tags["FMPS_Rating"] audio.save() else: - tags["FMPS_Rating"] = '{:.2f}'.format(value / 10) + tags["FMPS_Rating"] = "{:.2f}".format(value / 10) audio.save() tr.misc["FMPS_Rating"] = float(value / 10) @@ -2823,9 +2823,9 @@ def set_colour(colour): def get_themes(deco=False): themes = [] # full, name decos = {} - direcs = [install_directory + '/theme'] + direcs = [install_directory + "/theme"] if user_directory != install_directory: - direcs.append(user_directory + '/theme') + direcs.append(user_directory + "/theme") def scan_folders(folders): for folder in folders: @@ -2836,9 +2836,9 @@ def scan_folders(folders): if os.path.islink(path): path = os.readlink(path) if os.path.isfile(path): - if path[-7:] == '.ttheme': + if path[-7:] == ".ttheme": themes.append((path, os.path.basename(path).split(".")[0])) - elif path[-6:] == '.tdeco': + elif path[-6:] == ".tdeco": decos[os.path.basename(path).split(".")[0]] = path elif os.path.isdir(path): scan_folders([path]) @@ -2910,14 +2910,14 @@ def __init__(self) -> None: def get_end_folder(direc): for w in range(len(direc)): - if direc[-w - 1] == '\\' or direc[-w - 1] == '/': + if direc[-w - 1] == "\\" or direc[-w - 1] == "/": direc = direc[-w:] return direc return None def set_path(nt, path): - nt.fullpath = path.replace('\\', '/') + nt.fullpath = path.replace("\\", "/") nt.filename = os.path.basename(path) - nt.parent_folder_path = os.path.dirname(path.replace('\\', '/')) + nt.parent_folder_path = os.path.dirname(path.replace("\\", "/")) nt.parent_folder_name = get_end_folder(os.path.dirname(path)) nt.file_ext = os.path.splitext(os.path.basename(path))[1][1:].upper() @@ -2978,23 +2978,23 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" star_store.db = pickle.load(open(to_load, "rb")) except FileNotFoundError: - logging.error('No existing star.p file') + logging.error("No existing star.p file") except Exception: - logging.exception('Unknown error loading star.p file') + logging.exception("Unknown error loading star.p file") try: album_star_store.db = pickle.load(open(user_directory + "/album-star.p", "rb")) except FileNotFoundError: - logging.error('No existing album-star.p file') + logging.error("No existing album-star.p file") except Exception: - logging.exception('Unknown error loading album-star.p file') + logging.exception("Unknown error loading album-star.p file") try: if os.path.isfile(user_directory + "/lyrics_substitutions.json"): - with open(user_directory + "/lyrics_substitutions.json", 'r') as f: + with open(user_directory + "/lyrics_substitutions.json", "r") as f: prefs.lyrics_subs = json.load(f) except FileNotFoundError: - logging.error('No existing lyrics_substitutions.json file') + logging.error("No existing lyrics_substitutions.json file") except Exception: logging.exception("Unknown error loading lyrics_substitutions.json") @@ -3004,36 +3004,36 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" primary_stations = [] station = { - 'title': "SomaFM Groove Salad", + "title": "SomaFM Groove Salad", "stream_url": "http://ice3.somafm.com/groovesalad-128-mp3", - 'country': 'USA', - 'website_url': 'http://somafm.com/groovesalad', - 'icon': 'https://somafm.com/logos/120/groovesalad120.png' + "country": "USA", + "website_url": "http://somafm.com/groovesalad", + "icon": "https://somafm.com/logos/120/groovesalad120.png", } primary_stations.append(station) station = { - 'title': "SomaFM PopTron", + "title": "SomaFM PopTron", "stream_url": "http://ice3.somafm.com/poptron-128-mp3", - 'country': 'USA', - 'website_url': 'http://somafm.com/poptron/', - 'icon': 'https://somafm.com/logos/120/poptron120.jpg' + "country": "USA", + "website_url": "http://somafm.com/poptron/", + "icon": "https://somafm.com/logos/120/poptron120.jpg" } primary_stations.append(station) station = { - 'title': "SomaFM Vaporwaves", + "title": "SomaFM Vaporwaves", "stream_url": "http://ice4.somafm.com/vaporwaves-128-mp3", - 'country': 'USA', - 'website_url': 'https://somafm.com/vaporwaves', - 'icon': 'https://somafm.com/img3/vaporwaves400.png' + "country": "USA", + "website_url": "https://somafm.com/vaporwaves", + "icon": "https://somafm.com/img3/vaporwaves400.png" } primary_stations.append(station) station = { - 'title': "DKFM Shoegaze Radio", + "title": "DKFM Shoegaze Radio", "stream_url": "https://kathy.torontocast.com:2005/stream", - 'country': 'Canada', - 'website_url': 'https://decayfm.com', - 'icon': 'https://cdn-profiles.tunein.com/s193842/images/logod.png' + "country": "Canada", + "website_url": "https://decayfm.com", + "icon": "https://cdn-profiles.tunein.com/s193842/images/logod.png" } primary_stations.append(station) @@ -3444,7 +3444,7 @@ def pumper(): except Exception: logging.exception("Failed to load save file") if os.path.isfile(user_directory + "/state.p"): - logging.error('Error loading save file') + logging.error("Error loading save file") core_timer.set() logging.info(f"Database loaded in {round(perf_timer.get(), 3)} seconds.") @@ -3492,7 +3492,7 @@ def get_theme_number(name): def get_theme_name(number): if number == 0: - return 'Mindaro' + return "Mindaro" number -= 1 themes = get_themes() logging.info((number, themes)) @@ -3786,9 +3786,9 @@ def load_prefs(): # prefs.gst_output = cf.sync_add("string", "gst-output", prefs.gst_output, "GStreamer output pipeline specification. Only used with GStreamer backend.") # prefs.gst_use_custom_output = cf.sync_add("bool", "gst-use-custom-output", prefs.gst_use_custom_output, "Set this to true to apply any manual edits of the above string.") - if prefs.dc_device_setting == 'on': + if prefs.dc_device_setting == "on": prefs.dc_device = True - elif prefs.dc_device_setting == 'off': + elif prefs.dc_device_setting == "off": prefs.dc_device = False cf.br() @@ -3806,7 +3806,7 @@ def load_prefs(): cf.br() cf.add_text("[tag-editor]") - if system == 'windows' or msys: + if system == "windows" or msys: prefs.tag_editor_name = cf.sync_add("string", "tag-editor-name", "Picard", "Name to display in UI.") prefs.tag_editor_target = cf.sync_add( "string", "tag-editor-target", @@ -3941,7 +3941,7 @@ def load_prefs(): prefs.center_gallery_text = cf.sync_add("bool", "gallery-center-text", prefs.center_gallery_text) # show-current-on-transition", prefs.show_current_on_transition) - if system != 'windows': + if system != "windows": cf.br() cf.add_text("[fonts]") cf.add_comment("Changes will require app restart.") @@ -4177,10 +4177,10 @@ def load_prefs(): if lang: # Force set lang - f = gettext.find('tauon', localedir=locale_dir, languages=lang) + f = gettext.find("tauon", localedir=locale_dir, languages=lang) if f: - translation = gettext.translation('tauon', localedir=locale_dir, languages=lang) + translation = gettext.translation("tauon", localedir=locale_dir, languages=lang) translation.install() _ = translation.gettext @@ -4190,10 +4190,10 @@ def load_prefs(): else: # Auto detect lang - f = gettext.find('tauon', localedir=locale_dir) + f = gettext.find("tauon", localedir=locale_dir) if f: - translation = gettext.translation('tauon', localedir=locale_dir) + translation = gettext.translation("tauon", localedir=locale_dir) translation.install() _ = translation.gettext @@ -4220,9 +4220,9 @@ def load_prefs(): def SMTC_button_callback(button): if button == 1: - inp.media_key = 'Play' + inp.media_key = "Play" if button == 2: - inp.media_key = 'Pause' + inp.media_key = "Pause" if button == 3: inp.media_key = "Next" if button == 4: @@ -4327,17 +4327,17 @@ def scale_assets(scale_want: int, force: bool = False) -> None: try: # star_lines = view_prefs['star-lines'] - update_title = view_prefs['update-title'] - prefs.prefer_side = view_prefs['side-panel'] + update_title = view_prefs["update-title"] + prefs.prefer_side = view_prefs["side-panel"] prefs.dim_art = False # view_prefs['dim-art'] #gui.turbo = view_prefs['level-meter'] # pl_follow = view_prefs['pl-follow'] - scroll_enable = view_prefs['scroll-enable'] - break_enable = view_prefs['break-enable'] + scroll_enable = view_prefs["scroll-enable"] + break_enable = view_prefs["break-enable"] # dd_index = view_prefs['dd-index'] # custom_line_mode = view_prefs['custom-line'] # thick_lines = view_prefs['thick-lines'] - prefs.append_date = view_prefs['append-date'] + prefs.append_date = view_prefs["append-date"] except Exception: logging.exception("Failed to load settings!") @@ -4361,7 +4361,7 @@ def get_window_position(): # Access functions from libopenmpt for scanning tracker files class MOD(Structure): - _fields_ = [('ctl', c_char_p), ('value', c_char_p)] + _fields_ = [("ctl", c_char_p), ("value", c_char_p)] mpt = None @@ -4470,7 +4470,7 @@ def natural_get(tag, track, frame, attr): for frame in frames: if frame.rating: rating = frame.rating - nt.misc['POPM'] = frame.rating + nt.misc["POPM"] = frame.rating if len(nt.comment) > 4 and nt.comment[2] == "+": nt.comment = "" @@ -4491,7 +4491,7 @@ def natural_get(tag, track, frame, attr): for t in frame.text: d.append(t) if len(d) > 1: - nt.misc['artists'] = d + nt.misc["artists"] = d nt.artist = "; ".join(d) frames = tag.getall("TCON") @@ -4501,7 +4501,7 @@ def natural_get(tag, track, frame, attr): for t in frame.text: d.append(t) if len(d) > 1: - nt.misc['genres'] = d + nt.misc["genres"] = d nt.genre = " / ".join(d) track_no = natural_get(tags, None, "TRCK", None) @@ -4530,7 +4530,7 @@ def natural_get(tag, track, frame, attr): if tx: for item in tx: if item.owner == "http://musicbrainz.org": - nt.misc['musicbrainz_recordingid'] = item.data.decode() + nt.misc["musicbrainz_recordingid"] = item.data.decode() tx = tags.getall("TSOP") if tx: @@ -4540,35 +4540,35 @@ def natural_get(tag, track, frame, attr): if tx: for item in tx: if item.desc == "MusicBrainz Release Track Id": - nt.misc['musicbrainz_trackid'] = item.text[0] + nt.misc["musicbrainz_trackid"] = item.text[0] if item.desc == "MusicBrainz Album Id": - nt.misc['musicbrainz_albumid'] = item.text[0] + nt.misc["musicbrainz_albumid"] = item.text[0] if item.desc == "MusicBrainz Release Group Id": - nt.misc['musicbrainz_releasegroupid'] = item.text[0] + nt.misc["musicbrainz_releasegroupid"] = item.text[0] if item.desc == "MusicBrainz Artist Id": - nt.misc['musicbrainz_artistids'] = list(item.text) + nt.misc["musicbrainz_artistids"] = list(item.text) try: desc = item.desc.lower() if desc == "replaygain_track_gain": - nt.misc['replaygain_track_gain'] = float(item.text[0].strip(" dB")) + nt.misc["replaygain_track_gain"] = float(item.text[0].strip(" dB")) if desc == "replaygain_track_peak": - nt.misc['replaygain_track_peak'] = float(item.text[0]) + nt.misc["replaygain_track_peak"] = float(item.text[0]) if desc == "replaygain_album_gain": - nt.misc['replaygain_album_gain'] = float(item.text[0].strip(" dB")) + nt.misc["replaygain_album_gain"] = float(item.text[0].strip(" dB")) if desc == "replaygain_album_peak": - nt.misc['replaygain_album_peak'] = float(item.text[0]) + nt.misc["replaygain_album_peak"] = float(item.text[0]) except Exception: logging.exception("Tag Scan: Read Replay Gain MP3 error") logging.debug(nt.fullpath) if item.desc == "FMPS_RATING": - nt.misc['FMPS_Rating'] = float(item.text[0]) + nt.misc["FMPS_Rating"] = float(item.text[0]) def scan_ffprobe(nt): startupinfo = None - if system == 'windows' or msys: + if system == "windows" or msys: startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW try: @@ -4666,25 +4666,25 @@ def tag_scan(nt): # Loop through all files in the directory to find any matching M3U for file in os.listdir(dir_path): - if file.endswith('.m3u'): - with open(os.path.join(dir_path, file), encoding='utf-8', errors='replace') as f: + if file.endswith(".m3u"): + with open(os.path.join(dir_path, file), encoding="utf-8", errors="replace") as f: content = f.read() - if '�' in content: # Check for replacement marker - with open(os.path.join(dir_path, file), encoding='windows-1252') as b: + if "�" in content: # Check for replacement marker + with open(os.path.join(dir_path, file), encoding="windows-1252") as b: content = b.read() if "::" in content: a, b = content.split("::") if a == filename: - s = re.split(r'(?<!\\),', b) + s = re.split(r"(?<!\\),", b) try: st = int(s[1]) except Exception: logging.exception("Failed to assign st to int") continue if st == n: - nt.title = s[2].split(' - ')[0].replace("\\", "") - nt.artist = s[2].split(' - ')[1].replace("\\", "") - nt.album = s[2].split(' - ')[2].replace("\\", "") + nt.title = s[2].split(" - ")[0].replace("\\", "") + nt.artist = s[2].split(" - ")[1].replace("\\", "") + nt.album = s[2].split(" - ")[2].replace("\\", "") nt.length = hms_to_seconds(s[3]) break if not nt.title: @@ -4882,7 +4882,7 @@ def tag_scan(nt): if not nt.length: try: startupinfo = None - if system == 'windows' or msys: + if system == "windows" or msys: startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW result = subprocess.run([tauon.get_ffprobe(), "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", nt.fullpath], stdout=subprocess.PIPE, startupinfo=startupinfo) @@ -4924,24 +4924,24 @@ def in_get(key, tags): if t[1]: nt.disc_total = str(t[1]) - if '----:com.apple.iTunes:MusicBrainz Track Id' in tags: - nt.misc['musicbrainz_recordingid'] = in_get( + if "----:com.apple.iTunes:MusicBrainz Track Id" in tags: + nt.misc["musicbrainz_recordingid"] = in_get( "----:com.apple.iTunes:MusicBrainz Track Id", tags).decode() - if '----:com.apple.iTunes:MusicBrainz Release Track Id' in tags: - nt.misc['musicbrainz_trackid'] = in_get( + if "----:com.apple.iTunes:MusicBrainz Release Track Id" in tags: + nt.misc["musicbrainz_trackid"] = in_get( "----:com.apple.iTunes:MusicBrainz Release Track Id", tags).decode() - if '----:com.apple.iTunes:MusicBrainz Album Id' in tags: - nt.misc['musicbrainz_albumid'] = in_get( + if "----:com.apple.iTunes:MusicBrainz Album Id" in tags: + nt.misc["musicbrainz_albumid"] = in_get( "----:com.apple.iTunes:MusicBrainz Album Id", tags).decode() - if '----:com.apple.iTunes:MusicBrainz Release Group Id' in tags: - nt.misc['musicbrainz_releasegroupid'] = in_get( + if "----:com.apple.iTunes:MusicBrainz Release Group Id" in tags: + nt.misc["musicbrainz_releasegroupid"] = in_get( "----:com.apple.iTunes:MusicBrainz Release Group Id", tags).decode() - if '----:com.apple.iTunes:MusicBrainz Artist Id' in tags: - nt.misc['musicbrainz_artistids'] = [x.decode() for x in + if "----:com.apple.iTunes:MusicBrainz Artist Id" in tags: + nt.misc["musicbrainz_artistids"] = [x.decode() for x in tags.get("----:com.apple.iTunes:MusicBrainz Artist Id")] @@ -4973,7 +4973,7 @@ def in_get(key, tags): else: logging.exception("Error: Tag read failed on file:", nt.fullpath, "\n") except Exception: - logging.exception("Error printing error. Non utf8 not allowed:", nt.fullpath.encode('utf-8', 'surrogateescape').decode('utf-8', 'replace'), "\n") + logging.exception("Error printing error. Non utf8 not allowed:", nt.fullpath.encode("utf-8", "surrogateescape").decode("utf-8", "replace"), "\n") return nt return nt @@ -5655,7 +5655,7 @@ def set_volume(self, notify=True): return self.volume_update_timer.set() - self.playerCommand = 'volume' + self.playerCommand = "volume" self.playerCommandReady = True if notify: self.notify_update() @@ -5689,7 +5689,7 @@ def revert(self): self.start_time = pctl.master_library[self.track_queue[self.queue_step]].start_time self.start_time_target = self.start_time self.playing_length = pctl.master_library[self.track_queue[self.queue_step]].length - self.playerCommand = 'open' + self.playerCommand = "open" self.playerCommandReady = True self.playing_state = 1 @@ -5733,9 +5733,9 @@ def play_target_rr(self): self.start_time = pctl.master_library[self.track_queue[self.queue_step]].start_time self.start_time_target = self.start_time self.jump_time = random_start - self.playerCommand = 'open' + self.playerCommand = "open" if not prefs.use_jump_crossfade: - self.playerSubCommand = 'now' + self.playerSubCommand = "now" self.playerCommandReady = True self.playing_state = 1 radiobox.loaded_station = None @@ -5775,9 +5775,9 @@ def play_target(self, gapless=False, jump=False): self.decode_time = 0 self.jump_time = t - self.playerCommand = 'open' + self.playerCommand = "open" if jump: # and not prefs.use_jump_crossfade: - self.playerSubCommand = 'now' + self.playerSubCommand = "now" self.playerCommandReady = True @@ -5897,9 +5897,9 @@ def back(self): def stop(self, block=False, run=False): - self.playerCommand = 'stop' + self.playerCommand = "stop" if run: - self.playerCommand = 'runstop' + self.playerCommand = "runstop" if block: self.playerSubCommand = "return" @@ -5947,10 +5947,10 @@ def pause(self): if tauon.spotc and tauon.spotc.running and spot_ctl.playing: if self.playing_state == 1: - self.playerCommand = 'pauseon' + self.playerCommand = "pauseon" self.playerCommandReady = True elif self.playing_state == 2: - self.playerCommand = 'pauseoff' + self.playerCommand = "pauseoff" self.playerCommandReady = True if self.playing_state == 3: @@ -5972,10 +5972,10 @@ def pause(self): return if self.playing_state == 1: - self.playerCommand = 'pauseon' + self.playerCommand = "pauseon" self.playing_state = 2 elif self.playing_state == 2: - self.playerCommand = 'pauseoff' + self.playerCommand = "pauseoff" self.playing_state = 1 notify_song() @@ -5986,7 +5986,7 @@ def pause(self): def pause_only(self): if self.playing_state == 1: - self.playerCommand = 'pauseon' + self.playerCommand = "pauseon" self.playing_state = 2 self.playerCommandReady = True @@ -6011,7 +6011,7 @@ def seek_decimal(self, decimal): decimal = 0 self.new_time = pctl.playing_length * decimal #logging.info('seek to:' + str(pctl.new_time)) - self.playerCommand = 'seek' + self.playerCommand = "seek" self.playerCommandReady = True self.playing_time = self.new_time @@ -6036,7 +6036,7 @@ def seek_time(self, new): self.new_time = new self.playing_time = new - self.playerCommand = 'seek' + self.playerCommand = "seek" self.playerCommandReady = True if self.mpris is not None: @@ -6051,7 +6051,7 @@ def play(self): # Unpause if paused if self.playing_state == 2: - self.playerCommand = 'pauseoff' + self.playerCommand = "pauseoff" self.playerCommandReady = True self.playing_state = 1 self.notify_update() @@ -6262,8 +6262,8 @@ def test_progress(self): self.target_object = target self.start_time = target.start_time self.start_time_target = self.start_time - self.playerCommand = 'open' - self.playerSubCommand = 'repeat' + self.playerCommand = "open" + self.playerSubCommand = "repeat" self.playerCommandReady = True #self.render_playlist() @@ -6325,9 +6325,9 @@ def start_commit(self, id, repeat=False): self.target_object = target self.start_time = target.start_time self.start_time_target = self.start_time - self.playerCommand = 'open' + self.playerCommand = "open" if repeat: - self.playerSubCommand = 'repeat' + self.playerSubCommand = "repeat" self.playerCommandReady = True def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, play=True, dry=False): @@ -6696,19 +6696,19 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, if self.playlist_playing_position == len(self.playing_playlist()) - 1: if dry: return None - if prefs.end_setting == 'stop': + if prefs.end_setting == "stop": self.playing_state = 0 - self.playerCommand = 'runstop' + self.playerCommand = "runstop" self.playerCommandReady = True end_of_playlist = True - elif prefs.end_setting == 'advance' or prefs.end_setting == 'cycle': + elif prefs.end_setting == "advance" or prefs.end_setting == "cycle": # If at end playlist and not cycle mode, stop playback if pctl.active_playlist_playing == len( - pctl.multi_playlist) - 1 and not prefs.end_setting == 'cycle': + pctl.multi_playlist) - 1 and not prefs.end_setting == "cycle": self.playing_state = 0 - self.playerCommand = 'runstop' + self.playerCommand = "runstop" self.playerCommandReady = True end_of_playlist = True @@ -6740,7 +6740,7 @@ def advance(self, rr=False, quiet=False, inplace=False, end=False, force=False, return - elif prefs.end_setting == 'repeat': + elif prefs.end_setting == "repeat": pctl.playlist_playing_position = -1 pctl.advance(end=end, force=True, play=play) return @@ -6936,25 +6936,25 @@ def update_title_do(): line = pctl.master_library[pctl.track_queue[pctl.queue_step]].artist + " - " + \ pctl.master_library[pctl.track_queue[pctl.queue_step]].title # line += " : : Tauon Music Box" - line = line.encode('utf-8') + line = line.encode("utf-8") SDL_SetWindowTitle(t_window, line) else: line = "Tauon Music Box" - line = line.encode('utf-8') + line = line.encode("utf-8") SDL_SetWindowTitle(t_window, line) def open_encode_out(): - if system == 'windows' or msys: - line = r'explorer ' + prefs.encoder_output.replace("/", "\\") + if system == "windows" or msys: + line = r"explorer " + prefs.encoder_output.replace("/", "\\") subprocess.Popen(line) else: line = prefs.encoder_output line += "/" if macos: - subprocess.Popen(['open', line]) + subprocess.Popen(["open", line]) else: - subprocess.Popen(['xdg-open', line]) + subprocess.Popen(["xdg-open", line]) def g_open_encode_out(a, b, c): @@ -6963,7 +6963,7 @@ def g_open_encode_out(a, b, c): # -if system == 'linux' and not macos and not msys: +if system == "linux" and not macos and not msys: try: Notify.init("Tauon Music Box") @@ -7022,7 +7022,7 @@ def notify_song(notify_of_end=False, delay=0.0): if not notify_of_end: i_path = thumb_tracks.path(track) except Exception: - logging.exception(track.fullpath.encode('utf-8', 'replace').decode("utf-8")) + logging.exception(track.fullpath.encode("utf-8", "replace").decode("utf-8")) logging.error("Thumbnail error") top_line = track.title @@ -7080,7 +7080,7 @@ def get_network(self): def auth1(self): if not last_fm_enable: - show_message(_("Optional module python-pylast not installed"), mode='warning') + show_message(_("Optional module python-pylast not installed"), mode="warning") return # This is step one where the user clicks "login" @@ -7089,7 +7089,7 @@ def auth1(self): self.sg = pylast.SessionKeyGenerator(self.network) self.url = self.sg.get_web_auth_url() - show_message(_("Web auth page opened"), _("Once authorised click the 'done' button."), mode='arrow') + show_message(_("Web auth page opened"), _("Once authorised click the 'done' button."), mode="arrow") webbrowser.open(self.url, new=2, autoraise=True) def auth2(self): @@ -7111,12 +7111,12 @@ def auth2(self): prefs.last_fm_username = username except Exception as e: - if 'Unauthorized Token' in str(e): + if "Unauthorized Token" in str(e): logging.exception("Not authorized") - show_message(_("Error - Not authorized"), mode='error') + show_message(_("Error - Not authorized"), mode="error") else: logging.exception("Unknown error") - show_message(_("Error"), _('Unknown error.'), mode='error') + show_message(_("Error"), _("Unknown error."), mode="error") if not toggle_lfm_auto(mode=1): toggle_lfm_auto() @@ -7140,10 +7140,10 @@ def connect(self, m_notify=True): return True if prefs.last_fm_token is None: - show_message(_("No Last.Fm account registered"), _("Authorise an account in settings"), mode='info') + show_message(_("No Last.Fm account registered"), _("Authorise an account in settings"), mode="info") return - logging.info('Attempting to connect to Last.fm network') + logging.info("Attempting to connect to Last.fm network") try: @@ -7152,14 +7152,14 @@ def connect(self, m_notify=True): self.connected = True if m_notify: - show_message(_("Connection to Last.fm was successful."), mode='done') + show_message(_("Connection to Last.fm was successful."), mode="done") - logging.info('Connection to lastfm appears successful') + logging.info("Connection to lastfm appears successful") return True except Exception as e: logging.exception("Error connecting to Last.fm network") - show_message(_("Error connecting to Last.fm network"), str(e), mode='warning') + show_message(_("Error connecting to Last.fm network"), str(e), mode="warning") return False def toggle(self): @@ -7176,12 +7176,12 @@ def last_fm_only_connect(self): return False try: self.lastfm_network = pylast.LastFMNetwork(api_key=self.API_KEY, api_secret=self.API_SECRET) - logging.info('Connection appears successful') + logging.info("Connection appears successful") return True except Exception as e: logging.exception("Error communicating with Last.fm network") - show_message(_("Error communicating with Last.fm network"), str(e), mode='warning') + show_message(_("Error communicating with Last.fm network"), str(e), mode="warning") return False def no_user_connect(self): @@ -7189,12 +7189,12 @@ def no_user_connect(self): return False try: self.network = self.get_network()(api_key=self.API_KEY, api_secret=self.API_SECRET) - logging.info('Connection appears successful') + logging.info("Connection appears successful") return True except Exception as e: logging.exception("Error communicating with Last.fm network") - show_message(_("Error communicating with Last.fm network"), str(e), mode='warning') + show_message(_("Error communicating with Last.fm network"), str(e), mode="warning") return False def get_all_scrobbles_estimate_time(self): @@ -7383,7 +7383,7 @@ def scrobble(self, track_object, timestamp=None): except Exception as e: logging.exception("Failed to Scrobble!") - if 'retry' in str(e): + if "retry" in str(e): logging.warning("Retrying in a couple seconds...") time.sleep(7) @@ -7470,7 +7470,7 @@ def get_friends_love(self): self.network.enable_rate_limit() lastfm_user = self.network.get_user(username) friends = lastfm_user.get_friends(limit=None) - show_message(_("Getting friend data..."), _("This may take a very long time."), mode='info') + show_message(_("Getting friend data..."), _("This may take a very long time."), mode="info") for friend in friends: self.scanning_username = friend.name logging.info("Getting friend loves: " + friend.name) @@ -7493,7 +7493,7 @@ def get_friends_love(self): except Exception: logging.exception("There was an error getting friends loves") - show_message(_("There was an error getting friends loves"), "", mode='warning') + show_message(_("There was an error getting friends loves"), "", mode="warning") self.scanning_friends = False @@ -7505,7 +7505,7 @@ def dl_love(self): self.scanning_username = username if not username: - show_message(_("No username found"), mode='error') + show_message(_("No username found"), mode="error") return if len(username) > 25: @@ -7562,7 +7562,7 @@ def dl_love(self): return except Exception: logging.exception("This doesn't seem to be working :(") - show_message(_("This doesn't seem to be working :("), mode='error') + show_message(_("This doesn't seem to be working :("), mode="error") self.scanning_loves = False def update(self, track_object): @@ -7594,7 +7594,7 @@ def update(self, track_object): logging.exception("Error connecting to last.fm.") console.print("Error connecting to last.fm.", level=3) console.print("-- " + str(e), level=3) - if 'retry' in str(e): + if "retry" in str(e): return 2 # show_message(_("Could not update Last.fm. ", str(e), mode='warning') pctl.b_time -= 5000 @@ -7604,10 +7604,10 @@ def update(self, track_object): def get_backend_time(path): pctl.time_to_get = path - pctl.playerCommand = 'time' + pctl.playerCommand = "time" pctl.playerCommandReady = True - while pctl.playerCommand != 'done': + while pctl.playerCommand != "done": time.sleep(0.005) return pctl.time_to_get @@ -7638,7 +7638,7 @@ def listen_full(self, track_object, time): if prefs.scrobble_hold is True: return True if prefs.lb_token is None: - show_message(_("ListenBrains is enabled but there is no token."), _("How did this even happen."), mode='error') + show_message(_("ListenBrains is enabled but there is no token."), _("How did this even happen."), mode="error") title = track_object.title album = track_object.album @@ -7653,23 +7653,23 @@ def listen_full(self, track_object, time): additional = {} # MusicBrainz Artist IDs - if 'musicbrainz_artistids' in track_object.misc: - additional['artist_mbids'] = track_object.misc['musicbrainz_artistids'] + if "musicbrainz_artistids" in track_object.misc: + additional["artist_mbids"] = track_object.misc["musicbrainz_artistids"] # MusicBrainz Release ID - if 'musicbrainz_albumid' in track_object.misc: - additional['release_mbid'] = track_object.misc['musicbrainz_albumid'] + if "musicbrainz_albumid" in track_object.misc: + additional["release_mbid"] = track_object.misc["musicbrainz_albumid"] # MusicBrainz Recording ID - if 'musicbrainz_recordingid' in track_object.misc: - additional['recording_mbid'] = track_object.misc['musicbrainz_recordingid'] + if "musicbrainz_recordingid" in track_object.misc: + additional["recording_mbid"] = track_object.misc["musicbrainz_recordingid"] # MusicBrainz Track ID - if 'musicbrainz_trackid' in track_object.misc: - additional['track_mbid'] = track_object.misc['musicbrainz_trackid'] + if "musicbrainz_trackid" in track_object.misc: + additional["track_mbid"] = track_object.misc["musicbrainz_trackid"] if additional: - metadata['additional_info'] = additional + metadata["additional_info"] = additional # logging.info(additional) data["payload"].append({"track_metadata": metadata}) @@ -7677,7 +7677,7 @@ def listen_full(self, track_object, time): r = requests.post(self.url(), headers={"Authorization": "Token " + prefs.lb_token}, data=json.dumps(data)) if r.status_code != 200: - show_message(_("There was an error submitting data to ListenBrainz"), r.text, mode='warning') + show_message(_("There was an error submitting data to ListenBrainz"), r.text, mode="warning") return False return True @@ -7687,7 +7687,7 @@ def listen_playing(self, track_object): if prefs.scrobble_hold is True: return if prefs.lb_token is None: - show_message(_("ListenBrains is enabled but there is no token."), _("How did this even happen."), mode='error') + show_message(_("ListenBrains is enabled but there is no token."), _("How did this even happen."), mode="error") title = track_object.title album = track_object.album artist = get_artist_strip_feat(track_object) @@ -7701,20 +7701,20 @@ def listen_playing(self, track_object): additional = {} # MusicBrainz Artist IDs - if 'musicbrainz_artistids' in track_object.misc: - additional['artist_mbids'] = track_object.misc['musicbrainz_artistids'] + if "musicbrainz_artistids" in track_object.misc: + additional["artist_mbids"] = track_object.misc["musicbrainz_artistids"] # MusicBrainz Release ID - if 'musicbrainz_albumid' in track_object.misc: - additional['release_mbid'] = track_object.misc['musicbrainz_albumid'] + if "musicbrainz_albumid" in track_object.misc: + additional["release_mbid"] = track_object.misc["musicbrainz_albumid"] # MusicBrainz Recording ID - if 'musicbrainz_recordingid' in track_object.misc: - additional['recording_mbid'] = track_object.misc['musicbrainz_recordingid'] + if "musicbrainz_recordingid" in track_object.misc: + additional["recording_mbid"] = track_object.misc["musicbrainz_recordingid"] # MusicBrainz Track ID - if 'musicbrainz_trackid' in track_object.misc: - additional['track_mbid'] = track_object.misc['musicbrainz_trackid'] + if "musicbrainz_trackid" in track_object.misc: + additional["track_mbid"] = track_object.misc["musicbrainz_trackid"] if track_object.track_number: try: @@ -7729,13 +7729,13 @@ def listen_playing(self, track_object): additional["submission_client"] = t_title additional["media_player_version"] = str(n_version) - metadata['additional_info'] = additional + metadata["additional_info"] = additional data["payload"].append({"track_metadata": metadata}) # data["payload"][0]["listened_at"] = int(time.time()) r = requests.post(self.url(), headers={"Authorization": "Token " + prefs.lb_token}, data=json.dumps(data)) if r.status_code != 200: - show_message(_("There was an error submitting data to ListenBrainz"), r.text, mode='warning') + show_message(_("There was an error submitting data to ListenBrainz"), r.text, mode="warning") logging.error("There was an error submitting data to ListenBrainz") logging.error(r.status_code) logging.error(r.json()) @@ -7754,7 +7754,7 @@ def paste_key(self): if len(text) == 36 and text[8] == "-": prefs.lb_token = text else: - show_message(_("That is not a valid token."), mode='error') + show_message(_("That is not a valid token."), mode="error") def clear_key(self): @@ -7771,7 +7771,7 @@ def get_love(track_object): if star is None: return False - if 'L' in star[1]: + if "L" in star[1]: return True else: return False @@ -7782,7 +7782,7 @@ def get_love_index(index): if star is None: return False - if 'L' in star[1]: + if "L" in star[1]: return True else: return False @@ -7807,7 +7807,7 @@ def love(set=True, track_id=None, no_delay=False, notify=False, sync=True): star = star_store.full_get(track_id) if star is not None: - if 'L' in star[1]: + if "L" in star[1]: loved = True if set is False: @@ -7848,7 +7848,7 @@ def love(set=True, track_id=None, no_delay=False, notify=False, sync=True): lastfm.love(pctl.master_library[track_id].artist, pctl.master_library[track_id].title) except Exception: logging.exception("Failed updating last.fm love status") - show_message(_("Failed updating last.fm love status"), mode='warning') + show_message(_("Failed updating last.fm love status"), mode="warning") star[1] = star[1].replace("L", "") # = [star[0], star[1].strip("L"), star[2]] star_store.insert(track_id, star) show_message(_("Error updating love to last.fm!"), @@ -7869,7 +7869,7 @@ def love(set=True, track_id=None, no_delay=False, notify=False, sync=True): lastfm.unlove(pctl.master_library[track_id].artist, pctl.master_library[track_id].title) except Exception: logging.exception("Failed updating last.fm love status") - show_message(_("Failed updating last.fm love status"), mode='warning') + show_message(_("Failed updating last.fm love status"), mode="warning") star[1] = star[1] + "L" star_store.insert(track_id, star) if pctl.master_library[track_id].file_ext == "JELY": @@ -7894,12 +7894,12 @@ def maloja_get_scrobble_counts(): r = requests.get(url) if r.status_code != 200: - show_message(_("There was an error with the Maloja server"), r.text, mode='warning') + show_message(_("There was an error with the Maloja server"), r.text, mode="warning") lastfm.scanning_scrobbles = False return except Exception: logging.exception("There was an error reaching the Maloja server") - show_message(_("There was an error reaching the Maloja server"), mode='warning') + show_message(_("There was an error reaching the Maloja server"), mode="warning") lastfm.scanning_scrobbles = False return @@ -7960,11 +7960,11 @@ def maloja_scrobble(track): try: r = requests.post(url, data=d) if r.status_code != 200: - show_message(_("There was an error submitting data to Maloja server"), r.text, mode='warning') + show_message(_("There was an error submitting data to Maloja server"), r.text, mode="warning") return False except Exception: logging.exception("There was an error submitting data to Maloja server") - show_message(_("There was an error submitting data to Maloja server"), mode='warning') + show_message(_("There was an error submitting data to Maloja server"), mode="warning") return False return True @@ -8377,12 +8377,12 @@ def go(): f.seek(0) z = zipfile.ZipFile(f, mode="r") exe = z.open("ffmpeg-5.0.1-essentials_build/bin/ffmpeg.exe") - ff = open(os.path.join(user_directory, "ffmpeg.exe"), 'wb') + ff = open(os.path.join(user_directory, "ffmpeg.exe"), "wb") ff.write(exe.read()) ff.close() exe = z.open("ffmpeg-5.0.1-essentials_build/bin/ffprobe.exe") - ff = open(os.path.join(user_directory, "ffprobe.exe"), 'wb') + ff = open(os.path.join(user_directory, "ffprobe.exe"), "wb") ff.write(exe.read()) ff.close() @@ -8504,7 +8504,7 @@ def __init__(self): def connect(self): if not prefs.plex_username or not prefs.plex_password or not prefs.plex_servername: - show_message(_("Missing username, password and/or server name"), mode='warning') + show_message(_("Missing username, password and/or server name"), mode="warning") self.scanning = False return @@ -8514,7 +8514,7 @@ def connect(self): logging.warning("Unable to import python-plexapi, plex support will be disabled.") except Exception: logging.exception("Unknown error to import python-plexapi, plex support will be disabled.") - show_message(_("Error importing python-plexapi"), mode='error') + show_message(_("Error importing python-plexapi"), mode="error") self.scanning = False return @@ -8524,7 +8524,7 @@ def connect(self): except Exception: logging.exception("Error connecting to PLEX server, check login credentials and server accessibility.") show_message(_("Error connecting to PLEX server"), - _("Try checking login credentials and that the server is accessible."), mode='error') + _("Try checking login credentials and that the server is accessible."), mode="error") self.scanning = False return @@ -8571,7 +8571,7 @@ def get_albums(self, return_list=False): if track.is_network and track.file_ext == "PLEX": existing[track.url_key] = track_id - albums = self.resource.library.section('Music').albums() + albums = self.resource.library.section("Music").albums() gui.to_got = 0 for album in albums: @@ -8661,16 +8661,16 @@ def r(self, point, p=None, binary=False, get_url=False): params = { "u": prefs.subsonic_user, - 'v': "1.13.0", - 'c': t_title, - 'f': "json" + "v": "1.13.0", + "c": t_title, + "f": "json" } if prefs.subsonic_password_plain: params["p"] = prefs.subsonic_password else: params["t"] = hashlib.md5((prefs.subsonic_password + salt).encode()).hexdigest() - params['s'] = salt + params["s"] = salt if p: params.update(p) @@ -8704,7 +8704,7 @@ def resolve_stream(self, key): p = {"id": key} if prefs.network_stream_bitrate > 0: - p['maxBitRate'] = prefs.network_stream_bitrate + p["maxBitRate"] = prefs.network_stream_bitrate return self.r("stream", p={"id": key}, get_url=True) # logging.info(response.content) @@ -9029,7 +9029,7 @@ def connect(self): logging.info("Connect to koel...") if not prefs.koel_username or not prefs.koel_password or not prefs.koel_server_url: - show_message(_("Missing username, password and/or server URL"), mode='warning') + show_message(_("Missing username, password and/or server URL"), mode="warning") self.scanning = False return @@ -9508,13 +9508,13 @@ def key_callback(event): if event.event_type == "down": if event.scan_code == -179: - inp.media_key = 'Play' + inp.media_key = "Play" elif event.scan_code == -178: - inp.media_key = 'Stop' + inp.media_key = "Stop" elif event.scan_code == -177: - inp.media_key = 'Previous' + inp.media_key = "Previous" elif event.scan_code == -176: - inp.media_key = 'Next' + inp.media_key = "Next" gui.update += 1 tauon.wake() @@ -9574,22 +9574,22 @@ def update(self, playlist): pt = int(star_store.get(index)) gn = [] - if ',' in genre_r: + if "," in genre_r: for g in genre_r.split(","): g = g.rstrip(" ").lstrip(" ") if len(g) > 0: gn.append(g) - elif ';' in genre_r: + elif ";" in genre_r: for g in genre_r.split(";"): g = g.rstrip(" ").lstrip(" ") if len(g) > 0: gn.append(g) - elif '/' in genre_r: + elif "/" in genre_r: for g in genre_r.split("/"): g = g.rstrip(" ").lstrip(" ") if len(g) > 0: gn.append(g) - elif ' & ' in genre_r: + elif " & " in genre_r: for g in genre_r.split(" & "): g = g.rstrip(" ").lstrip(" ") if len(g) > 0: @@ -9601,32 +9601,32 @@ def update(self, playlist): for genre in gn: - if genre.lower() in {"", 'other', 'unknown', 'misc'}: + if genre.lower() in {"", "other", "unknown", "misc"}: genre = "<Genre Unspecified>" - if genre.lower() in {'jpop', 'japanese pop'}: - genre = 'J-Pop' - if genre.lower() in {'jrock', 'japanese rock'}: - genre = 'J-Rock' - if genre.lower() in {'alternative music', 'alt-rock', 'alternative', 'alternrock', 'alt'}: - genre = 'Alternative Rock' - if genre.lower() in {'jpunk', 'japanese punk'}: - genre = 'J-Punk' - if genre.lower() in {'post rock', 'post-rock'}: - genre = 'Post-Rock' - if genre.lower() in {'video game', 'game', 'game music', 'video game music', 'game ost'}: + if genre.lower() in {"jpop", "japanese pop"}: + genre = "J-Pop" + if genre.lower() in {"jrock", "japanese rock"}: + genre = "J-Rock" + if genre.lower() in {"alternative music", "alt-rock", "alternative", "alternrock", "alt"}: + genre = "Alternative Rock" + if genre.lower() in {"jpunk", "japanese punk"}: + genre = "J-Punk" + if genre.lower() in {"post rock", "post-rock"}: + genre = "Post-Rock" + if genre.lower() in {"video game", "game", "game music", "video game music", "game ost"}: genre = "Video Game Soundtrack" - if genre.lower() in {'general soundtrack', 'ost', 'Soundtracks'}: + if genre.lower() in {"general soundtrack", "ost", "Soundtracks"}: genre = "Soundtrack" - if genre.lower() in ('anime', 'アニメ', 'anime ost'): - genre = 'Anime Soundtrack' - if genre.lower() in {'同人'}: - genre = 'Doujin' - if genre.lower() in {'chill, chill out', 'chill-out'}: - genre = 'Chillout' + if genre.lower() in ("anime", "アニメ", "anime ost"): + genre = "Anime Soundtrack" + if genre.lower() in {"同人"}: + genre = "Doujin" + if genre.lower() in {"chill, chill out", "chill-out"}: + genre = "Chillout" genre = genre.title() - if len(genre) == 3 and genre[2] == 'm': + if len(genre) == 3 and genre[2] == "m": genre = genre.upper() if genre in genres: @@ -9979,12 +9979,12 @@ class XcursorImage(ctypes.Structure): _fields_ = [ ("version", c_uint32), ("size", c_uint32), - ('width', c_uint32), - ('height', c_uint32), - ('xhot', c_uint32), - ('yhot', c_uint32), - ('delay', c_uint32), - ('pixels', c_void_p), + ("width", c_uint32), + ("height", c_uint32), + ("xhot", c_uint32), + ("yhot", c_uint32), + ("delay", c_uint32), + ("pixels", c_void_p), ] try: @@ -10008,7 +10008,7 @@ def get_xcursor(name): cursor_left_side = get_xcursor("left_side") cursor_bottom_side = get_xcursor("bottom_side") - if SDL_GetCurrentVideoDriver() == b'wayland': + if SDL_GetCurrentVideoDriver() == b"wayland": cursor_standard = get_xcursor("left_ptr") cursor_text = get_xcursor("xterm") cursor_shift = get_xcursor("sb_h_double_arrow") @@ -10031,7 +10031,7 @@ def get_xcursor(name): # logging.error(SDL_GetError()) -if system == 'windows' or msys: +if system == "windows" or msys: gui.window_id = sss.info.win.window @@ -10114,16 +10114,16 @@ def bass_player_thread(player): try: player(pctl, gui, prefs, lfm_scrobbler, star_store, tauon) except Exception: - logging.exception('Exception on player thread') - show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode='error') + logging.exception("Exception on player thread") + show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") time.sleep(1) - show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode='error') + show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") time.sleep(1) - show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode='error') + show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") raise -if (system == 'windows' or msys) and taskbar_progress: +if (system == "windows" or msys) and taskbar_progress: class WinTask: @@ -10350,8 +10350,8 @@ def prime_fonts(): ddt.win_prime_font(standard_font, 30 + 4, 30, weight=standard_weight, y_offset=-12) ddt.win_prime_font(semibold_font, 9, 209, weight=bold_weight, y_offset=1) - ddt.win_prime_font('Arial', 10 + 4, 210, weight=600, y_offset=2) - ddt.win_prime_font('Arial', 11 + 3, 211, weight=600, y_offset=2) + ddt.win_prime_font("Arial", 10 + 4, 210, weight=600, y_offset=2) + ddt.win_prime_font("Arial", 11 + 3, 211, weight=600, y_offset=2) ddt.win_prime_font(semibold_font, 12 + 4, 212, weight=bold_weight, y_offset=1) ddt.win_prime_font(semibold_font, 13 + 3, 213, weight=bold_weight, y_offset=-1) ddt.win_prime_font(semibold_font, 14 + 2, 214, weight=bold_weight, y_offset=1) @@ -10417,7 +10417,7 @@ def prepare(self, w, h): g = io.BytesIO() g.seek(0) - im.save(g, 'PNG') + im.save(g, "PNG") g.seek(0) wop = rw_from_object(g) @@ -10524,7 +10524,7 @@ def find_synced_lyric_data(track): try: if os.path.isfile(os.path.join(direc, name)): - with open(os.path.join(direc, name), 'r', encoding='utf-8') as f: + with open(os.path.join(direc, name), "r", encoding="utf-8") as f: data = f.readlines() else: return None @@ -10862,7 +10862,7 @@ def __init__(self): def paste(self): if SDL_HasClipboardText(): - clip = SDL_GetClipboardText().decode('utf-8') + clip = SDL_GetClipboardText().decode("utf-8") self.paste_text = clip def copy(self): @@ -10871,7 +10871,7 @@ def copy(self): if not text: text = self.text if text != "": - SDL_SetClipboardText(text.encode('utf-8')) + SDL_SetClipboardText(text.encode("utf-8")) def set_text(self, text): @@ -11047,11 +11047,11 @@ def d(): self.selection = self.cursor_position if self.paste_text: - if 'http://' in self.text and 'http://' in self.paste_text: + if "http://" in self.text and "http://" in self.paste_text: self.text = "" self.paste_text = self.paste_text.rstrip(" ").lstrip(" ") - self.paste_text = self.paste_text.replace('\n', ' ').replace('\r', '') + self.paste_text = self.paste_text.replace("\n", " ").replace("\r", "") self.eliminate_selection() self.text = self.text[0: len(self.text) - self.cursor_position] + self.paste_text + self.text[len( @@ -11060,7 +11060,7 @@ def d(): # Paste via ctrl-v if key_ctrl_down and key_v_press: - clip = SDL_GetClipboardText().decode('utf-8') + clip = SDL_GetClipboardText().decode("utf-8") self.eliminate_selection() self.text = self.text[0: len(self.text) - self.cursor_position] + clip + self.text[len( self.text) - self.cursor_position:] @@ -11072,7 +11072,7 @@ def d(): if len(self.get_selection()) > 0: text = self.get_selection() if text != "": - SDL_SetClipboardText(text.encode('utf-8')) + SDL_SetClipboardText(text.encode("utf-8")) self.eliminate_selection() if key_ctrl_down and key_a_press: @@ -11156,7 +11156,7 @@ def d(): post = 0 text = self.text if secret: - text = '●' * len(self.text) + text = "●" * len(self.text) if mouse_position[0] < x + 1: self.selection = len(text) else: @@ -11182,12 +11182,12 @@ def d(): text = self.text[0: len(self.text) - self.cursor_position] if secret: - text = '●' * len(text) + text = "●" * len(text) a = ddt.get_text_w(text, font) text = self.text[0: len(self.text) - self.selection] if secret: - text = '●' * len(text) + text = "●" * len(text) b = ddt.get_text_w(text, font) top = y @@ -11200,26 +11200,26 @@ def d(): inf_comp = 0 text = self.get_selection(0) if secret: - text = '●' * len(text) + text = "●" * len(text) space = ddt.text((0, 0), text, colour, font) text = self.get_selection(1) if secret: - text = '●' * len(text) + text = "●" * len(text) space += ddt.text((0 + space - inf_comp, 0), text, [240, 240, 240, 255], font, bg=[40, 120, 180, 255], ) text = self.get_selection(2) if secret: - text = '●' * len(text) + text = "●" * len(text) ddt.text((0 + space - (inf_comp * 2), 0), text, colour, font) else: text = self.text if secret: - text = '●' * len(text) + text = "●" * len(text) ddt.text((0, 0), text, colour, font) text = self.text[0: len(self.text) - self.cursor_position] if secret: - text = '●' * len(text) + text = "●" * len(text) space = ddt.get_text_w(text, font) if TextBox.cursor and self.selection == self.cursor_position: @@ -11234,7 +11234,7 @@ def d(): width -= round(15 * gui.scale) text = self.text if secret: - text = '●' * len(text) + text = "●" * len(text) t_len = ddt.get_text_w(text, font) ddt.text((0, 0), text, colour, font) self.offset = 0 @@ -11288,13 +11288,13 @@ def __init__(self): def paste(self): if SDL_HasClipboardText(): - clip = SDL_GetClipboardText().decode('utf-8') + clip = SDL_GetClipboardText().decode("utf-8") - if 'http://' in self.text and 'http://' in clip: + if "http://" in self.text and "http://" in clip: self.text = "" clip = clip.rstrip(" ").lstrip(" ") - clip = clip.replace('\n', ' ').replace('\r', '') + clip = clip.replace("\n", " ").replace("\r", "") self.eliminate_selection() self.text = self.text[0: len(self.text) - self.cursor_position] + clip + self.text[len( @@ -11306,7 +11306,7 @@ def copy(self): if not text: text = self.text if text != "": - SDL_SetClipboardText(text.encode('utf-8')) + SDL_SetClipboardText(text.encode("utf-8")) def set_text(self, text): @@ -11471,7 +11471,7 @@ def d(): # Paste via ctrl-v if key_ctrl_down and key_v_press: - clip = SDL_GetClipboardText().decode('utf-8') + clip = SDL_GetClipboardText().decode("utf-8") self.eliminate_selection() self.text = self.text[0: len(self.text) - self.cursor_position] + clip + self.text[len( self.text) - self.cursor_position:] @@ -11483,7 +11483,7 @@ def d(): if len(self.get_selection()) > 0: text = self.get_selection() if text != "": - SDL_SetClipboardText(text.encode('utf-8')) + SDL_SetClipboardText(text.encode("utf-8")) self.eliminate_selection() if key_ctrl_down and key_a_press: @@ -11622,7 +11622,7 @@ def d(): self.paste() if secret: - space = ddt.text((x, y), '●' * len(self.text), colour, font) + space = ddt.text((x, y), "●" * len(self.text), colour, font) else: space = ddt.text((x, y), self.text, colour, font) @@ -11767,9 +11767,9 @@ def worker_render(self): parent_folder = key[0].parent_folder_path if parent_folder in folder_image_offsets: offset = folder_image_offsets[parent_folder] - img_name = str(key[2]) + "-" + str(size) + '-' + str(key[0].index) + "-" + str(offset) - if prefs.cache_gallery and os.path.isfile(os.path.join(g_cache_dir, img_name + '.jpg')): - source_image = open(os.path.join(g_cache_dir, img_name + '.jpg'), 'rb') + img_name = str(key[2]) + "-" + str(size) + "-" + str(key[0].index) + "-" + str(offset) + if prefs.cache_gallery and os.path.isfile(os.path.join(g_cache_dir, img_name + ".jpg")): + source_image = open(os.path.join(g_cache_dir, img_name + ".jpg"), "rb") # logging.info('load from cache') cache_load = True else: @@ -11785,12 +11785,12 @@ def worker_render(self): # del self.queue[0] continue - img_name = str(key[2]) + "-" + str(size) + '-' + str(key[0].index) + "-" + str(c_offset) + img_name = str(key[2]) + "-" + str(size) + "-" + str(key[0].index) + "-" + str(c_offset) # gall_render_last_timer.set() - if prefs.cache_gallery and os.path.isfile(os.path.join(g_cache_dir, img_name + '.jpg')): - source_image = open(os.path.join(g_cache_dir, img_name + '.jpg'), 'rb') + if prefs.cache_gallery and os.path.isfile(os.path.join(g_cache_dir, img_name + ".jpg")): + source_image = open(os.path.join(g_cache_dir, img_name + ".jpg"), "rb") logging.info("slow load image") cache_load = True @@ -11828,11 +11828,11 @@ def worker_render(self): im = album_art_gen.get_error_img(size) error = True - im.save(g, 'BMP') + im.save(g, "BMP") if not error and self.save_out and prefs.cache_gallery and not os.path.isfile( - os.path.join(g_cache_dir, img_name + '.jpg')): - im.save(os.path.join(g_cache_dir, img_name + '.jpg'), 'JPEG', quality=95) + os.path.join(g_cache_dir, img_name + ".jpg")): + im.save(os.path.join(g_cache_dir, img_name + ".jpg"), "JPEG", quality=95) g.seek(0) @@ -11847,8 +11847,8 @@ def worker_render(self): time.sleep(0.001) except Exception: - logging.exception('Image load failed on track: ' + key[0].fullpath) - console.print('ERROR: Image load failed on track: ') + logging.exception("Image load failed on track: " + key[0].fullpath) + console.print("ERROR: Image load failed on track: ") console.print("- " + key[0].fullpath) order = [0, None, None, None] self.gall[key] = order @@ -11979,9 +11979,9 @@ def path(self, track): return None image_name = track.album + track.parent_folder_path + str(offset) - image_name = hashlib.md5(image_name.encode('utf-8', 'replace')).hexdigest() + image_name = hashlib.md5(image_name.encode("utf-8", "replace")).hexdigest() - t_path = os.path.join(e_cache_dir, image_name + '.jpg') + t_path = os.path.join(e_cache_dir, image_name + ".jpg") if os.path.isfile(t_path): return t_path @@ -11993,7 +11993,7 @@ def path(self, track): im = im.convert("RGB") im.thumbnail((1000, 1000), Image.Resampling.LANCZOS) - im.save(t_path, 'JPEG') + im.save(t_path, "JPEG") return t_path @@ -12103,10 +12103,10 @@ def __init__(self): class AlbumArt(): def __init__(self): - self.image_types = {'jpg', 'JPG', 'jpeg', 'JPEG', 'PNG', 'png', 'BMP', 'bmp', 'GIF', 'gif', "jxl", "JXL"} - self.art_folder_names = {'art', 'scans', 'scan', 'booklet', 'images', 'image', 'cover', - 'covers', 'coverart', 'albumart', 'gallery', 'jacket', 'artwork', - 'bonus', 'bk', 'cover artwork', 'cover art'} + self.image_types = {"jpg", "JPG", "jpeg", "JPEG", "PNG", "png", "BMP", "bmp", "GIF", "gif", "jxl", "JXL"} + self.art_folder_names = {"art", "scans", "scan", "booklet", "images", "image", "cover", + "covers", "coverart", "albumart", "gallery", "jacket", "artwork", + "bonus", "bk", "cover artwork", "cover art"} self.source_cache = {} self.image_cache = [] self.current_wu = None @@ -12208,7 +12208,7 @@ def get_sources(self, tr): ins = len(source_list) for i in range(len(items_in_dir)): if os.path.splitext(items_in_dir[i])[1][1:] in self.image_types: - dir_path = os.path.join(direc, items_in_dir[i]).replace('\\', "/") + dir_path = os.path.join(direc, items_in_dir[i]).replace("\\", "/") # The image name "Folder" is likely desired to be prioritised over other names if os.path.splitext(os.path.basename(dir_path))[0] in ("Folder", "folder", "Cover", "cover"): source_list.insert(ins, [0, dir_path]) @@ -12221,7 +12221,7 @@ def get_sources(self, tr): for y in range(len(items_in_dir2)): if os.path.splitext(items_in_dir2[y])[1][1:] in self.image_types: - dir_path = os.path.join(subdirec, items_in_dir2[y]).replace('\\', "/") + dir_path = os.path.join(subdirec, items_in_dir2[y]).replace("\\", "/") source_list.append([0, dir_path]) self.source_cache[tr.index] = source_list @@ -12306,7 +12306,7 @@ def open_external(self, track_object): if source[offset][0] > 0: pic = album_art_gen.get_embed(track_object) if not pic: - show_message(_("Image save error."), _("No embedded album art."), mode='warning') + show_message(_("Image save error."), _("No embedded album art."), mode="warning") return 0 source_image = io.BytesIO(pic) @@ -12322,7 +12322,7 @@ def open_external(self, track_object): target = os.path.join(target, "embed-" + str(im.height) + "px-" + str(track_object.index) + ext) if len(pic) > 30: - with open(target, 'wb') as w: + with open(target, "wb") as w: w.write(pic) else: @@ -12390,7 +12390,7 @@ def get_embed(self, track): pic = None - if track.file_ext == 'MP3': + if track.file_ext == "MP3": try: tag = mutagen.id3.ID3(filepath) frame = tag.getall("APIC") @@ -12401,25 +12401,25 @@ def get_embed(self, track): if len(pic) < 30: pic = None - elif track.file_ext == 'FLAC': + elif track.file_ext == "FLAC": tag = Flac(filepath) tag.read(True) if tag.has_picture and len(tag.picture) > 30: pic = tag.picture - elif track.file_ext == 'APE': + elif track.file_ext == "APE": tag = Ape(filepath) tag.read() if tag.has_picture and len(tag.picture) > 30: pic = tag.picture - elif track.file_ext == 'M4A': + elif track.file_ext == "M4A": tag = M4a(filepath) tag.read(True) if tag.has_picture and len(tag.picture) > 30: pic = tag.picture - elif track.file_ext == 'OPUS' or track.file_ext == 'OGG' or track.file_ext == 'OGA': + elif track.file_ext == "OPUS" or track.file_ext == "OGG" or track.file_ext == "OGA": tag = Opus(filepath) tag.read() if tag.has_picture and len(tag.picture) > 30: @@ -12453,7 +12453,7 @@ def get_source_raw(self, offset, sources, track, subsource=None): cached_path = os.path.join(n_cache_dir, hashlib.md5(track.art_url_key.encode()).hexdigest()[:12]) if os.path.isfile(cached_path): - source_image = open(cached_path, 'rb') + source_image = open(cached_path, "rb") else: if track.file_ext == "SUB": source_image = subsonic.get_cover(track) @@ -12463,7 +12463,7 @@ def get_source_raw(self, offset, sources, track, subsource=None): response = urllib.request.urlopen(get_network_thumbnail_url(track), cafile=tauon.ca) source_image = io.BytesIO(response.read()) if source_image: - f = open(cached_path, 'wb') + f = open(cached_path, "wb") f.write(source_image.read()) f.close() source_image.seek(0) @@ -12472,7 +12472,7 @@ def get_source_raw(self, offset, sources, track, subsource=None): logging.exception("Failed to get source") else: - source_image = open(subsource[1], 'rb') + source_image = open(subsource[1], "rb") return source_image @@ -12550,7 +12550,7 @@ def get_background(self, track): # Get artist MBID try: s = musicbrainzngs.search_artists(artist, limit=1) - artist_id = s['artist-list'][0]['id'] + artist_id = s["artist-list"][0]["id"] except Exception: logging.exception("Failed to find artist MBID for: {artist}".format(artist=artist)) prefs.failed_background_artists.append(artist) @@ -12562,12 +12562,12 @@ def get_background(self, track): r = requests.get("http://webservice.fanart.tv/v3/music/" \ + artist_id + "?api_key=" + prefs.fatvap, timeout=(4, 10)) - artlink = r.json()['artistbackground'][0]['url'] + artlink = r.json()["artistbackground"][0]["url"] response = urllib.request.urlopen(artlink, cafile=tauon.ca) info = response.info() - assert info.get_content_maintype() == 'image' + assert info.get_content_maintype() == "image" t = io.BytesIO() t.seek(0) @@ -12579,7 +12579,7 @@ def get_background(self, track): assert l > 1000 # Cache image for future use - path = os.path.join(a_cache_dir, artist + '-ftv-full.jpg') + path = os.path.join(a_cache_dir, artist + "-ftv-full.jpg") with open(path, "wb") as f: f.write(t.read()) t.seek(0) @@ -12674,10 +12674,10 @@ def get_blur_im(self, track): g = io.BytesIO() g.seek(0) - a_channel = Image.new('L', im.size, 255) # 'L' 8-bit pixels, black and white + a_channel = Image.new("L", im.size, 255) # 'L' 8-bit pixels, black and white im.putalpha(a_channel) - im.save(g, 'PNG') + im.save(g, "PNG") g.seek(0) # source_image.close() @@ -12719,16 +12719,16 @@ def save_thumb(self, track_object, size, save_path, png=False, zoom=False): g = io.BytesIO() g.seek(0) if png: - im.save(g, 'PNG') + im.save(g, "PNG") else: - im.save(g, 'JPEG') + im.save(g, "JPEG") g.seek(0) return g if png: - im.save(save_path + '.png', 'PNG') + im.save(save_path + ".png", "PNG") else: - im.save(save_path + '.jpg', 'JPEG') + im.save(save_path + ".jpg", "JPEG") def display(self, track, location, box, fast=False, theme_only=False): @@ -12859,7 +12859,7 @@ def display(self, track, location, box, fast=False, theme_only=False): im = Image.open(os.path.join(install_directory, "assets", "load-error.png")) o_size = im.size im.thumbnail((box[0], box[1]), Image.Resampling.LANCZOS) - im.save(g, 'BMP') + im.save(g, "BMP") g.seek(0) # Processing for "Carbon" theme @@ -13471,22 +13471,22 @@ def fix_encoding(index, mode, enc): if old_star != None: star_store.remove(todo[q]) - if enc_field == 'All' or enc_field == 'Artist': + if enc_field == "All" or enc_field == "Artist": line = pctl.master_library[todo[q]].artist - line = line.encode("Latin-1", 'ignore') - line = line.decode(enc, 'ignore') + line = line.encode("Latin-1", "ignore") + line = line.decode(enc, "ignore") pctl.master_library[todo[q]].artist = line - if enc_field == 'All' or enc_field == 'Album': + if enc_field == "All" or enc_field == "Album": line = pctl.master_library[todo[q]].album - line = line.encode("Latin-1", 'ignore') - line = line.decode(enc, 'ignore') + line = line.encode("Latin-1", "ignore") + line = line.decode(enc, "ignore") pctl.master_library[todo[q]].album = line - if enc_field == 'All' or enc_field == 'Title': + if enc_field == "All" or enc_field == "Title": line = pctl.master_library[todo[q]].title - line = line.encode("Latin-1", 'ignore') - line = line.decode(enc, 'ignore') + line = line.encode("Latin-1", "ignore") + line = line.decode(enc, "ignore") pctl.master_library[todo[q]].title = line if old_star != None: @@ -13539,7 +13539,7 @@ def add_stations(stations, name): else: r = {} r["uid"] = uid_gen() - r["name"] = 'Default' + r["name"] = "Default" r["items"] = stations r["scroll"] = 0 pctl.radio_playlists.append(r) @@ -13727,23 +13727,23 @@ def load_xspf(path): for field in track: logging.info(field.tag) logging.info(field.text) - if 'title' in field.tag and field.text: - b['title'] = field.text - if 'location' in field.tag and field.text: + if "title" in field.tag and field.text: + b["title"] = field.text + if "location" in field.tag and field.text: l = field.text l = str(urllib.parse.unquote(l)) if l[:5] == "file:": - l = l.replace('file:', "") + l = l.replace("file:", "") l = l.lstrip("/") l = "/" + l - b['location'] = l - if 'creator' in field.tag and field.text: - b['artist'] = field.text - if 'album' in field.tag and field.text: - b['album'] = field.text - if 'duration' in field.tag and field.text: - b['duration'] = field.text + b["location"] = l + if "creator" in field.tag and field.text: + b["artist"] = field.text + if "album" in field.tag and field.text: + b["album"] = field.text + if "duration" in field.tag and field.text: + b["duration"] = field.text b["info"] = info b["name"] = name @@ -13752,7 +13752,7 @@ def load_xspf(path): except Exception: logging.exception("Error importing/parsing XSPF playlist") - show_message(_("Error importing XSPF playlist."), _("Sorry about that."), mode='warning') + show_message(_("Error importing XSPF playlist."), _("Sorry about that."), mode="warning") # tauon.log("-- Error parsing XSPF file") console.print("-- Error parsing XSPF file") return @@ -13782,7 +13782,7 @@ def load_xspf(path): missing = 0 if len(a) > 5000: - to_got = 'xspfl' + to_got = "xspfl" # Generate location dict location_dict = {} @@ -13802,9 +13802,9 @@ def load_xspf(path): found = False # Check if we already have a track with full file path in database - if not found and 'location' in track: + if not found and "location" in track: - location = track['location'] + location = track["location"] if location in location_dict: playlist.append(location_dict[location]) if not os.path.isfile(location): @@ -13815,12 +13815,12 @@ def load_xspf(path): continue # Then check for title, artist and filename match - if not found and 'location' in track and 'duration' in track and 'title' in track and 'artist' in track: - base = os.path.basename(track['location']) + if not found and "location" in track and "duration" in track and "title" in track and "artist" in track: + base = os.path.basename(track["location"]) if base in base_names: for index, bn in r_base_names.items(): va = pctl.master_library[index] - if va.artist == track['artist'] and va.title == track['title'] and \ + if va.artist == track["artist"] and va.title == track["title"] and \ os.path.isfile(va.fullpath) and \ va.filename == base: playlist.append(index) @@ -13832,9 +13832,9 @@ def load_xspf(path): continue # Then check for just title and artist match - if not found and 'title' in track and 'artist' in track and track['title'] in titles: + if not found and "title" in track and "artist" in track and track["title"] in titles: for key, value in pctl.master_library.items(): - if value.artist == track['artist'] and value.title == track['title'] and os.path.isfile(value.fullpath): + if value.artist == track["artist"] and value.title == track["title"] and os.path.isfile(value.fullpath): playlist.append(key) if not os.path.isfile(value.fullpath): missing += 1 @@ -13843,26 +13843,26 @@ def load_xspf(path): if found is True: continue - if not found and 'location' in track or 'title' in track: + if not found and "location" in track or "title" in track: nt = TrackClass() nt.index = pctl.master_count nt.found = False - if 'location' in track: - location = track['location'] + if "location" in track: + location = track["location"] set_path(nt, location) if os.path.isfile(location): nt.found = True - elif 'album' in track: - nt.parent_folder_name = track['album'] - if 'artist' in track: - nt.artist = track['artist'] - if 'title' in track: - nt.title = track['title'] - if 'duration' in track: - nt.length = int(float((track['duration'])) / 1000) - if 'album' in track: - nt.album = track['album'] + elif "album" in track: + nt.parent_folder_name = track["album"] + if "artist" in track: + nt.artist = track["artist"] + if "title" in track: + nt.title = track["title"] + if "duration" in track: + nt.length = int(float((track["duration"])) / 1000) + if "album" in track: + nt.album = track["album"] nt.is_cue = False if nt.found: nt = tag_scan(nt) @@ -13875,17 +13875,17 @@ def load_xspf(path): missing += 1 console.print("-- Failed to locate track", level=2) - if 'location' in track: - console.print("-- -- Expected path: " + track['location'], level=2) - if 'title' in track: - console.print("-- -- Title: " + track['title'], level=2) - if 'artist' in track: - console.print("-- -- Artist: " + track['artist'], level=2) - if 'album' in track: - console.print("-- -- Album: " + track['album'], level=2) + if "location" in track: + console.print("-- -- Expected path: " + track["location"], level=2) + if "title" in track: + console.print("-- -- Title: " + track["title"], level=2) + if "artist" in track: + console.print("-- -- Artist: " + track["artist"], level=2) + if "album" in track: + console.print("-- -- Album: " + track["album"], level=2) if missing > 0: - show_message(_('Failed to locate {N} out of {T} tracks.') + show_message(_("Failed to locate {N} out of {T} tracks.") .format(N=str(missing), T=str(len(a)))) #logging.info(playlist) if playlist: @@ -13903,7 +13903,7 @@ def load_xspf(path): encoding_menu = False enc_index = 0 enc_setting = 0 -enc_field = 'All' +enc_field = "All" gen_menu = False @@ -14711,7 +14711,7 @@ def render(self): # Close and display error if any tracks are not single local files if pctl.master_library[item].is_network is True: rename_track_box.active = False - show_message(_("Cannot rename"), _("One or more tracks is from a network location!"), mode='info') + show_message(_("Cannot rename"), _("One or more tracks is from a network location!"), mode="info") if pctl.master_library[item].is_cue is True: rename_track_box.active = False show_message(_("This function does not support renaming CUE Sheet tracks.")) @@ -14792,7 +14792,7 @@ def render(self): oldname = pctl.master_library[item].filename oldpath = pctl.master_library[item].fullpath - logging.info('Renaming...') + logging.info("Renaming...") star = star_store.full_get(item) star_store.remove(item) @@ -14832,18 +14832,18 @@ def render(self): total_todo -= 1 rename_track_box.active = False - logging.info('Done') + logging.info("Done") if pre_state == 1: pctl.revert() if total_todo != len(r_todo): show_message(_("Rename complete."), _("{N} / {T} filenames were written.") - .format(N=str(total_todo), T=str(len(r_todo))), mode='warning') + .format(N=str(total_todo), T=str(len(r_todo))), mode="warning") else: show_message(_("Rename complete."), _("{N} / {T} filenames were written.") - .format(N=str(total_todo), T=str(len(r_todo))), mode='done') + .format(N=str(total_todo), T=str(len(r_todo))), mode="done") pctl.notify_change() @@ -15185,7 +15185,7 @@ def __init__(self): self.id = None self.directory_text_box = TextBox2() self.default = { - "path": music_directory if music_directory else os.path.join(user_directory, 'playlists'), + "path": music_directory if music_directory else os.path.join(user_directory, "playlists"), "type": "xspf", "relative": False, "auto": False, @@ -15452,8 +15452,8 @@ def toggle_bio_size(): def flush_artist_bio(artist): - if os.path.isfile(os.path.join(a_cache_dir, artist + '-lfm.txt')): - os.remove(os.path.join(a_cache_dir, artist + '-lfm.txt')) + if os.path.isfile(os.path.join(a_cache_dir, artist + "-lfm.txt")): + os.remove(os.path.join(a_cache_dir, artist + "-lfm.txt")) artist_info_box.text = "" artist_info_box.artist_on = None @@ -15481,21 +15481,21 @@ def show_in_playlist(): pctl.render_playlist() -filter_icon = MenuIcon(asset_loader('filter.png', True)) +filter_icon = MenuIcon(asset_loader("filter.png", True)) filter_icon.colour = [43, 213, 255, 255] filter_icon.xoff = 1 -folder_icon = MenuIcon(asset_loader('folder.png', True)) -info_icon = MenuIcon(asset_loader('info.png', True)) +folder_icon = MenuIcon(asset_loader("folder.png", True)) +info_icon = MenuIcon(asset_loader("info.png", True)) folder_icon.colour = [244, 220, 66, 255] info_icon.colour = [61, 247, 163, 255] -power_bar_icon = asset_loader('power.png', True) +power_bar_icon = asset_loader("power.png", True) def open_folder_stem(path): - if system == 'windows' or msys: + if system == "windows" or msys: line = r'explorer /select,"%s"' % ( path.replace("/", "\\")) subprocess.Popen(line) @@ -15503,9 +15503,9 @@ def open_folder_stem(path): line = path line += "/" if macos: - subprocess.Popen(['open', line]) + subprocess.Popen(["open", line]) else: - subprocess.Popen(['xdg-open', line]) + subprocess.Popen(["xdg-open", line]) def open_folder_disable_test(index): @@ -15518,7 +15518,7 @@ def open_folder(index): show_message(_("Can't open folder of a network track.")) return - if system == 'windows' or msys: + if system == "windows" or msys: line = r'explorer /select,"%s"' % ( track.fullpath.replace("/", "\\")) subprocess.Popen(line) @@ -15527,9 +15527,9 @@ def open_folder(index): line += "/" if macos: line = track.fullpath - subprocess.Popen(['open', '-R', line]) + subprocess.Popen(["open", "-R", line]) else: - subprocess.Popen(['xdg-open', line]) + subprocess.Popen(["xdg-open", line]) def tag_to_new_playlist(tag_item): @@ -15600,18 +15600,18 @@ def move_playing_folder_to_stem(path, pl_id=None): return if len(target_base) < 4: - show_message(_("Safety interupt! The source path seems oddly short."), target_base, mode='error') + show_message(_("Safety interupt! The source path seems oddly short."), target_base, mode="error") return protect = ("", "Documents", "Music", "Desktop", "Downloads") for fo in protect: - if move_folder.strip('\\/') == os.path.join(os.path.expanduser('~'), fo).strip("\\/"): - show_message(_("Better not do anything to that folder!"), os.path.join(os.path.expanduser('~'), fo), - mode='warning') + if move_folder.strip("\\/") == os.path.join(os.path.expanduser("~"), fo).strip("\\/"): + show_message(_("Better not do anything to that folder!"), os.path.join(os.path.expanduser("~"), fo), + mode="warning") return if directory_size(move_folder) > 3000000000: - show_message(_("Folder size safety limit reached! (3GB)"), move_folder, mode='warning') + show_message(_("Folder size safety limit reached! (3GB)"), move_folder, mode="warning") return # Use target folder if it already is an artist folder @@ -15678,7 +15678,7 @@ def re_import4(id): load_order.notify = True load_order.playlist = pctl.multi_playlist[pctl.active_playlist_viewing][6] load_orders.append(copy.deepcopy(load_order)) - show_message(_("Rescanning folder..."), pctl.g(id).parent_folder_path, mode='info') + show_message(_("Rescanning folder..."), pctl.g(id).parent_folder_path, mode="info") def re_import3(stem): @@ -15698,7 +15698,7 @@ def re_import3(stem): load_order.notify = True load_order.playlist = pctl.multi_playlist[pctl.active_playlist_viewing][6] load_orders.append(copy.deepcopy(load_order)) - show_message(_("Rescanning folder..."), stem, mode='info') + show_message(_("Rescanning folder..."), stem, mode="info") def collapse_tree_deco(): @@ -15728,8 +15728,8 @@ def lock_folder_tree_deco(): return [colours.menu_text, colours.menu_background, _("Lock Panel")] -folder_tree_stem_menu.add(MenuItem(_('Open Folder'), open_folder_stem, pass_ref=True, icon=folder_icon)) -folder_tree_menu.add(MenuItem(_('Open Folder'), open_folder, pass_ref=True, pass_ref_deco=True, icon=folder_icon, disable_test=open_folder_disable_test)) +folder_tree_stem_menu.add(MenuItem(_("Open Folder"), open_folder_stem, pass_ref=True, icon=folder_icon)) +folder_tree_menu.add(MenuItem(_("Open Folder"), open_folder, pass_ref=True, pass_ref_deco=True, icon=folder_icon, disable_test=open_folder_disable_test)) lightning_menu.add(MenuItem(_("Filter to New Playlist"), tag_to_new_playlist, pass_ref=True, icon=filter_icon)) folder_tree_menu.add(MenuItem(_("Filter to New Playlist"), folder_to_new_playlist_by_track_id, pass_ref=True, icon=filter_icon)) @@ -15742,12 +15742,12 @@ def lock_folder_tree_deco(): folder_tree_stem_menu.br() -folder_tree_stem_menu.add(MenuItem(_('Collapse All'), collapse_tree, collapse_tree_deco)) +folder_tree_stem_menu.add(MenuItem(_("Collapse All"), collapse_tree, collapse_tree_deco)) folder_tree_stem_menu.add(MenuItem("lock", lock_folder_tree, lock_folder_tree_deco)) # folder_tree_menu.add("lock", lock_folder_tree, lock_folder_tree_deco) -gallery_menu.add(MenuItem(_('Open Folder'), open_folder, pass_ref=True, pass_ref_deco=True, icon=folder_icon, disable_test=open_folder_disable_test)) +gallery_menu.add(MenuItem(_("Open Folder"), open_folder, pass_ref=True, pass_ref_deco=True, icon=folder_icon, disable_test=open_folder_disable_test)) gallery_menu.add(MenuItem(_("Show in Playlist"), show_in_playlist)) @@ -15954,7 +15954,7 @@ def get_lyric_fire(track_object, silent=False): if not prefs.lyrics_enables: if not silent: show_message(_("There are no lyric sources enabled."), - _("See 'lyrics settings' under 'functions' tab in settings."), mode='info') + _("See 'lyrics settings' under 'functions' tab in settings."), mode="info") return t = lyrics_fetch_timer.get() @@ -15965,12 +15965,12 @@ def get_lyric_fire(track_object, silent=False): show_message(_("Let's be polite and try later.")) if t < -65: - show_message(_("Stop requesting lyrics AAAAAA."), mode='error') + show_message(_("Stop requesting lyrics AAAAAA."), mode="error") # If the user keeps pressing, lets mess with them haha lyrics_fetch_timer.force_set(t - 5) - return 'later' + return "later" if t > 0: lyrics_fetch_timer.set() @@ -16025,7 +16025,7 @@ def get_lyric_fire(track_object, silent=False): def get_lyric_wiki(track_object): if track_object.artist == "" or track_object.title == "": - show_message(_("Insufficient metadata to get lyrics"), mode='warning') + show_message(_("Insufficient metadata to get lyrics"), mode="warning") return shoot_dl = threading.Thread(target=get_lyric_fire, args=([track_object])) @@ -16076,7 +16076,7 @@ def search_lyrics_deco(track_object): return [line_colour, colours.menu_background, None] -showcase_menu.add(MenuItem(_('Search for Lyrics'), get_lyric_wiki, search_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +showcase_menu.add(MenuItem(_("Search for Lyrics"), get_lyric_wiki, search_lyrics_deco, pass_ref=True, pass_ref_deco=True)) def toggle_synced_lyrics(tr): @@ -16111,7 +16111,7 @@ def search_guitarparty_showtest(_): return gui.combo_mode and prefs.guitar_chords -showcase_menu.add(MenuItem(_('Search GuitarParty'), search_guitarparty, pass_ref=True, show_test=search_guitarparty_showtest)) +showcase_menu.add(MenuItem(_("Search GuitarParty"), search_guitarparty, pass_ref=True, show_test=search_guitarparty_showtest)) def paste_lyrics_deco(): @@ -16127,10 +16127,10 @@ def paste_lyrics(track_object): if SDL_HasClipboardText(): clip = SDL_GetClipboardText() #logging.info(clip) - track_object.lyrics = clip.decode('utf-8') + track_object.lyrics = clip.decode("utf-8") else: - logging.warning('NO TEXT TO PASTE') + logging.warning("NO TEXT TO PASTE") def paste_chord_lyrics(track_object): @@ -16147,8 +16147,8 @@ def clear_chord_lyrics(track_object): gc.clear(track_object) -showcase_menu.add(MenuItem(_('Paste Chord Lyrics'), paste_chord_lyrics, pass_ref=True, show_test=chord_lyrics_paste_show_test)) -showcase_menu.add(MenuItem(_('Clear Chord Lyrics'), clear_chord_lyrics, pass_ref=True, show_test=chord_lyrics_paste_show_test)) +showcase_menu.add(MenuItem(_("Paste Chord Lyrics"), paste_chord_lyrics, pass_ref=True, show_test=chord_lyrics_paste_show_test)) +showcase_menu.add(MenuItem(_("Clear Chord Lyrics"), clear_chord_lyrics, pass_ref=True, show_test=chord_lyrics_paste_show_test)) def copy_lyrics_deco(track_object): @@ -16188,25 +16188,25 @@ def show_sub_search(track_object): sub_lyrics_box.activate(track_object) -showcase_menu.add(MenuItem(_('Toggle Lyrics'), toggle_lyrics, toggle_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +showcase_menu.add(MenuItem(_("Toggle Lyrics"), toggle_lyrics, toggle_lyrics_deco, pass_ref=True, pass_ref_deco=True)) showcase_menu.add_sub(_("Misc…"), 150) -showcase_menu.add_to_sub(0, MenuItem(_('Substitute Search...'), show_sub_search, pass_ref=True)) -showcase_menu.add_to_sub(0, MenuItem(_('Paste Lyrics'), paste_lyrics, paste_lyrics_deco, pass_ref=True)) -showcase_menu.add_to_sub(0, MenuItem(_('Copy Lyrics'), copy_lyrics, copy_lyrics_deco, pass_ref=True, pass_ref_deco=True)) -showcase_menu.add_to_sub(0, MenuItem(_('Clear Lyrics'), clear_lyrics, clear_lyrics_deco, pass_ref=True, pass_ref_deco=True)) -showcase_menu.add_to_sub(0, MenuItem(_('Toggle art panel'), toggle_side_art, toggle_side_art_deco, show_test=lyrics_in_side_show)) -showcase_menu.add_to_sub(0, MenuItem(_('Toggle art position'), toggle_lyrics_panel_position, toggle_lyrics_panel_position_deco, +showcase_menu.add_to_sub(0, MenuItem(_("Substitute Search..."), show_sub_search, pass_ref=True)) +showcase_menu.add_to_sub(0, MenuItem(_("Paste Lyrics"), paste_lyrics, paste_lyrics_deco, pass_ref=True)) +showcase_menu.add_to_sub(0, MenuItem(_("Copy Lyrics"), copy_lyrics, copy_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +showcase_menu.add_to_sub(0, MenuItem(_("Clear Lyrics"), clear_lyrics, clear_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +showcase_menu.add_to_sub(0, MenuItem(_("Toggle art panel"), toggle_side_art, toggle_side_art_deco, show_test=lyrics_in_side_show)) +showcase_menu.add_to_sub(0, MenuItem(_("Toggle art position"), toggle_lyrics_panel_position, toggle_lyrics_panel_position_deco, show_test=lyrics_in_side_show)) -center_info_menu.add(MenuItem(_('Search for Lyrics'), get_lyric_wiki, search_lyrics_deco, pass_ref=True, pass_ref_deco=True)) -center_info_menu.add(MenuItem(_('Toggle Lyrics'), toggle_lyrics, toggle_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +center_info_menu.add(MenuItem(_("Search for Lyrics"), get_lyric_wiki, search_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +center_info_menu.add(MenuItem(_("Toggle Lyrics"), toggle_lyrics, toggle_lyrics_deco, pass_ref=True, pass_ref_deco=True)) center_info_menu.add_sub(_("Misc…"), 150) -center_info_menu.add_to_sub(0, MenuItem(_('Substitute Search...'), show_sub_search, pass_ref=True)) -center_info_menu.add_to_sub(0, MenuItem(_('Paste Lyrics'), paste_lyrics, paste_lyrics_deco, pass_ref=True)) -center_info_menu.add_to_sub(0, MenuItem(_('Copy Lyrics'), copy_lyrics, copy_lyrics_deco, pass_ref=True, pass_ref_deco=True)) -center_info_menu.add_to_sub(0, MenuItem(_('Clear Lyrics'), clear_lyrics, clear_lyrics_deco, pass_ref=True, pass_ref_deco=True)) -center_info_menu.add_to_sub(0, MenuItem(_('Toggle art panel'), toggle_side_art, toggle_side_art_deco, show_test=lyrics_in_side_show)) -center_info_menu.add_to_sub(0, MenuItem(_('Toggle art position'), toggle_lyrics_panel_position, toggle_lyrics_panel_position_deco, +center_info_menu.add_to_sub(0, MenuItem(_("Substitute Search..."), show_sub_search, pass_ref=True)) +center_info_menu.add_to_sub(0, MenuItem(_("Paste Lyrics"), paste_lyrics, paste_lyrics_deco, pass_ref=True)) +center_info_menu.add_to_sub(0, MenuItem(_("Copy Lyrics"), copy_lyrics, copy_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +center_info_menu.add_to_sub(0, MenuItem(_("Clear Lyrics"), clear_lyrics, clear_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +center_info_menu.add_to_sub(0, MenuItem(_("Toggle art panel"), toggle_side_art, toggle_side_art_deco, show_test=lyrics_in_side_show)) +center_info_menu.add_to_sub(0, MenuItem(_("Toggle art position"), toggle_lyrics_panel_position, toggle_lyrics_panel_position_deco, show_test=lyrics_in_side_show)) def save_embed_img_disable_test(track_object): @@ -16229,7 +16229,7 @@ def save_embed_img(track_object): pic = album_art_gen.get_embed(track_object) if not pic: - show_message(_("Image save error."), _("No embedded album art found file."), mode='warning') + show_message(_("Image save error."), _("No embedded album art found file."), mode="warning") return source_image = io.BytesIO(pic) @@ -16244,14 +16244,14 @@ def save_embed_img(track_object): target = os.path.join(folder, "embed-" + str(im.height) + "px-" + str(track_object.index) + ext) if len(pic) > 30: - with open(target, 'wb') as w: + with open(target, "wb") as w: w.write(pic) open_folder(track_object.index) except Exception: logging.exception("Unknown error trying to save an image") - show_message(_("Image save error."), _("A mysterious error occurred"), mode='error') + show_message(_("Image save error."), _("A mysterious error occurred"), mode="error") picture_menu = Menu(175) @@ -16339,7 +16339,7 @@ def cycle_offset_back(track_object): #picture_menu.add(_("Previous"), cycle_offset_back, cycle_image_deco, pass_ref=True, pass_ref_deco=True) # Extract embedded artwork from file -picture_menu.add(MenuItem(_('Extract Image'), save_embed_img, extract_image_deco, pass_ref=True, pass_ref_deco=True, disable_test=save_embed_img_disable_test)) +picture_menu.add(MenuItem(_("Extract Image"), save_embed_img, extract_image_deco, pass_ref=True, pass_ref_deco=True, disable_test=save_embed_img_disable_test)) def dl_art_deco(track_object): @@ -16388,8 +16388,8 @@ def download_art1(tr): try: show_message(_("Looking up MusicBrainz ID...")) - if 'musicbrainz_releasegroupid' not in tr.misc or 'musicbrainz_artistids' not in tr.misc or not tr.misc[ - 'musicbrainz_artistids']: + if "musicbrainz_releasegroupid" not in tr.misc or "musicbrainz_artistids" not in tr.misc or not tr.misc[ + "musicbrainz_artistids"]: logging.info("MusicBrainz ID lookup...") @@ -16401,16 +16401,16 @@ def download_art1(tr): s = musicbrainzngs.search_release_groups(tr.album, artist=artist, limit=1) - album_id = s['release-group-list'][0]['id'] - artist_id = s['release-group-list'][0]['artist-credit'][0]['artist']['id'] + album_id = s["release-group-list"][0]["id"] + artist_id = s["release-group-list"][0]["artist-credit"][0]["artist"]["id"] logging.info("Found release group ID: " + album_id) logging.info("Found artist ID: " + artist_id) else: - album_id = tr.misc['musicbrainz_releasegroupid'] - artist_id = tr.misc['musicbrainz_artistids'][0] + album_id = tr.misc["musicbrainz_releasegroupid"] + artist_id = tr.misc["musicbrainz_artistids"][0] logging.info("Using tagged release group ID: " + album_id) logging.info("Using tagged artist ID: " + artist_id) @@ -16422,8 +16422,8 @@ def download_art1(tr): r = requests.get("http://webservice.fanart.tv/v3/music/albums/" \ + artist_id + "?api_key=" + prefs.fatvap, timeout=(4, 10)) - artlink = r.json()['albums'][album_id]['albumcover'][0]['url'] - id = r.json()['albums'][album_id]['albumcover'][0]['id'] + artlink = r.json()["albums"][album_id]["albumcover"][0]["url"] + id = r.json()["albums"][album_id]["albumcover"][0]["id"] response = urllib.request.urlopen(artlink, cafile=tauon.ca) info = response.info() @@ -16435,21 +16435,21 @@ def download_art1(tr): l = t.tell() t.seek(0) - if info.get_content_maintype() == 'image' and l > 1000: + if info.get_content_maintype() == "image" and l > 1000: - if info.get_content_subtype() == 'jpeg': + if info.get_content_subtype() == "jpeg": filepath = os.path.join(tr.parent_folder_path, "cover-" + id + ".jpg") - elif info.get_content_subtype() == 'png': + elif info.get_content_subtype() == "png": filepath = os.path.join(tr.parent_folder_path, "cover-" + id + ".png") else: - show_message(_("Could not detect downloaded filetype."), mode='error') + show_message(_("Could not detect downloaded filetype."), mode="error") return - f = open(filepath, 'wb') + f = open(filepath, "wb") f.write(t.read()) f.close() - show_message(_("Cover art downloaded from fanart.tv"), mode='done') + show_message(_("Cover art downloaded from fanart.tv"), mode="done") # clear_img_cache() for track_id in default_playlist: if tr.parent_folder_path == pctl.g(track_id).parent_folder_path: @@ -16466,11 +16466,11 @@ def download_art1(tr): t.seek(0) if l > 1000: filepath = os.path.join(tr.parent_folder_path, album_id + ".jpg") - f = open(filepath, 'wb') + f = open(filepath, "wb") f.write(t.read()) f.close() - show_message(_("Cover art downloaded from MusicBrainz"), mode='done') + show_message(_("Cover art downloaded from MusicBrainz"), mode="done") # clear_img_cache() clear_track_image_cache(tr) @@ -16504,7 +16504,7 @@ def remove_embed_picture(track_object, dry=True): if key_shift_down or key_shiftr_down: tracks = [index] if track_object.is_cue or track_object.is_network: - show_message(_("Error - No handling for this kind of track"), mode='warning') + show_message(_("Error - No handling for this kind of track"), mode="warning") return else: tracks = [] @@ -16572,24 +16572,24 @@ def remove_embed_picture(track_object, dry=True): except Exception as e: logging.exception("Image remove error") - show_message(_("Image remove error"), mode='error') + show_message(_("Image remove error"), mode="error") return if dry: return removed if removed == 0: - show_message(_("Image removal failed."), mode='error') + show_message(_("Image removal failed."), mode="error") return elif removed == 1: - show_message(_("Deleted embedded picture from file"), mode='done') + show_message(_("Deleted embedded picture from file"), mode="done") else: - show_message(_("{N} files processed").local(N=removed), mode='done') + show_message(_("{N} files processed").local(N=removed), mode="done") if pr == 1: pctl.revert() -del_icon = asset_loader('del.png', True) +del_icon = asset_loader("del.png", True) delete_icon = MenuIcon(del_icon) @@ -16604,7 +16604,7 @@ def delete_file_image(track_object): logging.info("Deleted file: " + source) except Exception: logging.exception("Failed to delete file") - show_message(_("Something went wrong"), mode='error') + show_message(_("Something went wrong"), mode="error") def delete_track_image_deco(track_object): @@ -16653,7 +16653,7 @@ def delete_track_image(track_object): picture_menu.add(MenuItem(_("Delete Image File"), delete_track_image, delete_track_image_deco, pass_ref=True, pass_ref_deco=True, icon=delete_icon)) -picture_menu.add(MenuItem(_('Quick-Fetch Cover Art'), download_art1_fire, dl_art_deco, pass_ref=True, pass_ref_deco=True, disable_test=download_art1_fire_disable_test)) +picture_menu.add(MenuItem(_("Quick-Fetch Cover Art"), download_art1_fire, dl_art_deco, pass_ref=True, pass_ref_deco=True, disable_test=download_art1_fire_disable_test)) def toggle_gimage(mode=0): @@ -16682,16 +16682,16 @@ def ser_gimage(track_object): # picture_menu.add(_('Toggle art box'), toggle_side_art, toggle_side_art_deco) -picture_menu.add(MenuItem(_('Search for Lyrics'), get_lyric_wiki, search_lyrics_deco, pass_ref=True, pass_ref_deco=True)) -picture_menu.add(MenuItem(_('Toggle Lyrics'), toggle_lyrics, toggle_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +picture_menu.add(MenuItem(_("Search for Lyrics"), get_lyric_wiki, search_lyrics_deco, pass_ref=True, pass_ref_deco=True)) +picture_menu.add(MenuItem(_("Toggle Lyrics"), toggle_lyrics, toggle_lyrics_deco, pass_ref=True, pass_ref_deco=True)) gallery_menu.add_to_sub(0, MenuItem(_("Next"), cycle_offset, cycle_image_gal_deco, pass_ref=True, pass_ref_deco=True)) gallery_menu.add_to_sub(0, MenuItem(_("Previous"), cycle_offset_back, cycle_image_gal_deco, pass_ref=True, pass_ref_deco=True)) gallery_menu.add_to_sub(0, MenuItem(_("Open Image"), open_image, open_image_deco, pass_ref=True, pass_ref_deco=True, disable_test=open_image_disable_test)) -gallery_menu.add_to_sub(0, MenuItem(_('Extract Image'), save_embed_img, extract_image_deco, pass_ref=True, pass_ref_deco=True, disable_test=save_embed_img_disable_test)) -gallery_menu.add_to_sub(0, MenuItem(_('Delete Image <combined>'), delete_track_image, delete_track_image_deco, pass_ref=True, +gallery_menu.add_to_sub(0, MenuItem(_("Extract Image"), save_embed_img, extract_image_deco, pass_ref=True, pass_ref_deco=True, disable_test=save_embed_img_disable_test)) +gallery_menu.add_to_sub(0, MenuItem(_("Delete Image <combined>"), delete_track_image, delete_track_image_deco, pass_ref=True, pass_ref_deco=True)) #, icon=delete_icon) -gallery_menu.add_to_sub(0, MenuItem(_('Quick-Fetch Cover Art'), download_art1_fire, dl_art_deco, pass_ref=True, pass_ref_deco=True, disable_test=download_art1_fire_disable_test)) +gallery_menu.add_to_sub(0, MenuItem(_("Quick-Fetch Cover Art"), download_art1_fire, dl_art_deco, pass_ref=True, pass_ref_deco=True, disable_test=download_art1_fire_disable_test)) def append_here(): global cargo @@ -16842,41 +16842,41 @@ def parse_template(string, track_object, up_ext=False, strict=False): while set < len(string): if string[set] == "%" and set < len(string) - 1: set += 1 - if string[set] == 'n': + if string[set] == "n": if len(str(track_object.track_number)) < 2: output += "0" if strict: assert str(track_object.track_number) output += str(track_object.track_number) - elif string[set] == 'a': + elif string[set] == "a": if up_ext and track_object.album_artist != "": # Context of renaming a folder output += track_object.album_artist else: if strict: assert track_object.artist output += track_object.artist - elif string[set] == 't': + elif string[set] == "t": if strict: assert track_object.title output += track_object.title - elif string[set] == 'c': + elif string[set] == "c": if strict: assert track_object.composer output += track_object.composer - elif string[set] == 'd': + elif string[set] == "d": if strict: assert track_object.date output += track_object.date - elif string[set] == 'b': + elif string[set] == "b": if strict: assert track_object.album output += track_object.album - elif string[set] == 'x': + elif string[set] == "x": if up_ext: output += track_object.file_ext.upper() else: output += "." + track_object.file_ext.lower() - elif string[set] == 'u': + elif string[set] == "u": underscore = True else: output += string[set] @@ -16885,7 +16885,7 @@ def parse_template(string, track_object, up_ext=False, strict=False): output = output.rstrip(" -").lstrip(" -") if underscore: - output = output.replace(' ', "_") + output = output.replace(" ", "_") # Attempt to ensure the output text is filename safe output = filename_safe(output) @@ -16930,8 +16930,8 @@ def edit_generator_box(index): rename_playlist(index, generator=True) -tab_menu.add(MenuItem(_('Rename'), rename_playlist, pass_ref=True, hint="Ctrl+R")) -radio_tab_menu.add(MenuItem(_('Rename'), rename_playlist, pass_ref=True, hint="Ctrl+R")) +tab_menu.add(MenuItem(_("Rename"), rename_playlist, pass_ref=True, hint="Ctrl+R")) +radio_tab_menu.add(MenuItem(_("Rename"), rename_playlist, pass_ref=True, hint="Ctrl+R")) def pin_playlist_toggle(pl): @@ -16944,7 +16944,7 @@ def pl_pin_deco(pl): if pctl.multi_playlist[pl][8] == True: return [colours.menu_text, colours.menu_background, _("Pin")] else: - return [colours.menu_text, colours.menu_background, _('Unpin')] + return [colours.menu_text, colours.menu_background, _("Unpin")] tab_menu.add(MenuItem("Pin", pin_playlist_toggle, pl_pin_deco, pass_ref=True, pass_ref_deco=True)) @@ -16954,7 +16954,7 @@ def pl_lock_deco(pl): if pctl.multi_playlist[pl][9] == True: return [colours.menu_text, colours.menu_background, _("Unlock")] else: - return [colours.menu_text, colours.menu_background, _('Lock')] + return [colours.menu_text, colours.menu_background, _("Lock")] def view_pl_is_locked(_): @@ -16980,15 +16980,15 @@ def lock_colour_callback(): return None -lock_asset = asset_loader('lock.png', True) +lock_asset = asset_loader("lock.png", True) lock_icon = MenuIcon(lock_asset) -lock_icon.base_asset_mod = asset_loader('unlock.png', True) +lock_icon.base_asset_mod = asset_loader("unlock.png", True) lock_icon.colour = [240, 190, 10, 255] lock_icon.colour_callback = lock_colour_callback lock_icon.xoff = 4 lock_icon.yoff = -1 -tab_menu.add(MenuItem(_('Lock'), lock_playlist_toggle, pl_lock_deco, pass_ref=True, pass_ref_deco=True, icon=lock_icon, +tab_menu.add(MenuItem(_("Lock"), lock_playlist_toggle, pl_lock_deco, pass_ref=True, pass_ref_deco=True, icon=lock_icon, show_test=test_shift)) @@ -16998,12 +16998,12 @@ def export_m3u(pl, direc=None, relative=False, show=True): return 1 if not direc: - direc = os.path.join(user_directory, 'playlists') + direc = os.path.join(user_directory, "playlists") if not os.path.exists(direc): os.makedirs(direc) - target = os.path.join(direc, pctl.multi_playlist[pl][0] + '.m3u') + target = os.path.join(direc, pctl.multi_playlist[pl][0] + ".m3u") - f = open(target, 'w', encoding='utf-8') + f = open(target, "w", encoding="utf-8") f.write("#EXTM3U") for number in pctl.multi_playlist[pl][2]: track = pctl.master_library[number] @@ -17029,9 +17029,9 @@ def export_m3u(pl, direc=None, relative=False, show=True): if system == "windows" or msys: os.startfile(line) elif macos: - subprocess.Popen(['open', line]) + subprocess.Popen(["open", line]) else: - subprocess.Popen(['xdg-open', line]) + subprocess.Popen(["xdg-open", line]) return target @@ -17041,16 +17041,16 @@ def export_xspf(pl, direc=None, relative=False, show=True): return 1 if not direc: - direc = os.path.join(user_directory, 'playlists') + direc = os.path.join(user_directory, "playlists") if not os.path.exists(direc): os.makedirs(direc) - target = os.path.join(direc, pctl.multi_playlist[pl][0] + '.xspf') + target = os.path.join(direc, pctl.multi_playlist[pl][0] + ".xspf") - xport = open(target, 'w', encoding='utf-8') + xport = open(target, "w", encoding="utf-8") xport.write('<?xml version="1.0" encoding="UTF-8"?>\n') xport.write('<playlist version="1" xmlns="http://xspf.org/ns/0/">\n') - xport.write(' <trackList>\n') + xport.write(" <trackList>\n") for number in pctl.multi_playlist[pl][2]: track = pctl.master_library[number] @@ -17058,19 +17058,19 @@ def export_xspf(pl, direc=None, relative=False, show=True): if relative: path = os.path.relpath(path, start=direc) - xport.write(' <track>\n') + xport.write(" <track>\n") if track.title != "": - xport.write(' <title>' + urllib.parse.quote(track.title) + '\n') + xport.write(" " + urllib.parse.quote(track.title) + "\n") if track.is_cue is False and track.fullpath != "": - xport.write(' ' + urllib.parse.quote(path) + '\n') + xport.write(" " + urllib.parse.quote(path) + "\n") if track.artist != "": - xport.write(' ' + urllib.parse.quote(track.artist) + '\n') + xport.write(" " + urllib.parse.quote(track.artist) + "\n") if track.album != "": - xport.write(' ' + urllib.parse.quote(track.album) + '\n') - xport.write(' ' + str(int(track.length * 1000)) + '\n') - xport.write(' \n') - xport.write(' \n') - xport.write('\n\n') + xport.write(" " + urllib.parse.quote(track.album) + "\n") + xport.write(" " + str(int(track.length * 1000)) + "\n") + xport.write(" \n") + xport.write(" \n") + xport.write("\n\n") xport.close() if show: @@ -17079,9 +17079,9 @@ def export_xspf(pl, direc=None, relative=False, show=True): if system == "windows" or msys: os.startfile(line) elif macos: - subprocess.Popen(['open', line]) + subprocess.Popen(["open", line]) else: - subprocess.Popen(['xdg-open', line]) + subprocess.Popen(["xdg-open", line]) return target @@ -17146,9 +17146,9 @@ def convert_playlist(pl, get_list=False): for track in pctl.multi_playlist[pl][2]: if pctl.master_library[track].parent_folder_path == path: folder.append(track) - if prefs.transcode_codec == 'flac' and pctl.master_library[track].file_ext.lower() in ('mp3', 'opus', - 'm4a', 'mp4', - 'ogg', 'aac'): + if prefs.transcode_codec == "flac" and pctl.master_library[track].file_ext.lower() in ("mp3", "opus", + "m4a", "mp4", + "ogg", "aac"): show_message(_("This includes the conversion of a lossy codec to a lossless one!")) folders.append(folder) @@ -17176,7 +17176,7 @@ def test_pl_tab_locked(pl): # Clear playlist -tab_menu.add(MenuItem(_('Clear'), clear_playlist, pass_ref=True, disable_test=test_pl_tab_locked, pass_ref_deco=True)) +tab_menu.add(MenuItem(_("Clear"), clear_playlist, pass_ref=True, disable_test=test_pl_tab_locked, pass_ref_deco=True)) def move_radio_playlist(source, dest): @@ -17387,7 +17387,7 @@ def re_import2(pl): load_orders.append(copy.deepcopy(load_order)) if paths: - show_message(_("Rescanning folders..."), mode='info') + show_message(_("Rescanning folders..."), mode="info") def rescan_all_folders(): @@ -17452,7 +17452,7 @@ def index_key(index): # This splits the line by groups of numbers, causing the sorting algorithum to sort # by those numbers. Should work for filenames, even with the disc number in the name. try: - return [tryint(c) for c in re.split('([0-9]+)', s)] + return [tryint(c) for c in re.split("([0-9]+)", s)] except Exception: logging.exception("Failed to parse as int, returning 'a'") return "a" @@ -17609,19 +17609,19 @@ def export_stats(pl): total_size = sum(seen_files.values()) stats_gen.update(pl) - line = _('Playlist:') + '\n' + pctl.multi_playlist[pl][0] + "\n\n" - line += _('Generated:') + '\n' + time.strftime("%c") + "\n\n" - line += _('Tracks in playlist:') + '\n' + str(tracks_in_playlist) + line = _("Playlist:") + "\n" + pctl.multi_playlist[pl][0] + "\n\n" + line += _("Generated:") + "\n" + time.strftime("%c") + "\n\n" + line += _("Tracks in playlist:") + "\n" + str(tracks_in_playlist) line += "\n\n" - line += _("Repeats in playlist:") + '\n' + line += _("Repeats in playlist:") + "\n" unique = len(set(pctl.multi_playlist[pl][2])) line += str(tracks_in_playlist - unique) line += "\n\n" - line += _('Total local size:') + '\n' + get_filesize_string(total_size) + "\n\n" - line += _('Playlist duration:') + '\n' + str(datetime.timedelta(seconds=int(playlist_time))) + "\n\n" - line += _('Total playtime:') + '\n' + str(datetime.timedelta(seconds=int(play_time))) + "\n\n" + line += _("Total local size:") + "\n" + get_filesize_string(total_size) + "\n\n" + line += _("Playlist duration:") + "\n" + str(datetime.timedelta(seconds=int(playlist_time))) + "\n\n" + line += _("Total playtime:") + "\n" + str(datetime.timedelta(seconds=int(play_time))) + "\n\n" - line += _("Track types:") + '\n' + line += _("Track types:") + "\n" if tracks_in_playlist: types = sorted(seen_types, key=seen_types.get, reverse=True) for type in types: @@ -17637,7 +17637,7 @@ def export_stats(pl): line += "\n\n" if tracks_in_playlist: - line += _("Percent of tracks are CUE type:") + '\n' + line += _("Percent of tracks are CUE type:") + "\n" perc = are_cue / tracks_in_playlist if perc == 0: perc = 0 @@ -17650,7 +17650,7 @@ def export_stats(pl): line += "\n\n" if tracks_in_playlist and mp3_bitrates: - line += _("MP3 bitrates (kbps):") + '\n' + line += _("MP3 bitrates (kbps):") + "\n" rates = sorted(mp3_bitrates, key=mp3_bitrates.get, reverse=True) others = 0 for rate in rates: @@ -17669,7 +17669,7 @@ def export_stats(pl): line += "\n\n" if tracks_in_playlist and ogg_bitrates: - line += _("OGG bitrates (kbps):") + '\n' + line += _("OGG bitrates (kbps):") + "\n" rates = sorted(ogg_bitrates, key=ogg_bitrates.get, reverse=True) others = 0 for rate in rates: @@ -17722,15 +17722,15 @@ def export_stats(pl): for i, item in enumerate(ls[:50]): line += str(i + 1) + ".\t" + stt2(item[1]) + "\t" + item[0] + "\n" - line = line.encode('utf-8') - xport = open(user_directory + '/stats.txt', 'wb') + line = line.encode("utf-8") + xport = open(user_directory + "/stats.txt", "wb") xport.write(line) xport.close() target = os.path.join(user_directory, "stats.txt") if system == "windows" or msys: os.startfile(target) elif macos: - subprocess.call(['open', target]) + subprocess.call(["open", target]) else: subprocess.call(["xdg-open", target]) @@ -17864,9 +17864,9 @@ def pl_toggle_playlist_break(ref): delete_icon.xoff = 3 delete_icon.colour = [249, 70, 70, 255] -tab_menu.add(MenuItem(_('Delete'), delete_playlist_force, pass_ref=True, hint="Ctrl+W", icon=delete_icon, +tab_menu.add(MenuItem(_("Delete"), delete_playlist_force, pass_ref=True, hint="Ctrl+W", icon=delete_icon, disable_test=test_pl_tab_locked, pass_ref_deco=True)) -radio_tab_menu.add(MenuItem(_('Delete'), delete_playlist_force, pass_ref=True, hint="Ctrl+W", icon=delete_icon, +radio_tab_menu.add(MenuItem(_("Delete"), delete_playlist_force, pass_ref=True, hint="Ctrl+W", icon=delete_icon, disable_test=test_pl_tab_locked, pass_ref_deco=True)) @@ -17909,14 +17909,14 @@ def new_playlist(switch=True): return len(pctl.multi_playlist) - 1 -heartx_icon = MenuIcon(asset_loader('heart-menu.png', True)) -spot_heartx_icon = MenuIcon(asset_loader('heart-menu.png', True)) -transcode_icon = MenuIcon(asset_loader('transcode.png', True)) -mod_folder_icon = MenuIcon(asset_loader('mod_folder.png', True)) -settings_icon = MenuIcon(asset_loader('settings2.png', True)) -rename_tracks_icon = MenuIcon(asset_loader('pen.png', True)) -add_icon = MenuIcon(asset_loader('new.png', True)) -spot_asset = asset_loader('spot.png', True) +heartx_icon = MenuIcon(asset_loader("heart-menu.png", True)) +spot_heartx_icon = MenuIcon(asset_loader("heart-menu.png", True)) +transcode_icon = MenuIcon(asset_loader("transcode.png", True)) +mod_folder_icon = MenuIcon(asset_loader("mod_folder.png", True)) +settings_icon = MenuIcon(asset_loader("settings2.png", True)) +rename_tracks_icon = MenuIcon(asset_loader("pen.png", True)) +add_icon = MenuIcon(asset_loader("new.png", True)) +spot_asset = asset_loader("spot.png", True) spot_icon = MenuIcon(spot_asset) spot_icon.colour = [30, 215, 96, 255] spot_icon.xoff = 5 @@ -18773,15 +18773,15 @@ def regen_playlist_async(pl): tab_menu.add_to_sub(1, MenuItem(_("Sort by Imported Tracks"), imported_sort, pass_ref=True)) tab_menu.add_to_sub(1, MenuItem(_("Sort by Imported Folders"), imported_sort_folders, pass_ref=True)) tab_menu.add_to_sub(1, MenuItem(_("Sort by Filepath"), standard_sort, pass_ref=True)) -tab_menu.add_to_sub(1, MenuItem(_('Sort Track Numbers'), sort_track_2, pass_ref=True)) -tab_menu.add_to_sub(1, MenuItem(_('Sort Year per Artist'), year_sort, pass_ref=True)) -tab_menu.add_to_sub(1, MenuItem(_('Make Playlist Auto-Sorting'), make_auto_sorting, pass_ref=True)) +tab_menu.add_to_sub(1, MenuItem(_("Sort Track Numbers"), sort_track_2, pass_ref=True)) +tab_menu.add_to_sub(1, MenuItem(_("Sort Year per Artist"), year_sort, pass_ref=True)) +tab_menu.add_to_sub(1, MenuItem(_("Make Playlist Auto-Sorting"), make_auto_sorting, pass_ref=True)) tab_menu.br() -tab_menu.add(MenuItem(_('Rescan Folder'), re_import2, rescan_deco, pass_ref=True, pass_ref_deco=True)) +tab_menu.add(MenuItem(_("Rescan Folder"), re_import2, rescan_deco, pass_ref=True, pass_ref_deco=True)) -tab_menu.add(MenuItem(_('Paste'), s_append, paste_deco, pass_ref=True)) +tab_menu.add(MenuItem(_("Paste"), s_append, paste_deco, pass_ref=True)) tab_menu.add(MenuItem(_("Append Playing"), append_current_playing, append_deco, pass_ref=True)) tab_menu.br() @@ -19053,7 +19053,7 @@ def export_playlist_albums(pl): playtimes[last_folder] = playtimes.get(last_folder, 0) + int(star_store.get(id)) filename = f"{user_directory}/{name}.csv" - xport = open(filename, 'w') + xport = open(filename, "w") xport.write("Album name;Artist;Release date;Genre;Rating;Playtime;Folder path") @@ -19075,13 +19075,13 @@ def export_playlist_albums(pl): xport.write(csv_string(track.parent_folder_path)) xport.close() - show_message(_("Export complete."), _("Saved as: ") + filename, mode='done') + show_message(_("Export complete."), _("Saved as: ") + filename, mode="done") tab_menu.add_to_sub(2, MenuItem(_("Export Playlist Stats"), export_stats, pass_ref=True)) tab_menu.add_to_sub(2, MenuItem(_("Export Albums CSV"), export_playlist_albums, pass_ref=True)) -tab_menu.add_to_sub(2, MenuItem(_('Transcode All'), convert_playlist, pass_ref=True)) -tab_menu.add_to_sub(2, MenuItem(_('Rescan Tags'), rescan_tags, pass_ref=True)) +tab_menu.add_to_sub(2, MenuItem(_("Transcode All"), convert_playlist, pass_ref=True)) +tab_menu.add_to_sub(2, MenuItem(_("Rescan Tags"), rescan_tags, pass_ref=True)) # tab_menu.add_to_sub(_('Forget Import Folder'), 2, forget_pl_import_folder, rescan_deco, pass_ref=True, pass_ref_deco=True) # tab_menu.add_to_sub(_('Re-Import Last Folder'), 1, re_import, pass_ref=True) # tab_menu.add_to_sub(_('Quick Export XSPF'), 2, export_xspf, pass_ref=True) @@ -19482,16 +19482,16 @@ def gen_comment(pl): cm = pctl.master_library[item].comment if len(cm) > 20 and \ cm[0] != "0" and \ - 'http://' not in cm and \ - 'www.' not in cm and \ - 'Release' not in cm and \ - 'EAC' not in cm and \ - '@' not in cm and \ - '.com' not in cm and \ - 'ipped' not in cm and \ - 'ncoded' not in cm and \ - 'ExactA' not in cm and \ - 'WWW.' not in cm and \ + "http://" not in cm and \ + "www." not in cm and \ + "Release" not in cm and \ + "EAC" not in cm and \ + "@" not in cm and \ + ".com" not in cm and \ + "ipped" not in cm and \ + "ncoded" not in cm and \ + "ExactA" not in cm and \ + "WWW." not in cm and \ cm[2] != "+" and \ cm[1] != "+": playlist.append(item) @@ -19871,13 +19871,13 @@ def get_playing_line(): artist = pctl.master_library[pctl.track_queue[pctl.queue_step]].artist return artist + " - " + title else: - return 'Stopped' + return "Stopped" def reload_config_file(): if transcode_list: - show_message(_("Cannot reload while a transcode is in progress!"), mode='error') + show_message(_("Cannot reload while a transcode is in progress!"), mode="error") return load_prefs() @@ -19885,7 +19885,7 @@ def reload_config_file(): ddt.force_subpixel_text = prefs.force_subpixel_text ddt.clear_text_cache() - pctl.playerCommand = 'reload' + pctl.playerCommand = "reload" pctl.playerCommandReady = True show_message(_("Configuration reloaded"), mode="done") gui.update_layout() @@ -19897,10 +19897,10 @@ def open_config_file(): if system == "windows" or msys: os.startfile(target) elif macos: - subprocess.call(['open', "-t", target]) + subprocess.call(["open", "-t", target]) else: subprocess.call(["xdg-open", target]) - show_message(_("Config file opened."), _('Click "Reload" if you made any changes'), mode='arrow') + show_message(_("Config file opened."), _('Click "Reload" if you made any changes'), mode="arrow") # reload_config_file() # gui.message_box = False gui.opened_config_file = True @@ -19916,7 +19916,7 @@ def open_keymap_file(): if system == "windows" or msys: os.startfile(target) elif macos: - subprocess.call(['open', target]) + subprocess.call(["open", target]) else: subprocess.call(["xdg-open", target]) @@ -19929,7 +19929,7 @@ def open_file(target): if system == "windows" or msys: os.startfile(target) elif macos: - subprocess.call(['open', target]) + subprocess.call(["open", target]) else: subprocess.call(["xdg-open", target]) @@ -19939,7 +19939,7 @@ def open_data_directory(): if system == "windows" or msys: os.startfile(target) elif macos: - subprocess.call(['open', target]) + subprocess.call(["open", target]) else: subprocess.call(["xdg-open", target]) @@ -19970,11 +19970,11 @@ def convert_folder(index): return folder = [index] - if prefs.transcode_codec == 'flac' and track_object.file_ext.lower() in ('mp3', 'opus', - 'mp4', 'ogg', - 'aac'): + if prefs.transcode_codec == "flac" and track_object.file_ext.lower() in ("mp3", "opus", + "mp4", "ogg", + "aac"): show_message(_("NO! Bad user!"), _("Im not going to let you transcode a lossy codec to a lossless one!"), - mode='warning') + mode="warning") return folder = [index] @@ -19993,11 +19993,11 @@ def convert_folder(index): folder.append(item) #logging.info(prefs.transcode_codec) #logging.info(track_object.file_ext) - if prefs.transcode_codec == 'flac' and track_object.file_ext.lower() in ('mp3', 'opus', - 'mp4', 'ogg', - 'aac'): + if prefs.transcode_codec == "flac" and track_object.file_ext.lower() in ("mp3", "opus", + "mp4", "ogg", + "aac"): show_message(_("NO! Bad user!"), _("Im not going to let you transcode a lossy codec to a lossless one!"), - mode='warning') + mode="warning") return @@ -20129,7 +20129,7 @@ def lightning_paste(): for item in cargo: if move_path != pctl.g(item).parent_folder_path: show_message(_("More than one folder is in the clipboard"), - _('This function can only move one folder at a time.'), mode='info') + _("This function can only move one folder at a time."), mode="info") return match_track = pctl.g(default_playlist[shift_selection[0]]) @@ -20171,30 +20171,30 @@ def lightning_paste(): logging.info("Upper folder is: " + upper) if len(move_path) < 4: - show_message(_("Safety interupt! The source path seems oddly short."), move_path, mode='error') + show_message(_("Safety interupt! The source path seems oddly short."), move_path, mode="error") return if not os.path.isdir(upper): - show_message(_("The target directory is missing!"), upper, mode='warning') + show_message(_("The target directory is missing!"), upper, mode="warning") return if not os.path.isdir(move_path): - show_message(_("The source directory is missing!"), move_path, mode='warning') + show_message(_("The source directory is missing!"), move_path, mode="warning") return protect = ("", "Documents", "Music", "Desktop", "Downloads") for fo in protect: - if move_path.strip('\\/') == os.path.join(os.path.expanduser('~'), fo).strip("\\/"): - show_message(_("Better not do anything to that folder!"), os.path.join(os.path.expanduser('~'), fo), - mode='warning') + if move_path.strip("\\/") == os.path.join(os.path.expanduser("~"), fo).strip("\\/"): + show_message(_("Better not do anything to that folder!"), os.path.join(os.path.expanduser("~"), fo), + mode="warning") return if directory_size(move_path) > 3000000000: - show_message(_("Folder size safety limit reached! (3GB)"), move_path, mode='warning') + show_message(_("Folder size safety limit reached! (3GB)"), move_path, mode="warning") return if len(next(os.walk(move_path))[2]) > max(20, len(to_move) * 2): - show_message(_("Safety interupt! The source folder seems to have many files."), move_path, mode='warning') + show_message(_("Safety interupt! The source folder seems to have many files."), move_path, mode="warning") return artist = move_track.artist @@ -20347,7 +20347,7 @@ def s_cut(): del_selected() -playlist_menu.add(MenuItem('Paste', paste, paste_deco)) +playlist_menu.add(MenuItem("Paste", paste, paste_deco)) def paste_playlist_coast_fire(): @@ -20389,9 +20389,9 @@ def paste_playlist_coast_album_deco(): return [line_colour, colours.menu_background, None] -playlist_menu.add(MenuItem(_('Add Playing Spotify Album'), paste_playlist_coast_album, paste_playlist_coast_album_deco, +playlist_menu.add(MenuItem(_("Add Playing Spotify Album"), paste_playlist_coast_album, paste_playlist_coast_album_deco, show_test=spotify_show_test)) -playlist_menu.add(MenuItem(_('Add Playing Spotify Track'), paste_playlist_coast_track, paste_playlist_coast_album_deco, +playlist_menu.add(MenuItem(_("Add Playing Spotify Track"), paste_playlist_coast_track, paste_playlist_coast_album_deco, show_test=spotify_show_test)) def refind_playing(): @@ -20445,10 +20445,10 @@ def del_selected(force_delete=False): if force_delete: try: os.remove(tr.fullpath) - show_message(_("Files deleted"), mode='info') + show_message(_("Files deleted"), mode="info") except Exception: logging.exception("Error deleting one or more files") - show_message(_("Error deleting one or more files"), mode='error') + show_message(_("Error deleting one or more files"), mode="error") else: undo.bk_tracks(pctl.active_playlist_viewing, li) @@ -20483,8 +20483,8 @@ def show_in_gal(track, silent=False): # Create track context menu track_menu = Menu(195, show_icons=True) -track_menu.add(MenuItem(_('Open Folder'), open_folder, pass_ref=True, pass_ref_deco=True, icon=folder_icon, disable_test=open_folder_disable_test)) -track_menu.add(MenuItem(_('Track Info…'), activate_track_box, pass_ref=True, icon=info_icon)) +track_menu.add(MenuItem(_("Open Folder"), open_folder, pass_ref=True, pass_ref_deco=True, icon=folder_icon, disable_test=open_folder_disable_test)) +track_menu.add(MenuItem(_("Track Info…"), activate_track_box, pass_ref=True, icon=info_icon)) def last_fm_test(ignore): @@ -20549,7 +20549,7 @@ def love_index(): # Mark track as 'liked' -track_menu.add(MenuItem('Love', love_index, love_decox, icon=heartx_icon)) +track_menu.add(MenuItem("Love", love_index, love_decox, icon=heartx_icon)) def toggle_spotify_like_ref(): tr = pctl.g(r_menu_index) @@ -20583,13 +20583,13 @@ def spot_heart_menu_colour(): else: return None -heart_spot_icon = MenuIcon(asset_loader('heart-menu.png', True)) +heart_spot_icon = MenuIcon(asset_loader("heart-menu.png", True)) heart_spot_icon.colour = [30, 215, 96, 255] heart_spot_icon.xoff = 1 heart_spot_icon.yoff = 0 heart_spot_icon.colour_callback = spot_heart_menu_colour -track_menu.add(MenuItem('Spotify Like Track', toggle_spotify_like_ref, toggle_spotify_like_row_deco, show_test=spot_like_show_test, icon=heart_spot_icon)) +track_menu.add(MenuItem("Spotify Like Track", toggle_spotify_like_ref, toggle_spotify_like_row_deco, show_test=spot_like_show_test, icon=heart_spot_icon)) def add_to_queue(ref): @@ -20674,22 +20674,22 @@ def add_to_queue_next(ref): # prefs.show_queue ^= True -track_menu.add(MenuItem(_('Add to Queue'), add_to_queue, pass_ref=True, hint="MB3")) +track_menu.add(MenuItem(_("Add to Queue"), add_to_queue, pass_ref=True, hint="MB3")) -track_menu.add(MenuItem(_('↳ After Current Track'), add_to_queue_next, pass_ref=True, show_test=test_shift)) +track_menu.add(MenuItem(_("↳ After Current Track"), add_to_queue_next, pass_ref=True, show_test=test_shift)) -track_menu.add(MenuItem(_('Show in Gallery'), show_in_gal, pass_ref=True, show_test=test_show)) +track_menu.add(MenuItem(_("Show in Gallery"), show_in_gal, pass_ref=True, show_test=test_show)) track_menu.add_sub(_("Meta…"), 160) track_menu.br() # track_menu.add('Cut', s_cut, pass_ref=False) # track_menu.add('Remove', del_selected) -track_menu.add(MenuItem(_('Copy'), s_copy, pass_ref=False)) +track_menu.add(MenuItem(_("Copy"), s_copy, pass_ref=False)) # track_menu.add(_('Paste + Transfer Folder'), lightning_paste, pass_ref=False, show_test=lightning_move_test) -track_menu.add(MenuItem(_('Paste'), menu_paste, paste_deco, pass_ref=True)) +track_menu.add(MenuItem(_("Paste"), menu_paste, paste_deco, pass_ref=True)) def delete_track(track_ref): @@ -20712,27 +20712,27 @@ def delete_track(track_ref): if os.path.exists(fullpath): try: os.remove(fullpath) - show_message(_("File deleted"), fullpath, mode='info') + show_message(_("File deleted"), fullpath, mode="info") except Exception: logging.exception("Error deleting file") - show_message(_("Error deleting file"), fullpath, mode='error') + show_message(_("Error deleting file"), fullpath, mode="error") else: show_message(_("File moved to trash")) except Exception: try: os.remove(fullpath) - show_message(_("File deleted"), fullpath, mode='info') + show_message(_("File deleted"), fullpath, mode="info") except Exception: logging.exception("Error deleting file") - show_message(_("Error deleting file"), fullpath, mode='error') + show_message(_("Error deleting file"), fullpath, mode="error") reload() refind_playing() pctl.notify_change() -track_menu.add(MenuItem(_('Delete Track File'), delete_track, pass_ref=True, icon=delete_icon, show_test=test_shift)) +track_menu.add(MenuItem(_("Delete Track File"), delete_track, pass_ref=True, icon=delete_icon, show_test=test_shift)) track_menu.br() @@ -20763,28 +20763,28 @@ def delete_folder(index, force=False): track = pctl.master_library[index] if track.is_network: - show_message(_("Cannot physically delete"), _("One or more tracks is from a network location!"), mode='info') + show_message(_("Cannot physically delete"), _("One or more tracks is from a network location!"), mode="info") return old = track.parent_folder_path if len(old) < 5: - show_message(_("This folder path seems short, I don't wanna try delete that"), mode='warning') + show_message(_("This folder path seems short, I don't wanna try delete that"), mode="warning") return if not os.path.exists(old): - show_message(_("Error deleting folder. The folder seems to be missing."), _("It's gone! Just gone!"), mode='error') + show_message(_("Error deleting folder. The folder seems to be missing."), _("It's gone! Just gone!"), mode="error") return protect = ("", "Documents", "Music", "Desktop", "Downloads") for fo in protect: - if old.strip('\\/') == os.path.join(os.path.expanduser('~'), fo).strip("\\/"): - show_message(_("Woah, careful there!"), _("I don't think we should delete that folder."), mode='warning') + if old.strip("\\/") == os.path.join(os.path.expanduser("~"), fo).strip("\\/"): + show_message(_("Woah, careful there!"), _("I don't think we should delete that folder."), mode="warning") return if directory_size(old) > 1500000000: - show_message(_("Delete size safety limit reached! (1.5GB)"), old, mode='warning') + show_message(_("Delete size safety limit reached! (1.5GB)"), old, mode="warning") return try: @@ -20808,11 +20808,11 @@ def delete_folder(index, force=False): if not os.path.exists(old): if force: - show_message(_("Folder deleted."), old, mode='done') + show_message(_("Folder deleted."), old, mode="done") else: - show_message(_("Folder sent to trash."), old, mode='done') + show_message(_("Folder sent to trash."), old, mode="done") else: - show_message(_("Hmm, its still there"), old, mode='error') + show_message(_("Hmm, its still there"), old, mode="error") if album_mode: prep_gal() @@ -20821,11 +20821,11 @@ def delete_folder(index, force=False): except Exception: if force: logging.exception("Unable to comply, could not delete folder. Try checking permissions.") - show_message(_("Unable to comply."), _("Could not delete folder. Try checking permissions."), mode='error') + show_message(_("Unable to comply."), _("Could not delete folder. Try checking permissions."), mode="error") else: logging.exception("Folder could not be trashed, try again while holding shift to force delete.") show_message(_("Folder could not be trashed."), _("Try again while holding shift to force delete."), - mode='error') + mode="error") tree_view_box.clear_target_pl(pctl.active_playlist_viewing) gui.pl_update += 1 @@ -20838,7 +20838,7 @@ def rename_parent(index, template): track = pctl.master_library[index] if track.is_network: - show_message(_("Cannot rename"), _("One or more tracks is from a network location!"), mode='info') + show_message(_("Cannot rename"), _("One or more tracks is from a network location!"), mode="info") return old = track.parent_folder_path @@ -20847,22 +20847,22 @@ def rename_parent(index, template): new = parse_template2(template, track) if len(new) < 1: - show_message(_("Rename error."), _("The generated name is too short"), mode='warning') + show_message(_("Rename error."), _("The generated name is too short"), mode="warning") return if len(old) < 5: - show_message(_("Rename error."), _("This folder path seems short, I don't wanna try rename that"), mode='warning') + show_message(_("Rename error."), _("This folder path seems short, I don't wanna try rename that"), mode="warning") return if not os.path.exists(old): - show_message(_("Rename Failed. The original folder is missing."), mode='warning') + show_message(_("Rename Failed. The original folder is missing."), mode="warning") return protect = ("", "Documents", "Music", "Desktop", "Downloads") for fo in protect: - if os.path.normpath(old) == os.path.normpath(os.path.join(os.path.expanduser('~'), fo)): - show_message(_("Woah, careful there!"), _("I don't think we should rename that folder."), mode='warning') + if os.path.normpath(old) == os.path.normpath(os.path.join(os.path.expanduser("~"), fo)): + show_message(_("Woah, careful there!"), _("I don't think we should rename that folder."), mode="warning") return logging.info(track.parent_folder_path) @@ -20887,7 +20887,7 @@ def rename_parent(index, template): return if os.path.exists(new_parent_path): - show_message(_("Rename Failed."), _("A folder with that name already exists"), mode='warning') + show_message(_("Rename Failed."), _("A folder with that name already exists"), mode="warning") return if key == pctl.track_queue[pctl.queue_step] and pctl.playing_state > 0: @@ -20902,10 +20902,10 @@ def rename_parent(index, template): # Fix any other tracks paths that contain the old path if os.path.normpath(object.fullpath)[:len(old)] == os.path.normpath(old) \ - and os.path.normpath(object.fullpath)[len(old)] in ('/', '\\'): - object.fullpath = os.path.join(new_parent_path, object.fullpath[len(old):].lstrip('\\/')) + and os.path.normpath(object.fullpath)[len(old)] in ("/", "\\"): + object.fullpath = os.path.join(new_parent_path, object.fullpath[len(old):].lstrip("\\/")) object.parent_folder_path = os.path.join(new_parent_path, - object.parent_folder_path[len(old):].lstrip('\\/')) + object.parent_folder_path[len(old):].lstrip("\\/")) search_string_cache.pop(object.index, None) search_dia_string_cache.pop(object.index, None) @@ -20916,10 +20916,10 @@ def rename_parent(index, template): logging.info(new_parent_path) except Exception: logging.exception("Rename failed, something went wrong!") - show_message(_("Rename Failed!"), _("Something went wrong, sorry."), mode='error') + show_message(_("Rename Failed!"), _("Something went wrong, sorry."), mode="error") return - show_message(_("Folder renamed."), _("Renamed to: {name}").format(name=new), mode='done') + show_message(_("Folder renamed."), _("Renamed to: {name}").format(name=new), mode="done") if pre_state == 1: pctl.revert() @@ -20961,7 +20961,7 @@ def move_folder_up(index, do=False): track = pctl.master_library[index] if track.is_network: - show_message(_("Cannot move"), _("One or more tracks is from a network location!"), mode='info') + show_message(_("Cannot move"), _("One or more tracks is from a network location!"), mode="info") return parent_folder = os.path.dirname(track.parent_folder_path) @@ -20971,7 +20971,7 @@ def move_folder_up(index, do=False): if not os.path.exists(track.parent_folder_path): if do: - show_message(_("Error shifting directory"), _("The directory does not appear to exist"), mode='warning') + show_message(_("Error shifting directory"), _("The directory does not appear to exist"), mode="warning") return False if len(os.listdir(parent_folder)) > 1: @@ -21000,7 +21000,7 @@ def move_folder_up(index, do=False): except Exception as e: logging.exception("System Error!") - show_message(_("System Error!"), str(e), mode='error') + show_message(_("System Error!"), str(e), mode="error") # Fix any other tracks paths that contain the old path old = track.parent_folder_path @@ -21008,10 +21008,10 @@ def move_folder_up(index, do=False): for key, object in pctl.master_library.items(): if os.path.normpath(object.fullpath)[:len(old)] == os.path.normpath(old) \ - and os.path.normpath(object.fullpath)[len(old)] in ('/', '\\'): - object.fullpath = os.path.join(new_parent_path, object.fullpath[len(old):].lstrip('\\/')) + and os.path.normpath(object.fullpath)[len(old)] in ("/", "\\"): + object.fullpath = os.path.join(new_parent_path, object.fullpath[len(old):].lstrip("\\/")) object.parent_folder_path = os.path.join(new_parent_path, - object.parent_folder_path[len(old):].lstrip('\\/')) + object.parent_folder_path[len(old):].lstrip("\\/")) search_string_cache.pop(object.index, None) search_dia_string_cache.pop(object.index, None) @@ -21027,7 +21027,7 @@ def clean_folder(index, do=False): track = pctl.master_library[index] if track.is_network: - show_message(_("Cannot clean"), _("One or more tracks is from a network location!"), mode='info') + show_message(_("Cannot clean"), _("One or more tracks is from a network location!"), mode="info") return folder = track.parent_folder_path @@ -21037,10 +21037,10 @@ def clean_folder(index, do=False): return 0 try: for item in os.listdir(folder): - if ('AlbumArt' == item[:8] and '.jpg' in item.lower()) \ - or 'desktop.ini' == item \ - or 'Thumbs.db' == item \ - or '.DS_Store' == item: + if ("AlbumArt" == item[:8] and ".jpg" in item.lower()) \ + or "desktop.ini" == item \ + or "Thumbs.db" == item \ + or ".DS_Store" == item: to_purge.append(item) found += 1 @@ -21054,7 +21054,7 @@ def clean_folder(index, do=False): if do: for item in to_purge: if os.path.isfile(os.path.join(folder, item)): - logging.info('Deleting File: ' + os.path.join(folder, item)) + logging.info("Deleting File: " + os.path.join(folder, item)) os.remove(os.path.join(folder, item)) # clear_img_cache() @@ -21064,7 +21064,7 @@ def clean_folder(index, do=False): except Exception: logging.exception("Error deleting files, may not have permission or file may be set to read-only") - show_message(_("Error deleting files."), _("May not have permission or file may be set to read-only"), mode='warning') + show_message(_("Error deleting files."), _("May not have permission or file may be set to read-only"), mode="warning") return 0 return found @@ -21228,36 +21228,36 @@ def editor(index): if not os.path.isfile(prefs.tag_editor_target.strip('"')): logging.info(prefs.tag_editor_target) - show_message(_("Application not found"), prefs.tag_editor_target, mode='info') + show_message(_("Application not found"), prefs.tag_editor_target, mode="info") return ok = True if not ok: - show_message(_("Tag editor app does not appear to be installed."), mode='warning') + show_message(_("Tag editor app does not appear to be installed."), mode="warning") if flatpak_mode: show_message(_("App not found on host OR insufficient Flatpak permissions."), _(" For details, see {link}").format(link="https://github.com/Taiko2k/Tauon/wiki/Flatpak-Extra-Steps"), - mode='bubble') + mode="bubble") return - if 'picard' in prefs.tag_editor_target: + if "picard" in prefs.tag_editor_target: app_switch = " --d " line = prefix + app + app_switch + file_line show_message(prefs.tag_editor_name + " launched.", "Fields will be updated once application is closed.", - mode='arrow') + mode="arrow") gui.update = 1 complete = subprocess.run(shlex.split(line), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - if 'picard' in prefs.tag_editor_target: + if "picard" in prefs.tag_editor_target: r = complete.stderr.decode() for line in r.split("\n"): - if 'file._rename' in line and ' Moving file ' in line: + if "file._rename" in line and " Moving file " in line: a, b = line.split(" Moving file ")[1].split(" => ") a = a.strip("'").strip('"') b = b.strip("'").strip('"') @@ -21339,8 +21339,8 @@ def launch_editor_selection(index): # track_menu.add('Reload Metadata', reload_metadata, pass_ref=True) track_menu.add_to_sub(0, MenuItem(_("Rescan Tags"), reload_metadata, pass_ref=True)) -mbp_icon = MenuIcon(asset_loader('mbp-g.png')) -mbp_icon.base_asset = asset_loader('mbp-gs.png') +mbp_icon = MenuIcon(asset_loader("mbp-g.png")) +mbp_icon.base_asset = asset_loader("mbp-gs.png") mbp_icon.xoff = 2 mbp_icon.yoff = -1 @@ -21376,7 +21376,7 @@ def show_lyrics_menu(index): def recode(text, enc): - return text.encode("Latin-1", 'ignore').decode(enc, 'ignore') + return text.encode("Latin-1", "ignore").decode(enc, "ignore") def intel_moji(index): @@ -21395,8 +21395,8 @@ def intel_moji(index): lot = set(lot) - l_artist = track.artist.encode("Latin-1", 'ignore') - l_album = track.album.encode("Latin-1", 'ignore') + l_artist = track.artist.encode("Latin-1", "ignore") + l_album = track.album.encode("Latin-1", "ignore") detect = None if track.artist not in track.parent_folder_path: @@ -21494,7 +21494,7 @@ def cut_selection(): def clip_ar_al(index): line = pctl.master_library[index].artist + " - " + \ pctl.master_library[index].album - SDL_SetClipboardText(line.encode('utf-8')) + SDL_SetClipboardText(line.encode("utf-8")) def clip_ar(index): @@ -21502,7 +21502,7 @@ def clip_ar(index): line = pctl.master_library[index].album_artist else: line = pctl.master_library[index].artist - SDL_SetClipboardText(line.encode('utf-8')) + SDL_SetClipboardText(line.encode("utf-8")) def clip_title(index): @@ -21513,13 +21513,13 @@ def clip_title(index): else: line = n_track.parent_folder_name - SDL_SetClipboardText(line.encode('utf-8')) + SDL_SetClipboardText(line.encode("utf-8")) selection_menu = Menu(200, show_icons=False) folder_menu = Menu(193, show_icons=True) -folder_menu.add(MenuItem(_('Open Folder'), open_folder, pass_ref=True, pass_ref_deco=True, icon=folder_icon, disable_test=open_folder_disable_test)) +folder_menu.add(MenuItem(_("Open Folder"), open_folder, pass_ref=True, pass_ref_deco=True, icon=folder_icon, disable_test=open_folder_disable_test)) folder_menu.add(MenuItem(_("Modify Folder…"), rename_folders, pass_ref=True, pass_ref_deco=True, icon=mod_folder_icon, disable_test=rename_folders_disable_test)) folder_tree_menu.add(MenuItem(_("Modify Folder…"), rename_folders, pass_ref=True, pass_ref_deco=True, icon=mod_folder_icon, disable_test=rename_folders_disable_test)) @@ -21541,7 +21541,7 @@ def clip_title(index): folder_tree_menu.add(MenuItem(_("Enqueue Album Next"), add_album_to_queue_fc, pass_ref=True)) folder_tree_menu.br() -folder_tree_menu.add(MenuItem(_('Collapse All'), collapse_tree, collapse_tree_deco)) +folder_tree_menu.add(MenuItem(_("Collapse All"), collapse_tree, collapse_tree_deco)) folder_tree_menu.add(MenuItem("lock", lock_folder_tree, lock_folder_tree_deco)) @@ -21572,7 +21572,7 @@ def toggle_transfer(mode=0): if prefs.show_transfer: show_message(_("Warning! Using this function moves physical folders."), _("This menu entry appears after selecting 'copy'. See manual (github wiki) for more info."), - mode='info') + mode="info") transcode_icon.colour = [239, 74, 157, 255] @@ -21582,15 +21582,15 @@ def transcode_deco(): if key_shift_down or key_shiftr_down: return [colours.menu_text, colours.menu_background, _("Transcode Single")] else: - return [colours.menu_text, colours.menu_background, _('Transcode Folder')] + return [colours.menu_text, colours.menu_background, _("Transcode Folder")] -folder_menu.add(MenuItem(_('Rescan Tags'), reload_metadata, pass_ref=True)) +folder_menu.add(MenuItem(_("Rescan Tags"), reload_metadata, pass_ref=True)) folder_menu.add(MenuItem(_("Edit fields…"), activate_trans_editor)) -folder_menu.add(MenuItem(_('Vacuum Playtimes'), vacuum_playtimes, pass_ref=True, show_test=test_shift)) -folder_menu.add(MenuItem(_('Transcode Folder'), convert_folder, transcode_deco, pass_ref=True, icon=transcode_icon, +folder_menu.add(MenuItem(_("Vacuum Playtimes"), vacuum_playtimes, pass_ref=True, show_test=test_shift)) +folder_menu.add(MenuItem(_("Transcode Folder"), convert_folder, transcode_deco, pass_ref=True, icon=transcode_icon, show_test=toggle_transcode)) -gallery_menu.add(MenuItem(_('Transcode Folder'), convert_folder, transcode_deco, pass_ref=True, icon=transcode_icon, +gallery_menu.add(MenuItem(_("Transcode Folder"), convert_folder, transcode_deco, pass_ref=True, icon=transcode_icon, show_test=toggle_transcode)) folder_menu.br() @@ -21624,7 +21624,7 @@ def get_album_spot_url_deco(track_id): return [colours.menu_text, colours.menu_background, text] -folder_menu.add(MenuItem('Lookup Spotify Album URL', get_album_spot_url, get_album_spot_url_deco, pass_ref=True, +folder_menu.add(MenuItem("Lookup Spotify Album URL", get_album_spot_url, get_album_spot_url_deco, pass_ref=True, pass_ref_deco=True, show_test=spotify_show_test, icon=spot_icon)) @@ -21665,7 +21665,7 @@ def add_to_spotify_library(track_id): shoot_dl.start() -folder_menu.add(MenuItem('Add to Spotify Library', add_to_spotify_library, add_to_spotify_library_deco, pass_ref=True, +folder_menu.add(MenuItem("Add to Spotify Library", add_to_spotify_library, add_to_spotify_library_deco, pass_ref=True, pass_ref_deco=True, show_test=spotify_show_test, icon=spot_icon)) @@ -21679,16 +21679,16 @@ def selection_queue_deco(): total = get_hms_time(total) - text = (_('Queue {N}').format(N=len(shift_selection))) + f" [{total}]" + text = (_("Queue {N}").format(N=len(shift_selection))) + f" [{total}]" return [colours.menu_text, colours.menu_background, text] -selection_menu.add(MenuItem(_('Add to queue'), add_selected_to_queue_multi, selection_queue_deco)) +selection_menu.add(MenuItem(_("Add to queue"), add_selected_to_queue_multi, selection_queue_deco)) selection_menu.br() -selection_menu.add(MenuItem(_('Rescan Tags'), reload_metadata_selection)) +selection_menu.add(MenuItem(_("Rescan Tags"), reload_metadata_selection)) selection_menu.add(MenuItem(_("Edit fields…"), activate_trans_editor)) @@ -21700,18 +21700,18 @@ def selection_queue_deco(): # It's complicated # folder_menu.add(_('Copy Folder From Library'), lightning_copy) -selection_menu.add(MenuItem(_('Copy'), s_copy)) -selection_menu.add(MenuItem(_('Cut'), s_cut)) -selection_menu.add(MenuItem(_('Remove'), del_selected)) -selection_menu.add(MenuItem(_('Delete Files'), force_del_selected, show_test=test_shift, icon=delete_icon)) +selection_menu.add(MenuItem(_("Copy"), s_copy)) +selection_menu.add(MenuItem(_("Cut"), s_cut)) +selection_menu.add(MenuItem(_("Remove"), del_selected)) +selection_menu.add(MenuItem(_("Delete Files"), force_del_selected, show_test=test_shift, icon=delete_icon)) -folder_menu.add(MenuItem(_('Copy'), s_copy)) -gallery_menu.add(MenuItem(_('Copy'), s_copy)) +folder_menu.add(MenuItem(_("Copy"), s_copy)) +gallery_menu.add(MenuItem(_("Copy"), s_copy)) # folder_menu.add(_('Cut'), s_cut) # folder_menu.add(_('Paste + Transfer Folder'), lightning_paste, pass_ref=False, show_test=lightning_move_test) # gallery_menu.add(_('Paste + Transfer Folder'), lightning_paste, pass_ref=False, show_test=lightning_move_test) -folder_menu.add(MenuItem(_('Remove'), del_selected)) -gallery_menu.add(MenuItem(_('Remove'), del_selected)) +folder_menu.add(MenuItem(_("Remove"), del_selected)) +gallery_menu.add(MenuItem(_("Remove"), del_selected)) def toggle_rym(mode=0): @@ -21772,7 +21772,7 @@ def ser_rym(index): def copy_to_clipboard(text): - SDL_SetClipboardText(text.encode(errors='surrogateescape')) + SDL_SetClipboardText(text.encode(errors="surrogateescape")) def copy_from_clipboard(): @@ -21786,7 +21786,7 @@ def clip_aar_al(index): else: line = pctl.master_library[index].album_artist + " - " + \ pctl.master_library[index].album - SDL_SetClipboardText(line.encode('utf-8')) + SDL_SetClipboardText(line.encode("utf-8")) def ser_gen_thread(tr): @@ -21831,29 +21831,29 @@ def ser_wiki(index): webbrowser.open(line, new=2, autoraise=True) -track_menu.add(MenuItem(_('Search Artist on Wikipedia'), ser_wiki, pass_ref=True, show_test=toggle_wiki)) +track_menu.add(MenuItem(_("Search Artist on Wikipedia"), ser_wiki, pass_ref=True, show_test=toggle_wiki)) -track_menu.add(MenuItem(_('Search Track on Genius'), ser_gen, pass_ref=True, show_test=toggle_gen)) +track_menu.add(MenuItem(_("Search Track on Genius"), ser_gen, pass_ref=True, show_test=toggle_gen)) -son_icon = MenuIcon(asset_loader('sonemic-g.png')) -son_icon.base_asset = asset_loader('sonemic-gs.png') +son_icon = MenuIcon(asset_loader("sonemic-g.png")) +son_icon.base_asset = asset_loader("sonemic-gs.png") son_icon.xoff = 1 -track_menu.add(MenuItem(_('Search Artist on Sonemic'), ser_rym, pass_ref=True, icon=son_icon, show_test=toggle_rym)) +track_menu.add(MenuItem(_("Search Artist on Sonemic"), ser_rym, pass_ref=True, icon=son_icon, show_test=toggle_rym)) -band_icon = MenuIcon(asset_loader('band.png', True)) +band_icon = MenuIcon(asset_loader("band.png", True)) band_icon.xoff = 0 band_icon.yoff = 1 band_icon.colour = [96, 147, 158, 255] -track_menu.add(MenuItem(_('Search Artist on Bandcamp'), ser_band, pass_ref=True, icon=band_icon, show_test=toggle_band)) +track_menu.add(MenuItem(_("Search Artist on Bandcamp"), ser_band, pass_ref=True, icon=band_icon, show_test=toggle_band)) def clip_ar_tr(index): line = pctl.master_library[index].artist + " - " + \ pctl.master_library[index].title - SDL_SetClipboardText(line.encode('utf-8')) + SDL_SetClipboardText(line.encode("utf-8")) # Copy metadata to clipboard @@ -21890,7 +21890,7 @@ def get_track_spot_url_deco(): def get_spot_artist_track(index): get_artist_spot(pctl.g(index)) -track_menu.add_to_sub(1, MenuItem(_('Show Full Artist'), get_spot_artist_track, pass_ref=True, icon=spot_icon)) +track_menu.add_to_sub(1, MenuItem(_("Show Full Artist"), get_spot_artist_track, pass_ref=True, icon=spot_icon)) def get_album_spot_active(tr=None): if tr is None: @@ -21915,11 +21915,11 @@ def get_album_spot_active(tr=None): def get_spot_album_track(index): get_album_spot_active(pctl.g(index)) -track_menu.add_to_sub(1, MenuItem(_('Show Full Album'), get_spot_album_track, pass_ref=True, icon=spot_icon)) +track_menu.add_to_sub(1, MenuItem(_("Show Full Album"), get_spot_album_track, pass_ref=True, icon=spot_icon)) -track_menu.add_to_sub(1, MenuItem(_('Copy Track URL'), get_track_spot_url, get_track_spot_url_deco, pass_ref=True, +track_menu.add_to_sub(1, MenuItem(_("Copy Track URL"), get_track_spot_url, get_track_spot_url_deco, pass_ref=True, icon=spot_icon)) def get_spot_recs(tr=None): @@ -21939,7 +21939,7 @@ def get_spot_recs(tr=None): def get_spot_recs_track(index): get_spot_recs(pctl.g(index)) -track_menu.add_to_sub(1, MenuItem(_('Get Recommended'), get_spot_recs_track, pass_ref=True, +track_menu.add_to_sub(1, MenuItem(_("Get Recommended"), get_spot_recs_track, pass_ref=True, icon=spot_icon)) @@ -21979,7 +21979,7 @@ def queue_deco(): track_menu.br() -track_menu.add(MenuItem(_('Transcode Folder'), convert_folder, transcode_deco, pass_ref=True, icon=transcode_icon, +track_menu.add(MenuItem(_("Transcode Folder"), convert_folder, transcode_deco, pass_ref=True, icon=transcode_icon, show_test=toggle_transcode)) @@ -22073,7 +22073,7 @@ def spec2_def(): if prefs.backend == 2: show_message(_("Not implemented")) # gui.turbo = True - prefs.spec2_colour_setting = 'custom' + prefs.spec2_colour_setting = "custom" gui.update_layout() @@ -22307,11 +22307,11 @@ def sort_ass(h, invert=False, custom_list=None, custom_name=""): key = key_scrobbles if name == "P": key = key_playcount - if name == 'Starline': + if name == "Starline": key = best - if name == 'Rating': + if name == "Rating": key = key_rating - if name == 'Comment': + if name == "Comment": key = key_comment if name == "Codec": key = key_codec @@ -23003,22 +23003,22 @@ def stt2(sec): hours, rem = divmod(rem, 3600) min, sec = divmod(rem, 60) - s_day = str(days) + 'd' - if s_day == '0d': + s_day = str(days) + "d" + if s_day == "0d": s_day = " " - s_hours = str(hours) + 'h' - if s_hours == '0h' and s_day == ' ': + s_hours = str(hours) + "h" + if s_hours == "0h" and s_day == " ": s_hours = " " - s_min = str(min) + 'm' + s_min = str(min) + "m" - return s_day.rjust(3) + ' ' + s_hours.rjust(3) + ' ' + s_min.rjust(3) + return s_day.rjust(3) + " " + s_hours.rjust(3) + " " + s_min.rjust(3) def export_database(): - path = user_directory + '/DatabaseExport.csv' - xport = open(path, 'w') + path = user_directory + "/DatabaseExport.csv" + xport = open(path, "w") xport.write("Artist;Title;Album;Album artist;Track number;Type;Duration;Release date;Genre;Playtime;File path") @@ -23044,7 +23044,7 @@ def export_database(): xport.write(csv_string(track.fullpath)) xport.close() - show_message(_("Export complete."), _("Saved as: ") + path, mode='done') + show_message(_("Export complete."), _("Saved as: ") + path, mode="done") def q_to_playlist(): @@ -23057,7 +23057,7 @@ def q_to_playlist(): x_menu.add_to_sub(0, MenuItem(_("Export as CSV"), export_database)) -x_menu.add_to_sub(0, MenuItem(_('Rescan All Folders'), rescan_all_folders)) +x_menu.add_to_sub(0, MenuItem(_("Rescan All Folders"), rescan_all_folders)) x_menu.add_to_sub(0, MenuItem(_("Play History to Playlist"), q_to_playlist)) x_menu.add_to_sub(0, MenuItem(_("Reset Image Cache"), clear_img_cache)) @@ -23141,7 +23141,7 @@ def clear_ratings(): if not key_shift_down: show_message(_("This will delete all track and album ratings from the local database!"), _("Press button again while holding shift key if you're sure you want to do that."), - mode='warning') + mode="warning") return else: for key, star in star_store.db.items(): @@ -23231,12 +23231,12 @@ def set_mini_mode_D(): set_mini_mode() -mode_menu.add(MenuItem(_('Tab'), set_mini_mode_D)) -mode_menu.add(MenuItem(_('Mini'), set_mini_mode_A1)) +mode_menu.add(MenuItem(_("Tab"), set_mini_mode_D)) +mode_menu.add(MenuItem(_("Mini"), set_mini_mode_A1)) # mode_menu.add(_('Mini Mode Large'), set_mini_mode_A2) -mode_menu.add(MenuItem(_('Slate'), set_mini_mode_C1)) -mode_menu.add(MenuItem(_('Square'), set_mini_mode_B1)) -mode_menu.add(MenuItem(_('Square Large'), set_mini_mode_B2)) +mode_menu.add(MenuItem(_("Slate"), set_mini_mode_C1)) +mode_menu.add(MenuItem(_("Square"), set_mini_mode_B1)) +mode_menu.add(MenuItem(_("Square Large"), set_mini_mode_B2)) def copy_bb_metadata(): @@ -23251,7 +23251,7 @@ def copy_bb_metadata(): mode_menu.br() -mode_menu.add(MenuItem(_('Copy Title to Clipboard'), copy_bb_metadata)) +mode_menu.add(MenuItem(_("Copy Title to Clipboard"), copy_bb_metadata)) extra_menu = Menu(175, show_icons=True) @@ -23269,7 +23269,7 @@ def random_track(): pctl.show_current() -extra_menu.add(MenuItem(_('Random Track'), random_track, hint=';')) +extra_menu.add(MenuItem(_("Random Track"), random_track, hint=";")) def random_album(): @@ -23291,24 +23291,24 @@ def radio_random(): pctl.advance(rr=True) -radiorandom_icon = MenuIcon(asset_loader('radiorandom.png', True)) -revert_icon = MenuIcon(asset_loader('revert.png', True)) +radiorandom_icon = MenuIcon(asset_loader("radiorandom.png", True)) +revert_icon = MenuIcon(asset_loader("revert.png", True)) radiorandom_icon.xoff = 1 radiorandom_icon.yoff = 0 radiorandom_icon.colour = [153, 229, 133, 255] -extra_menu.add(MenuItem(_('Radio Random'), radio_random, hint='/', icon=radiorandom_icon)) +extra_menu.add(MenuItem(_("Radio Random"), radio_random, hint="/", icon=radiorandom_icon)) revert_icon.xoff = 1 revert_icon.yoff = 0 revert_icon.colour = [229, 102, 59, 255] -extra_menu.add(MenuItem(_('Revert'), pctl.revert, hint='Shift+/', icon=revert_icon)) +extra_menu.add(MenuItem(_("Revert"), pctl.revert, hint="Shift+/", icon=revert_icon)) # extra_menu.add('Toggle Repeat', toggle_repeat, hint='COMMA') # extra_menu.add('Toggle Random', toggle_random, hint='PERIOD') -extra_menu.add(MenuItem(_('Clear Queue'), clear_queue, queue_deco, hint="Alt+Shift+Q")) +extra_menu.add(MenuItem(_("Clear Queue"), clear_queue, queue_deco, hint="Alt+Shift+Q")) def heart_menu_colour(): @@ -23324,14 +23324,14 @@ def heart_menu_colour(): return None -heart_icon = MenuIcon(asset_loader('heart-menu.png', True)) -heart_row_icon = asset_loader('heart-track.png', True) -heart_notify_icon = asset_loader('heart-notify.png', True) -heart_notify_break_icon = asset_loader('heart-notify-break.png', True) +heart_icon = MenuIcon(asset_loader("heart-menu.png", True)) +heart_row_icon = asset_loader("heart-track.png", True) +heart_notify_icon = asset_loader("heart-notify.png", True) +heart_notify_break_icon = asset_loader("heart-notify-break.png", True) # spotify_row_icon = asset_loader('spotify-row.png', True) -star_pc_icon = asset_loader('star-pc.png', True) -star_row_icon = asset_loader('star.png', True) -star_half_row_icon = asset_loader('star-half.png', True) +star_pc_icon = asset_loader("star-pc.png", True) +star_row_icon = asset_loader("star.png", True) +star_half_row_icon = asset_loader("star-half.png", True) def draw_rating_widget(x, y, n_track, album=False): @@ -23445,7 +23445,7 @@ def select_love(notify=False): shoot_love.start() -extra_menu.add(MenuItem('Love', bar_love_notify, love_deco, icon=heart_icon)) +extra_menu.add(MenuItem("Love", bar_love_notify, love_deco, icon=heart_icon)) def toggle_spotify_like_active2(tr): @@ -23497,12 +23497,12 @@ def locate_artist(): track = pctl.g(default_playlist[i]) if current is False: if track.artist == artist or track.album_artist == artist or ( - 'artists' in track.misc and artist in track.misc['artists']): + "artists" in track.misc and artist in track.misc["artists"]): block_starts.append(i) current = True else: if track.artist != artist and track.album_artist != artist or ( - 'artists' in track.misc and artist in track.misc['artists']): + "artists" in track.misc and artist in track.misc["artists"]): current = False if block_starts: @@ -23545,7 +23545,7 @@ def activate_search_overlay(): search_over.spotify_mode = False -extra_menu.add(MenuItem(_('Global Search'), activate_search_overlay, hint="Ctrl+G")) +extra_menu.add(MenuItem(_("Global Search"), activate_search_overlay, hint="Ctrl+G")) def get_album_spot_url_active(): @@ -23603,14 +23603,14 @@ def spot_transfer_playback_here(): tauon.spot_ctl.preparing_spotify = True if not (spot_ctl.playing or spot_ctl.coasting): spot_ctl.update(start=True) - pctl.playerCommand = 'spotcon' + pctl.playerCommand = "spotcon" pctl.playerCommandReady = True pctl.playing_state = 3 shooter(spot_ctl.transfer_to_tauon) extra_menu.br() -extra_menu.add(MenuItem('Spotify Like Track', toggle_spotify_like_active, toggle_spotify_like_active_deco, +extra_menu.add(MenuItem("Spotify Like Track", toggle_spotify_like_active, toggle_spotify_like_active_deco, show_test=spotify_show_test, icon=spot_heartx_icon)) def spot_import_albums(): @@ -23805,7 +23805,7 @@ def toggle_notifications(mode=0): if prefs.show_notifications: if not de_notify_support: - show_message(_("Notifications for this DE not supported"), '', mode='warning') + show_message(_("Notifications for this DE not supported"), "", mode="warning") # def toggle_al_pref_album_artist(mode=0): @@ -23858,7 +23858,7 @@ def level_meter_special_2(): gui.level_meter_colour_mode = 2 -theme_files = os.listdir(install_directory + '/theme') +theme_files = os.listdir(install_directory + "/theme") theme_files.sort() @@ -23887,7 +23887,7 @@ def lastfm_colour(): return None -last_fm_icon = asset_loader('as.png', True) +last_fm_icon = asset_loader("as.png", True) lastfm_icon = MenuIcon(last_fm_icon) if gui.scale == 2: @@ -23909,8 +23909,8 @@ def lastfm_menu_test(a): return False -lb_icon = MenuIcon(asset_loader('lb-g.png')) -lb_icon.base_asset = asset_loader('lb-gs.png') +lb_icon = MenuIcon(asset_loader("lb-g.png")) +lb_icon.base_asset = asset_loader("lb-gs.png") def lb_mode(): @@ -23955,17 +23955,17 @@ def get_album_art_url(tr): return if not release_group_id: - release_group_id = tr.misc.get('musicbrainz_releasegroupid') + release_group_id = tr.misc.get("musicbrainz_releasegroupid") if not release_id: - release_id = tr.misc.get('musicbrainz_albumid') + release_id = tr.misc.get("musicbrainz_albumid") if not release_group_id: try: #logging.info("lookup release group id") s = musicbrainzngs.search_release_groups(tr.album, artist=artist, limit=1) - release_group_id = s['release-group-list'][0]['id'] - tr.misc['musicbrainz_releasegroupid'] = release_group_id + release_group_id = s["release-group-list"][0]["id"] + tr.misc["musicbrainz_releasegroupid"] = release_group_id #logging.info("got release group id") except Exception: logging.exception("Error lookup mbid for discord") @@ -23975,8 +23975,8 @@ def get_album_art_url(tr): try: #logging.info("lookup release id") s = musicbrainzngs.search_releases(tr.album, artist=artist, limit=1) - release_id = s['release-list'][0]['id'] - tr.misc['musicbrainz_albumid'] = release_id + release_id = s["release-list"][0]["id"] + tr.misc["musicbrainz_albumid"] = release_id #logging.info("got release group id") except Exception: logging.exception("Error lookup mbid for discord") @@ -24053,7 +24053,7 @@ def discord_loop(): asyncio.set_event_loop(asyncio.new_event_loop()) # logging.info("Attempting to connect to Discord...") - client_id = '954253873160286278' + client_id = "954253873160286278" RPC = Presence(client_id) RPC.connect() @@ -24305,7 +24305,7 @@ def library_deco(): if gui.set_mode: return [tc, colours.menu_background, _("Disable Columns")] else: - return [tc, colours.menu_background, _('Enable Columns')] + return [tc, colours.menu_background, _("Enable Columns")] def break_deco(): @@ -24318,7 +24318,7 @@ def break_deco(): if pctl.multi_playlist[pctl.active_playlist_viewing][4] == 0: return [tex, colours.menu_background, _("Disable Title Breaks")] else: - return [tex, colours.menu_background, _('Enable Title Breaks')] + return [tex, colours.menu_background, _("Enable Title Breaks")] def toggle_playlist_break(): @@ -24361,7 +24361,7 @@ def transcode_single(item, manual_directroy=None, manual_name=None): if os.path.exists(path): os.remove(path) logging.info("Downloading file...") - with requests.get(url, params=params) as response, open(path, 'wb') as out_file: + with requests.get(url, params=params) as response, open(path, "wb") as out_file: out_file.write(response.content) logging.info("Download complete") cleanup = True @@ -24376,15 +24376,15 @@ def transcode_single(item, manual_directroy=None, manual_name=None): out_line = encode_track_name(t) - target_out = output + _('output') + str(track) + "." + codec + target_out = output + _("output") + str(track) + "." + codec command = tauon.get_ffmpeg() + " " if not t.is_cue: command += '-i "' else: - command += '-ss ' + str(t.start_time) - command += ' -t ' + str(t.length) + command += "-ss " + str(t.start_time) + command += " -t " + str(t.length) command += ' -i "' @@ -24403,14 +24403,14 @@ def transcode_single(item, manual_directroy=None, manual_name=None): if t.date != "": command += '-metadata year="' + str(t.date).replace('"', "").replace("'", "") + '" ' - if codec != 'flac': + if codec != "flac": command += " -b:a " + str(bitrate) + "k -vn " command += '"' + target_out.replace('"', '\\"') + '"' # logging.info(shlex.split(command)) startupinfo = None - if system == 'windows' or msys: + if system == "windows" or msys: startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW @@ -24422,7 +24422,7 @@ def transcode_single(item, manual_directroy=None, manual_name=None): logging.info("FFmpeg finished") if codec == "opus" and prefs.transcode_opus_as: - codec = 'ogg' + codec = "ogg" # logging.info(target_out) @@ -24521,13 +24521,13 @@ def cue_scan(content, tn): MAIN_PERFORMER = LINE[11:len(LINE) - 2] - if 'REM DATE' in LINE: + if "REM DATE" in LINE: DATE = LINE[9:len(LINE) - 1] - if 'REM GENRE' in LINE: + if "REM GENRE" in LINE: GENRE = LINE[10:len(LINE) - 1] - if 'TRACK ' in LINE: + if "TRACK " in LINE: break for LINE in reversed(content): @@ -24567,10 +24567,10 @@ def cue_scan(content, tn): if LINE[i] == '"': switch = 1 - elif 'TRACK ' in LINE: + elif "TRACK " in LINE: pos = 0 - while LINE[pos] != 'K': + while LINE[pos] != "K": pos += 1 if pos > 15: return 1 @@ -24610,7 +24610,7 @@ def cue_scan(content, tn): if ALBUM: nt.album = ALBUM if DATE: - nt.date = DATE.replace('"', '') + nt.date = DATE.replace('"', "") nt.track_number = TN nt.start_time = START nt.is_cue = True @@ -24710,7 +24710,7 @@ def click_artist(self, name, get_list=False, search_lists=None): n = name.lower() if tr.artist.lower() == n \ or tr.album_artist.lower() == n \ - or ('artists' in tr.misc and name in tr.misc['artists']): + or ("artists" in tr.misc and name in tr.misc["artists"]): if item not in playlist: playlist.append(item) @@ -25405,23 +25405,23 @@ def render(self): ddt.text_background_colour = colours.message_box_bg - if gui.message_mode == 'info': + if gui.message_mode == "info": message_info_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_info_icon.h / 2) - 1) - elif gui.message_mode == 'warning': + elif gui.message_mode == "warning": message_warning_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_info_icon.h / 2) - 1) - elif gui.message_mode == 'done': + elif gui.message_mode == "done": message_tick_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_info_icon.h / 2) - 1) - elif gui.message_mode == 'arrow': + elif gui.message_mode == "arrow": message_arrow_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_info_icon.h / 2) - 1) - elif gui.message_mode == 'download': + elif gui.message_mode == "download": message_download_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_info_icon.h / 2) - 1) - elif gui.message_mode == 'error': + elif gui.message_mode == "error": message_error_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_error_icon.h / 2) - 1) - elif gui.message_mode == 'bubble': + elif gui.message_mode == "bubble": message_bubble_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_bubble_icon.h / 2) - 1) - elif gui.message_mode == 'link': + elif gui.message_mode == "link": message_info_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_bubble_icon.h / 2) - 1) - elif gui.message_mode == 'confirm': + elif gui.message_mode == "confirm": message_info_icon.render(x + 14 * gui.scale, y + int(h / 2) - int(message_info_icon.h / 2) - 1) ddt.text((x + 62 * gui.scale, y + 9 * gui.scale), gui.message_text, colours.message_box_text, 15) if draw.button("Yes", (w // 2 + x) - 70 * gui.scale, y + 32 * gui.scale, w=60*gui.scale): @@ -25432,7 +25432,7 @@ def render(self): if gui.message_subtext: ddt.text((x + 62 * gui.scale, y + 11 * gui.scale), gui.message_text, colours.message_box_text, 15) - if gui.message_mode == "bubble" or gui.message_mode == 'link': + if gui.message_mode == "bubble" or gui.message_mode == "link": link_pa = draw_linked_text((x + 63 * gui.scale, y + (9 + 22) * gui.scale), gui.message_subtext, colours.message_box_text, 12) link_activate(x + 63 * gui.scale, y + (9 + 22) * gui.scale, link_pa) @@ -25599,7 +25599,7 @@ def worker2(): br = 0 - if search_over.searched_text in ('the', 'and'): + if search_over.searched_text in ("the", "and"): continue search_over.sip = True @@ -25632,7 +25632,7 @@ def worker2(): year_mode = True cn_mode = False - if use_cc and re.search(r'[\u4e00-\u9fff\u3400-\u4dbf\u20000-\u2a6df\u2a700-\u2b73f\u2b740-\u2b81f\u2b820-\u2ceaf\uf900-\ufaff\u2f800-\u2fa1f]', o_text): + if use_cc and re.search(r"[\u4e00-\u9fff\u3400-\u4dbf\u20000-\u2a6df\u2a700-\u2b73f\u2b740-\u2b81f\u2b820-\u2ceaf\uf900-\ufaff\u2f800-\u2fa1f]", o_text): t_cn = s2t.convert(o_text) s_cn = t2s.convert(o_text) cn_mode = True @@ -25776,8 +25776,8 @@ def worker2(): if search_magic(s_text, title + artist + filename + album + sartist + album_artist): - if 'artists' in t.misc and t.misc['artists']: - for a in t.misc['artists']: + if "artists" in t.misc and t.misc["artists"]: + for a in t.misc["artists"]: if search_magic(s_text, a.lower()): value = 1 @@ -26011,7 +26011,7 @@ def add_from_cue(path): try: j = False try: - with open(path, encoding='shiftjis') as f: + with open(path, encoding="shiftjis") as f: content = f.readlines() for line in content: for c in j_chars: @@ -26022,7 +26022,7 @@ def add_from_cue(path): except Exception: logging.exception("Failed opening file as shiftjis") if not j: - with open(path, encoding='windows-1251') as f: + with open(path, encoding="windows-1251") as f: content = f.readlines() console.print("-- Fallback encoding read as windows-1251") @@ -26141,7 +26141,7 @@ def add_from_cue(path): if line.endswith("AUDIO"): line = line[:-5] - c = loaded_cue_cache.get((file_path.replace('\\', '/'), int(line.strip()))) + c = loaded_cue_cache.get((file_path.replace("\\", "/"), int(line.strip()))) if c is not None: nt = c else: @@ -26151,7 +26151,7 @@ def add_from_cue(path): nt.fullpath = file_path nt.filename = file_name - nt.parent_folder_path = os.path.dirname(file_path.replace('\\', '/')) + nt.parent_folder_path = os.path.dirname(file_path.replace("\\", "/")) nt.parent_folder_name = os.path.splitext(os.path.basename(file_path))[0] nt.file_ext = os.path.splitext(file_name)[1][1:].upper() nt.is_cue = True @@ -26163,7 +26163,7 @@ def add_from_cue(path): nt.composer = cue_songwriter nt.genre = cue_genre nt.album = cue_album - nt.date = cue_date.replace('"', '') + nt.date = cue_date.replace('"', "") nt.track_number = int(line.strip()) if nt.track_number == 1: nt.size = os.path.getsize(nt.fullpath) @@ -26275,12 +26275,12 @@ def add_file(path, force_scan=False): logging.error("File to import missing") return 0 - if os.path.splitext(path)[1][1:] in {"CUE", 'cue'}: + if os.path.splitext(path)[1][1:] in {"CUE", "cue"}: add_from_cue(path) return 0 - if path.lower().endswith('.xspf'): - logging.info('Found XSPF file at: ' + path) + if path.lower().endswith(".xspf"): + logging.info("Found XSPF file at: " + path) load_xspf(path) return 0 @@ -26296,7 +26296,7 @@ def add_file(path, force_scan=False): if os.path.splitext(path)[1][1:].lower() in Archive_Formats: if not prefs.auto_extract: show_message(_("You attempted to drop an archive."), - _('However the "extract archive" function is not enabled.'), mode='info') + _('However the "extract archive" function is not enabled.'), mode="info") else: type = os.path.splitext(path)[1][1:].lower() split = os.path.splitext(path) @@ -26314,31 +26314,31 @@ def add_file(path, force_scan=False): b = to_got to_got = "ex" gui.update += 1 - zip_ref = zipfile.ZipFile(path, 'r') + zip_ref = zipfile.ZipFile(path, "r") zip_ref.extractall(target_dir) zip_ref.close() except RuntimeError as e: logging.exception("Zip error") to_got = b - if 'encrypted' in e: + if "encrypted" in e: show_message(_("Failed to extract zip archive."), _("The archive is encrypted. You'll need to extract it manually with the password."), - mode='warning') + mode="warning") else: show_message(_("Failed to extract zip archive."), _("Maybe archive is corrupted? Does disk have enough space and have write permission?"), - mode='warning') + mode="warning") return 1 except Exception: logging.exception("Zip error 2") to_got = b show_message(_("Failed to extract zip archive."), _("Maybe archive is corrupted? Does disk have enough space and have write permission?"), - mode='warning') + mode="warning") return 1 - elif type == 'rar': + elif type == "rar": b = to_got try: to_got = "ex" @@ -26350,11 +26350,11 @@ def add_file(path, force_scan=False): except Exception: logging.exception("Failed to extract rar archive.") to_got = b - show_message(_("Failed to extract rar archive."), mode='warning') + show_message(_("Failed to extract rar archive."), mode="warning") return 1 - elif type == '7z': + elif type == "7z": b = to_got try: to_got = "ex" @@ -26366,7 +26366,7 @@ def add_file(path, force_scan=False): except Exception: logging.exception("Failed to extract 7z archive.") to_got = b - show_message(_("Failed to extract 7z archive."), mode='warning') + show_message(_("Failed to extract 7z archive."), mode="warning") return 1 @@ -26394,7 +26394,7 @@ def add_file(path, force_scan=False): send2trash(path) except Exception: logging.exception("Could not move archive to trash") - show_message(_("Could not move archive to trash"), path, mode='info') + show_message(_("Could not move archive to trash"), path, mode="info") to_got = b gets(target_dir) @@ -26406,7 +26406,7 @@ def add_file(path, force_scan=False): to_got += 1 gui.update = 1 - path = path.replace('\\', '/') + path = path.replace("\\", "/") if path in loaded_pathes_cache: de = loaded_pathes_cache[path] @@ -26503,9 +26503,9 @@ def gets(direc, force_scan=False): if snap_mode: show_message(_("Permission error accessing one or more files."), _("If this location is on external media, see https://") + "github.com/Taiko2k/TauonMusicBox/wiki/Snap-Permissions", - mode='bubble') + mode="bubble") else: - show_message(_("Permission error accessing one or more files"), mode='warning') + show_message(_("Permission error accessing one or more files"), mode="warning") return except Exception: @@ -26530,10 +26530,10 @@ def gets(direc, force_scan=False): if len(items_in_dir[q]) > 2 and items_in_dir[q][0:2] == "._": continue - add_file(os.path.join(direc, items_in_dir[q]).replace('\\', '/'), force_scan) + add_file(os.path.join(direc, items_in_dir[q]).replace("\\", "/"), force_scan) - elif os.path.splitext(items_in_dir[q])[1][1:] in {"CUE", 'cue'}: - add_from_cue(os.path.join(direc, items_in_dir[q]).replace('\\', '/')) + elif os.path.splitext(items_in_dir[q])[1][1:] in {"CUE", "cue"}: + add_from_cue(os.path.join(direc, items_in_dir[q]).replace("\\", "/")) if gui.im_cancel: return @@ -26544,9 +26544,9 @@ def cache_paths(): for key, value in pctl.master_library.items(): if value.is_network: continue - dic[value.fullpath.replace('\\', '/')] = key + dic[value.fullpath.replace("\\", "/")] = key if value.is_cue: - dic2[(value.fullpath.replace('\\', '/'), value.track_number)] = value + dic2[(value.fullpath.replace("\\", "/"), value.track_number)] = value return dic, dic2 @@ -26654,7 +26654,7 @@ def cache_paths(): del move_jobs[0] if job[0].strip("\\/") == job[1].strip("\\/"): - show_message(_("Folder copy error."), _("The target and source are the same."), mode='info') + show_message(_("Folder copy error."), _("The target and source are the same."), mode="info") gui.update += 1 move_in_progress = False continue @@ -26665,7 +26665,7 @@ def cache_paths(): logging.exception("Failed to copy directory") move_in_progress = False gui.update += 1 - show_message(_("The folder copy has failed!"), _('Some files may have been written.'), mode='warning') + show_message(_("The folder copy has failed!"), _("Some files may have been written."), mode="warning") continue if job[2] == True: @@ -26674,14 +26674,14 @@ def cache_paths(): except Exception: logging.exception("Failed to delete directory") - show_message(_("Something has gone horribly wrong!"), _("Could not delete {name}").format(name=job[0]), mode='error') + show_message(_("Something has gone horribly wrong!"), _("Could not delete {name}").format(name=job[0]), mode="error") gui.update += 1 move_in_progress = False return - show_message(_("Folder move complete."), _("Folder name: {name}").format(name=job[3]), mode='done') + show_message(_("Folder move complete."), _("Folder name: {name}").format(name=job[3]), mode="done") else: - show_message(_("Folder copy complete."), _("Folder name: {name}").format(name=job[3]), mode='done') + show_message(_("Folder copy complete."), _("Folder name: {name}").format(name=job[3]), mode="done") move_in_progress = False load_orders.append(job[4]) @@ -26728,7 +26728,7 @@ def cache_paths(): cm_clean_db = False show_message(_("Cleaning complete."), _("{N} items were removed from the database.") - .format(N=str(items_removed)), mode='done') + .format(N=str(items_removed)), mode="done") if album_mode: reload_albums(True) if gui.combo_mode: @@ -26775,8 +26775,8 @@ def cache_paths(): # Create new empty folder to output tracks to os.makedirs(prefs.encoder_output + folder_name) - full_wav_out_p = prefs.encoder_output + 'output.wav' - full_target_out_p = prefs.encoder_output + 'output.' + prefs.transcode_codec + full_wav_out_p = prefs.encoder_output + "output.wav" + full_target_out_p = prefs.encoder_output + "output." + prefs.transcode_codec if os.path.isfile(full_wav_out_p): os.remove(full_wav_out_p) if os.path.isfile(full_target_out_p): @@ -26786,7 +26786,7 @@ def cache_paths(): if not os.path.isdir(cache_dir): os.makedirs(cache_dir) - if prefs.transcode_codec in ('opus', 'ogg', 'flac', 'mp3'): + if prefs.transcode_codec in ("opus", "ogg", "flac", "mp3"): global core_use cores = os.cpu_count() @@ -26841,7 +26841,7 @@ def cache_paths(): logging.exception("Transcode failed") transcode_state = "Transcode Error" time.sleep(0.2) - show_message(_("Transcode failed."), _("An error was encountered."), mode='error') + show_message(_("Transcode failed."), _("An error was encountered."), mode="error") gui.update += 1 time.sleep(0.1) del transcode_list[0] @@ -26850,15 +26850,15 @@ def cache_paths(): if gui.tc_cancel: gui.tc_cancel = False show_message(_("The transcode was canceled before completion."), _("Incomplete files will remain."), - mode='warning') + mode="warning") else: line = _("Press F9 to show output.") - if prefs.transcode_codec == 'flac': + if prefs.transcode_codec == "flac": line = _("Note that any associated output picture is a thumbnail and not an exact copy.") if not gui.sync_progress: if not gui.message_box: - show_message(_("Encoding complete."), line, mode='done') - if system == 'linux' and de_notify_support: + show_message(_("Encoding complete."), line, mode="done") + if system == "linux" and de_notify_support: g_tc_notify.show() if to_scan: @@ -27055,7 +27055,7 @@ def gen_power2(): tags = {} # [tag name]: (first position, number of times we saw it) tag_list = [] - last = 'a' + last = "a" noise = 0 def key(tag): @@ -27215,12 +27215,12 @@ def reload_albums(quiet=False, return_playlist=-1, custom_list=None): def star_line_toggle(mode=0): if mode == 1: - return gui.star_mode == 'line' + return gui.star_mode == "line" - if gui.star_mode == 'line': - gui.star_mode = 'none' + if gui.star_mode == "line": + gui.star_mode = "none" else: - gui.star_mode = 'line' + gui.star_mode = "line" gui.show_ratings = False @@ -27236,12 +27236,12 @@ def star_toggle(mode=0): else: if mode == 1: - return gui.star_mode == 'star' + return gui.star_mode == "star" - if gui.star_mode == 'star': - gui.star_mode = 'none' + if gui.star_mode == "star": + gui.star_mode = "none" else: - gui.star_mode = 'star' + gui.star_mode = "star" # gui.show_ratings = False gui.update += 1 @@ -27277,7 +27277,7 @@ def rating_toggle(mode=0): if gui.show_ratings: # gui.show_hearts = False - gui.star_mode = 'none' + gui.star_mode = "none" prefs.rating_playtime_stars = True if not prefs.write_ratings: show_message(_("Note that ratings are stored in the local database and not written to tags.")) @@ -27477,7 +27477,7 @@ def toggle_enable_web(mode=0): args=[pctl, prefs, gui, album_art_gen, install_directory, strings, tauon]) webThread.daemon = True webThread.start() - show_message(_("Web server starting"), _("External connections will be accepted."), mode='done') + show_message(_("Web server starting"), _("External connections will be accepted."), mode="done") elif prefs.enable_web is False: if tauon.radio_server is not None: @@ -27498,7 +27498,7 @@ def toggle_lfm_auto(mode=0): return prefs.auto_lfm prefs.auto_lfm ^= True if prefs.auto_lfm and not last_fm_enable: - show_message(_("Optional module python-pylast not installed"), mode='warning') + show_message(_("Optional module python-pylast not installed"), mode="warning") prefs.auto_lfm = False # if prefs.auto_lfm: # lastfm.hold = False @@ -27510,7 +27510,7 @@ def toggle_lb(mode=0): if mode == 1: return lb.enable if not lb.enable and not prefs.lb_token: - show_message(_("Can't enable this if there's no token."), mode='warning') + show_message(_("Can't enable this if there's no token."), mode="warning") return lb.enable ^= True @@ -27519,7 +27519,7 @@ def toggle_maloja(mode=0): if mode == 1: return prefs.maloja_enable if not prefs.maloja_url or not prefs.maloja_key: - show_message(_("One or more fields is missing."), mode='warning') + show_message(_("One or more fields is missing."), mode="warning") return prefs.maloja_enable ^= True @@ -27574,38 +27574,38 @@ def toggle_guitar_chords(mode=0): def switch_single(mode=0): if mode == 1: - if prefs.transcode_mode == 'single': + if prefs.transcode_mode == "single": return True else: return False - prefs.transcode_mode = 'single' + prefs.transcode_mode = "single" def switch_mp3(mode=0): if mode == 1: - if prefs.transcode_codec == 'mp3': + if prefs.transcode_codec == "mp3": return True else: return False - prefs.transcode_codec = 'mp3' + prefs.transcode_codec = "mp3" def switch_ogg(mode=0): if mode == 1: - if prefs.transcode_codec == 'ogg': + if prefs.transcode_codec == "ogg": return True else: return False - prefs.transcode_codec = 'ogg' + prefs.transcode_codec = "ogg" def switch_opus(mode=0): if mode == 1: - if prefs.transcode_codec == 'opus': + if prefs.transcode_codec == "opus": return True else: return False - prefs.transcode_codec = 'opus' + prefs.transcode_codec = "opus" def switch_opus_ogg(mode=0): @@ -27629,7 +27629,7 @@ def toggle_transcode_output(mode=0): show_message( _("DANGER! This will delete the original files. Keeping a backup is recommended in case of malfunction."), _("For safety, this setting will default to off. Embedded thumbnails are not kept so you may want to extract them first."), - mode='warning') + mode="warning") else: transcode_icon.colour = [239, 74, 157, 255] @@ -27651,18 +27651,18 @@ def toggle_transcode_inplace(mode=0): show_message( _("DANGER! This will delete the original files. Keeping a backup is recommended in case of malfunction."), _("For safety, this setting will reset on restart. Embedded thumbnails are not kept so you may want to extract them first."), - mode='warning') + mode="warning") else: transcode_icon.colour = [239, 74, 157, 255] def switch_flac(mode=0): if mode == 1: - if prefs.transcode_codec == 'flac': + if prefs.transcode_codec == "flac": return True else: return False - prefs.transcode_codec = 'flac' + prefs.transcode_codec = "flac" def toggle_sbt(mode=0): @@ -27737,7 +27737,7 @@ def toggle_eq(mode=0): if mode == 1: return prefs.use_eq prefs.use_eq ^= True - pctl.playerCommand = 'seteq' + pctl.playerCommand = "seteq" pctl.playerCommandReady = True @@ -27769,7 +27769,7 @@ def reload_backend(): pctl.playerCommandReady = True wait = 0 - while pctl.playerCommand != 'done': + while pctl.playerCommand != "done": time.sleep(0.01) wait += 1 if wait > 200: @@ -27812,7 +27812,7 @@ def gen_chart(): except Exception: logging.exception("There was an error generating the chart") gui.generating_chart = False - show_message(_("There was an error generating the chart"), _("Sorry!"), mode='error') + show_message(_("There was an error generating the chart"), _("Sorry!"), mode="error") return gui.generating_chart = False @@ -27820,10 +27820,10 @@ def gen_chart(): if path: open_file(path) else: - show_message(_("There was an error generating the chart"), _("Sorry!"), mode='error') + show_message(_("There was an error generating the chart"), _("Sorry!"), mode="error") return - show_message(_("Chart generated"), mode='done') + show_message(_("Chart generated"), mode="done") class Over: @@ -27833,12 +27833,12 @@ def __init__(self): self.init2done = False - self.about_image = asset_loader('v4-a.png') - self.about_image2 = asset_loader('v4-b.png') - self.about_image3 = asset_loader('v4-c.png') - self.about_image4 = asset_loader('v4-d.png') - self.about_image5 = asset_loader('v4-e.png') - self.about_image6 = asset_loader('v4-f.png') + self.about_image = asset_loader("v4-a.png") + self.about_image2 = asset_loader("v4-b.png") + self.about_image3 = asset_loader("v4-c.png") + self.about_image4 = asset_loader("v4-d.png") + self.about_image5 = asset_loader("v4-e.png") + self.about_image6 = asset_loader("v4-f.png") self.title_image = asset_loader("title.png", True) # self.tab_width = round(115 * gui.scale) @@ -27849,7 +27849,7 @@ def __init__(self): self.box_y = 100 self.item_x_offset = round(25 * gui.scale) - self.current_path = os.path.expanduser('~') + self.current_path = os.path.expanduser("~") self.view_offset = 0 self.ext_ratio = {} self.last_db_size = -1 @@ -28178,12 +28178,12 @@ def eq(self, x0, y0, w0, h0): prefs.eq[i] = target - pctl.playerCommand = 'seteq' + pctl.playerCommand = "seteq" pctl.playerCommandReady = True if self.right_click: prefs.eq[i] = 0 - pctl.playerCommand = 'seteq' + pctl.playerCommand = "seteq" pctl.playerCommandReady = True start = (q / range) * center @@ -28277,7 +28277,7 @@ def audio(self, x0, y0, w0, h0): old = prefs.avoid_resampling prefs.avoid_resampling = self.toggle_square(x, self.box_y + self.h - 27 * gui.scale, prefs.avoid_resampling, _("Avoid resampling")) if prefs.avoid_resampling != old: - pctl.playerCommand = 'reload' + pctl.playerCommand = "reload" pctl.playerCommandReady = True if not old: show_message(_("Tip: To get samplerate to DAC you may need to check some settings, see:"), @@ -28330,7 +28330,7 @@ def audio(self, x0, y0, w0, h0): def reload_device(self, _): - pctl.playerCommand = 'reload' + pctl.playerCommand = "reload" pctl.playerCommandReady = True def toggle_lyrics_view(self): @@ -28847,7 +28847,7 @@ def last_fm_box(self, x0, y0, w0, h0): y = y0 + round(20 * gui.scale) if self.account_view == 12: - ddt.text((x, y), 'TIDAL', colours.box_sub_text, 213) + ddt.text((x, y), "TIDAL", colours.box_sub_text, 213) y += round(30 * gui.scale) @@ -28886,7 +28886,7 @@ def last_fm_box(self, x0, y0, w0, h0): shooter(tidal.fav_tracks) if self.account_view == 11: - ddt.text((x, y), 'Tauon Satellite', colours.box_sub_text, 213) + ddt.text((x, y), "Tauon Satellite", colours.box_sub_text, 213) y += round(30 * gui.scale) @@ -28930,7 +28930,7 @@ def last_fm_box(self, x0, y0, w0, h0): elif self.account_view == 9: - ddt.text((x, y), _('Maloja Server'), colours.box_sub_text, 213) + ddt.text((x, y), _("Maloja Server"), colours.box_sub_text, 213) if self.button(x + 260 * gui.scale, y, _("?")): show_message(_("Maloja is a self-hosted scrobble server."), _("See here to learn more: {link}").format(link="https://github.com/krateng/maloja"), mode="link") @@ -28985,16 +28985,16 @@ def last_fm_box(self, x0, y0, w0, h0): url += "/test" try: - r = requests.get(url, params={'key': prefs.maloja_key}) + r = requests.get(url, params={"key": prefs.maloja_key}) if r.status_code == 403: - show_message(_("Connection appeared successful but the API key was invalid"), mode='warning') + show_message(_("Connection appeared successful but the API key was invalid"), mode="warning") elif r.status_code == 200: - show_message(_("Connection to Maloja server was successful."), mode='done') + show_message(_("Connection to Maloja server was successful."), mode="done") else: - show_message(_("The Maloja server returned an error"), r.text, mode='warning') + show_message(_("The Maloja server returned an error"), r.text, mode="warning") except Exception: logging.exception("Could not communicate with the Maloja server") - show_message(_("Could not communicate with the Maloja server"), mode='warning') + show_message(_("Could not communicate with the Maloja server"), mode="warning") y += round(30 * gui.scale) @@ -29006,7 +29006,7 @@ def last_fm_box(self, x0, y0, w0, h0): if self.account_view == 8: - ddt.text((x, y), 'Spotify', colours.box_sub_text, 213) + ddt.text((x, y), "Spotify", colours.box_sub_text, 213) prefs.spot_mode = self.toggle_square(x + 80 * gui.scale, y + 2 * gui.scale, prefs.spot_mode, _("Enable")) y += round(30 * gui.scale) @@ -29112,7 +29112,7 @@ def last_fm_box(self, x0, y0, w0, h0): if self.account_view == 7: - ddt.text((x, y), _('Airsonic/Subsonic network streaming'), colours.box_sub_text, 213) + ddt.text((x, y), _("Airsonic/Subsonic network streaming"), colours.box_sub_text, 213) if inp.key_tab_press: self.account_text_field += 1 @@ -29173,7 +29173,7 @@ def last_fm_box(self, x0, y0, w0, h0): if self.account_view == 10: - ddt.text((x, y), _('Jellyfin network streaming'), colours.box_sub_text, 213) + ddt.text((x, y), _("Jellyfin network streaming"), colours.box_sub_text, 213) if inp.key_tab_press: self.account_text_field += 1 @@ -29246,7 +29246,7 @@ def last_fm_box(self, x0, y0, w0, h0): if self.account_view == 6: - ddt.text((x, y), _('koel network streaming'), colours.box_sub_text, 213) + ddt.text((x, y), _("koel network streaming"), colours.box_sub_text, 213) if inp.key_tab_press: self.account_text_field += 1 @@ -29303,7 +29303,7 @@ def last_fm_box(self, x0, y0, w0, h0): if self.account_view == 5: - ddt.text((x, y), _('PLEX network streaming'), colours.box_sub_text, 213) + ddt.text((x, y), _("PLEX network streaming"), colours.box_sub_text, 213) if inp.key_tab_press: self.account_text_field += 1 @@ -29359,7 +29359,7 @@ def last_fm_box(self, x0, y0, w0, h0): if self.account_view == 4: - ddt.text((x, y), 'fanart.tv', colours.box_sub_text, 213) + ddt.text((x, y), "fanart.tv", colours.box_sub_text, 213) y += 25 * gui.scale ddt.text((x + 0 * gui.scale, y, 4, 270 * gui.scale, 600), @@ -29536,7 +29536,7 @@ def last_fm_box(self, x0, y0, w0, h0): if self.account_view == 2: - ddt.text((x, y), 'ListenBrainz', colours.box_sub_text, 213) + ddt.text((x, y), "ListenBrainz", colours.box_sub_text, 213) y += 30 * gui.scale self.button(x, y, _("Paste Token"), lb.paste_key) @@ -29567,7 +29567,7 @@ def clear_local_loves(self): if not key_shift_down: show_message(_("This will mark all tracks in local database as unloved!"), _("Press button again while holding shift key if you're sure you want to do that."), - mode='warning') + mode="warning") return for key, star in star_store.db.items(): @@ -29733,7 +29733,7 @@ def codec_config(self, x0, y0, w0, h0): self.toggle_square(x, y, switch_flac, "FLAC") y += 25 * gui.scale self.toggle_square(x, y, switch_opus, "OPUS") - if prefs.transcode_codec == 'opus': + if prefs.transcode_codec == "opus": self.toggle_square(x + 120 * gui.scale, y, switch_opus_ogg, _("Save opus as .ogg extension")) y += 25 * gui.scale self.toggle_square(x, y, switch_ogg, "OGG Vorbis") @@ -29744,7 +29744,7 @@ def codec_config(self, x0, y0, w0, h0): # if prefs.transcode_codec == 'mp3' and not shutil.which("lame"): # ddt.draw_text((x + 90 * gui.scale, y - 3 * gui.scale), "LAME not detected!", [220, 110, 110, 255], 12) - if prefs.transcode_codec != 'flac': + if prefs.transcode_codec != "flac": y += 35 * gui.scale prefs.transcode_bitrate = self.slide_control(x, y, _("Bitrate"), "kbs", prefs.transcode_bitrate, 32, 320, 8) @@ -29885,7 +29885,7 @@ def config_b(self, x0, y0, w0, h0): old = x11 x11 = self.toggle_square(x, y, x11, _("Prefer x11 when running in Wayland")) if old is False and x11 is True: - with open(x11_path, 'a'): + with open(x11_path, "a"): pass elif old is True and x11 is False: os.remove(x11_path) @@ -29910,15 +29910,15 @@ def about(self, x0, y0, w0, h0): if pctl.playing_object() is not None: genre = pctl.playing_object().genre.lower() - if any(s in genre for s in ['ock', 'lt']): + if any(s in genre for s in ["ock", "lt"]): self.about_image2.render(icon_rect[0], icon_rect[1]) - elif any(s in genre for s in ['kpop', 'k-pop', 'anime']): + elif any(s in genre for s in ["kpop", "k-pop", "anime"]): self.about_image6.render(icon_rect[0], icon_rect[1]) - elif any(s in genre for s in ['syn', 'pop']): + elif any(s in genre for s in ["syn", "pop"]): self.about_image3.render(icon_rect[0], icon_rect[1]) - elif any(s in genre for s in ['tro', 'cid']): + elif any(s in genre for s in ["tro", "cid"]): self.about_image4.render(icon_rect[0], icon_rect[1]) - elif any(s in genre for s in ['uture']): + elif any(s in genre for s in ["uture"]): self.about_image5.render(icon_rect[0], icon_rect[1]) else: genre = "" @@ -30216,28 +30216,28 @@ def topchart(self, x0, y0, w0, h0): if prefs.chart_cascade: if prefs.chart_d1: - prefs.chart_c1 = self.slide_control(x, y, _("Level 1"), '', prefs.chart_c1, 2, 20, 1, width=35) + prefs.chart_c1 = self.slide_control(x, y, _("Level 1"), "", prefs.chart_c1, 2, 20, 1, width=35) y += 22 * gui.scale if prefs.chart_d2: - prefs.chart_c2 = self.slide_control(x, y, _("Level 2"), '', prefs.chart_c2, 2, 20, 1, width=35) + prefs.chart_c2 = self.slide_control(x, y, _("Level 2"), "", prefs.chart_c2, 2, 20, 1, width=35) y += 22 * gui.scale if prefs.chart_d3: - prefs.chart_c3 = self.slide_control(x, y, _("Level 3"), '', prefs.chart_c3, 2, 20, 1, width=35) + prefs.chart_c3 = self.slide_control(x, y, _("Level 3"), "", prefs.chart_c3, 2, 20, 1, width=35) y -= 44 * gui.scale x += 133 * gui.scale - prefs.chart_d1 = self.slide_control(x, y, _("by"), '', prefs.chart_d1, 0, 10, 1, width=35) + prefs.chart_d1 = self.slide_control(x, y, _("by"), "", prefs.chart_d1, 0, 10, 1, width=35) y += 22 * gui.scale - prefs.chart_d2 = self.slide_control(x, y, _("by"), '', prefs.chart_d2, 0, 10, 1, width=35) + prefs.chart_d2 = self.slide_control(x, y, _("by"), "", prefs.chart_d2, 0, 10, 1, width=35) y += 22 * gui.scale - prefs.chart_d3 = self.slide_control(x, y, _("by"), '', prefs.chart_d3, 0, 10, 1, width=35) + prefs.chart_d3 = self.slide_control(x, y, _("by"), "", prefs.chart_d3, 0, 10, 1, width=35) x -= 133 * gui.scale else: - prefs.chart_rows = self.slide_control(x, y, _("Rows"), '', prefs.chart_rows, 1, 100, 1, width=35) + prefs.chart_rows = self.slide_control(x, y, _("Rows"), "", prefs.chart_rows, 1, 100, 1, width=35) y += 22 * gui.scale - prefs.chart_columns = self.slide_control(x, y, _("Columns"), '', prefs.chart_columns, 1, 100, 1, width=35) + prefs.chart_columns = self.slide_control(x, y, _("Columns"), "", prefs.chart_columns, 1, 100, 1, width=35) y += 22 * gui.scale y += 35 * gui.scale @@ -30299,7 +30299,7 @@ def topchart(self, x0, y0, w0, h0): show_message(_("Be patient!")) else: if not prefs.chart_font: - show_message(_("No font set in config"), mode='error') + show_message(_("No font set in config"), mode="error") else: shoot = threading.Thread(target=gen_chart) shoot.daemon = True @@ -30341,7 +30341,7 @@ def stats(self, x0, y0, w0, h0): return ww = ddt.get_text_w(_("Chart generator..."), 211) + 30 * gui.scale - if system == 'linux' and self.button(x0 + w0 - ww, y + 15 * gui.scale, _("Chart generator...")): + if system == "linux" and self.button(x0 + w0 - ww, y + 15 * gui.scale, _("Chart generator...")): self.chart_view = 1 ddt.text_background_colour = colours.box_background @@ -30389,7 +30389,7 @@ def stats(self, x0, y0, w0, h0): line = seconds_to_day_hms(self.stats_pl_length, strings.day, strings.days) ddt.text((x1, y1), _("Tracks in playlist"), lt_colour, lt_font) - ddt.text((x2, y1), py_locale.format_string('%d', len(default_playlist), True), colours.box_sub_text, 12) + ddt.text((x2, y1), py_locale.format_string("%d", len(default_playlist), True), colours.box_sub_text, 12) y1 += 20 * gui.scale ddt.text((x1, y1), _("Albums in playlist"), lt_colour, lt_font) ddt.text((x2, y1), str(self.stats_pl_albums), colours.box_sub_text, 12) @@ -30423,7 +30423,7 @@ def stats(self, x0, y0, w0, h0): y1 += 40 * gui.scale ddt.text((x1, y1), _("Tracks in database"), lt_colour, lt_font) - ddt.text((x2, y1), py_locale.format_string('%d', len(pctl.master_library), True), colours.box_sub_text, 12) + ddt.text((x2, y1), py_locale.format_string("%d", len(pctl.master_library), True), colours.box_sub_text, 12) y1 += 20 * gui.scale ddt.text((x1, y1), _("Total albums"), lt_colour, lt_font) ddt.text((x2, y1), str(self.total_albums), colours.box_sub_text, 12) @@ -30490,9 +30490,9 @@ def config_v(self, x0, y0, w0, h0): x = x0 + self.item_x_offset y = y0 + 17 * gui.scale - self.toggle_square(x, y, rating_toggle, _('Track ratings')) + self.toggle_square(x, y, rating_toggle, _("Track ratings")) y += round(25 * gui.scale) - self.toggle_square(x, y, album_rating_toggle, _('Album ratings')) + self.toggle_square(x, y, album_rating_toggle, _("Album ratings")) y += round(35 * gui.scale) self.toggle_square(x, y, heart_toggle, " ") @@ -30535,20 +30535,20 @@ def config_v(self, x0, y0, w0, h0): y += round(25 * gui.scale) - if self.toggle_square(x, y, prefs.row_title_format == 2, _('Left align title style')): + if self.toggle_square(x, y, prefs.row_title_format == 2, _("Left align title style")): prefs.row_title_format = 2 else: prefs.row_title_format = 1 y += round(25 * gui.scale) - prefs.row_title_genre = self.toggle_square(x + round(10 * gui.scale), y, prefs.row_title_genre, _('Show album genre')) + prefs.row_title_genre = self.toggle_square(x + round(10 * gui.scale), y, prefs.row_title_genre, _("Show album genre")) y += round(25 * gui.scale) - self.toggle_square(x, y, toggle_append_date, _('Show album release year')) + self.toggle_square(x, y, toggle_append_date, _("Show album release year")) y += round(25 * gui.scale) - self.toggle_square(x, y, toggle_append_total_time, _('Show album duration')) + self.toggle_square(x, y, toggle_append_total_time, _("Show album duration")) y += round(35 * gui.scale) if self.toggle_square(x, y, prefs.row_title_separator_type == 0, " - "): @@ -30577,26 +30577,26 @@ def config_v(self, x0, y0, w0, h0): def set_playlist_cycle(self, mode=0): if mode == 1: return True if prefs.end_setting == "cycle" else False - prefs.end_setting = 'cycle' + prefs.end_setting = "cycle" # global pl_follow # pl_follow = False def set_playlist_advance(self, mode=0): if mode == 1: return True if prefs.end_setting == "advance" else False - prefs.end_setting = 'advance' + prefs.end_setting = "advance" # global pl_follow # pl_follow = False def set_playlist_stop(self, mode=0): if mode == 1: return True if prefs.end_setting == "stop" else False - prefs.end_setting = 'stop' + prefs.end_setting = "stop" def set_playlist_repeat(self, mode=0): if mode == 1: return True if prefs.end_setting == "repeat" else False - prefs.end_setting = 'repeat' + prefs.end_setting = "repeat" def small_preset(self): @@ -30959,16 +30959,16 @@ def __init__(self): self.index_playing = -1 self.drag_zone_start_x = 300 * gui.scale - self.exit_button = asset_loader('ex.png', True) - self.maximize_button = asset_loader('max.png', True) - self.restore_button = asset_loader('restore.png', True) - self.restore_button = asset_loader('restore.png', True) - self.playlist_icon = asset_loader('playlist.png', True) - self.return_icon = asset_loader('return.png', True) - self.artist_list_icon = asset_loader('artist-list.png', True) - self.folder_list_icon = asset_loader('folder-list.png', True) - self.dl_button = asset_loader('dl.png', True) - self.overflow_icon = asset_loader('overflow.png', True) + self.exit_button = asset_loader("ex.png", True) + self.maximize_button = asset_loader("max.png", True) + self.restore_button = asset_loader("restore.png", True) + self.restore_button = asset_loader("restore.png", True) + self.playlist_icon = asset_loader("playlist.png", True) + self.return_icon = asset_loader("return.png", True) + self.artist_list_icon = asset_loader("artist-list.png", True) + self.folder_list_icon = asset_loader("folder-list.png", True) + self.dl_button = asset_loader("dl.png", True) + self.overflow_icon = asset_loader("overflow.png", True) self.drag_slide_timer = Timer(100) self.tab_d_click_timer = Timer(10) @@ -31600,7 +31600,7 @@ def render(self): ay = y + 4 ay -= 6 * self.adds[k][2].get() / 0.3 - ddt.text((x + tab_width - 3, int(round(ay)), 1), '+' + str(self.adds[k][1]), + ddt.text((x + tab_width - 3, int(round(ay)), 1), "+" + str(self.adds[k][1]), colours.pluse_colour, 212, bg=bg) gui.update += 1 @@ -31738,7 +31738,7 @@ def render(self): if inp.mouse_click: inp.mouse_click = False show_message(_("It looks like something is being downloaded..."), _("Let's check back later..."), - mode='info') + mode="info") else: @@ -31763,11 +31763,11 @@ def render(self): if loading_in_progress: bg = colours.status_info_text - if to_got == 'xspf': + if to_got == "xspf": text = _("Importing XSPF playlist") - elif to_got == 'xspfl': + elif to_got == "xspfl": text = _("Importing XSPF playlist...") - elif to_got == 'ex': + elif to_got == "ex": text = _("Extracting Archive...") else: text = _("Importing... ") + str(to_got) # + "/" + str(to_get) @@ -31938,15 +31938,15 @@ def __init__(self): self.volume_bar_size = [135 * gui.scale, 14 * gui.scale] self.volume_bar_position = [0, 45 * gui.scale] - self.play_button = asset_loader('play.png', True) - self.forward_button = asset_loader('ff.png', True) - self.back_button = asset_loader('bb.png', True) - self.repeat_button = asset_loader('tauon_repeat.png', True) - self.repeat_button_off = asset_loader('tauon_repeat_off.png', True) - self.shuffle_button_off = asset_loader('tauon_shuffle_off.png', True) - self.shuffle_button = asset_loader('tauon_shuffle.png', True) - self.repeat_button_a = asset_loader('tauon_repeat_a.png', True) - self.shuffle_button_a = asset_loader('tauon_shuffle_a.png', True) + self.play_button = asset_loader("play.png", True) + self.forward_button = asset_loader("ff.png", True) + self.back_button = asset_loader("bb.png", True) + self.repeat_button = asset_loader("tauon_repeat.png", True) + self.repeat_button_off = asset_loader("tauon_repeat_off.png", True) + self.shuffle_button_off = asset_loader("tauon_shuffle_off.png", True) + self.shuffle_button = asset_loader("tauon_shuffle.png", True) + self.repeat_button_a = asset_loader("tauon_repeat_a.png", True) + self.shuffle_button_a = asset_loader("tauon_shuffle_a.png", True) self.buffer_shard = asset_loader("shard.png", True) @@ -32370,7 +32370,7 @@ def render(self): text_time = get_display_time(pctl.playing_length - pctl.playing_time) ddt.text((x + 1 * gui.scale, y), text_time, colours.time_playing, fonts.bottom_panel_time) - ddt.text((x - 5 * gui.scale, y), '-', colours.time_playing, + ddt.text((x - 5 * gui.scale, y), "-", colours.time_playing, fonts.bottom_panel_time) elif gui.display_time_mode == 2: @@ -32789,9 +32789,9 @@ def __init__(self): self.volume_bar_size = [135 * gui.scale, 14 * gui.scale] self.volume_bar_position = [0, 45 * gui.scale] - self.play_button = asset_loader('play.png', True) - self.forward_button = asset_loader('ff.png', True) - self.back_button = asset_loader('bb.png', True) + self.play_button = asset_loader("play.png", True) + self.forward_button = asset_loader("ff.png", True) + self.back_button = asset_loader("bb.png", True) self.scrob_stick = 0 @@ -32968,7 +32968,7 @@ def render(self): text_time = get_display_time(pctl.playing_length - pctl.playing_time) ddt.text((x + 1 * gui.scale, y), text_time, colours.time_playing, fonts.bottom_panel_time) - ddt.text((x - 5 * gui.scale, y), '-', colours.time_playing, + ddt.text((x - 5 * gui.scale, y), "-", colours.time_playing, fonts.bottom_panel_time) elif gui.display_time_mode == 2: @@ -33955,7 +33955,7 @@ def restore_full_mode(): gui.update_layout() if prefs.art_bg: - tm.ready('style') + tm.ready("style") def line_render(n_track, p_track, y, this_line_playing, album_fade, start_x, width, style=1, ry=None): @@ -34040,7 +34040,7 @@ def line_render(n_track, p_track, y, this_line_playing, album_fade, start_x, wid star_x = 0 total = star_store.get(index) - if gui.star_mode == 'line' and total > 0 and pctl.master_library[index].length > 0: + if gui.star_mode == "line" and total > 0 and pctl.master_library[index].length > 0: ratio = total / pctl.master_library[index].length if ratio > 0.55: @@ -34076,7 +34076,7 @@ def line_render(n_track, p_track, y, this_line_playing, album_fade, start_x, wid star_x += round(70 * gui.scale) - if gui.star_mode == 'star' and total > 0 and pctl.master_library[ + if gui.star_mode == "star" and total > 0 and pctl.master_library[ index].length != 0: sx = width + start_x - 40 * gui.scale - offset_font_extra @@ -34167,7 +34167,7 @@ def line_render(n_track, p_track, y, this_line_playing, album_fade, start_x, wid for name in pctl.master_library[index].lfm_friend_likes: # Limit to number of hears to display - if gui.star_mode == 'none': + if gui.star_mode == "none": if count > 6: break else: @@ -34204,7 +34204,7 @@ def line_render(n_track, p_track, y, this_line_playing, album_fade, start_x, wid if display_queue: li = str(marks[0] + 1) - if li == '1': + if li == "1": li = "N" # if item[0] == n_track.index and item[1] == p_track and item[2] == pctl.active_playlist_viewing if pctl.playing_ready() and n_track.index == pctl.track_queue[ @@ -34672,7 +34672,7 @@ def full_render(self): ref.append(default_playlist[item]) for item in shift_selection: - default_playlist[item] = 'old' + default_playlist[item] = "old" for item in shift_selection: if move_on_title: @@ -34681,11 +34681,11 @@ def full_render(self): default_playlist.insert(track_position + 1, "new") for b in reversed(range(len(default_playlist))): - if default_playlist[b] == 'old': + if default_playlist[b] == "old": del default_playlist[b] shift_selection = [] for b in range(len(default_playlist)): - if default_playlist[b] == 'new': + if default_playlist[b] == "new": shift_selection.append(b) default_playlist[b] = ref.pop(0) @@ -35071,7 +35071,7 @@ def full_render(self): total = star_store.get_by_object(n_track) if total > 0 and n_track.length != 0 and wid > 0: - if gui.star_mode == 'star': + if gui.star_mode == "star": star = star_count(total, n_track.length) - 1 rr = 0 @@ -35205,7 +35205,7 @@ def full_render(self): elif item[0] == "Lyrics": text = "" if n_track.lyrics != "": - text = 'Y' + text = "Y" colour = colours.index_text norm_colour = colour if this_line_playing is True: @@ -35213,7 +35213,7 @@ def full_render(self): elif item[0] == "CUE": text = "" if n_track.is_cue: - text = 'Y' + text = "Y" colour = colours.index_text norm_colour = colour if this_line_playing is True: @@ -35742,7 +35742,7 @@ def search_title(self, text): self.search_radio_browser("/json/stations/search?order=votes&limit=250&reverse=true&name=" + text) def is_m3u(self, url): - return url.lower().endswith('.m3u') or url.lower().endswith('.m3u8') + return url.lower().endswith(".m3u") or url.lower().endswith(".m3u8") def extract_stream_m3u(self, url, recursion_limit=5): if recursion_limit <= 0: @@ -35756,11 +35756,11 @@ def extract_stream_m3u(self, url, recursion_limit=5): return None content = response.text - lines = content.strip().split('\n') + lines = content.strip().split("\n") for line in lines: line = line.strip() - if not line.startswith('#') and len(line) > 0: + if not line.startswith("#") and len(line) > 0: if self.is_m3u(line): next_url = urllib.parse.urljoin(url, line) return self.extract_stream_m3u(next_url, recursion_limit - 1) @@ -36001,7 +36001,7 @@ def browser_get_hosts(self): """ hosts = [] # get all hosts from DNS - ips = socket.getaddrinfo('all.api.radio-browser.info', + ips = socket.getaddrinfo("all.api.radio-browser.info", 80, 0, 0, socket.IPPROTO_TCP) for ip_tupple in ips: try: @@ -36136,8 +36136,8 @@ def search_radio_browser2(self, param): uri = self.host + param req = urllib.request.Request(uri) - req.add_header('User-Agent', t_agent) - req.add_header('Content-Type', 'application/json') + req.add_header("User-Agent", t_agent) + req.add_header("Content-Type", "application/json") response = urllib.request.urlopen(req, cafile=tauon.ca) data = response.read() data = json.loads(data.decode()) @@ -36849,9 +36849,9 @@ def __init__(self): self.indicate_w = round(2 * gui.scale) - self.lock_icon = asset_loader('lock-corner.png', True) - self.pin_icon = asset_loader('dia-pin.png', True) - self.gen_icon = asset_loader('gen-gear.png', True) + self.lock_icon = asset_loader("lock-corner.png", True) + self.pin_icon = asset_loader("dia-pin.png", True) + self.gen_icon = asset_loader("gen-gear.png", True) self.spot_icon = asset_loader("spot-playlist.png", True) @@ -37157,7 +37157,7 @@ def draw(self, x, y, w, h): ay -= 6 * gui.scale * self.adds[k][2].get() / 0.3 ddt.text((tab_start + tab_width - 10 * gui.scale, int(round(ay)), 1), - '+' + str(self.adds[k][1]), colours.pluse_colour, 212, bg=real_bg) + "+" + str(self.adds[k][1]), colours.pluse_colour, 212, bg=real_bg) gui.update += 1 ddt.rect((tab_start + tab_width, yy, self.indicate_w, self.tab_h - self.indicate_w), @@ -37302,8 +37302,8 @@ def toggle_artist_list_threshold_deco(): else: save = artist_list_box.saves.get(pctl.multi_playlist[pctl.active_playlist_viewing][6]) if save and save[5] == 0: - return [colours.menu_text_disabled, colours.menu_background, _('Include All Artists')] - return [colours.menu_text, colours.menu_background, _('Include All Artists')] + return [colours.menu_text_disabled, colours.menu_background, _("Include All Artists")] + return [colours.menu_text, colours.menu_background, _("Include All Artists")] artist_list_menu.add_to_sub(0, MenuItem(_("Sort Alphabetically"), aa_sort_alpha)) artist_list_menu.add_to_sub(0, MenuItem(_("Sort by Popularity"), aa_sort_popular)) @@ -37324,13 +37324,13 @@ def save_discogs_artist_thumb(artist, filepath): # Search for Discogs artist id url = "https://api.discogs.com/database/search" - r = requests.get(url, params={"query": artist, "type": "artist", 'token': prefs.discogs_pat}, + r = requests.get(url, params={"query": artist, "type": "artist", "token": prefs.discogs_pat}, headers={"User-Agent": t_agent}) id = r.json()["results"][0]["id"] # Search artist info, get images url = "https://api.discogs.com/artists/" + str(id) - r = requests.get(url, headers={"User-Agent": t_agent}, params={'token': prefs.discogs_pat}) + r = requests.get(url, headers={"User-Agent": t_agent}, params={"token": prefs.discogs_pat}) images = r.json()["images"] # Respect rate limit @@ -37340,12 +37340,12 @@ def save_discogs_artist_thumb(artist, filepath): # Find a square image in list of images for image in images: - if image['height'] == image['width']: + if image["height"] == image["width"]: logging.info("Found square") - url = image['uri'] + url = image["uri"] break else: - url = images[0]['uri'] + url = images[0]["uri"] response = urllib.request.urlopen(url, cafile=tauon.ca) im = Image.open(response) @@ -37365,7 +37365,7 @@ def save_discogs_artist_thumb(artist, filepath): lower = width + upper im = im.crop((left, upper, right, lower)) - im.save(filepath, 'JPEG', quality=90) + im.save(filepath, "JPEG", quality=90) im.close() logging.info("Found artist image from Discogs") @@ -37376,7 +37376,7 @@ def save_fanart_artist_thumb(mbid, filepath, preview=False): r = requests.get("http://webservice.fanart.tv/v3/music/" \ + mbid + "?api_key=" + prefs.fatvap, timeout=5) #logging.info(r.json()) - thumblink = r.json()['artistthumb'][0]['url'] + thumblink = r.json()["artistthumb"][0]["url"] if preview: thumblink = thumblink.replace("/fanart/music", "/preview/music") @@ -37391,15 +37391,15 @@ def save_fanart_artist_thumb(mbid, filepath, preview=False): l = t.tell() t.seek(0) - if info.get_content_maintype() == 'image' and l > 1000: - f = open(filepath, 'wb') + if info.get_content_maintype() == "image" and l > 1000: + f = open(filepath, "wb") f.write(t.read()) f.close() if prefs.fanart_notify: prefs.fanart_notify = False show_message(_("Notice: Artist image sourced from fanart.tv"), - _("They encourage you to contribute at {link}").format(link="https://fanart.tv"), mode='link') + _("They encourage you to contribute at {link}").format(link="https://fanart.tv"), mode="link") logging.info("Found artist thumbnail from fanart.tv") @@ -37464,7 +37464,7 @@ def load_img(self, artist): im.thumbnail((self.thumb_size, self.thumb_size), Image.Resampling.LANCZOS) - im.save(g, 'PNG') + im.save(g, "PNG") g.seek(0) wop = rw_from_object(g) @@ -37513,10 +37513,10 @@ def worker(self): artist = self.to_fetch f_artist = filename_safe(artist) - filename = f_artist + '-lfm.png' - filename2 = f_artist + '-lfm.txt' - filename3 = f_artist + '-ftv.jpg' - filename4 = f_artist + '-dcg.jpg' + filename = f_artist + "-lfm.png" + filename2 = f_artist + "-lfm.txt" + filename3 = f_artist + "-ftv.jpg" + filename4 = f_artist + "-dcg.jpg" filepath = os.path.join(a_cache_dir, filename) filepath2 = os.path.join(a_cache_dir, filename2) filepath3 = os.path.join(a_cache_dir, filename3) @@ -37582,15 +37582,15 @@ def prep(self): track = pctl.g(item) - if 'artists' in track.misc: - artists = track.misc['artists'] + if "artists" in track.misc: + artists = track.misc["artists"] else: if prefs.artist_list_prefer_album_artist and track.album_artist: artists = track.album_artist else: artists = get_artist_strip_feat(track) - artists = [x.strip() for x in artists.split(';')] + artists = [x.strip() for x in artists.split(";")] pp = 0 if prefs.artist_list_sort_mode == "play": @@ -37687,7 +37687,7 @@ def locate_artist(self, track): for i, item in enumerate(self.current_artists): if item == track.artist or item == track.album_artist or ( - 'artists' in track.misc and item in track.misc['artists']): + "artists" in track.misc and item in track.misc["artists"]): self.scroll_position = i break @@ -37946,7 +37946,7 @@ def draw_card(self, artist, x, y, w): for i in range(len(default_playlist)): track = pctl.g(default_playlist[i]) if track.artist.casefold() == this_artist or track.album_artist.casefold() == this_artist or ( - 'artists' in track.misc and artist in track.misc['artists']): + "artists" in track.misc and artist in track.misc["artists"]): # Matchin artist if not in_artist: in_artist = True @@ -38819,7 +38819,7 @@ def queue_pause_deco(): if pctl.pause_queue: return [colours.menu_text, colours.menu_background, _("Resume Queue")] else: - return [colours.menu_text, colours.menu_background, _('Pause Queue')] + return [colours.menu_text, colours.menu_background, _("Pause Queue")] # def finish_current_deco(): @@ -39006,7 +39006,7 @@ def toggle_auto_stop_deco(self): if enabled: return [colours.menu_text, colours.menu_background, _("Cancel Auto-Stop")] else: - return [colours.menu_text, colours.menu_background, _('Auto-Stop')] + return [colours.menu_text, colours.menu_background, _("Auto-Stop")] def queue_remove_show(self, id): @@ -39440,11 +39440,11 @@ def art_metadata_overlay(right, bottom, showc): line = "" if showc[0] == 1: - line += 'E ' + line += "E " elif showc[0] == 2: - line += 'N ' + line += "N " else: - line += 'F ' + line += "F " line += str(showc[2] + 1) + "/" + str(showc[1]) @@ -39458,11 +39458,11 @@ def art_metadata_overlay(right, bottom, showc): line = "" if showc[0] == 1: - line += 'Embedded' + line += "Embedded" elif showc[0] == 2: - line += 'Network' + line += "Network" else: - line += 'File' + line += "File" y = bottom - 76 * gui.scale @@ -39793,7 +39793,7 @@ def load(self, path, box_size=None): if box_size is not None: im.thumbnail(box_size, Image.Resampling.LANCZOS) - im.save(g, 'BMP') + im.save(g, "BMP") g.seek(0) self.image_data = g logging.info("Save BMP to memory") @@ -39908,14 +39908,14 @@ def draw(self, x, y, w, h): return if self.min_rq_timer.get() < 10: # Limit rate - if os.path.isfile(os.path.join(a_cache_dir, artist + '-lfm.txt')): + if os.path.isfile(os.path.join(a_cache_dir, artist + "-lfm.txt")): pass else: self.status = _("Cooldown...") wait = True if pctl.playing_time < 2: - if os.path.isfile(os.path.join(a_cache_dir, artist + '-lfm.txt')): + if os.path.isfile(os.path.join(a_cache_dir, artist + "-lfm.txt")): pass else: self.status = "..." @@ -39954,15 +39954,15 @@ def draw(self, x, y, w, h): word = word.rstrip(".") if word.strip()[:4] == "www.": word = "http://" + word - if 'bandcamp' in word: + if "bandcamp" in word: self.urls.append((word.strip(), [200, 150, 70, 255], "B")) - elif 'soundcloud' in word: + elif "soundcloud" in word: self.urls.append((word.strip(), [220, 220, 70, 255], "S")) - elif 'twitter' in word: + elif "twitter" in word: self.urls.append((word.strip(), [80, 110, 230, 255], "T")) - elif 'facebook' in word: + elif "facebook" in word: self.urls.append((word.strip(), [60, 60, 230, 255], "F")) - elif 'youtube' in word: + elif "youtube" in word: self.urls.append((word.strip(), [210, 50, 50, 255], "Y")) else: self.urls.append((word.strip(), [120, 200, 60, 255], "W")) @@ -40051,9 +40051,9 @@ def get_data(self, artist, get_img_path=False, force_dl=False): f_artist = filename_safe(artist) - img_filename = f_artist + '-ftv-full.jpg' - text_filename = f_artist + '-lfm.txt' - img_filepath_dcg = os.path.join(a_cache_dir, f_artist + '-dcg.jpg') + img_filename = f_artist + "-ftv-full.jpg" + text_filename = f_artist + "-lfm.txt" + img_filepath_dcg = os.path.join(a_cache_dir, f_artist + "-dcg.jpg") img_filepath = os.path.join(a_cache_dir, img_filename) text_filepath = os.path.join(a_cache_dir, text_filename) @@ -40062,11 +40062,11 @@ def get_data(self, artist, get_img_path=False, force_dl=False): os.path.join(user_directory, "artist-pictures/" + f_artist + ".png"), os.path.join(user_directory, "artist-pictures/" + f_artist + ".jpg"), os.path.join(user_directory, "artist-pictures/" + f_artist + ".webp"), - os.path.join(a_cache_dir, f_artist + '-ftv-full.jpg'), - os.path.join(a_cache_dir, f_artist + '-lfm.png'), - os.path.join(a_cache_dir, f_artist + '-lfm.jpg'), - os.path.join(a_cache_dir, f_artist + '-lfm.webp'), - os.path.join(a_cache_dir, f_artist + '-dcg.jpg') + os.path.join(a_cache_dir, f_artist + "-ftv-full.jpg"), + os.path.join(a_cache_dir, f_artist + "-lfm.png"), + os.path.join(a_cache_dir, f_artist + "-lfm.jpg"), + os.path.join(a_cache_dir, f_artist + "-lfm.webp"), + os.path.join(a_cache_dir, f_artist + "-dcg.jpg") ] if get_img_path: @@ -40126,7 +40126,7 @@ def get_data(self, artist, get_img_path=False, force_dl=False): self.text = data[1] # cover_link = data[2] # Save text as file - f = open(text_filepath, 'w', encoding='utf-8') + f = open(text_filepath, "w", encoding="utf-8") f.write(self.text) f.close() logging.info("Save bio text") @@ -40152,7 +40152,7 @@ def get_data(self, artist, get_img_path=False, force_dl=False): if not artist_picture_render.show and data[4]: try: r = requests.get(data[4]) - html = BeautifulSoup(r.text, 'html.parser') + html = BeautifulSoup(r.text, "html.parser") tag = html.find("meta", property="og:image") url = tag["content"] if url: @@ -40275,7 +40275,7 @@ def save_format_b(self, track): t = t.replace("\r", "") - f = open(os.path.join(self.store_b, cache_title), 'w') + f = open(os.path.join(self.store_b, cache_title), "w") f.write(t) f.close() @@ -40367,9 +40367,9 @@ def fetch(self, track): try: - r = requests.get('http://api.guitarparty.com/v2/songs/?query=' + urllib.parse.quote(cache_title), + r = requests.get("http://api.guitarparty.com/v2/songs/?query=" + urllib.parse.quote(cache_title), headers={"Guitarparty-Api-Key": "e9c0e543798c4249c24f698022ced5dd0c583ec7"}) - d = r.json()['objects'][0]['body'] + d = r.json()["objects"][0]["body"] self.prep_folders() f = open(os.path.join(self.store_a, cache_title), "w") @@ -40584,8 +40584,8 @@ def loader(self): #logging.info("found cached") elif station.get("icon") and station["icon"] not in prefs.radio_thumb_bans: try: - r = requests.get(station.get("icon"), headers={'User-Agent': t_agent}, timeout=5, stream=True) - if r.status_code != 200 or int(r.headers.get('Content-Length', 0)) > 2000000: + r = requests.get(station.get("icon"), headers={"User-Agent": t_agent}, timeout=5, stream=True) + if r.status_code != 200 or int(r.headers.get("Content-Length", 0)) > 2000000: raise Exception("Error get radio thumb") except Exception: logging.exception("error get radio thumb") @@ -40629,7 +40629,7 @@ def loader(self): im = im.resize((size, size), Image.Resampling.LANCZOS) g = io.BytesIO() g.seek(0) - im.save(g, 'PNG') + im.save(g, "PNG") g.seek(0) wop = rw_from_object(g) s_image = IMG_Load_RW(wop, 0) @@ -41994,31 +41994,31 @@ def download_img(link, target_folder, track): try: response = urllib.request.urlopen(link, cafile=tauon.ca) info = response.info() - if info.get_content_maintype() == 'image': - if info.get_content_subtype() == 'jpeg': - save_target = os.path.join(target_dir, 'image.jpg') - f = open(save_target, 'wb') + if info.get_content_maintype() == "image": + if info.get_content_subtype() == "jpeg": + save_target = os.path.join(target_dir, "image.jpg") + f = open(save_target, "wb") f.write(response.read()) f.close() # clear_img_cache() clear_track_image_cache(track) - elif info.get_content_subtype() == 'png': - save_target = os.path.join(target_dir, 'image.png') - f = open(save_target, 'wb') + elif info.get_content_subtype() == "png": + save_target = os.path.join(target_dir, "image.png") + f = open(save_target, "wb") f.write(response.read()) f.close() # clear_img_cache() clear_track_image_cache(track) else: - show_message(_("Image types other than PNG or JPEG are currently not supported"), mode='warning') + show_message(_("Image types other than PNG or JPEG are currently not supported"), mode="warning") else: - show_message(_("The link does not appear to refer to an image file."), mode='warning') + show_message(_("The link does not appear to refer to an image file."), mode="warning") gui.image_downloading = False except Exception as e: logging.exception("Image download failed") - show_message(_("Image download failed."), str(e), mode='warning') + show_message(_("Image download failed."), str(e), mode="warning") gui.image_downloading = False @@ -42248,15 +42248,15 @@ def check_playback_running(self): tm.ready_playback() try: - tm.d['caster'] = [lambda: x, [tauon], None] + tm.d["caster"] = [lambda: x, [tauon], None] except Exception: logging.exception("Failed to cast") -tm.d['worker'] = [worker1, (), None] -tm.d['search'] = [worker2, (), None] -tm.d['gallery'] = [worker3, (), None] -tm.d['style'] = [worker4, (), None] -tm.d['radio-thumb'] = [radio_thumb_gen.loader, (), None] +tm.d["worker"] = [worker1, (), None] +tm.d["search"] = [worker2, (), None] +tm.d["gallery"] = [worker3, (), None] +tm.d["style"] = [worker4, (), None] +tm.d["radio-thumb"] = [radio_thumb_gen.loader, (), None] tm.ready("search") tm.ready("gallery") @@ -42294,7 +42294,7 @@ def check_playback_running(self): for item in sys.argv: if (os.path.isdir(item) or os.path.isfile( - item) or "file://" in item) and '.py' not in item and 'tauon.exe' not in item: + item) or "file://" in item) and ".py" not in item and "tauon.exe" not in item: open_uri(item) sv = SDL_version() @@ -42306,7 +42306,7 @@ def check_playback_running(self): # if prefs.backend == 2: # logging.warning("Using GStreamer as fallback. Some functions disabled") if prefs.backend == 0: - show_message(_("ERROR: No backend found"), mode='error') + show_message(_("ERROR: No backend found"), mode="error") class Undo: @@ -42326,7 +42326,7 @@ def undo(self): if job[0] == "playlist": pctl.multi_playlist.append(job[1]) switch_playlist(len(pctl.multi_playlist) - 1) - elif job[0] == 'tracks': + elif job[0] == "tracks": uid = job[1] li = job[2] @@ -42350,7 +42350,7 @@ def undo(self): if not pctl.playlist_view_position < i < pctl.playlist_view_position + gui.playlist_view_length: pctl.playlist_view_position = i console.print("DEBUG: Position changed by undo") - elif job[0] == 'ptt': + elif job[0] == "ptt": j, fr, fr_s, fr_scr, so, to_s, to_scr = job star_store.insert(fr.index, fr_s) star_store.insert(to.index, to_s) @@ -42854,7 +42854,7 @@ def update_layout_do(): update_set() if prefs.art_bg: - tm.ready('style') + tm.ready("style") # SDL_RenderClear(renderer) # SDL_RenderPresent(renderer) @@ -42928,15 +42928,15 @@ def save_state(): return # view_prefs['star-lines'] = star_lines - view_prefs['update-title'] = update_title - view_prefs['side-panel'] = prefs.prefer_side - view_prefs['dim-art'] = prefs.dim_art + view_prefs["update-title"] = update_title + view_prefs["side-panel"] = prefs.prefer_side + view_prefs["dim-art"] = prefs.dim_art #view_prefs['level-meter'] = gui.turbo # view_prefs['pl-follow'] = pl_follow - view_prefs['scroll-enable'] = scroll_enable - view_prefs['break-enable'] = break_enable + view_prefs["scroll-enable"] = scroll_enable + view_prefs["break-enable"] = break_enable # view_prefs['dd-index'] = dd_index - view_prefs['append-date'] = prefs.append_date + view_prefs["append-date"] = prefs.append_date ds = [] for v in pctl.master_library.values(): @@ -43151,7 +43151,7 @@ def save_state(): spot_ctl.save_token() - with open(user_directory + "/lyrics_substitutions.json", 'w') as f: + with open(user_directory + "/lyrics_substitutions.json", "w") as f: json.dump(prefs.lyrics_subs, f, ) save_prefs() @@ -43294,7 +43294,7 @@ def drop_file(target): global mouse_down global drag_mode - if system != 'windows' and sdl_version >= 204: + if system != "windows" and sdl_version >= 204: gmp = get_global_mouse() gwp = get_window_position() i_x = gmp[0] - gwp[0] @@ -43372,10 +43372,10 @@ def drop_file(target): if not os.path.exists(target) and flatpak_mode: show_message(_("Could not access! Possible insufficient Flatpak permissions."), _(" For details, see {link}").format(link="https://github.com/Taiko2k/TauonMusicBox/wiki/Flatpak-Extra-Steps"), - mode='bubble') + mode="bubble") load_order = LoadClass() - load_order.target = target.replace('\\', '/') + load_order.target = target.replace("\\", "/") if os.path.isdir(load_order.target): quick_import_done.append(load_order.target) @@ -43484,7 +43484,7 @@ def drop_file(target): mouse_wheel = 0 pref_box.scroll = 0 new_playlist_cooldown = False - input_text = '' + input_text = "" inp.level_2_enter = False mouse_enter_window = False @@ -43624,8 +43624,8 @@ def drop_file(target): link = event.drop.file.decode() #logging.info(link) - if pctl.playing_ready() and link.startswith('http'): - if system != 'windows' and sdl_version >= 204: + if pctl.playing_ready() and link.startswith("http"): + if system != "windows" and sdl_version >= 204: gmp = get_global_mouse() gwp = get_window_position() i_x = gmp[0] - gwp[0] @@ -43647,7 +43647,7 @@ def drop_file(target): i_x = i_x.contents.value / logical_size[0] * window_size[0] if coll_point((i_x, i_y), gui.main_art_box): - logging.info('Drop picture...') + logging.info("Drop picture...") #logging.info(link) gui.image_downloading = True track = pctl.playing_object() @@ -43670,7 +43670,7 @@ def drop_file(target): power += 5 dropped_file_sdl = event.drop.file #logging.info(dropped_file_sdl) - target = str(urllib.parse.unquote(dropped_file_sdl.decode("utf-8", errors='surrogateescape'))).replace("file:///", "/").replace("\r", + target = str(urllib.parse.unquote(dropped_file_sdl.decode("utf-8", errors="surrogateescape"))).replace("file:///", "/").replace("\r", "") #logging.info(target) drop_file(target) @@ -43693,7 +43693,7 @@ def drop_file(target): #logging.info("edit text") editline = event.edit.text #logging.info(editline) - editline = editline.decode("utf-8", 'ignore') + editline = editline.decode("utf-8", "ignore") k_input = True gui.update += 1 @@ -43852,7 +43852,7 @@ def drop_file(target): elif event.type == SDL_TEXTINPUT: k_input = True power += 5 - input_text += event.text.text.decode('utf-8') + input_text += event.text.text.decode("utf-8") gui.update += 1 #logging.info(input_text) @@ -44134,7 +44134,7 @@ def drop_file(target): key_end_press = False mouse_wheel = 0 pref_box.scroll = 0 - input_text = '' + input_text = "" inp.level_2_enter = False if c_yax != 0: @@ -44182,20 +44182,20 @@ def drop_file(target): switch_playlist(n - 1) n += 1 - if keymaps.test('cycle-playlist-left'): + if keymaps.test("cycle-playlist-left"): if gui.album_tab_mode and key_left_press: pass else: if is_level_zero() or quick_search_mode: cycle_playlist_pinned(1) - if keymaps.test('cycle-playlist-right'): + if keymaps.test("cycle-playlist-right"): if gui.album_tab_mode and key_right_press: pass else: if is_level_zero() or quick_search_mode: cycle_playlist_pinned(-1) - if keymaps.test('toggle-console'): + if keymaps.test("toggle-console"): console.show ^= True if keymaps.test("toggle-fullscreen"): @@ -44221,11 +44221,11 @@ def drop_file(target): if keymaps.test("show-encode-folder"): open_encode_out() - if keymaps.test('toggle-left-panel'): + if keymaps.test("toggle-left-panel"): gui.lsp ^= True update_layout_do() - if keymaps.test('toggle-last-left-panel'): + if keymaps.test("toggle-last-left-panel"): toggle_left_last() update_layout_do() @@ -44280,7 +44280,7 @@ def drop_file(target): pctl.new_time = 0 pctl.playing_time = 0 pctl.decode_time = 0 - pctl.playerCommand = 'seek' + pctl.playerCommand = "seek" pctl.playerCommandReady = True if keymaps.test("goto-top"): @@ -44332,10 +44332,10 @@ def drop_file(target): if key_ctrl_down and key_z_press: undo.undo() - if keymaps.test('quit'): + if keymaps.test("quit"): tauon.exit("Quit keyboard shortcut pressed") - if keymaps.test('testkey'): # F7: test + if keymaps.test("testkey"): # F7: test pctl.playerCommand = "unload" pctl.playerCommandReady = True pass @@ -44532,7 +44532,7 @@ def drop_file(target): if mouse_down is True: gui.update += 1 - if keymaps.test('pagedown'): # key_PGD: + if keymaps.test("pagedown"): # key_PGD: if len(default_playlist) > 10: pctl.playlist_view_position += gui.playlist_view_length - 4 if pctl.playlist_view_position > len(default_playlist): @@ -44541,7 +44541,7 @@ def drop_file(target): pctl.selected_in_playlist = pctl.playlist_view_position console.print("DEBUG: Position changed by page key") shift_selection.clear() - if keymaps.test('pageup'): + if keymaps.test("pageup"): if len(default_playlist) > 0: pctl.playlist_view_position -= gui.playlist_view_length - 4 if pctl.playlist_view_position < 0: @@ -44648,13 +44648,13 @@ def drop_file(target): if keymaps.test("random-album"): random_album() - if keymaps.test('opacity-up'): + if keymaps.test("opacity-up"): prefs.window_opacity += .05 if prefs.window_opacity > 1: prefs.window_opacity = 1 SDL_SetWindowOpacity(t_window, prefs.window_opacity) - if keymaps.test('opacity-down'): + if keymaps.test("opacity-down"): prefs.window_opacity -= .05 if prefs.window_opacity < .30: prefs.window_opacity = .30 @@ -44729,27 +44729,27 @@ def drop_file(target): # mouse_down = False if inp.media_key: - if inp.media_key == 'Play': + if inp.media_key == "Play": if pctl.playing_state == 0: pctl.play() else: pctl.pause() - elif inp.media_key == 'Pause': + elif inp.media_key == "Pause": pctl.pause_only() - elif inp.media_key == 'Stop': + elif inp.media_key == "Stop": pctl.stop() - elif inp.media_key == 'Next': + elif inp.media_key == "Next": pctl.advance() - elif inp.media_key == 'Previous': + elif inp.media_key == "Previous": pctl.back() - elif inp.media_key == 'Rewind': + elif inp.media_key == "Rewind": pctl.seek_time(pctl.playing_time - 10) - elif inp.media_key == 'FastForward': + elif inp.media_key == "FastForward": pctl.seek_time(pctl.playing_time + 10) - elif inp.media_key == 'Repeat': + elif inp.media_key == "Repeat": toggle_repeat() - elif inp.media_key == 'Shuffle': + elif inp.media_key == "Shuffle": toggle_random() inp.media_key = "" @@ -44779,14 +44779,14 @@ def drop_file(target): # Prepare loader thread with load order for order in load_orders: if order.stage == 0: - order.traget = order.target.replace('\\', '/') + order.traget = order.target.replace("\\", "/") order.stage = 1 if os.path.isdir(order.traget): loaderCommand = LC_Folder else: loaderCommand = LC_File - if order.traget.endswith('.xspf'): - to_got = 'xspf' + if order.traget.endswith(".xspf"): + to_got = "xspf" to_get = 0 else: to_got = 1 @@ -44872,7 +44872,7 @@ def drop_file(target): except Exception: logging.exception("Error loading theme file") raise - show_message(_("Error loading theme file"), "", mode='warning') + show_message(_("Error loading theme file"), "", mode="warning") if theme == 0: gui.theme_name = "Mindaro" @@ -44933,7 +44933,7 @@ def drop_file(target): album_art_gen.clear_cache() style_overlay.radio_meta = None if prefs.art_bg: - tm.ready('style') + tm.ready("style") fields.clear() gui.cursor_want = 0 @@ -45286,17 +45286,17 @@ def drop_file(target): ref.append(default_playlist[item]) for item in shift_selection: - default_playlist[item] = 'old' + default_playlist[item] = "old" for item in shift_selection: default_playlist.insert(track_position, "new") for b in reversed(range(len(default_playlist))): - if default_playlist[b] == 'old': + if default_playlist[b] == "old": del default_playlist[b] shift_selection = [] for b in range(len(default_playlist)): - if default_playlist[b] == 'new': + if default_playlist[b] == "new": shift_selection.append(b) default_playlist[b] = ref.pop(0) @@ -45929,7 +45929,7 @@ def drop_file(target): if order.replace_stem: for ii, id in reversed(list(enumerate(pctl.multi_playlist[target_pl][2]))): pfp = pctl.g(id).parent_folder_path - if pfp.startswith(order.target.replace('\\', '/')): + if pfp.startswith(order.target.replace("\\", "/")): if pfp.rstrip("/\\") == order.target.rstrip("/\\") or \ (len(pfp) > len(order.target) and pfp[ len(order.target.rstrip("/\\"))] in ("/", "\\")): @@ -45950,7 +45950,7 @@ def drop_file(target): gui.update += 2 gui.pl_update += 2 if order.notify and gui.message_box and len(load_orders) == 1: - show_message(_("Rescan folders complete."), mode='done') + show_message(_("Rescan folders complete."), mode="done") reload() tree_view_box.clear_target_pl(target_pl) @@ -47074,7 +47074,7 @@ def drop_file(target): if tc.bitrate not in (0, "", "0"): ddt.text((x1, y1), _("Bitrate"), key_colour_off, 212, max_w=70 * gui.scale) line = str(tc.bitrate) - if tc.file_ext in ('FLAC', 'OPUS', 'APE', 'WV'): + if tc.file_ext in ("FLAC", "OPUS", "APE", "WV"): line = "≈" + line line += _(" kbps") ddt.text((x2, y1), line, value_colour, 312) @@ -47107,12 +47107,12 @@ def drop_file(target): if coll(rect): ddt.text((x1, y1), _("Duration"), key_colour_on, 212) if inp.mouse_click: - copy_to_clipboard(time.strftime('%M:%S', time.gmtime(tc.length)).lstrip("0")) + copy_to_clipboard(time.strftime("%M:%S", time.gmtime(tc.length)).lstrip("0")) show_message(_("Copied text to clipboard")) inp.mouse_click = False else: ddt.text((x1, y1), _("Duration"), key_colour_off, 212) - line = time.strftime('%M:%S', time.gmtime(tc.length)) + line = time.strftime("%M:%S", time.gmtime(tc.length)) ddt.text((x2, y1), line, value_colour, value_font) # ----------- @@ -47216,7 +47216,7 @@ def drop_file(target): if coll(rect) and key_shift_down and mouse_wheel != 0: star_store.add(r_menu_index, 60 * mouse_wheel) - line = time.strftime('%H:%M:%S', + line = time.strftime("%H:%M:%S", time.gmtime(total)) ddt.text((x1, y1), _("Play time"), key_colour_off, 212, max_w=70 * gui.scale) @@ -47247,7 +47247,7 @@ def drop_file(target): # ddt.draw_text((x1, y1), "Comment", key_colour_off, 12) if "\n" not in tc.comment and ( - 'http://' in tc.comment or 'www.' in tc.comment or 'https://' in tc.comment) and ddt.get_text_w( + "http://" in tc.comment or "www." in tc.comment or "https://" in tc.comment) and ddt.get_text_w( tc.comment, 12) < 335 * gui.scale: link_pa = draw_linked_text((x2, y1), tc.comment, value_colour, 12) @@ -47446,7 +47446,7 @@ def drop_file(target): if len(search_text.text) == 0: gui.search_error = False - if len(search_text.text) != 0 and search_text.text[0] == '/': + if len(search_text.text) != 0 and search_text.text[0] == "/": # if "/love" in search_text.text: # line = "last.fm loved tracks from user. Format: /love " # else: @@ -47479,11 +47479,11 @@ def drop_file(target): search_text.draw(rect[0] + 8 * gui.scale, rect[1] + 6 * gui.scale, colours.grey(250), font=213) if (key_shift_down or ( - len(search_text.text) > 0 and search_text.text[0] == '/')) and inp.key_return_press: + len(search_text.text) > 0 and search_text.text[0] == "/")) and inp.key_return_press: inp.key_return_press = False playlist = [] if len(search_text.text) > 0: - if search_text.text[0] == '/': + if search_text.text[0] == "/": if search_text.text.lower() == "/random" or search_text.text.lower() == "/shuffle": gen_500_random(pctl.active_playlist_viewing) @@ -47495,9 +47495,9 @@ def drop_file(target): else: if search_text.text[-1] == "/": - tt_title = search_text.text.replace('/', "") + tt_title = search_text.text.replace("/", "") else: - search_text.text = search_text.text.replace('/', "") + search_text.text = search_text.text.replace("/", "") tt_title = search_text.text search_text.text = search_text.text.lower() for item in default_playlist: @@ -47855,7 +47855,7 @@ def drop_file(target): if level == -1: time_colour = [0,0,0,0] - w = ddt.text((rect[0] + 10 * gui.scale, yy), item[2].strftime('%H:%M:%S'), time_colour, 311, + w = ddt.text((rect[0] + 10 * gui.scale, yy), item[2].strftime("%H:%M:%S"), time_colour, 311, rect[2] - 60 * gui.scale, bg=[5,5,5,255]) ddt.text((w + rect[0] + 17 * gui.scale, yy), message, text_colour, 311, rect[2] - 60 * gui.scale, bg=[5,5,5,255]) @@ -47867,7 +47867,7 @@ def drop_file(target): text = "" for item in console.messages[-50:]: - text += item[2].strftime('%H:%M:%S') + " " + item[0] + "\n" + text += item[2].strftime("%H:%M:%S") + " " + item[0] + "\n" copy_to_clipboard(text) show_message(_("Lines copied to clipboard"), mode="done") diff --git a/src/tauon/t_modules/t_spot.py b/src/tauon/t_modules/t_spot.py index 46e75547f..a017f20ef 100644 --- a/src/tauon/t_modules/t_spot.py +++ b/src/tauon/t_modules/t_spot.py @@ -39,7 +39,7 @@ try: import tekore as tk except ModuleNotFoundError: - logging.warning("Unable to import Tekore, Spotify support will be disabled..") + logging.warning("Unable to import Tekore, Spotify support will be disabled.") except Exception: logging.exception("Unkown error trying to import Tekore, Spotify support will be disabled.") else: From 967a8fb69f0855f25c234801a076198ba2745702 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Wed, 20 Nov 2024 19:41:44 +0100 Subject: [PATCH 53/63] t_main: Convert part of SDL code from spaces to tabs, log rest of used directories too --- src/tauon/t_modules/t_main.py | 324 ++++++++++++++++++---------------- 1 file changed, 167 insertions(+), 157 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 405fa8ef4..83ac0481d 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -641,7 +641,15 @@ if not os.path.isdir(music_directory): music_directory = None -logging.info("Install directory: " + install_directory) +logging.info(f"Install directory: {install_directory}") +logging.info(f"Config directory: {config_directory}") +logging.info(f"Cache directory: {cache_directory}") +logging.info(f"Home directory: {home_directory}") +logging.info(f"Music directory: {music_directory}") +logging.info(f"Download directory: {download_directory}") +logging.info(f"Asset directory: {asset_directory}") +#logging.info(f"SVG directory: {svg_directory}") +#logging.info(f"Scaled Asset Directory: {scaled_asset_directory}") old_backend = 2 @@ -9968,78 +9976,79 @@ def draw_window_border(): cursor_bottom_side = cursor_standard if msys: - cursor_br_corner = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE) - cursor_right_side = cursor_shift - cursor_left_side = cursor_shift - cursor_top_side = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS) - cursor_bottom_side = cursor_top_side + cursor_br_corner = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE) + cursor_right_side = cursor_shift + cursor_left_side = cursor_shift + cursor_top_side = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS) + cursor_bottom_side = cursor_top_side elif not msys and system == "linux": - try: - class XcursorImage(ctypes.Structure): - _fields_ = [ - ("version", c_uint32), - ("size", c_uint32), - ("width", c_uint32), - ("height", c_uint32), - ("xhot", c_uint32), - ("yhot", c_uint32), - ("delay", c_uint32), - ("pixels", c_void_p), - ] + try: + class XcursorImage(ctypes.Structure): + _fields_ = [ + ("version", c_uint32), + ("size", c_uint32), + ("width", c_uint32), + ("height", c_uint32), + ("xhot", c_uint32), + ("yhot", c_uint32), + ("delay", c_uint32), + ("pixels", c_void_p), + ] - try: - xcu = ctypes.cdll.LoadLibrary("libXcursor.so") - except Exception: - logging.exception("Failed to load libXcursor.so, will try libXcursor.so.1") - xcu = ctypes.cdll.LoadLibrary("libXcursor.so.1") - xcu.XcursorLibraryLoadImage.restype = ctypes.POINTER(XcursorImage) - - def get_xcursor(name): - c1 = xcu.XcursorLibraryLoadImage(c_char_p(name.encode()), c_char_p(os.environ["XCURSOR_THEME"].encode()), c_int(int(os.environ["XCURSOR_SIZE"]))).contents - sdl_surface = SDL_CreateRGBSurfaceWithFormatFrom(c1.pixels, c1.width, c1.height, 32, c1.width * 4, SDL_PIXELFORMAT_ARGB8888) - cursor = SDL_CreateColorCursor(sdl_surface, round(c1.xhot), round(c1.yhot)) - xcu.XcursorImageDestroy(ctypes.byref(c1)) - SDL_FreeSurface(sdl_surface) - return cursor - - cursor_br_corner = get_xcursor("se-resize") - cursor_right_side = get_xcursor("right_side") - cursor_top_side = get_xcursor("top_side") - cursor_left_side = get_xcursor("left_side") - cursor_bottom_side = get_xcursor("bottom_side") - - if SDL_GetCurrentVideoDriver() == b"wayland": - cursor_standard = get_xcursor("left_ptr") - cursor_text = get_xcursor("xterm") - cursor_shift = get_xcursor("sb_h_double_arrow") - cursor_hand = get_xcursor("hand2") - SDL_SetCursor(cursor_standard) + try: + xcu = ctypes.cdll.LoadLibrary("libXcursor.so") + except Exception: + logging.exception("Failed to load libXcursor.so, will try libXcursor.so.1") + xcu = ctypes.cdll.LoadLibrary("libXcursor.so.1") + xcu.XcursorLibraryLoadImage.restype = ctypes.POINTER(XcursorImage) + + def get_xcursor(name): + c1 = xcu.XcursorLibraryLoadImage(c_char_p(name.encode()), c_char_p(os.environ["XCURSOR_THEME"].encode()), c_int(int(os.environ["XCURSOR_SIZE"]))).contents + sdl_surface = SDL_CreateRGBSurfaceWithFormatFrom(c1.pixels, c1.width, c1.height, 32, c1.width * 4, SDL_PIXELFORMAT_ARGB8888) + cursor = SDL_CreateColorCursor(sdl_surface, round(c1.xhot), round(c1.yhot)) + xcu.XcursorImageDestroy(ctypes.byref(c1)) + SDL_FreeSurface(sdl_surface) + return cursor + + cursor_br_corner = get_xcursor("se-resize") + cursor_right_side = get_xcursor("right_side") + cursor_top_side = get_xcursor("top_side") + cursor_left_side = get_xcursor("left_side") + cursor_bottom_side = get_xcursor("bottom_side") + + if SDL_GetCurrentVideoDriver() == b"wayland": + cursor_standard = get_xcursor("left_ptr") + cursor_text = get_xcursor("xterm") + cursor_shift = get_xcursor("sb_h_double_arrow") + cursor_hand = get_xcursor("hand2") + SDL_SetCursor(cursor_standard) - except Exception: - logging.exception("Error loading xcursor") + except Exception: + logging.exception("Error loading xcursor") if not maximized and gui.maximized: - SDL_MaximizeWindow(t_window) + SDL_MaximizeWindow(t_window) # logging.error(SDL_GetError()) -# t_window = SDL_CreateShapedWindow(window_title, -# SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, -# window_size[0], window_size[1], -# flags) +# t_window = SDL_CreateShapedWindow( +# window_title, +# SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, +# window_size[0], window_size[1], +# flags) # logging.error(SDL_GetError()) if system == "windows" or msys: - gui.window_id = sss.info.win.window + gui.window_id = sss.info.win.window # try: -# SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, b"1") +# SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, b"1") # # except Exception: -# logging.exception("old version of SDL detected") +# logging.exception("old version of SDL detected") # get window surface and set up renderer # renderer = SDL_CreateRenderer(t_window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC) @@ -10064,10 +10073,10 @@ def get_xcursor(name): # gui.max_window_tex = 1000 # if window_size[0] > gui.max_window_tex or window_size[1] > gui.max_window_tex: # -# while window_size[0] > gui.max_window_tex: -# gui.max_window_tex += 1000 -# while window_size[1] > gui.max_window_tex: -# gui.max_window_tex += 1000 +# while window_size[0] > gui.max_window_tex: +# gui.max_window_tex += 1000 +# while window_size[1] > gui.max_window_tex: +# gui.max_window_tex += 1000 # # gui.ttext = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, gui.max_window_tex, gui.max_window_tex) # @@ -10108,76 +10117,76 @@ def get_xcursor(name): def bass_player_thread(player): - # logging.basicConfig(filename=user_directory + '/crash.log', level=logging.ERROR, - # format='%(asctime)s %(levelname)s %(name)s %(message)s') + # logging.basicConfig(filename=user_directory + '/crash.log', level=logging.ERROR, + # format='%(asctime)s %(levelname)s %(name)s %(message)s') - try: - player(pctl, gui, prefs, lfm_scrobbler, star_store, tauon) - except Exception: - logging.exception("Exception on player thread") - show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") - time.sleep(1) - show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") - time.sleep(1) - show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") - raise + try: + player(pctl, gui, prefs, lfm_scrobbler, star_store, tauon) + except Exception: + logging.exception("Exception on player thread") + show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") + time.sleep(1) + show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") + time.sleep(1) + show_message(_("Playback thread has crashed. Sorry about that."), _("App will need to be restarted."), mode="error") + raise if (system == "windows" or msys) and taskbar_progress: - class WinTask: - - def __init__(self, ): - self.start = time.time() - self.updated_state = 0 - self.window_id = gui.window_id - import comtypes.client as cc - cc.GetModule(install_directory + "\\TaskbarLib.tlb") - import comtypes.gen.TaskbarLib as tbl - self.taskbar = cc.CreateObject( - "{56FDF344-FD6D-11d0-958A-006097C9A090}", - interface=tbl.ITaskbarList3) - self.taskbar.HrInit() - - self.d_timer = Timer() - - def update(self, force=False): - if self.d_timer.get() > 2 or force: - self.d_timer.set() - - if pctl.playing_state == 1 and self.updated_state != 1: - self.taskbar.SetProgressState(self.window_id, 0x2) - - if pctl.playing_state == 1: - self.updated_state = 1 - if pctl.playing_length > 2: - perc = int(pctl.playing_time * 100 / int(pctl.playing_length)) - if perc < 2: - perc = 1 - elif perc > 100: - prec = 100 - else: - perc = 0 + class WinTask: - self.taskbar.SetProgressValue(self.window_id, perc, 100) + def __init__(self, ): + self.start = time.time() + self.updated_state = 0 + self.window_id = gui.window_id + import comtypes.client as cc + cc.GetModule(install_directory + "\\TaskbarLib.tlb") + import comtypes.gen.TaskbarLib as tbl + self.taskbar = cc.CreateObject( + "{56FDF344-FD6D-11d0-958A-006097C9A090}", + interface=tbl.ITaskbarList3) + self.taskbar.HrInit() - elif pctl.playing_state == 2 and self.updated_state != 2: - self.updated_state = 2 - self.taskbar.SetProgressState(self.window_id, 0x8) + self.d_timer = Timer() - elif pctl.playing_state == 0 and self.updated_state != 0: - self.updated_state = 0 - self.taskbar.SetProgressState(self.window_id, 0x2) - self.taskbar.SetProgressValue(self.window_id, 0, 100) + def update(self, force=False): + if self.d_timer.get() > 2 or force: + self.d_timer.set() + if pctl.playing_state == 1 and self.updated_state != 1: + self.taskbar.SetProgressState(self.window_id, 0x2) - if os.path.isfile(install_directory + "/TaskbarLib.tlb"): - logging.info("Taskbar progress enabled") - pctl.windows_progress = WinTask() + if pctl.playing_state == 1: + self.updated_state = 1 + if pctl.playing_length > 2: + perc = int(pctl.playing_time * 100 / int(pctl.playing_length)) + if perc < 2: + perc = 1 + elif perc > 100: + prec = 100 + else: + perc = 0 - else: - pctl.taskbar_progress = False - logging.warning("Could not find TaskbarLib.tlb") + self.taskbar.SetProgressValue(self.window_id, perc, 100) + + elif pctl.playing_state == 2 and self.updated_state != 2: + self.updated_state = 2 + self.taskbar.SetProgressState(self.window_id, 0x8) + + elif pctl.playing_state == 0 and self.updated_state != 0: + self.updated_state = 0 + self.taskbar.SetProgressState(self.window_id, 0x2) + self.taskbar.SetProgressValue(self.window_id, 0, 100) + + + if os.path.isfile(install_directory + "/TaskbarLib.tlb"): + logging.info("Taskbar progress enabled") + pctl.windows_progress = WinTask() + + else: + pctl.taskbar_progress = False + logging.warning("Could not find TaskbarLib.tlb") # --------------------------------------------------------------------------------------------- @@ -10185,12 +10194,12 @@ def update(self, force=False): def coll_point(l, r): - # rect point collision detection - return r[0] < l[0] <= r[0] + r[2] and r[1] <= l[1] <= r[1] + r[3] + # rect point collision detection + return r[0] < l[0] <= r[0] + r[2] and r[1] <= l[1] <= r[1] + r[3] def coll(r): - return r[0] < mouse_position[0] <= r[0] + r[2] and r[1] <= mouse_position[1] <= r[1] + r[3] + return r[0] < mouse_position[0] <= r[0] + r[2] and r[1] <= mouse_position[1] <= r[1] + r[3] ddt = TDraw(renderer) @@ -10202,50 +10211,51 @@ def coll(r): class Drawing: - def button(self, text, x, y, w=None, h=None, font=212, text_highlight_colour=None, text_colour=None, - background_colour=None, background_highlight_colour=None, press=None, tooltip=""): + def button( + self, text, x, y, w=None, h=None, font=212, text_highlight_colour=None, text_colour=None, + background_colour=None, background_highlight_colour=None, press=None, tooltip=""): - if w is None: - w = ddt.get_text_w(text, font) + 18 * gui.scale - if h is None: - h = 22 * gui.scale + if w is None: + w = ddt.get_text_w(text, font) + 18 * gui.scale + if h is None: + h = 22 * gui.scale - rect = (x, y, w, h) - fields.add(rect) + rect = (x, y, w, h) + fields.add(rect) - if text_highlight_colour is None: - text_highlight_colour = colours.box_button_text_highlight - if text_colour is None: - text_colour = colours.box_button_text - if background_colour is None: - background_colour = colours.box_button_background - if background_highlight_colour is None: - background_highlight_colour = colours.box_button_background_highlight + if text_highlight_colour is None: + text_highlight_colour = colours.box_button_text_highlight + if text_colour is None: + text_colour = colours.box_button_text + if background_colour is None: + background_colour = colours.box_button_background + if background_highlight_colour is None: + background_highlight_colour = colours.box_button_background_highlight - click = False + click = False - if press is None: - press = inp.mouse_click + if press is None: + press = inp.mouse_click - if coll(rect): - if tooltip: - tool_tip.test(x + 15 * gui.scale, y - 28 * gui.scale, tooltip) - ddt.rect(rect, background_highlight_colour) + if coll(rect): + if tooltip: + tool_tip.test(x + 15 * gui.scale, y - 28 * gui.scale, tooltip) + ddt.rect(rect, background_highlight_colour) - # if background_highlight_colour[3] != 255: - # background_highlight_colour = None + # if background_highlight_colour[3] != 255: + # background_highlight_colour = None - ddt.text((rect[0] + int(rect[2] / 2), rect[1] + 2 * gui.scale, 2), text, text_highlight_colour, font, - bg=background_highlight_colour) - if press: - click = True - else: - ddt.rect(rect, background_colour) - if background_highlight_colour[3] != 255: - background_colour = None - ddt.text((rect[0] + int(rect[2] / 2), rect[1] + 2 * gui.scale, 2), text, text_colour, font, - bg=background_colour) - return click + ddt.text( + (rect[0] + int(rect[2] / 2), rect[1] + 2 * gui.scale, 2), text, text_highlight_colour, font, bg=background_highlight_colour) + if press: + click = True + else: + ddt.rect(rect, background_colour) + if background_highlight_colour[3] != 255: + background_colour = None + ddt.text( + (rect[0] + int(rect[2] / 2), rect[1] + 2 * gui.scale, 2), text, text_colour, font, bg=background_colour) + return click draw = Drawing() From 400cb9e70ad4126c084fa38a21d51a52b2b70728 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Wed, 20 Nov 2024 20:00:00 +0100 Subject: [PATCH 54/63] t_main: Fix setting xcursor when the env vars are empty --- src/tauon/t_modules/t_main.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 83ac0481d..52e20bc6d 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -10002,8 +10002,14 @@ class XcursorImage(ctypes.Structure): xcu = ctypes.cdll.LoadLibrary("libXcursor.so.1") xcu.XcursorLibraryLoadImage.restype = ctypes.POINTER(XcursorImage) - def get_xcursor(name): - c1 = xcu.XcursorLibraryLoadImage(c_char_p(name.encode()), c_char_p(os.environ["XCURSOR_THEME"].encode()), c_int(int(os.environ["XCURSOR_SIZE"]))).contents + def get_xcursor(name: str): + xcursor_theme = "" + if "XCURSOR_THEME" in os.environ: + xcursor_theme = os.environ["XCURSOR_THEME"] + xcursor_size = "0" + if "XCURSOR_SIZE" in os.environ: + xcursor_theme = os.environ["XCURSOR_SIZE"] + c1 = xcu.XcursorLibraryLoadImage(c_char_p(name.encode()), c_char_p(xcursor_theme.encode()), c_int(int(xcursor_size))).contents sdl_surface = SDL_CreateRGBSurfaceWithFormatFrom(c1.pixels, c1.width, c1.height, 32, c1.width * 4, SDL_PIXELFORMAT_ARGB8888) cursor = SDL_CreateColorCursor(sdl_surface, round(c1.xhot), round(c1.yhot)) xcu.XcursorImageDestroy(ctypes.byref(c1)) From 96e79a48d8dc24432773ccfa802c64b10a9e0888 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Wed, 20 Nov 2024 21:12:02 +0100 Subject: [PATCH 55/63] t_main: Fix var typo --- src/tauon/t_modules/t_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 52e20bc6d..ff67bbcb1 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -10008,7 +10008,7 @@ def get_xcursor(name: str): xcursor_theme = os.environ["XCURSOR_THEME"] xcursor_size = "0" if "XCURSOR_SIZE" in os.environ: - xcursor_theme = os.environ["XCURSOR_SIZE"] + xcursor_size = os.environ["XCURSOR_SIZE"] c1 = xcu.XcursorLibraryLoadImage(c_char_p(name.encode()), c_char_p(xcursor_theme.encode()), c_int(int(xcursor_size))).contents sdl_surface = SDL_CreateRGBSurfaceWithFormatFrom(c1.pixels, c1.width, c1.height, 32, c1.width * 4, SDL_PIXELFORMAT_ARGB8888) cursor = SDL_CreateColorCursor(sdl_surface, round(c1.xhot), round(c1.yhot)) From 6f169b7f581c4098e9feb4140fe61c210221afc4 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Wed, 20 Nov 2024 21:52:18 +0100 Subject: [PATCH 56/63] t_main: Only set Xcursor if both XCURSOR_THEME and XCURSOR_SIZE are set --- src/tauon/t_modules/t_main.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index ff67bbcb1..832758686 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -9981,19 +9981,19 @@ def draw_window_border(): cursor_left_side = cursor_shift cursor_top_side = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS) cursor_bottom_side = cursor_top_side -elif not msys and system == "linux": +elif not msys and system == "linux" and "XCURSOR_THEME" in os.environ and "XCURSOR_SIZE" in os.environ: try: class XcursorImage(ctypes.Structure): _fields_ = [ - ("version", c_uint32), - ("size", c_uint32), - ("width", c_uint32), - ("height", c_uint32), - ("xhot", c_uint32), - ("yhot", c_uint32), - ("delay", c_uint32), - ("pixels", c_void_p), - ] + ("version", c_uint32), + ("size", c_uint32), + ("width", c_uint32), + ("height", c_uint32), + ("xhot", c_uint32), + ("yhot", c_uint32), + ("delay", c_uint32), + ("pixels", c_void_p) + ] try: xcu = ctypes.cdll.LoadLibrary("libXcursor.so") @@ -10003,12 +10003,12 @@ class XcursorImage(ctypes.Structure): xcu.XcursorLibraryLoadImage.restype = ctypes.POINTER(XcursorImage) def get_xcursor(name: str): - xcursor_theme = "" - if "XCURSOR_THEME" in os.environ: - xcursor_theme = os.environ["XCURSOR_THEME"] - xcursor_size = "0" - if "XCURSOR_SIZE" in os.environ: - xcursor_size = os.environ["XCURSOR_SIZE"] + if "XCURSOR_THEME" not in os.environ: + raise ValueError("Missing XCURSOR_THEME in env") + if "XCURSOR_SIZE" not in os.environ: + raise ValueError("Missing XCURSOR_SIZE in env") + xcursor_theme = os.environ["XCURSOR_THEME"] + xcursor_size = os.environ["XCURSOR_SIZE"] c1 = xcu.XcursorLibraryLoadImage(c_char_p(name.encode()), c_char_p(xcursor_theme.encode()), c_int(int(xcursor_size))).contents sdl_surface = SDL_CreateRGBSurfaceWithFormatFrom(c1.pixels, c1.width, c1.height, 32, c1.width * 4, SDL_PIXELFORMAT_ARGB8888) cursor = SDL_CreateColorCursor(sdl_surface, round(c1.xhot), round(c1.yhot)) From b723cdc331765929c4cc71f53094dce5e9424cdc Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Wed, 20 Nov 2024 23:01:39 +0100 Subject: [PATCH 57/63] t_main: Catch errors for and simplify loading Star, Album Star and State databases --- src/tauon/t_modules/t_main.py | 89 ++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index 832758686..a322a481f 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -2968,43 +2968,44 @@ def show_message(line1: str, line2: str ="", line3: str = "", mode: str = "info" gbc.disable() ggc = 2 -try: - sp1 = user_directory + "/star.p" - sp2 = user_directory + "/star.p.backup" - - s1 = 0 - s2 = 0 - - if os.path.isfile(sp1): - s1 = os.path.getsize(sp1) - if os.path.isfile(sp2): - s2 = os.path.getsize(sp2) - to_load = sp1 - if s2 > s1: - logging.info("Loading backup star.p") - to_load = sp2 - - star_store.db = pickle.load(open(to_load, "rb")) -except FileNotFoundError: - logging.error("No existing star.p file") -except Exception: - logging.exception("Unknown error loading star.p file") +star_path1 = Path(user_directory) / "star.p" +star_path2 = Path(user_directory) / "star.p.backup" +star_size1 = 0 +star_size2 = 0 +to_load = star_path1 +if star_path1.is_file(): + star_size1 = star_path1.stat().st_size +if star_path2.is_file(): + star_size2 = star_path2.stat().st_size +if star_size2 > star_size1: + logging.warning("Loading backup star.p as it was bigger than regular file!") + to_load = star_path2 +if star_size1 == 0 and star_size2 == 0: + logging.warning("Star database file is missing, first run? Will create one anew!") +else: + try: + star_store.db = pickle.load(open(to_load, "rb")) + except Exception: + logging.exception("Unknown error loading star.p file") -try: - album_star_store.db = pickle.load(open(user_directory + "/album-star.p", "rb")) -except FileNotFoundError: - logging.error("No existing album-star.p file") -except Exception: - logging.exception("Unknown error loading album-star.p file") -try: - if os.path.isfile(user_directory + "/lyrics_substitutions.json"): +album_star_path = Path(user_directory) / "album-star.p" +if album_star_path.is_file(): + try: + album_star_store.db = pickle.load(open(album_star_path, "rb")) + except Exception: + logging.exception("Unknown error loading album-star.p file") +else: + logging.warning("Album star database file is missing, first run? Will create one anew!") + +if os.path.isfile(user_directory + "/lyrics_substitutions.json"): + try: with open(user_directory + "/lyrics_substitutions.json", "r") as f: prefs.lyrics_subs = json.load(f) -except FileNotFoundError: - logging.error("No existing lyrics_substitutions.json file") -except Exception: - logging.exception("Unknown error loading lyrics_substitutions.json") + except FileNotFoundError: + logging.error("No existing lyrics_substitutions.json file") + except Exception: + logging.exception("Unknown error loading lyrics_substitutions.json") perf_timer.set() @@ -3065,18 +3066,20 @@ def pumper(): shoot_pump.daemon = True shoot_pump.start() +state_path1 = Path(user_directory) / "state.p" +state_path2 = Path(user_directory) / "state.p.backup" for t in range(2): + # os.path.getsize(user_directory + "/state.p") < 100 try: - - # if os.path.isfile(user_directory + "/state.p.backup") and ( - # - # not os.path.isfile(user_directory + "/state.p") or - # os.path.getsize(user_directory + "/state.p") < 100 - # ) if t == 0: - state_file = open(user_directory + "/state.p", "rb") + if not state_path1.is_file(): + continue + state_file = open(state_path1, "rb") if t == 1: - state_file = open(user_directory + "/state.p.backup", "rb") + if not state_path2.is_file(): + logging.warning("State database file is missing, first run? Will create one anew!") + break + state_file = open(state_path2, "rb") # def tt(): # while True: @@ -3087,7 +3090,7 @@ def pumper(): save = pickle.load(state_file) if t == 1: - logging.warning("Using backup state") + logging.warning("Loading backup state.p!") if save[63] is not None: prefs.ui_scale = save[63] @@ -3451,8 +3454,6 @@ def pumper(): break except Exception: logging.exception("Failed to load save file") - if os.path.isfile(user_directory + "/state.p"): - logging.error("Error loading save file") core_timer.set() logging.info(f"Database loaded in {round(perf_timer.get(), 3)} seconds.") From cabb31a93fa90de8a2a0ddf77abe98e56c0a83ec Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Wed, 20 Nov 2024 23:37:07 +0100 Subject: [PATCH 58/63] t_main: Fix mishandling SDL_WINDOWEVENT_DISPLAY_CHANGED causing the Grr error --- src/tauon/t_modules/t_main.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tauon/t_modules/t_main.py b/src/tauon/t_modules/t_main.py index a322a481f..c2f24a647 100644 --- a/src/tauon/t_modules/t_main.py +++ b/src/tauon/t_modules/t_main.py @@ -43905,11 +43905,15 @@ def drop_file(target): key_focused = 1 gui.update += 1 - elif event.window.event == SDL_WINDOWEVENT_RESIZED or event.window.event == SDL_WINDOWEVENT_DISPLAY_CHANGED: + elif event.window.event == SDL_WINDOWEVENT_DISPLAY_CHANGED: + # SDL_WINDOWEVENT_DISPLAY_CHANGED logs new display ID as data1 (0 or 1 or 2...), it not width, and data 2 is always 0 + pass + elif event.window.event == SDL_WINDOWEVENT_RESIZED: + # SDL_WINDOWEVENT_RESIZED logs width to data1 and height to data2 if event.window.data1 < 500: - logging.error("Grrr why this happen, stupid bug - reproducible when moving window from one screen to another in Plasma") + logging.error("Window width is less than 500, grrr why does this happen, stupid bug") SDL_SetWindowSize(t_window, logical_size[0], logical_size[1]) - elif restore_ignore_timer.get() > 1 or event.window.event == SDL_WINDOWEVENT_DISPLAY_CHANGED: # Hacky + elif restore_ignore_timer.get() > 1: # Hacky gui.update = 2 logical_size[0] = event.window.data1 From 9ef2879a9484e4ae0745a4302ba6b5008891a937 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Wed, 20 Nov 2024 23:59:35 +0100 Subject: [PATCH 59/63] win-build.sh: Attempt to fix it up for current state of things --- win-build.sh | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/win-build.sh b/win-build.sh index 89cc11f00..f88a3be2f 100755 --- a/win-build.sh +++ b/win-build.sh @@ -1,20 +1,52 @@ -#!/bin/bash +#!/usr/bin/env bash +set -euo pipefail + rm -rf dist/tauon -pyinstaller --additional-hooks-dir='extra\pyinstaller-hooks' --hidden-import 'infi.systray' --hidden-import 'pylast' --hidden-import 'tekore' --add-binary 'C:\msys64\mingw64\lib\girepository-1.0\Rsvg-2.0.typelib;gi_typelibs' --add-binary 'lib/libphazor.so;lib' --add-binary 'C:\msys64\mingw64\bin\libFLAC.dll;.' --add-binary 'C:\msys64\mingw64\bin\libmpg123-0.dll;.' --add-binary 'C:\msys64\mingw64\bin\libogg-0.dll;.' --add-binary 'C:\msys64\mingw64\bin\libopenmpt-0.dll;.' --add-binary 'C:\msys64\mingw64\bin\libopus-0.dll;.' --add-binary 'C:\msys64\mingw64\bin\libopusfile-0.dll;.' --add-binary 'C:\msys64\mingw64\bin\libsamplerate-0.dll;.' --add-binary 'C:\msys64\mingw64\bin\libvorbis-0.dll;.' --add-binary 'C:\msys64\mingw64\bin\libvorbisfile-3.dll;.' --add-binary 'C:\msys64\mingw64\bin\libwavpack-1.dll;.' --add-binary 'C:\msys64\mingw64\bin\SDL2.dll;.' --add-binary 'C:\msys64\mingw64\bin\SDL2_image.dll;.' --add-binary 'C:\msys64\mingw64\bin\libgme.dll;.' --hidden-import 'pip' --hidden-import 'packaging.requirements' --hidden-import 'pkg_resources.py2_warn' --hidden-import 'requests' tauon.py -w -i assets/icon.ico -mkdir dist/tauon/tekore + +pyinstaller \ + --additional-hooks-dir='extra\pyinstaller-hooks' \ + --hidden-import 'infi.systray' \ + --hidden-import 'pylast' \ + --hidden-import 'tekore' \ + --add-binary 'C:\msys64\mingw64\lib\girepository-1.0\Rsvg-2.0.typelib;gi_typelibs' \ + --add-binary 'lib/libphazor.so;lib' \ + --add-binary 'C:\msys64\mingw64\bin\libFLAC.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libmpg123-0.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libogg-0.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libopenmpt-0.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libopus-0.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libopusfile-0.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libsamplerate-0.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libvorbis-0.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libvorbisfile-3.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libwavpack-1.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\SDL2.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\SDL2_image.dll;.' \ + --add-binary 'C:\msys64\mingw64\bin\libgme.dll;.' \ + --hidden-import 'pip' \ + --hidden-import 'packaging.requirements' \ + --hidden-import 'pkg_resources.py2_warn' \ + --hidden-import 'requests' \ + src/tauon/tauon.py \ + -w -i assets/icon.ico + +mkdir -p dist/tauon/tekore + #cp C:/msys64/mingw64/lib/python3.10/site-packages/tekore/VERSION dist/tauon/tekore/VERSION -cp -r theme dist/tauon/ -cp -r assets dist/tauon/ -cp -r locale dist/tauon/ -cp -r templates dist/tauon/ -cp -r lib dist/tauon/ -cp input.txt dist/tauon/ + +cp -r src/tauon/theme dist/tauon/ +cp -r src/tauon/assets dist/tauon/ +cp -r src/tauon/locale dist/tauon/ +cp -r src/tauon/templates dist/tauon/ +cp -r src/tauon/lib dist/tauon/ + rm -rf dist/tauon/share/icons rm -rf dist/tauon/share/locale rm -rf dist/tauon/share/tcl/tzdata rm -rf dist/tauon/tcl/tzdata + mkdir dist/tauon/etc cp -r fonts dist/tauon/ 2>/dev/null || echo 'Fonts are not present!' cp -r /mingw64/etc/fonts dist/tauon/etc cp librespot.exe dist/tauon/ -cp TaskbarLib.tlb dist/tauon/ 2>/dev/null || echo 'TLB is not present!' \ No newline at end of file +cp TaskbarLib.tlb dist/tauon/ 2>/dev/null || echo 'TLB is not present!' From 6a61a3bc16029b3ea849db094f80b6970921bb3f Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Thu, 21 Nov 2024 00:01:27 +0100 Subject: [PATCH 60/63] Move Windows requirements to /requirements_windows.txt --- extra/win-requirements.txt => requirements_windows.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename extra/win-requirements.txt => requirements_windows.txt (100%) diff --git a/extra/win-requirements.txt b/requirements_windows.txt similarity index 100% rename from extra/win-requirements.txt rename to requirements_windows.txt From 6c68d5ec4bfa44c0941c121c43be540eb4808f80 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Thu, 21 Nov 2024 00:05:57 +0100 Subject: [PATCH 61/63] requirements_windows.txt: Sort and add PyGObject otherwise we lack gi --- requirements_windows.txt | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/requirements_windows.txt b/requirements_windows.txt index b33fcc4c6..3b8d17270 100644 --- a/requirements_windows.txt +++ b/requirements_windows.txt @@ -1,17 +1,20 @@ -comtypes -keyboard -pylast -PySDL2 -pyinstaller -Send2Trash -requests beautifulsoup4 -PlexAPI -musicbrainzngs -unidecode +comtypes # Windows dep +# dbus-python # Linux dep infi.systray +keyboard # Windows dep +musicbrainzngs mutagen -natsort -tekore -pypresence -opencc-python-reimplemented +natsort # optdep +opencc-python-reimplemented # Windows version of openCC optdep +# Pillow # Linux dep +PlexAPI +PyGObject +pyinstaller +pylast>=3.1.0 +pypresence # optdep +PySDL2 +requests +Send2Trash +tekore # optdep +unidecode From 02a2c827afa9be4cf47f19147a5b0943c2b862a3 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Thu, 21 Nov 2024 02:17:38 +0100 Subject: [PATCH 62/63] phazor.c: Fix opusfile include --- src/phazor/phazor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phazor/phazor.c b/src/phazor/phazor.c index ceceea3f2..7252e50d3 100644 --- a/src/phazor/phazor.c +++ b/src/phazor/phazor.c @@ -66,7 +66,7 @@ #include #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" -#include "opusfile.h" +#include "opus/opusfile.h" #include #include #include From 29245a3bd96e726be92a981ff8c85df56401a064 Mon Sep 17 00:00:00 2001 From: Martin Rys Date: Thu, 21 Nov 2024 03:30:48 +0100 Subject: [PATCH 63/63] hook-pylast.py: Spacing and quotes --- extra/pyinstaller-hooks/hook-pylast.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extra/pyinstaller-hooks/hook-pylast.py b/extra/pyinstaller-hooks/hook-pylast.py index 4274e2e17..609135263 100644 --- a/extra/pyinstaller-hooks/hook-pylast.py +++ b/extra/pyinstaller-hooks/hook-pylast.py @@ -1,2 +1,3 @@ from PyInstaller.utils.hooks import copy_metadata -datas = copy_metadata('pylast') + +datas = copy_metadata("pylast")