ui updates, move print to logging debug/error/info, other stuff that i forgor?

This commit is contained in:
billypom on debian 2025-03-14 20:06:43 -04:00
parent eff515cd32
commit 2efe108f8c
15 changed files with 252 additions and 95 deletions

View File

@ -4,23 +4,31 @@ PyQt5 music player for Linux inspired by MusicBee & iTunes
## Installation: ## Installation:
clone the repo clone the repo
``` ```bash
git clone https://github.com/billypom/musicpom git clone https://github.com/billypom/musicpom
``` ```
install system packages install system packages
``` ```bash
sudo apt install ffmpeg, python3-pyqt5 sudo apt install ffmpeg, python3-pyqt5
``` ```
create environment create environment
``` ```bash
cd musicpom cd musicpom
virtualenv venv virtualenv venv
cd .. cd ..
cd musicpom cd musicpom
pip install -r requirements.txt pip install -r requirements.txt
``` ```
run the program
create ui.py from ui.ui
```bash
pyuic5 ui.ui -o ui.py
``` ```
run
```bash
python3 main.py python3 main.py
``` ```
@ -28,12 +36,13 @@ python3 main.py
- [x] right-click menu - [x] right-click menu
- [x] editable lyrics window - [x] editable lyrics window
- [x] batch metadata changer (red text on fields that have differing info) - [x] batch metadata changer (red highlight fields that have differing info)
- [x] playlists - [x] playlists
- [ ] delete songs from library (del key || right-click delete) - [ ] delete songs from library (del key || right-click delete)
- [ ] .wav, .ogg, .flac convertor - [ ] .wav, .ogg, .flac convertor
- [ ] FIXME: dbaccess is instantiated for every track being reorganized - [ ] FIXME: dbaccess is instantiated for every track being reorganized
- [ ] automatic "radio" based on artist or genre - [ ] automatic "radio" based on artist or genre
- [ ] search bar, full text search on song, artist, album - [ ] search bar, full text search on song, artist, album
- [ ] when table is focused, start typing to match against the primary sort column
- [ ] "installer" - put files in /opt? script to install and uninstall - [ ] "installer" - put files in /opt? script to install and uninstall
- [ ] .deb package? - [ ] .deb package?

View File

@ -1,5 +1,6 @@
import os import os
import tempfile import tempfile
from logging import debug
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QGraphicsPixmapItem, QGraphicsPixmapItem,
QGraphicsScene, QGraphicsScene,
@ -56,7 +57,7 @@ class AlbumArtGraphicsView(QGraphicsView):
if urls: if urls:
first_url = urls[0].toLocalFile() first_url = urls[0].toLocalFile()
if first_url.lower().endswith((".png", ".jpg", ".jpeg")): if first_url.lower().endswith((".png", ".jpg", ".jpeg")):
print(f"dropped {first_url}") debug(f"dropped {first_url}")
self.albumArtDropped.emit( self.albumArtDropped.emit(
first_url first_url
) # emit signal that album art was dropped ) # emit signal that album art was dropped

View File

@ -8,6 +8,7 @@ from PyQt5.QtWidgets import (
from PyQt5.QtGui import QFont from PyQt5.QtGui import QFont
from components.ErrorDialog import ErrorDialog from components.ErrorDialog import ErrorDialog
from utils import set_id3_tag from utils import set_id3_tag
from logging import debug
class LyricsWindow(QDialog): class LyricsWindow(QDialog):
@ -37,7 +38,7 @@ class LyricsWindow(QDialog):
value=self.input_field.toPlainText(), value=self.input_field.toPlainText(),
) )
if success: if success:
print("lyrical success! yay") debug("lyrical success! yay")
else: else:
error_dialog = ErrorDialog("Could not save lyrics :( sad") error_dialog = ErrorDialog("Could not save lyrics :( sad")
error_dialog.exec() error_dialog.exec()

View File

@ -15,6 +15,7 @@ from utils.get_id3_tags import get_id3_tags
from utils.set_id3_tag import set_id3_tag from utils.set_id3_tag import set_id3_tag
from utils.update_song_in_database import update_song_in_database from utils.update_song_in_database import update_song_in_database
from utils.id3_tag_mapping import id3_tag_mapping from utils.id3_tag_mapping import id3_tag_mapping
from logging import debug
# import re # import re
@ -74,8 +75,8 @@ class MetadataWindow(QDialog):
tag_sets[tag].append(song_data[tag].text[0]) tag_sets[tag].append(song_data[tag].text[0])
except KeyError: except KeyError:
pass pass
print("tag sets:") debug("tag sets:")
print(tag_sets) debug(tag_sets)
# UI Creation # UI Creation
current_layout = QHBoxLayout() current_layout = QHBoxLayout()

View File

@ -43,7 +43,7 @@ from utils.get_id3_tags import get_id3_tags
from utils.get_album_art import get_album_art from utils.get_album_art import get_album_art
from utils import set_id3_tag from utils import set_id3_tag
from subprocess import Popen from subprocess import Popen
import logging from logging import debug, error
import configparser import configparser
import os import os
import shutil import shutil
@ -146,7 +146,7 @@ class MusicTable(QTableView):
# in order to sort the data more effectively & have more control over UI refreshes. # in order to sort the data more effectively & have more control over UI refreshes.
# Disconnect these signals to prevent unnecessary loads # Disconnect these signals to prevent unnecessary loads
logging.info("sort_table_by_multiple_columns()") debug("sort_table_by_multiple_columns()")
self.disconnect_data_changed() self.disconnect_data_changed()
self.disconnect_layout_changed() self.disconnect_layout_changed()
sort_orders = [] sort_orders = []
@ -168,7 +168,7 @@ class MusicTable(QTableView):
# `len(config_sort_orders)` number of SELECTs # `len(config_sort_orders)` number of SELECTs
for i in reversed(range(len(sort_orders))): for i in reversed(range(len(sort_orders))):
if sort_orders[i] is not None: if sort_orders[i] is not None:
logging.info(f"sorting column {i} by {sort_orders[i]}") debug(f"sorting column {i} by {sort_orders[i]}")
self.sortByColumn(i, sort_orders[i]) self.sortByColumn(i, sort_orders[i])
self.connect_data_changed() self.connect_data_changed()
@ -298,7 +298,7 @@ class MusicTable(QTableView):
try: try:
self.model2.removeRow(index) self.model2.removeRow(index)
except Exception as e: except Exception as e:
logging.info(f" delete_songs() failed | {e}") debug(f" delete_songs() failed | {e}")
self.connect_data_changed() self.connect_data_changed()
def open_directory(self): def open_directory(self):
@ -343,7 +343,7 @@ class MusicTable(QTableView):
else: else:
raise RuntimeError("No USLT tags found in song metadata") raise RuntimeError("No USLT tags found in song metadata")
except Exception as e: except Exception as e:
logging.error(f"show_lyrics_menu() | could not retrieve lyrics | {e}") error(f"show_lyrics_menu() | could not retrieve lyrics | {e}")
lyrics = "" lyrics = ""
lyrics_window = LyricsWindow(selected_song_filepath, lyrics) lyrics_window = LyricsWindow(selected_song_filepath, lyrics)
lyrics_window.exec_() lyrics_window.exec_()
@ -370,7 +370,7 @@ class MusicTable(QTableView):
if e is None: if e is None:
return return
data = e.mimeData() data = e.mimeData()
logging.info(f"dropEvent data: {data}") debug(f"dropEvent data: {data}")
if data and data.hasUrls(): if data and data.hasUrls():
directories = [] directories = []
files = [] files = []
@ -384,8 +384,8 @@ class MusicTable(QTableView):
# append 1 file # append 1 file
files.append(path) files.append(path)
e.accept() e.accept()
print(f"directories: {directories}") debug(f"directories: {directories}")
print(f"files: {files}") debug(f"files: {files}")
if directories: if directories:
worker = Worker(self.get_audio_files_recursively, directories) worker = Worker(self.get_audio_files_recursively, directories)
worker.signals.signal_progress.connect(self.handle_progress) worker.signals.signal_progress.connect(self.handle_progress)
@ -444,7 +444,7 @@ class MusicTable(QTableView):
def on_cell_data_changed(self, topLeft: QModelIndex, bottomRight: QModelIndex): def on_cell_data_changed(self, topLeft: QModelIndex, bottomRight: QModelIndex):
"""Handles updating ID3 tags when data changes in a cell""" """Handles updating ID3 tags when data changes in a cell"""
logging.info("on_cell_data_changed") debug("on_cell_data_changed")
if isinstance(self.model2, QStandardItemModel): if isinstance(self.model2, QStandardItemModel):
# get the ID of the row that was edited # get the ID of the row that was edited
id_index = self.model2.index(topLeft.row(), 0) # ID is column 0, always id_index = self.model2.index(topLeft.row(), 0) # ID is column 0, always
@ -458,7 +458,7 @@ class MusicTable(QTableView):
# update the ID3 information # update the ID3 information
user_input_data = topLeft.data() user_input_data = topLeft.data()
edited_column_name = self.database_columns[topLeft.column()] edited_column_name = self.database_columns[topLeft.column()]
logging.info(f"edited column name: {edited_column_name}") debug(f"edited column name: {edited_column_name}")
response = set_id3_tag(filepath, edited_column_name, user_input_data) response = set_id3_tag(filepath, edited_column_name, user_input_data)
if response: if response:
# Update the library with new metadata # Update the library with new metadata
@ -518,9 +518,9 @@ class MusicTable(QTableView):
"UPDATE song SET filepath = ? WHERE filepath = ?", "UPDATE song SET filepath = ? WHERE filepath = ?",
(new_path, filepath), (new_path, filepath),
) )
logging.info(f"reorganize_files() | Moved: {filepath} -> {new_path}") debug(f"reorganize_files() | Moved: {filepath} -> {new_path}")
except Exception as e: except Exception as e:
logging.warning( error(
f"reorganize_files() | Error moving file: {filepath} | {e}" f"reorganize_files() | Error moving file: {filepath} | {e}"
) )
# Draw the rest of the owl # Draw the rest of the owl
@ -539,7 +539,7 @@ class MusicTable(QTableView):
- Drag & Drop song(s) on tableView - Drag & Drop song(s) on tableView
- File > Open > List of song(s) - File > Open > List of song(s)
""" """
logging.info(f"add files, files: {files}") debug(f"add files, files: {files}")
worker = Worker(add_files_to_library, files) worker = Worker(add_files_to_library, files)
worker.signals.signal_progress.connect(self.qapp.handle_progress) worker.signals.signal_progress.connect(self.qapp.handle_progress)
worker.signals.signal_finished.connect(self.load_music_table) worker.signals.signal_finished.connect(self.load_music_table)
@ -547,7 +547,7 @@ class MusicTable(QTableView):
threadpool = self.qapp.threadpool threadpool = self.qapp.threadpool
threadpool.start(worker) threadpool.start(worker)
else: else:
logging.warning("Application window could not be found") error("Application window could not be found")
def load_music_table(self, *playlist_id): def load_music_table(self, *playlist_id):
""" """
@ -566,7 +566,7 @@ class MusicTable(QTableView):
# Fetch playlist data # Fetch playlist data
selected_playlist_id = playlist_id[0] selected_playlist_id = playlist_id[0]
try: try:
logging.info( debug(
f"load_music_table() | selected_playlist_id: {selected_playlist_id}" f"load_music_table() | selected_playlist_id: {selected_playlist_id}"
) )
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
@ -575,7 +575,7 @@ class MusicTable(QTableView):
(selected_playlist_id,), (selected_playlist_id,),
) )
except Exception as e: except Exception as e:
logging.warning(f"load_music_table() | Unhandled exception: {e}") error(f"load_music_table() | Unhandled exception: {e}")
return return
else: # Load the library else: # Load the library
# Fetch playlist data # Fetch playlist data
@ -586,7 +586,7 @@ class MusicTable(QTableView):
(), (),
) )
except Exception as e: except Exception as e:
logging.warning(f"load_music_table() | Unhandled exception: {e}") error(f"load_music_table() | Unhandled exception: {e}")
return return
# Populate the model # Populate the model
for row_data in data: for row_data in data:
@ -612,7 +612,7 @@ class MusicTable(QTableView):
def restore_scroll_position(self) -> None: def restore_scroll_position(self) -> None:
"""Restores the scroll position""" """Restores the scroll position"""
logging.info("restore_scroll_position") debug("restore_scroll_position")
# QTimer.singleShot( # QTimer.singleShot(
# 100, # 100,
# lambda: self.verticalScrollBar().setValue(self.vertical_scroll_position), # lambda: self.verticalScrollBar().setValue(self.vertical_scroll_position),

View File

@ -1,6 +1,7 @@
from PyQt5.QtWidgets import QListWidget, QTreeWidget, QTreeWidgetItem from PyQt5.QtWidgets import QListWidget, QTreeWidget, QTreeWidgetItem
from PyQt5.QtCore import pyqtSignal from PyQt5.QtCore import pyqtSignal
import DBA import DBA
from logging import debug
class PlaylistWidgetItem(QTreeWidgetItem): class PlaylistWidgetItem(QTreeWidgetItem):
@ -36,7 +37,7 @@ class PlaylistsPane(QTreeWidget):
def playlist_clicked(self, item): def playlist_clicked(self, item):
if isinstance(item, PlaylistWidgetItem): if isinstance(item, PlaylistWidgetItem):
print(f"ID: {item.id}, name: {item.text(0)}") debug(f"ID: {item.id}, name: {item.text(0)}")
self.playlist_db_id_choice = item.id self.playlist_db_id_choice = item.id
self.playlistChoiceSignal.emit(int(item.id)) self.playlistChoiceSignal.emit(int(item.id))
elif item.text(0).lower() == "all songs": elif item.text(0).lower() == "all songs":

1
create_ui.sh Executable file
View File

@ -0,0 +1 @@
pyuic5 ui.ui -o ui.py

View File

@ -10,6 +10,7 @@ from mutagen.id3._frames import APIC
from configparser import ConfigParser from configparser import ConfigParser
import traceback import traceback
import DBA import DBA
from logging import debug
from ui import Ui_MainWindow from ui import Ui_MainWindow
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QFileDialog, QFileDialog,
@ -290,7 +291,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
"""Start playback of `tableView.current_song_filepath` & moves playback slider""" """Start playback of `tableView.current_song_filepath` & moves playback slider"""
# get metadata # get metadata
self.current_song_metadata = self.tableView.get_current_song_metadata() self.current_song_metadata = self.tableView.get_current_song_metadata()
print(f'current_song_metadata: {self.current_song_metadata}')
# read the file # read the file
url = QUrl.fromLocalFile(self.tableView.get_current_song_filepath()) url = QUrl.fromLocalFile(self.tableView.get_current_song_filepath())
# load the audio content # load the audio content
@ -369,7 +369,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
# delete APIC data # delete APIC data
try: try:
audio = ID3(file) audio = ID3(file)
print(audio) debug(audio)
if "APIC:" in audio: if "APIC:" in audio:
del audio["APIC:"] del audio["APIC:"]
logging.info("Deleting album art") logging.info("Deleting album art")
@ -426,12 +426,14 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
try: try:
self.current_volume = self.volumeSlider.value() self.current_volume = self.volumeSlider.value()
self.player.setVolume(self.current_volume) self.player.setVolume(self.current_volume)
self.volumeLabel = str(self.current_volume)
except Exception as e: except Exception as e:
logging.error(f"main.py volume_changed() | Changing volume error: {e}") logging.error(f"main.py volume_changed() | Changing volume error: {e}")
def speed_changed(self, rate: int) -> None: def speed_changed(self, rate: int) -> None:
"""Handles playback speed changes""" """Handles playback speed changes"""
self.player.setPlaybackRate(rate / 50) self.player.setPlaybackRate(rate / 50)
self.speedLabel.setText(str(round(rate/50, 2)))
def on_play_clicked(self) -> None: def on_play_clicked(self) -> None:
"""Updates the Play & Pause buttons when clicked""" """Updates the Play & Pause buttons when clicked"""

View File

@ -1,34 +1,37 @@
import sys import sys
from mutagen.id3 import ID3, APIC from mutagen.id3 import ID3
# i just added the below line - APIC was originally in the above
# but pyright yelled at me...
from mutagen.id3._frames import APIC
import os import os
import logging from logging import debug
def print_id3_tags(file_path): def print_id3_tags(file_path):
"""Prints all ID3 tags for a given audio file.""" """Prints all ID3 tags for a given audio file to debug out."""
try: try:
audio = ID3(file_path) audio = ID3(file_path)
except Exception as e: except Exception as e:
print(f"Error reading ID3 tags: {e}") debug(f"Error reading ID3 tags: {e}")
return return
for tag in audio.keys(): for tag in audio.keys():
# Special handling for APIC frames (attached pictures) # Special handling for APIC frames (attached pictures)
if isinstance(audio[tag], APIC): if isinstance(audio[tag], APIC):
print( debug(
f"{tag}: Picture, MIME type: {audio[tag].mime}, Description: {audio[tag].desc}" f"{tag}: Picture, MIME type: {audio[tag].mime}, Description: {audio[tag].desc}"
) )
else: else:
print(f"{tag}: {audio[tag].pprint()}") debug(f"{tag}: {audio[tag].pprint()}")
def main(): def main():
if len(sys.argv) != 2: if len(sys.argv) != 2:
print("Usage: python show_id3_tags.py /path/to/audio/file") debug("Usage: python show_id3_tags.py /path/to/audio/file")
sys.exit(1) sys.exit(1)
file_path = sys.argv[1] file_path = sys.argv[1]
if not os.path.exists(file_path): if not os.path.exists(file_path):
print("File does not exist.") debug("File does not exist.")
sys.exit(1) sys.exit(1)
print_id3_tags(file_path) print_id3_tags(file_path)

79
ui.py
View File

@ -81,15 +81,51 @@ class Ui_MainWindow(object):
self.playbackSlider.setOrientation(QtCore.Qt.Horizontal) self.playbackSlider.setOrientation(QtCore.Qt.Horizontal)
self.playbackSlider.setObjectName("playbackSlider") self.playbackSlider.setObjectName("playbackSlider")
self.horizontalLayout.addWidget(self.playbackSlider) self.horizontalLayout.addWidget(self.playbackSlider)
self.timeHorizontalLayout2 = QtWidgets.QHBoxLayout()
self.timeHorizontalLayout2.setObjectName("timeHorizontalLayout2")
self.startTimeLabel = QtWidgets.QLabel(self.centralwidget) self.startTimeLabel = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Monospace")
font.setItalic(False)
self.startTimeLabel.setFont(font)
self.startTimeLabel.setObjectName("startTimeLabel") self.startTimeLabel.setObjectName("startTimeLabel")
self.horizontalLayout.addWidget(self.startTimeLabel) self.timeHorizontalLayout2.addWidget(self.startTimeLabel)
self.slashLabel = QtWidgets.QLabel(self.centralwidget) self.slashLabel = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Monospace")
font.setItalic(False)
self.slashLabel.setFont(font)
self.slashLabel.setObjectName("slashLabel") self.slashLabel.setObjectName("slashLabel")
self.horizontalLayout.addWidget(self.slashLabel) self.timeHorizontalLayout2.addWidget(self.slashLabel)
self.endTimeLabel = QtWidgets.QLabel(self.centralwidget) self.endTimeLabel = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Monospace")
font.setBold(True)
font.setItalic(False)
font.setWeight(75)
self.endTimeLabel.setFont(font)
self.endTimeLabel.setObjectName("endTimeLabel") self.endTimeLabel.setObjectName("endTimeLabel")
self.horizontalLayout.addWidget(self.endTimeLabel) self.timeHorizontalLayout2.addWidget(self.endTimeLabel)
self.horizontalLayout.addLayout(self.timeHorizontalLayout2)
self.speedSlider = QtWidgets.QSlider(self.centralwidget)
self.speedSlider.setMinimum(0)
self.speedSlider.setMaximum(100)
self.speedSlider.setSingleStep(1)
self.speedSlider.setProperty("value", 50)
self.speedSlider.setOrientation(QtCore.Qt.Horizontal)
self.speedSlider.setInvertedAppearance(False)
self.speedSlider.setTickPosition(QtWidgets.QSlider.TicksAbove)
self.speedSlider.setObjectName("speedSlider")
self.horizontalLayout.addWidget(self.speedSlider)
self.speedLabel = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Monospace")
self.speedLabel.setFont(font)
self.speedLabel.setObjectName("speedLabel")
self.horizontalLayout.addWidget(self.speedLabel)
self.horizontalLayout.setStretch(0, 4)
self.horizontalLayout.setStretch(2, 4)
self.horizontalLayout.setStretch(3, 1)
self.vLayoutPlaybackVisuals.addLayout(self.horizontalLayout) self.vLayoutPlaybackVisuals.addLayout(self.horizontalLayout)
self.PlotWidget = PlotWidget(self.centralwidget) self.PlotWidget = PlotWidget(self.centralwidget)
self.PlotWidget.setObjectName("PlotWidget") self.PlotWidget.setObjectName("PlotWidget")
@ -127,6 +163,8 @@ class Ui_MainWindow(object):
self.hLayoutControls = QtWidgets.QHBoxLayout() self.hLayoutControls = QtWidgets.QHBoxLayout()
self.hLayoutControls.setSpacing(6) self.hLayoutControls.setSpacing(6)
self.hLayoutControls.setObjectName("hLayoutControls") self.hLayoutControls.setObjectName("hLayoutControls")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.hLayoutControls.addItem(spacerItem)
self.previousButton = QtWidgets.QPushButton(self.centralwidget) self.previousButton = QtWidgets.QPushButton(self.centralwidget)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(28) font.setPointSize(28)
@ -145,6 +183,13 @@ class Ui_MainWindow(object):
self.nextButton.setFont(font) self.nextButton.setFont(font)
self.nextButton.setObjectName("nextButton") self.nextButton.setObjectName("nextButton")
self.hLayoutControls.addWidget(self.nextButton) self.hLayoutControls.addWidget(self.nextButton)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.hLayoutControls.addItem(spacerItem1)
self.hLayoutControls.setStretch(0, 1)
self.hLayoutControls.setStretch(1, 2)
self.hLayoutControls.setStretch(2, 2)
self.hLayoutControls.setStretch(3, 2)
self.hLayoutControls.setStretch(4, 1)
self.verticalLayout_3.addLayout(self.hLayoutControls) self.verticalLayout_3.addLayout(self.hLayoutControls)
self.hLayoutControls2 = QtWidgets.QHBoxLayout() self.hLayoutControls2 = QtWidgets.QHBoxLayout()
self.hLayoutControls2.setSpacing(6) self.hLayoutControls2.setSpacing(6)
@ -153,22 +198,21 @@ class Ui_MainWindow(object):
self.volumeSlider.setMaximum(100) self.volumeSlider.setMaximum(100)
self.volumeSlider.setProperty("value", 50) self.volumeSlider.setProperty("value", 50)
self.volumeSlider.setOrientation(QtCore.Qt.Horizontal) self.volumeSlider.setOrientation(QtCore.Qt.Horizontal)
self.volumeSlider.setTickPosition(QtWidgets.QSlider.TicksAbove)
self.volumeSlider.setObjectName("volumeSlider") self.volumeSlider.setObjectName("volumeSlider")
self.hLayoutControls2.addWidget(self.volumeSlider) self.hLayoutControls2.addWidget(self.volumeSlider)
self.volumeLabel = QtWidgets.QLabel(self.centralwidget)
self.volumeLabel.setObjectName("volumeLabel")
self.hLayoutControls2.addWidget(self.volumeLabel)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.hLayoutControls2.addItem(spacerItem2)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setObjectName("pushButton")
self.hLayoutControls2.addWidget(self.pushButton)
self.hLayoutControls2.setStretch(0, 1)
self.hLayoutControls2.setStretch(2, 4)
self.hLayoutControls2.setStretch(3, 1)
self.verticalLayout_3.addLayout(self.hLayoutControls2) self.verticalLayout_3.addLayout(self.hLayoutControls2)
self.hLayoutControls3 = QtWidgets.QHBoxLayout()
self.hLayoutControls3.setObjectName("hLayoutControls3")
self.speedSlider = QtWidgets.QSlider(self.centralwidget)
self.speedSlider.setMinimum(0)
self.speedSlider.setMaximum(100)
self.speedSlider.setSingleStep(1)
self.speedSlider.setProperty("value", 50)
self.speedSlider.setOrientation(QtCore.Qt.Horizontal)
self.speedSlider.setInvertedAppearance(False)
self.speedSlider.setTickPosition(QtWidgets.QSlider.NoTicks)
self.speedSlider.setObjectName("speedSlider")
self.hLayoutControls3.addWidget(self.speedSlider)
self.verticalLayout_3.addLayout(self.hLayoutControls3)
self.verticalLayout_3.setStretch(0, 20) self.verticalLayout_3.setStretch(0, 20)
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar = QtWidgets.QMenuBar(MainWindow)
@ -227,9 +271,12 @@ class Ui_MainWindow(object):
self.startTimeLabel.setText(_translate("MainWindow", "00:00")) self.startTimeLabel.setText(_translate("MainWindow", "00:00"))
self.slashLabel.setText(_translate("MainWindow", "/")) self.slashLabel.setText(_translate("MainWindow", "/"))
self.endTimeLabel.setText(_translate("MainWindow", "00:00")) self.endTimeLabel.setText(_translate("MainWindow", "00:00"))
self.speedLabel.setText(_translate("MainWindow", "1.00"))
self.previousButton.setText(_translate("MainWindow", "⏮️")) self.previousButton.setText(_translate("MainWindow", "⏮️"))
self.playButton.setText(_translate("MainWindow", "▶️")) self.playButton.setText(_translate("MainWindow", "▶️"))
self.nextButton.setText(_translate("MainWindow", "⏭️")) self.nextButton.setText(_translate("MainWindow", "⏭️"))
self.volumeLabel.setText(_translate("MainWindow", "50"))
self.pushButton.setText(_translate("MainWindow", "nothing"))
self.menuFile.setTitle(_translate("MainWindow", "File")) self.menuFile.setTitle(_translate("MainWindow", "File"))
self.menuEdit.setTitle(_translate("MainWindow", "Edit")) self.menuEdit.setTitle(_translate("MainWindow", "Edit"))
self.menuView.setTitle(_translate("MainWindow", "View")) self.menuView.setTitle(_translate("MainWindow", "View"))

158
ui.ui
View File

@ -17,7 +17,7 @@
<string/> <string/>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="20,0,0,0"> <layout class="QVBoxLayout" name="verticalLayout_3" stretch="20,0,0">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,2"> <layout class="QVBoxLayout" name="verticalLayout" stretch="1,2">
<property name="spacing"> <property name="spacing">
@ -126,7 +126,7 @@
<item> <item>
<layout class="QVBoxLayout" name="vLayoutPlaybackVisuals"> <layout class="QVBoxLayout" name="vLayoutPlaybackVisuals">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="4,0,4,1">
<item> <item>
<widget class="QSlider" name="playbackSlider"> <widget class="QSlider" name="playbackSlider">
<property name="orientation"> <property name="orientation">
@ -135,23 +135,84 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="startTimeLabel"> <layout class="QHBoxLayout" name="timeHorizontalLayout2">
<property name="text"> <item>
<string>00:00</string> <widget class="QLabel" name="startTimeLabel">
<property name="font">
<font>
<family>Monospace</family>
<italic>false</italic>
</font>
</property>
<property name="text">
<string>00:00</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="slashLabel">
<property name="font">
<font>
<family>Monospace</family>
<italic>false</italic>
</font>
</property>
<property name="text">
<string>/</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="endTimeLabel">
<property name="font">
<font>
<family>Monospace</family>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>00:00</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSlider" name="speedSlider">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="slashLabel"> <widget class="QLabel" name="speedLabel">
<property name="text"> <property name="font">
<string>/</string> <font>
<family>Monospace</family>
</font>
</property> </property>
</widget>
</item>
<item>
<widget class="QLabel" name="endTimeLabel">
<property name="text"> <property name="text">
<string>00:00</string> <string>1.00</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -217,10 +278,23 @@
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="hLayoutControls"> <layout class="QHBoxLayout" name="hLayoutControls" stretch="1,2,2,2,1">
<property name="spacing"> <property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item> <item>
<widget class="QPushButton" name="previousButton"> <widget class="QPushButton" name="previousButton">
<property name="font"> <property name="font">
@ -257,10 +331,23 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="hLayoutControls2"> <layout class="QHBoxLayout" name="hLayoutControls2" stretch="1,0,4,1">
<property name="spacing"> <property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
@ -275,34 +362,35 @@
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
</widget> </widget>
</item> </item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="hLayoutControls3">
<item> <item>
<widget class="QSlider" name="speedSlider"> <widget class="QLabel" name="volumeLabel">
<property name="minimum"> <property name="text">
<number>0</number> <string>50</string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>50</number>
</property> </property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="invertedAppearance"> <property name="sizeHint" stdset="0">
<bool>false</bool> <size>
<width>40</width>
<height>20</height>
</size>
</property> </property>
<property name="tickPosition"> </spacer>
<enum>QSlider::NoTicks</enum> </item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>nothing</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -1,4 +1,5 @@
import DBA import DBA
from logging import debug
def delete_and_create_library_database(): def delete_and_create_library_database():
@ -6,6 +7,6 @@ def delete_and_create_library_database():
with open("utils/delete_and_create_library.sql", "r") as file: with open("utils/delete_and_create_library.sql", "r") as file:
lines = file.read() lines = file.read()
for statement in lines.split(";"): for statement in lines.split(";"):
print(f"executing [{statement}]") debug(f"executing [{statement}]")
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.execute(statement, ()) db.execute(statement, ())

View File

@ -7,6 +7,7 @@ from PyQt5 import QtCore
from pydub import AudioSegment from pydub import AudioSegment
import numpy as np import numpy as np
from scipy.ndimage.filters import gaussian_filter1d from scipy.ndimage.filters import gaussian_filter1d
from logging import info
class FFTAnalyser(QtCore.QThread): class FFTAnalyser(QtCore.QThread):
@ -57,7 +58,7 @@ class FFTAnalyser(QtCore.QThread):
freq = np.fft.fftfreq(fourier.size, d=0.05) freq = np.fft.fftfreq(fourier.size, d=0.05)
amps = 2 / v_sample.size * np.abs(fourier) amps = 2 / v_sample.size * np.abs(fourier)
data = np.array([freq, amps]).T data = np.array([freq, amps]).T
# print(data) # info(data)
point_range = 1 / self.resolution point_range = 1 / self.resolution
point_samples = [] point_samples = []

View File

@ -1,5 +1,5 @@
from mutagen.id3 import ID3 from mutagen.id3 import ID3
import logging from logging import debug, error
def get_album_art(file: str) -> bytes: def get_album_art(file: str) -> bytes:
@ -18,7 +18,7 @@ def get_album_art(file: str) -> bytes:
if audio.getall("APIC"): if audio.getall("APIC"):
return audio.getall("APIC")[0].data return audio.getall("APIC")[0].data
except Exception as e: except Exception as e:
print(f"Error retrieving album art: {e}") error(f"Error retrieving album art: {e}")
with open(default_image_path, "rb") as f: with open(default_image_path, "rb") as f:
logging.info("loading placeholder album art") debug("loading placeholder album art")
return f.read() return f.read()

View File

@ -1,4 +1,5 @@
import DBA import DBA
from logging import debug
def initialize_db(): def initialize_db():
@ -6,6 +7,6 @@ def initialize_db():
with open("utils/init.sql", "r") as file: with open("utils/init.sql", "r") as file:
lines = file.read() lines = file.read()
for statement in lines.split(";"): for statement in lines.split(";"):
print(f"executing [{statement}]") debug(f"executing [{statement}]")
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.execute(statement, ()) db.execute(statement, ())