# Standard library imports from __future__ import annotations import ctypes from dataclasses import dataclass import datetime as dt from enum import auto, Enum import functools import platform from time import sleep from typing import Optional, NamedTuple # Third party imports import numpy as np import pyqtgraph as pg # type: ignore from sqlalchemy.orm.session import Session import vlc # type: ignore # PyQt imports from PyQt6.QtCore import ( pyqtSignal, QObject, QThread, ) from pyqtgraph import PlotWidget from pyqtgraph.graphicsItems.PlotDataItem import PlotDataItem # type: ignore from pyqtgraph.graphicsItems.LinearRegionItem import LinearRegionItem # type: ignore # App imports from config import Config from log import log from models import PlaylistRows from vlcmanager import VLCManager class Col(Enum): START_GAP = 0 TITLE = auto() ARTIST = auto() INTRO = auto() DURATION = auto() START_TIME = auto() END_TIME = auto() LAST_PLAYED = auto() BITRATE = auto() NOTE = auto() def singleton(cls): """ Make a class a Singleton class (see https://realpython.com/primer-on-python-decorators/#creating-singletons) """ @functools.wraps(cls) def wrapper_singleton(*args, **kwargs): if not wrapper_singleton.instance: wrapper_singleton.instance = cls(*args, **kwargs) return wrapper_singleton.instance wrapper_singleton.instance = None return wrapper_singleton class FileErrors(NamedTuple): path: str error: str class ApplicationError(Exception): """ Custom exception """ pass class AudioMetadata(NamedTuple): start_gap: int = 0 silence_at: int = 0 fade_at: int = 0 @singleton @dataclass class MusicMusterSignals(QObject): """ Class for all MusicMuster signals. See: - https://zetcode.com/gui/pyqt5/eventssignals/ - https://stackoverflow.com/questions/62654525/ emit-a-signal-from-another-class-to-main-class and Singleton class at https://refactoring.guru/design-patterns/singleton/python/example#example-0 """ begin_reset_model_signal = pyqtSignal(int) enable_escape_signal = pyqtSignal(bool) end_reset_model_signal = pyqtSignal(int) next_track_changed_signal = pyqtSignal() resize_rows_signal = pyqtSignal(int) search_songfacts_signal = pyqtSignal(str) search_wikipedia_signal = pyqtSignal(str) show_warning_signal = pyqtSignal(str, str) span_cells_signal = pyqtSignal(int, int, int, int, int) status_message_signal = pyqtSignal(str, int) track_ended_signal = pyqtSignal() def __post_init__(self): super().__init__() class Tags(NamedTuple): artist: str title: str bitrate: int duration: int class TrackInfo(NamedTuple): track_id: int row_number: int