fixes and idk
This commit is contained in:
parent
69ce4bc763
commit
d01a743c45
@ -75,58 +75,38 @@ class MusicTable(QTableView):
|
|||||||
focusEnterSignal = pyqtSignal()
|
focusEnterSignal = pyqtSignal()
|
||||||
focusLeaveSignal = pyqtSignal()
|
focusLeaveSignal = pyqtSignal()
|
||||||
|
|
||||||
def focusInEvent(self, e):
|
|
||||||
"""
|
|
||||||
Event filter: when self is focused
|
|
||||||
"""
|
|
||||||
self.focusEnterSignal.emit()
|
|
||||||
# arrow keys act normal
|
|
||||||
super().focusInEvent(e)
|
|
||||||
|
|
||||||
def focusOutEvent(self, e):
|
|
||||||
"""
|
|
||||||
Event filter: when self becomes unfocused
|
|
||||||
"""
|
|
||||||
self.focusLeaveSignal.emit()
|
|
||||||
|
|
||||||
def __init__(self, parent=None, application_window=None):
|
def __init__(self, parent=None, application_window=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
# why do i need this?
|
# why do i need this?
|
||||||
self.application_window = application_window
|
self.application_window = application_window
|
||||||
|
self.config = ConfigParser()
|
||||||
# NOTE: wtf is actually going on here with the models?
|
|
||||||
# Create QStandardItemModel
|
|
||||||
# Create QSortFilterProxyModel
|
|
||||||
# Set QSortFilterProxyModel source to QStandardItemModel
|
|
||||||
# Set QTableView model to the Proxy model
|
|
||||||
# so it looks like this, i guess:
|
|
||||||
# QTableView model2 = QSortFilterProxyModel(QStandardItemModel)
|
|
||||||
|
|
||||||
# need a standard item model to do actions on cells
|
|
||||||
self.model2: QStandardItemModel = QStandardItemModel()
|
|
||||||
# proxy model for sorting i guess?
|
|
||||||
self.proxymodel = QSortFilterProxyModel()
|
|
||||||
self.proxymodel.setSourceModel(self.model2)
|
|
||||||
self.setModel(self.proxymodel)
|
|
||||||
self.setSortingEnabled(True)
|
|
||||||
self.search_string = None
|
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
cfg_file = (
|
cfg_file = (
|
||||||
Path(user_config_dir(appname="musicpom", appauthor="billypom"))
|
Path(user_config_dir(appname="musicpom", appauthor="billypom"))
|
||||||
/ "config.ini"
|
/ "config.ini"
|
||||||
)
|
)
|
||||||
self.config = ConfigParser()
|
|
||||||
self.config.read(cfg_file)
|
self.config.read(cfg_file)
|
||||||
debug(f"music table config: {self.config}")
|
debug(f"music table config: {self.config}")
|
||||||
|
|
||||||
# Threads
|
# NOTE:
|
||||||
self.threadpool = QThreadPool
|
# QTableView model2 = QSortFilterProxyModel(QStandardItemModel)
|
||||||
# headers class thing
|
#
|
||||||
self.headers = HeaderTags()
|
# wtf is actually going on here with the models?
|
||||||
|
# Create QStandardItemModel
|
||||||
|
# Create QSortFilterProxyModel
|
||||||
|
# Set QSortFilterProxyModel source to QStandardItemModel
|
||||||
|
# Set QTableView model to the Proxy model
|
||||||
|
# so it looks like that, i guess
|
||||||
|
|
||||||
|
# need a QStandardItemModel to do actions on cells
|
||||||
|
self.model2: QStandardItemModel = QStandardItemModel()
|
||||||
|
self.proxymodel = QSortFilterProxyModel()
|
||||||
|
self.search_string = None
|
||||||
|
self.threadpool = QThreadPool
|
||||||
|
self.headers = HeaderTags()
|
||||||
# db names of headers
|
# db names of headers
|
||||||
self.database_columns = str(self.config["table"]["columns"]).split(",")
|
self.database_columns: list[str] = str(
|
||||||
|
self.config["table"]["columns"]).split(",")
|
||||||
self.vertical_scroll_position = 0
|
self.vertical_scroll_position = 0
|
||||||
self.selected_song_filepath = ""
|
self.selected_song_filepath = ""
|
||||||
self.selected_song_qmodel_index: QModelIndex
|
self.selected_song_qmodel_index: QModelIndex
|
||||||
@ -135,6 +115,11 @@ class MusicTable(QTableView):
|
|||||||
self.current_song_qmodel_index: QModelIndex
|
self.current_song_qmodel_index: QModelIndex
|
||||||
self.selected_playlist_id: int | None = None
|
self.selected_playlist_id: int | None = None
|
||||||
|
|
||||||
|
# proxy model for sorting i guess?
|
||||||
|
self.proxymodel.setSourceModel(self.model2)
|
||||||
|
self.setModel(self.proxymodel)
|
||||||
|
self.setSortingEnabled(True)
|
||||||
|
|
||||||
# Properties
|
# Properties
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
self.setHorizontalScrollBarPolicy(
|
self.setHorizontalScrollBarPolicy(
|
||||||
@ -175,6 +160,20 @@ class MusicTable(QTableView):
|
|||||||
# | |
|
# | |
|
||||||
# |_________________|
|
# |_________________|
|
||||||
|
|
||||||
|
def focusInEvent(self, e):
|
||||||
|
"""
|
||||||
|
Event filter: when self is focused
|
||||||
|
"""
|
||||||
|
self.focusEnterSignal.emit()
|
||||||
|
# arrow keys act normal
|
||||||
|
super().focusInEvent(e)
|
||||||
|
|
||||||
|
def focusOutEvent(self, e):
|
||||||
|
"""
|
||||||
|
Event filter: when self becomes unfocused
|
||||||
|
"""
|
||||||
|
self.focusLeaveSignal.emit()
|
||||||
|
|
||||||
def resizeEvent(self, e: typing.Optional[QResizeEvent]) -> None:
|
def resizeEvent(self, e: typing.Optional[QResizeEvent]) -> None:
|
||||||
"""Do something when the QTableView is resized"""
|
"""Do something when the QTableView is resized"""
|
||||||
if e is None:
|
if e is None:
|
||||||
@ -490,7 +489,8 @@ class MusicTable(QTableView):
|
|||||||
"""
|
"""
|
||||||
worker = Worker(add_files_to_database, files)
|
worker = Worker(add_files_to_database, files)
|
||||||
_ = worker.signals.signal_progress.connect(self.qapp.handle_progress)
|
_ = worker.signals.signal_progress.connect(self.qapp.handle_progress)
|
||||||
_ = worker.signals.signal_result.connect(self.on_add_files_to_database_finished)
|
_ = worker.signals.signal_result.connect(
|
||||||
|
self.on_add_files_to_database_finished)
|
||||||
worker.signals.signal_finished.connect(self.load_music_table)
|
worker.signals.signal_finished.connect(self.load_music_table)
|
||||||
if self.qapp:
|
if self.qapp:
|
||||||
threadpool = self.qapp.threadpool
|
threadpool = self.qapp.threadpool
|
||||||
@ -660,7 +660,7 @@ class MusicTable(QTableView):
|
|||||||
def reorganize_files(self, filepaths, progress_callback=None):
|
def reorganize_files(self, filepaths, progress_callback=None):
|
||||||
"""
|
"""
|
||||||
Reorganizes files into Artist/Album/Song,
|
Reorganizes files into Artist/Album/Song,
|
||||||
based on self.config['directories'][reorganize_destination']
|
based on self.config['settings'][reorganize_destination']
|
||||||
"""
|
"""
|
||||||
debug("reorganizing files")
|
debug("reorganizing files")
|
||||||
# FIXME: batch update, instead of doing 1 file at a time
|
# FIXME: batch update, instead of doing 1 file at a time
|
||||||
@ -671,7 +671,7 @@ class MusicTable(QTableView):
|
|||||||
# FIXME: change reorganize location in config, try to reorganize, failed - old reference
|
# FIXME: change reorganize location in config, try to reorganize, failed - old reference
|
||||||
|
|
||||||
# Get target directory
|
# Get target directory
|
||||||
target_dir = str(self.config["directories"]["reorganize_destination"])
|
target_dir = str(self.config["settings"]["reorganize_destination"])
|
||||||
for filepath in filepaths:
|
for filepath in filepaths:
|
||||||
# Read file metadata
|
# Read file metadata
|
||||||
artist, album = get_reorganize_vars(filepath)
|
artist, album = get_reorganize_vars(filepath)
|
||||||
@ -737,7 +737,8 @@ class MusicTable(QTableView):
|
|||||||
self.selected_playlist_id = playlist_id[0]
|
self.selected_playlist_id = playlist_id[0]
|
||||||
try:
|
try:
|
||||||
with DBA.DBAccess() as db:
|
with DBA.DBAccess() as db:
|
||||||
query = f"SELECT id, {fields} FROM song JOIN song_playlist sp ON id = sp.song_id WHERE sp.playlist_id = ?"
|
query = f"SELECT id, {
|
||||||
|
fields} FROM song JOIN song_playlist sp ON id = sp.song_id WHERE sp.playlist_id = ?"
|
||||||
# fulltext search
|
# fulltext search
|
||||||
if self.search_string:
|
if self.search_string:
|
||||||
# params = 3 * [self.search_string]
|
# params = 3 * [self.search_string]
|
||||||
@ -821,7 +822,8 @@ class MusicTable(QTableView):
|
|||||||
db_name: str = self.config.get("settings", "db").split("/").pop()
|
db_name: str = self.config.get("settings", "db").split("/").pop()
|
||||||
db_filename = self.config.get("settings", "db")
|
db_filename = self.config.get("settings", "db")
|
||||||
self.playlistStatsSignal.emit(
|
self.playlistStatsSignal.emit(
|
||||||
f"Songs: {row_count} | Total time: {total_time} | {db_name} | {db_filename}"
|
f"Songs: {row_count} | Total time: {
|
||||||
|
total_time} | {db_name} | {db_filename}"
|
||||||
)
|
)
|
||||||
self.loadMusicTableSignal.emit()
|
self.loadMusicTableSignal.emit()
|
||||||
self.connect_data_changed()
|
self.connect_data_changed()
|
||||||
|
|||||||
70
main.py
70
main.py
@ -57,6 +57,8 @@ from utils import (
|
|||||||
add_files_to_database,
|
add_files_to_database,
|
||||||
set_album_art,
|
set_album_art,
|
||||||
id3_remap,
|
id3_remap,
|
||||||
|
get_album_art,
|
||||||
|
Worker
|
||||||
)
|
)
|
||||||
from components import (
|
from components import (
|
||||||
HeaderTags,
|
HeaderTags,
|
||||||
@ -68,9 +70,6 @@ from components import (
|
|||||||
ExportPlaylistWindow,
|
ExportPlaylistWindow,
|
||||||
SearchLineEdit,
|
SearchLineEdit,
|
||||||
)
|
)
|
||||||
from utils.get_album_art import get_album_art
|
|
||||||
# from utils.Worker import Worker
|
|
||||||
from utils import Worker
|
|
||||||
|
|
||||||
# good help with signals slots in threads
|
# good help with signals slots in threads
|
||||||
# https://stackoverflow.com/questions/52993677/how-do-i-setup-signals-and-slots-in-pyqt-with-qthreads-in-both-directions
|
# https://stackoverflow.com/questions/52993677/how-do-i-setup-signals-and-slots-in-pyqt-with-qthreads-in-both-directions
|
||||||
@ -162,18 +161,23 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.playbackSlider.sliderReleased.connect(
|
self.playbackSlider.sliderReleased.connect(
|
||||||
lambda: self.player.setPosition(self.playbackSlider.value())
|
lambda: self.player.setPosition(self.playbackSlider.value())
|
||||||
) # sliderReleased works better than sliderMoved
|
) # sliderReleased works better than sliderMoved
|
||||||
self.volumeSlider.sliderMoved[int].connect(lambda: self.on_volume_changed())
|
self.volumeSlider.sliderMoved[int].connect(
|
||||||
|
lambda: self.on_volume_changed())
|
||||||
self.speedSlider.sliderMoved.connect(
|
self.speedSlider.sliderMoved.connect(
|
||||||
lambda: self.on_speed_changed(self.speedSlider.value())
|
lambda: self.on_speed_changed(self.speedSlider.value())
|
||||||
)
|
)
|
||||||
# self.speedSlider.doubleClicked.connect(lambda: self.on_speed_changed(1))
|
# self.speedSlider.doubleClicked.connect(lambda: self.on_speed_changed(1))
|
||||||
self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause
|
self.playButton.clicked.connect(
|
||||||
|
self.on_play_clicked) # Click to play/pause
|
||||||
self.previousButton.clicked.connect(self.on_prev_clicked)
|
self.previousButton.clicked.connect(self.on_prev_clicked)
|
||||||
self.nextButton.clicked.connect(self.on_next_clicked) # Click to next song
|
self.nextButton.clicked.connect(
|
||||||
|
self.on_next_clicked) # Click to next song
|
||||||
|
|
||||||
# FILE MENU
|
# FILE MENU
|
||||||
self.actionOpenFiles.triggered.connect(self.open_files) # Open files window
|
self.actionOpenFiles.triggered.connect(
|
||||||
self.actionNewPlaylist.triggered.connect(self.playlistTreeView.create_playlist)
|
self.open_files) # Open files window
|
||||||
|
self.actionNewPlaylist.triggered.connect(
|
||||||
|
self.playlistTreeView.create_playlist)
|
||||||
self.actionExportPlaylist.triggered.connect(self.export_playlist)
|
self.actionExportPlaylist.triggered.connect(self.export_playlist)
|
||||||
|
|
||||||
# EDIT MENU
|
# EDIT MENU
|
||||||
@ -195,14 +199,16 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.lineEditSearch: QLineEdit
|
self.lineEditSearch: QLineEdit
|
||||||
|
|
||||||
# CONNECTIONS
|
# CONNECTIONS
|
||||||
self.lineEditSearch.textTypedSignal.connect(self.handle_search_box_text)
|
self.lineEditSearch.textTypedSignal.connect(
|
||||||
|
self.handle_search_box_text)
|
||||||
# tableView
|
# tableView
|
||||||
self.tableView.playSignal.connect(self.play_audio_file)
|
self.tableView.playSignal.connect(self.play_audio_file)
|
||||||
self.tableView.playPauseSignal.connect(
|
self.tableView.playPauseSignal.connect(
|
||||||
self.on_play_clicked
|
self.on_play_clicked
|
||||||
) # Spacebar toggle play/pause signal
|
) # Spacebar toggle play/pause signal
|
||||||
self.tableView.handleProgressSignal.connect(self.handle_progress)
|
self.tableView.handleProgressSignal.connect(self.handle_progress)
|
||||||
self.tableView.searchBoxSignal.connect(self.handle_search_box_visibility)
|
self.tableView.searchBoxSignal.connect(
|
||||||
|
self.handle_search_box_visibility)
|
||||||
self.tableView.playlistStatsSignal.connect(
|
self.tableView.playlistStatsSignal.connect(
|
||||||
self.set_permanent_status_bar_message
|
self.set_permanent_status_bar_message
|
||||||
)
|
)
|
||||||
@ -213,7 +219,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.playlistTreeView.playlistChoiceSignal.connect(
|
self.playlistTreeView.playlistChoiceSignal.connect(
|
||||||
self.tableView.load_music_table
|
self.tableView.load_music_table
|
||||||
)
|
)
|
||||||
self.playlistTreeView.allSongsSignal.connect(self.tableView.load_music_table)
|
self.playlistTreeView.allSongsSignal.connect(
|
||||||
|
self.tableView.load_music_table)
|
||||||
|
|
||||||
# albumGraphicsView
|
# albumGraphicsView
|
||||||
self.albumGraphicsView.albumArtDropped.connect(
|
self.albumGraphicsView.albumArtDropped.connect(
|
||||||
@ -315,7 +322,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
current_real_index = self.tableView.current_song_qmodel_index
|
current_real_index = self.tableView.current_song_qmodel_index
|
||||||
try:
|
try:
|
||||||
index = self.tableView.proxymodel.mapFromSource(current_real_index)
|
index = self.tableView.proxymodel.mapFromSource(current_real_index)
|
||||||
except:
|
except Exception:
|
||||||
return
|
return
|
||||||
row: int = index.row()
|
row: int = index.row()
|
||||||
prev_row: int = row - 1
|
prev_row: int = row - 1
|
||||||
@ -392,7 +399,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
def load_config(self) -> None:
|
def load_config(self) -> None:
|
||||||
"""does what it says"""
|
"""does what it says"""
|
||||||
cfg_file = (
|
cfg_file = (
|
||||||
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
|
Path(user_config_dir(appname="musicpom",
|
||||||
|
appauthor="billypom")) / "config.ini"
|
||||||
)
|
)
|
||||||
self.config.read(cfg_file)
|
self.config.read(cfg_file)
|
||||||
debug("load_config()")
|
debug("load_config()")
|
||||||
@ -470,7 +478,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
selected_songs = self.tableView.get_selected_songs_filepaths()
|
selected_songs = self.tableView.get_selected_songs_filepaths()
|
||||||
for song in selected_songs:
|
for song in selected_songs:
|
||||||
debug(
|
debug(
|
||||||
f"main.py set_album_art_for_selected_songs() | updating album art for {song}"
|
f"main.py set_album_art_for_selected_songs() | updating album art for {
|
||||||
|
song}"
|
||||||
)
|
)
|
||||||
set_album_art(song, album_art_path)
|
set_album_art(song, album_art_path)
|
||||||
|
|
||||||
@ -497,7 +506,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.playbackSlider.setMaximum(self.player.duration())
|
self.playbackSlider.setMaximum(self.player.duration())
|
||||||
slider_position = self.player.position()
|
slider_position = self.player.position()
|
||||||
self.playbackSlider.setValue(slider_position)
|
self.playbackSlider.setValue(slider_position)
|
||||||
current_minutes, current_seconds = divmod(slider_position / 1000, 60)
|
current_minutes, current_seconds = divmod(
|
||||||
|
slider_position / 1000, 60)
|
||||||
duration_minutes, duration_seconds = divmod(
|
duration_minutes, duration_seconds = divmod(
|
||||||
self.player.duration() / 1000, 60
|
self.player.duration() / 1000, 60
|
||||||
)
|
)
|
||||||
@ -548,7 +558,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
def create_playlist(self) -> None:
|
def create_playlist(self) -> None:
|
||||||
"""Creates a database record for a playlist, given a name"""
|
"""Creates a database record for a playlist, given a name"""
|
||||||
window = CreatePlaylistWindow(self.playlistCreatedSignal)
|
window = CreatePlaylistWindow(self.playlistCreatedSignal)
|
||||||
window.playlistCreatedSignal.connect(self.add_latest_playlist_to_tree) # type: ignore
|
window.playlistCreatedSignal.connect(
|
||||||
|
self.add_latest_playlist_to_tree) # type: ignore
|
||||||
window.exec_()
|
window.exec_()
|
||||||
|
|
||||||
def import_playlist(self) -> None:
|
def import_playlist(self) -> None:
|
||||||
@ -574,8 +585,10 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
preferences_window = PreferencesWindow(
|
preferences_window = PreferencesWindow(
|
||||||
self.reloadConfigSignal, self.reloadDatabaseSignal
|
self.reloadConfigSignal, self.reloadDatabaseSignal
|
||||||
)
|
)
|
||||||
preferences_window.reloadConfigSignal.connect(self.load_config) # type: ignore
|
preferences_window.reloadConfigSignal.connect(
|
||||||
preferences_window.reloadDatabaseSignal.connect(self.tableView.load_music_table) # type: ignore
|
self.load_config) # type: ignore
|
||||||
|
preferences_window.reloadDatabaseSignal.connect(
|
||||||
|
self.tableView.load_music_table) # type: ignore
|
||||||
preferences_window.exec_() # Display the preferences window modally
|
preferences_window.exec_() # Display the preferences window modally
|
||||||
|
|
||||||
# Quick Actions
|
# Quick Actions
|
||||||
@ -609,9 +622,11 @@ def update_database_file() -> bool:
|
|||||||
Reads the database file (specified by config file)
|
Reads the database file (specified by config file)
|
||||||
"""
|
"""
|
||||||
cfg_file = (
|
cfg_file = (
|
||||||
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
|
Path(user_config_dir(appname="musicpom",
|
||||||
|
appauthor="billypom")) / "config.ini"
|
||||||
)
|
)
|
||||||
cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom")))
|
cfg_path = str(Path(user_config_dir(
|
||||||
|
appname="musicpom", appauthor="billypom")))
|
||||||
config = ConfigParser()
|
config = ConfigParser()
|
||||||
config.read(cfg_file)
|
config.read(cfg_file)
|
||||||
db_filepath: str = config.get("settings", "db")
|
db_filepath: str = config.get("settings", "db")
|
||||||
@ -620,9 +635,10 @@ def update_database_file() -> bool:
|
|||||||
if not db_filepath.startswith(cfg_path):
|
if not db_filepath.startswith(cfg_path):
|
||||||
new_path = f"{cfg_path}/{db_filepath}"
|
new_path = f"{cfg_path}/{db_filepath}"
|
||||||
debug(
|
debug(
|
||||||
f"Set new config [db] database path: \n> Current: {db_filepath}\n> New:{new_path}"
|
f"Set new config [db] database path: \n> Current: {
|
||||||
|
db_filepath}\n> New:{new_path}"
|
||||||
)
|
)
|
||||||
config["db"]["database"] = new_path
|
config["settings"]["db"] = new_path
|
||||||
# Save the config
|
# Save the config
|
||||||
with open(cfg_file, "w") as configfile:
|
with open(cfg_file, "w") as configfile:
|
||||||
config.write(configfile)
|
config.write(configfile)
|
||||||
@ -654,9 +670,11 @@ def update_config_file() -> ConfigParser:
|
|||||||
If the user config file is not up to date, update it with examples from sample config
|
If the user config file is not up to date, update it with examples from sample config
|
||||||
"""
|
"""
|
||||||
cfg_file = (
|
cfg_file = (
|
||||||
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
|
Path(user_config_dir(appname="musicpom",
|
||||||
|
appauthor="billypom")) / "config.ini"
|
||||||
)
|
)
|
||||||
cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom")))
|
cfg_path = str(Path(user_config_dir(
|
||||||
|
appname="musicpom", appauthor="billypom")))
|
||||||
|
|
||||||
# If config path doesn't exist, create it
|
# If config path doesn't exist, create it
|
||||||
if not os.path.exists(cfg_path):
|
if not os.path.exists(cfg_path):
|
||||||
@ -720,8 +738,8 @@ if __name__ == "__main__":
|
|||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
clipboard = app.clipboard()
|
clipboard = app.clipboard()
|
||||||
# Dark theme >:3
|
# Dark theme >:3
|
||||||
qdarktheme.setup_theme()
|
# qdarktheme.setup_theme()
|
||||||
# qdarktheme.setup_theme("auto") # this is supposed to work but doesnt
|
qdarktheme.setup_theme("auto") # this is supposed to work but doesnt
|
||||||
# Show the UI
|
# Show the UI
|
||||||
ui = ApplicationWindow(clipboard)
|
ui = ApplicationWindow(clipboard)
|
||||||
# window size
|
# window size
|
||||||
|
|||||||
@ -3,7 +3,8 @@ matplotlib
|
|||||||
appdirs
|
appdirs
|
||||||
pyqt5
|
pyqt5
|
||||||
pydub
|
pydub
|
||||||
pyqtdarktheme-fork; python_version > '3.11'
|
audioop-lts
|
||||||
pyqtdarktheme; python_version < '3.12'
|
pyqtdarktheme-fork; python_version < '3.11'
|
||||||
|
pyqtdarktheme; python_version > '3.12'
|
||||||
pyqtgraph
|
pyqtgraph
|
||||||
scipy
|
scipy
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user