diff --git a/components/AlbumArtGraphicsView.py b/components/AlbumArtGraphicsView.py index 3348f02..68064cf 100644 --- a/components/AlbumArtGraphicsView.py +++ b/components/AlbumArtGraphicsView.py @@ -1,6 +1,12 @@ import os import tempfile -from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QMenu, QAction +from PyQt5.QtWidgets import ( + QGraphicsPixmapItem, + QGraphicsScene, + QGraphicsView, + QMenu, + QAction, +) from PyQt5.QtCore import QEvent, Qt, pyqtSignal, QUrl, QPoint from PyQt5.QtGui import ( QDragEnterEvent, @@ -22,8 +28,8 @@ class AlbumArtGraphicsView(QGraphicsView): def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) - self.setContextMenuPolicy(Qt.CustomContextMenu) - self.scene = QGraphicsScene + self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) + self.album_art_scene: QGraphicsScene = QGraphicsScene() self.customContextMenuRequested.connect(self.showContextMenu) def dragEnterEvent(self, event: QDragEnterEvent | None): @@ -35,6 +41,8 @@ class AlbumArtGraphicsView(QGraphicsView): event.ignore() def dragMoveEvent(self, event: QDragMoveEvent | None): + if event is None: + return if event.mimeData().hasUrls(): event.accept() else: @@ -42,6 +50,8 @@ class AlbumArtGraphicsView(QGraphicsView): def dropEvent(self, event: QDropEvent | None): """Handles drag and drop pic onto view to add album art to songs""" + if event is None: + return urls = event.mimeData().urls() if urls: first_url = urls[0].toLocalFile() @@ -74,10 +84,36 @@ class AlbumArtGraphicsView(QGraphicsView): # DO contextMenu.exec_(self.mapToGlobal(position)) # Show the menu + def load_album_art(self, album_art_data: bytes) -> None: + """Displays the album art for the currently playing track in the GraphicsView""" + if album_art_data: + # Clear the scene + try: + self.album_art_scene.clear() + except Exception: + pass + # Reset the scene + self.setScene(self.album_art_scene) + # Create pixmap for album art + pixmap = QPixmap() + pixmap.loadFromData(album_art_data) + # Create a QGraphicsPixmapItem for more control over pic + pixmap_item = QGraphicsPixmapItem(pixmap) + pixmap_item.setTransformationMode( + Qt.TransformationMode.SmoothTransformation + ) # For better quality scaling + # Add pixmap item to the scene + self.album_art_scene.addItem(pixmap_item) + # Set the scene + self.setScene(self.album_art_scene) + # Adjust the album art scaling + self.adjust_pixmap_scaling(pixmap_item) + def copy_album_art_to_clipboard(self): """Copies album art to the clipboard""" if not self.scene().items(): return # dont care if no pic + # FIXME: i want types here. what is actually going on... clipboard = self.qapp.clipboard() pixmap_item = self.scene().items()[0] clipboard.setPixmap(pixmap_item.pixmap()) @@ -96,7 +132,7 @@ class AlbumArtGraphicsView(QGraphicsView): else: pixmap = clipboard.pixmap() # Put image on screen and emit signal for ID3 tags to be updated - if pixmap != None: # Add pixmap raw data image + if pixmap is not None: # Add pixmap raw data image try: self.scene().clear() except Exception: @@ -114,6 +150,18 @@ class AlbumArtGraphicsView(QGraphicsView): """Emits a signal for the album art of the current song to be deleted""" self.albumArtDeleted.emit() + def adjust_pixmap_scaling(self, pixmap_item) -> None: + """Adjust the scaling of the pixmap item to fit the QGraphicsView, maintaining aspect ratio""" + viewWidth = self.width() + viewHeight = self.height() + pixmapSize = pixmap_item.pixmap().size() + # Calculate scaling factor while maintaining aspect ratio + scaleX = viewWidth / pixmapSize.width() + scaleY = viewHeight / pixmapSize.height() + scaleFactor = min(scaleX, scaleY) + # Apply scaling to the pixmap item + pixmap_item.setScale(scaleFactor) + def load_qapp(self, qapp): """Necessary for talking between components...""" self.qapp = qapp diff --git a/main.py b/main.py index d651d69..bcad990 100644 --- a/main.py +++ b/main.py @@ -287,7 +287,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): # get metadata self.current_song_metadata = self.tableView.get_current_song_metadata() logging.info("current song metadata: %s", self.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()) # load the audio content @@ -315,44 +314,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): 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: - """Displays the album art for the currently playing track in the GraphicsView""" - if self.current_song_album_art: - # Clear the scene - try: - self.album_art_scene.clear() - except Exception: - pass - # Reset the scene - self.albumGraphicsView.setScene(None) - # Create pixmap for album art - pixmap = QPixmap() - pixmap.loadFromData(album_art_data) - # Create a QGraphicsPixmapItem for more control over pic - pixmap_item = QGraphicsPixmapItem(pixmap) - pixmap_item.setTransformationMode( - Qt.TransformationMode.SmoothTransformation - ) # For better quality scaling - # Add pixmap item to the scene - self.album_art_scene.addItem(pixmap_item) - # Set the scene - self.albumGraphicsView.setScene(self.album_art_scene) - # Adjust the album art scaling - self.adjust_pixmap_scaling(pixmap_item) - - def adjust_pixmap_scaling(self, pixmap_item) -> None: - """Adjust the scaling of the pixmap item to fit the QGraphicsView, maintaining aspect ratio""" - viewWidth = self.albumGraphicsView.width() - viewHeight = self.albumGraphicsView.height() - pixmapSize = pixmap_item.pixmap().size() - # Calculate scaling factor while maintaining aspect ratio - scaleX = viewWidth / pixmapSize.width() - scaleY = viewHeight / pixmapSize.height() - scaleFactor = min(scaleX, scaleY) - # Apply scaling to the pixmap item - pixmap_item.setScale(scaleFactor) + album_art_data = self.tableView.get_current_song_album_art() + self.albumGraphicsView.load_album_art(album_art_data) def set_album_art_for_selected_songs(self, album_art_path: str) -> None: """Sets the ID3 tag APIC (album art) for all selected song filepaths""" diff --git a/utils/get_album_art.py b/utils/get_album_art.py index 1afa5ff..27beaea 100644 --- a/utils/get_album_art.py +++ b/utils/get_album_art.py @@ -1,22 +1,23 @@ from mutagen.id3 import ID3, APIC -def get_album_art(file): + +def get_album_art(file: str) -> bytes: """Get the album art for an audio file # Parameters `file` | str | Fully qualified path to file # Returns Data for album art or default file """ - default_image_path = './assets/default_album_art.jpg' + default_image_path = "./assets/default_album_art.jpg" try: audio = ID3(file) - for tag in audio.getall('APIC'): + for tag in audio.getall("APIC"): if tag.type == 3: # 3 is the type for front cover return tag.data - if audio.getall('APIC'): - return audio.getall('APIC')[0].data + if audio.getall("APIC"): + return audio.getall("APIC")[0].data except Exception as e: print(f"Error retrieving album art: {e}") - with open(default_image_path, 'rb') as file: - print(f'album art type: {type(file.read())}') - return file.read() + with open(default_image_path, "rb") as f: + print(f"album art type: {type(f.read())}") + return f.read()