musicpom/components/AlbumArtGraphicsView.py

120 lines
4.1 KiB
Python

import os
import tempfile
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QMenu, QAction
from PyQt5.QtCore import QEvent, Qt, pyqtSignal, QUrl, QPoint
from PyQt5.QtGui import (
QDragEnterEvent,
QDragMoveEvent,
QDropEvent,
QClipboard,
QPixmap,
)
class AlbumArtGraphicsView(QGraphicsView):
"""
Displays the album art of the currently playing song
"""
albumArtDropped = pyqtSignal(str)
albumArtDeleted = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.scene = QGraphicsScene
self.customContextMenuRequested.connect(self.showContextMenu)
def dragEnterEvent(self, event: QDragEnterEvent | None):
if not event:
return
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dragMoveEvent(self, event: QDragMoveEvent | None):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dropEvent(self, event: QDropEvent | None):
"""Handles drag and drop pic onto view to add album art to songs"""
urls = event.mimeData().urls()
if urls:
first_url = urls[0].toLocalFile()
if first_url.lower().endswith((".png", ".jpg", ".jpeg")):
print(f"dropped {first_url}")
self.albumArtDropped.emit(
first_url
) # emit signal that album art was dropped
event.accept()
return
event.ignore()
def showContextMenu(self, position: QPoint):
"""Handles showing a context menu when right clicking the album art"""
contextMenu = QMenu(self) # Create the menu
copyAction = QAction("Copy", self) # Add the actions
pasteAction = QAction("Paste", self)
deleteAction = QAction("Delete", self)
copyAction.triggered.connect(
self.copy_album_art_to_clipboard
) # Add the signal triggers
pasteAction.triggered.connect(self.paste_album_art_from_clipboard)
deleteAction.triggered.connect(self.delete_album_art)
contextMenu.addAction(copyAction) # Add actions to the menu
contextMenu.addAction(pasteAction)
contextMenu.addAction(deleteAction)
# DO
contextMenu.exec_(self.mapToGlobal(position)) # Show the menu
def copy_album_art_to_clipboard(self):
"""Copies album art to the clipboard"""
if not self.scene().items():
return # dont care if no pic
clipboard = self.qapp.clipboard()
pixmap_item = self.scene().items()[0]
clipboard.setPixmap(pixmap_item.pixmap())
def paste_album_art_from_clipboard(self):
"""Handles pasting album art into a song via system clipboard"""
clipboard = self.qapp.clipboard()
mime_data = clipboard.mimeData()
# Check if clipboard data is raw data or filepath
pixmap = None
if mime_data.hasUrls():
for url in mime_data.urls():
file_path = url.toLocalFile()
if os.path.isfile(file_path):
pixmap = QPixmap(file_path)
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
try:
self.scene().clear()
except Exception:
pass
self.scene().addPixmap(pixmap)
# Create temp file for pic
temp_file, file_path = tempfile.mkstemp(suffix=".jpg")
os.close(temp_file) # close the file
pixmap.save(file_path, "JPEG")
self.albumArtDropped.emit(
file_path
) # emit signal that album art was pasted
def delete_album_art(self):
"""Emits a signal for the album art of the current song to be deleted"""
self.albumArtDeleted.emit()
def load_qapp(self, qapp):
"""Necessary for talking between components..."""
self.qapp = qapp