typing and reorganization

This commit is contained in:
tsi-billypom 2024-07-30 15:45:00 -04:00
parent 6c7d962899
commit f466821ece
5 changed files with 92 additions and 103 deletions

View File

@ -1,8 +1,8 @@
from PyQt5 import QtWidgets
import numpy as np import numpy as np
from PyQt5 import QtWidgets
from utils import FFTAnalyser from utils import FFTAnalyser
class AudioVisualizer(QtWidgets.QWidget): class AudioVisualizer(QtWidgets.QWidget):
"""_Audio Visualizer component_ """_Audio Visualizer component_
@ -12,6 +12,7 @@ class AudioVisualizer(QtWidgets.QWidget):
Returns: Returns:
_type_: _description_ _type_: _description_
""" """
def __init__(self, media_player): def __init__(self, media_player):
super().__init__() super().__init__()
self.media_player = media_player self.media_player = media_player

179
new.py
View File

@ -10,7 +10,6 @@ from mutagen.id3 import ID3
from mutagen.id3._frames import APIC from mutagen.id3._frames import APIC
from configparser import ConfigParser from configparser import ConfigParser
import DBA import DBA
from ui import Ui_MainWindow
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QFileDialog, QFileDialog,
@ -33,34 +32,32 @@ from components import (
) )
class MainWindow(QMainWindow, Ui_MainWindow): class MainWindow(QMainWindow):
def __init__(self): def __init__(self):
super(MainWindow, self).__init__() super(MainWindow, self).__init__()
global stopped global stopped
stopped = False stopped = False
# Initialization # Vars
self.setupUi(self) self.setupUi(self)
self.setWindowTitle("MusicPom") self.setWindowTitle("MusicPom")
self.selected_song_filepath = None self.selected_song_filepath: str | None = None
self.current_song_filepath = None self.current_song_filepath: str | None = None
self.current_song_metadata = None self.current_song_metadata: ID3 | dict | None = None
self.current_song_album_art = None self.current_song_album_art: bytes | None = None
self.album_art_scene = QGraphicsScene() self.album_art_scene: QGraphicsScene = QGraphicsScene()
self.config = configparser.ConfigParser() self.config: ConfigParser = configparser.ConfigParser()
self.player: QMediaPlayer = QMediaPlayer() # Audio player object
self.probe: QAudioProbe = QAudioProbe() # Gets audio data
self.audio_visualizer: AudioVisualizer = AudioVisualizer(self.player)
self.current_volume: int = 50
# Initialization
self.config.read("config.ini") self.config.read("config.ini")
self.player = QMediaPlayer() # Audio player object
self.audio_visualizer = AudioVisualizer(self.player)
self.current_volume = 50
self.player.setVolume(self.current_volume) self.player.setVolume(self.current_volume)
# Audio probe for processing audio signal in real time # Audio probe for processing audio signal in real time
# Provides faster updates than move_slider
self.probe = QAudioProbe() # Gets audio data
self.probe.setSource(self.player) self.probe.setSource(self.player)
self.probe.audioBufferProbed.connect(self.process_probe) self.probe.audioBufferProbed.connect(self.process_probe)
# Slider Timer (realtime playback feedback horizontal bar) # Slider Timer (realtime playback feedback horizontal bar)
self.timer = QTimer(self) # Audio timing things self.timer: QTimer = QTimer(self) # Audio timing things
self.timer.start( self.timer.start(
150 150
) # 150ms update interval solved problem with drag seeking halting playback ) # 150ms update interval solved problem with drag seeking halting playback
@ -84,42 +81,39 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# |_____________| # |_____________|
# FIXME: moving the slider while playing is happening frequently causes playback to halt - the pyqtgraph is also affected by this # FIXME: moving the slider while playing is happening frequently causes playback to halt - the pyqtgraph is also affected by this
# so it must be affecting our QMediaPlayer as well
# self.playbackSlider.sliderMoved[int].connect( # self.playbackSlider.sliderMoved[int].connect(
# lambda: self.player.setPosition(self.playbackSlider.value()) # lambda: self.player.setPosition(self.playbackSlider.value())
# ) # )
self.playbackSlider.sliderReleased[int].connect( self.playbackSlider.sliderReleased.connect(
lambda: self.player.setPosition(self.playbackSlider.value()) lambda: self.player.setPosition(self.playbackSlider.value())
) # maybe sliderReleased works better than sliderMoved ) # maybe sliderReleased works better than sliderMoved
self.volumeSlider.sliderMoved[int].connect( self.volumeSlider.sliderMoved[int].connect(
lambda: self.volume_changed() lambda: self.volume_changed()
) # Move slider to adjust volume ) # Move slider to adjust volume
self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause # Playback controls
self.previousButton.clicked.connect( self.playButton.clicked.connect(self.on_play_clicked)
self.on_previous_clicked self.prevButton.clicked.connect(self.on_previous_clicked)
) # Click to previous song self.nextButton.clicked.connect(self.on_next_clicked)
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.open_files) # Open files window
# EDIT MENU # EDIT MENU
# VIEW MENU
self.actionPreferences.triggered.connect( self.actionPreferences.triggered.connect(
self.open_preferences self.open_preferences
) # Open preferences menu ) # Open preferences menu
# VIEW MENU
# QUICK ACTIONS MENU # QUICK ACTIONS MENU
self.actionScanLibraries.triggered.connect(self.scan_libraries) self.actionScanLibraries.triggered.connect(self.scan_libraries)
self.actionDeleteLibrary.triggered.connect(self.clear_database) self.actionDeleteLibrary.triggered.connect(self.clear_database)
self.actionDeleteDatabase.triggered.connect(self.delete_database) self.actionDeleteDatabase.triggered.connect(self.delete_database)
## tableView triggers ## Music Table | self.tableView triggers
self.tableView.doubleClicked.connect( # Listens for the double click event, then plays the song
self.play_audio_file self.tableView.doubleClicked.connect(self.play_audio_file)
) # Listens for the double click event, then plays the song # Listens for the enter key event, then plays the song
self.tableView.enterKey.connect( self.tableView.enterKey.connect(self.play_audio_file)
self.play_audio_file # Spacebar for toggle play/pause
) # Listens for the enter key event, then plays the song self.tableView.playPauseSignal.connect(self.on_play_clicked)
self.tableView.playPauseSignal.connect( # Album Art | self.albumGraphicsView
self.on_play_clicked
) # Spacebar toggle play/pause signal
# albumGraphicsView
self.albumGraphicsView.albumArtDropped.connect( self.albumGraphicsView.albumArtDropped.connect(
self.set_album_art_for_selected_songs self.set_album_art_for_selected_songs
) )
@ -141,8 +135,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
MainWindow.setObjectName("MainWindow") MainWindow.setObjectName("MainWindow")
MainWindow.resize(1152, 894) MainWindow.resize(1152, 894)
MainWindow.setStatusTip("") MainWindow.setStatusTip("")
# Main
self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget") self.centralwidget.setObjectName("centralwidget")
#
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_3.setObjectName("verticalLayout_3") self.verticalLayout_3.setObjectName("verticalLayout_3")
self.hLayoutHead = QtWidgets.QHBoxLayout() self.hLayoutHead = QtWidgets.QHBoxLayout()
@ -262,12 +258,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.verticalLayout_3.addLayout(self.hLayoutMusicTable) self.verticalLayout_3.addLayout(self.hLayoutMusicTable)
self.hLayoutControls = QtWidgets.QHBoxLayout() self.hLayoutControls = QtWidgets.QHBoxLayout()
self.hLayoutControls.setObjectName("hLayoutControls") self.hLayoutControls.setObjectName("hLayoutControls")
self.previousButton = QtWidgets.QPushButton(self.centralwidget) self.prevButton = QtWidgets.QPushButton(self.centralwidget)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(28) font.setPointSize(28)
self.previousButton.setFont(font) self.prevButton.setFont(font)
self.previousButton.setObjectName("previousButton") self.prevButton.setObjectName("prevButton")
self.hLayoutControls.addWidget(self.previousButton) self.hLayoutControls.addWidget(self.prevButton)
self.playButton = QtWidgets.QPushButton(self.centralwidget) self.playButton = QtWidgets.QPushButton(self.centralwidget)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(28) font.setPointSize(28)
@ -342,7 +338,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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.previousButton.setText(_translate("MainWindow", "⏮️")) self.prevButton.setText(_translate("MainWindow", "⏮️"))
self.playButton.setText(_translate("MainWindow", "▶️")) self.playButton.setText(_translate("MainWindow", "▶️"))
self.nextButton.setText(_translate("MainWindow", "⏭️")) self.nextButton.setText(_translate("MainWindow", "⏭️"))
self.menuFile.setTitle(_translate("MainWindow", "File")) self.menuFile.setTitle(_translate("MainWindow", "File"))
@ -372,39 +368,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.config.write(configfile) self.config.write(configfile)
super().closeEvent(a0) super().closeEvent(a0)
def play_audio_file(self) -> None:
"""Start playback of tableView.current_song_filepath track & moves playback slider"""
self.current_song_metadata = (
self.tableView.get_current_song_metadata()
) # get metadata
self.current_song_album_art = self.tableView.get_current_song_album_art()
url = QUrl.fromLocalFile(
self.tableView.get_current_song_filepath()
) # read the file
content = QMediaContent(url) # load the audio content
self.player.setMedia(content) # what content to play
self.player.play() # play
self.move_slider() # mover
# assign metadata
artist = (
self.current_song_metadata["TPE1"][0]
if "artist" in self.current_song_metadata
else None
)
album = (
self.current_song_metadata["TALB"][0]
if "album" in self.current_song_metadata
else None
)
title = self.current_song_metadata["TIT2"][0]
# edit labels
self.artistLabel.setText(artist)
self.albumLabel.setText(album)
self.titleLabel.setText(title)
# set album artwork
self.load_album_art(self.current_song_album_art)
def load_album_art(self, album_art_data) -> None: def load_album_art(self, album_art_data) -> None:
"""Displays the album art for the currently playing track in the GraphicsView""" """Displays the album art for the currently playing track in the GraphicsView"""
if self.current_song_album_art: if self.current_song_album_art:
@ -494,6 +457,56 @@ class MainWindow(QMainWindow, Ui_MainWindow):
except Exception as e: except Exception as e:
print(f"Error processing {file}: {e}") print(f"Error processing {file}: {e}")
def play_audio_file(self) -> None:
"""Start playback of tableView.current_song_filepath track & moves playback slider"""
self.current_song_metadata = self.tableView.get_current_song_metadata()
self.current_song_album_art = self.tableView.get_current_song_album_art()
# read the file
url = QUrl.fromLocalFile(self.tableView.get_current_song_filepath())
content = QMediaContent(url) # load the audio content
self.player.setMedia(content) # what content to play
self.player.play() # play
self.move_slider() # mover
# assign metadata
artist = (
self.current_song_metadata["TPE1"][0]
if "artist" in self.current_song_metadata
else None
)
album = (
self.current_song_metadata["TALB"][0]
if "album" in self.current_song_metadata
else None
)
title = self.current_song_metadata["TIT2"][0]
# edit labels
self.artistLabel.setText(artist)
self.albumLabel.setText(album)
self.titleLabel.setText(title)
# set album artwork
self.load_album_art(self.current_song_album_art)
def on_play_clicked(self) -> None:
"""Updates the Play & Pause buttons when clicked"""
if self.player.state() == QMediaPlayer.State.PlayingState:
self.player.pause()
self.playButton.setText("▶️")
else:
if self.player.state() == QMediaPlayer.State.PausedState:
self.player.play()
self.playButton.setText("⏸️")
else:
self.play_audio_file()
self.playButton.setText("⏸️")
def on_previous_clicked(self) -> None:
""""""
print("previous")
def on_next_clicked(self) -> None:
print("next")
def update_audio_visualization(self) -> None: def update_audio_visualization(self) -> None:
"""Handles upading points on the pyqtgraph visual""" """Handles upading points on the pyqtgraph visual"""
self.clear_audio_visualization() self.clear_audio_visualization()
@ -535,26 +548,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
except Exception as e: except Exception as e:
print(f"Changing volume error: {e}") print(f"Changing volume error: {e}")
def on_play_clicked(self) -> None:
"""Updates the Play & Pause buttons when clicked"""
if self.player.state() == QMediaPlayer.State.PlayingState:
self.player.pause()
self.playButton.setText("▶️")
else:
if self.player.state() == QMediaPlayer.State.PausedState:
self.player.play()
self.playButton.setText("⏸️")
else:
self.play_audio_file()
self.playButton.setText("⏸️")
def on_previous_clicked(self) -> None:
""""""
print("previous")
def on_next_clicked(self) -> None:
print("next")
def open_files(self) -> None: def open_files(self) -> None:
"""Opens the open files window""" """Opens the open files window"""
open_files_window = QFileDialog( open_files_window = QFileDialog(

View File

@ -1,3 +1,4 @@
from .fft_analyser import FFTAnalyser
from .id3_timestamp_to_datetime import id3_timestamp_to_datetime from .id3_timestamp_to_datetime import id3_timestamp_to_datetime
from .initialize_db import initialize_db from .initialize_db import initialize_db
from .safe_get import safe_get from .safe_get import safe_get
@ -7,6 +8,5 @@ from .set_id3_tag import set_id3_tag
from .delete_and_create_library_database import delete_and_create_library_database from .delete_and_create_library_database import delete_and_create_library_database
from .update_song_in_library import update_song_in_library from .update_song_in_library import update_song_in_library
from .scan_for_music import scan_for_music from .scan_for_music import scan_for_music
from .fft_analyser import FFTAnalyser
from .add_files_to_library import add_files_to_library from .add_files_to_library import add_files_to_library
from .handle_year_and_date_id3_tag import handle_year_and_date_id3_tag from .handle_year_and_date_id3_tag import handle_year_and_date_id3_tag

View File

@ -1,14 +1,9 @@
# Credit # Credit
# https://github.com/ravenkls/MilkPlayer/blob/master/audio/fft_analyser.py # https://github.com/ravenkls/MilkPlayer/blob/master/audio/fft_analyser.py
# std
import time import time
import os import os
# qt
from PyQt5 import QtCore from PyQt5 import QtCore
# other
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

View File

@ -1,5 +1,5 @@
import logging import logging
from components.ErrorDialog import ErrorDialog from components import ErrorDialog
from utils.handle_year_and_date_id3_tag import handle_year_and_date_id3_tag from utils.handle_year_and_date_id3_tag import handle_year_and_date_id3_tag
from mutagen.id3 import ID3 from mutagen.id3 import ID3
from mutagen.id3._util import ID3NoHeaderError from mutagen.id3._util import ID3NoHeaderError