diff --git a/components/MusicTable.py b/components/MusicTable.py
index 4379328..2ca97c2 100644
--- a/components/MusicTable.py
+++ b/components/MusicTable.py
@@ -1,24 +1,97 @@
import DBA
from PyQt5.QtGui import QStandardItem, QStandardItemModel
-from PyQt5.QtWidgets import QTableView
+from PyQt5.QtWidgets import QTableView, QApplication
+from PyQt5.QtCore import QTimer
+from tinytag import TinyTag
class MusicTable(QTableView):
- def __init__(self):
- super().__init__()
+ def __init__(self, parent=None, qapp=None):
+ QTableView.__init__(self, parent)
+ self.headers = ['title', 'artist', 'album', 'genre', 'codec', 'year', 'path']
+ self.model = QStandardItemModel()
+ self.model.setHorizontalHeaderLabels(self.headers)
+ self.songChanged = None
+ self.selected_song_filepath = None
+ self.current_song_filepath = None
+ self.qapp = None
+ # self.tableView.resizeColumnsToContents()
+ self.clicked.connect(self.set_selected_song_filepath) # These are faster than the click/double determination
+ self.doubleClicked.connect(self.set_current_song_filepath) # These are faster than the click/double determination
+ self.fetch_library()
+
+ def mousePressEvent(self, event):
+ self.last = "Click"
+ QTableView.mousePressEvent(self, event) # Keep original functionality
+
+ def mouseReleaseEvent(self, event):
+ if self.last == "Click":
+ QTimer.singleShot(self.qapp.instance().doubleClickInterval(),
+ self.performSingleClickAction)
+ else:
+ # Perform double click action.
+ self.set_current_song_filepath
+ self.message = "Double Click"
+ self.update()
+ QTableView.mouseReleaseEvent(self, event) # Keep original functionality
+
+ def mouseDoubleClickEvent(self, event):
+ self.last = "Double Click"
+ self.doubleClicked.emit(self.selectionModel().currentIndex())
+ QTableView.mouseDoubleClickEvent(self, event) # Keep original functionality
+
+ def performSingleClickAction(self):
+ if self.last == "Click":
+ self.message = "Click"
+ self.update()
+
+ def get_selected_rows(self):
+ """Returns a list of indexes for every selected row"""
+ rows = []
+ for idx in self.selectionModel().siblingAtColumn():
+ rows.append(idx.row())
+ return rows
+
+ def set_selected_song_filepath(self):
+ """Sets the filepath of the currently selected song"""
+ self.selected_song_filepath = self.currentIndex().siblingAtColumn(self.headers.index('path')).data()
+ print(f'Selected song: {self.selected_song_filepath}')
+
+ def set_current_song_filepath(self):
+ """Sets the filepath of the currently playing/chosen song"""
+ self.current_song_filepath = self.currentIndex().siblingAtColumn(self.headers.index('path')).data()
+ print(f'Current song: {self.current_song_filepath}')
+
+ def get_selected_song_filepath(self):
+ """Returns the selected song filepath"""
+ return self.selected_song_filepath
+
+ def get_selected_song_metadata(self):
+ """Returns the current/chosen song's ID3 tags"""
+ return TinyTag.get(self.selected_song_filepath)
+
+ def get_current_song_filepath(self):
+ """Returns the current/chosen song filepath"""
+ return self.current_song_filepath
+
+ def get_current_song_metadata(self):
+ """Returns the current/chosen song's ID3 tags"""
+ return TinyTag.get(self.current_song_filepath)
+
+
+ def fetch_library(self):
# Fetch library data
- with DBA.DBAccess() as db: # returns a tuple, 1 row just for metadata purposes
+ with DBA.DBAccess() as db:
data = db.query('SELECT title, artist, album, genre, codec, album_date, filepath FROM library;', ())
- headers = ['title', 'artist', 'album', 'genre', 'codec', 'year', 'path']
- # Create a model
- model = QStandardItemModel()
- model.setHorizontalHeaderLabels(headers)
# Populate the model
for row_data in data:
items = [QStandardItem(str(item)) for item in row_data]
- model.appendRow(items)
- # Set the model to the tableView
- self.tableView.setModel(model)
- # self.tableView.resizeColumnsToContents()
- self.music_table.clicked.connect(self.set_clicked_cell_filepath)
+ self.model.appendRow(items)
+ # Set the model to the tableView (we are the tableview)
+ self.setModel(self.model)
+
+ def load_qapp(self, qapp):
+ self.qapp = qapp
+
+
\ No newline at end of file
diff --git a/main.py b/main.py
index ca36107..5d29ef6 100644
--- a/main.py
+++ b/main.py
@@ -9,24 +9,29 @@ from utils import scan_for_music
from utils import initialize_library_database
from utils import AudioVisualizer
from pyqtgraph import mkBrush
+from components import MusicTable
class ApplicationWindow(QMainWindow, Ui_MainWindow):
- def __init__(self):
+ def __init__(self, qapp):
super(ApplicationWindow, self).__init__()
self.setupUi(self)
self.setWindowTitle('MusicPom')
self.selected_song_filepath = None
self.current_song_filepath = None
+ self.current_song_metadata = None
+ self.qapp = qapp
+ print(f'ApplicationWindow self.qapp: {self.qapp}')
+ self.tableView.load_qapp(self.qapp)
global stopped
stopped = False
# Initialization
- self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface) # Audio player
+ self.player = QMediaPlayer() # Audio player
self.probe = QAudioProbe() # Get audio data
self.timer = QTimer(self) # Audio timing things
- self.model = QStandardItemModel() # Table library listing
+ # self.model = QStandardItemModel() # Table library listing
self.audio_visualizer = AudioVisualizer(self.player)
self.current_volume = 50
self.player.setVolume(self.current_volume)
@@ -36,33 +41,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.probe.setSource(self.player)
self.probe.audioBufferProbed.connect(self.process_probe)
- # Probably move all the table logic to its own class
- # Promote the wigdet to my custom class from utils
- # inherit from QTableView
- # then i can handle click events for editing metadata in a class
-
- # current song should also be its own class
- # selected song should be its own class too...
-
- # ______________
- # | |
- # | Table making |
- # | |
- # |______________|
-
- # Fetch library data
- with DBA.DBAccess() as db:
- data = db.query('SELECT title, artist, album, genre, codec, album_date, filepath FROM library;', ())
- headers = ['title', 'artist', 'album', 'genre', 'codec', 'year', 'path']
- self.model.setHorizontalHeaderLabels(headers)
- for row_data in data: # Populate the model
- items = [QStandardItem(str(item)) for item in row_data]
- self.model.appendRow(items)
- # Set the model to the tableView
- self.tableView.setModel(self.model)
- # self.tableView.resizeColumnsToContents()
-
-
# Slider Timer (realtime playback feedback horizontal bar)
self.timer.start(150) # 150ms update interval solved problem with drag seeking halting playback
self.timer.timeout.connect(self.move_slider)
@@ -79,27 +57,39 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
# Connections
- self.playbackSlider.sliderMoved[int].connect(lambda: self.player.setPosition(self.playbackSlider.value()))
- self.volumeSlider.sliderMoved[int].connect(lambda: self.volume_changed())
- self.playButton.clicked.connect(self.on_play_clicked)
+ # ! FIXME moving the slider while playing is happening frequently causes playback to halt - the pyqtgraph is also affected by this
+ self.playbackSlider.sliderMoved[int].connect(lambda: self.player.setPosition(self.playbackSlider.value())) # Move slidet to adjust playback time
+ self.volumeSlider.sliderMoved[int].connect(lambda: self.volume_changed()) # Move slider to adjust volume
+ self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause
# self.pauseButton.clicked.connect(self.on_pause_clicked)
- self.previousButton.clicked.connect(self.on_previous_clicked)
- self.nextButton.clicked.connect(self.on_next_clicked)
- self.tableView.clicked.connect(self.set_clicked_cell_filepath)
- self.actionPreferences.triggered.connect(self.actionPreferencesClicked)
- self.actionScanLibraries.triggered.connect(self.scan_libraries)
- self.actionClearDatabase.triggered.connect(initialize_library_database)
+ self.previousButton.clicked.connect(self.on_previous_clicked) # Click to previous song
+ self.nextButton.clicked.connect(self.on_next_clicked) # Click to next song
+ # self.tableView.clicked.connect(self.set_clicked_cell_filepath)
+ self.actionPreferences.triggered.connect(self.actionPreferencesClicked) # Open preferences menu
+ self.actionScanLibraries.triggered.connect(self.scan_libraries) # Scan library
+ self.actionClearDatabase.triggered.connect(initialize_library_database) # Clear database
+ self.tableView.doubleClicked.connect(self.play_audio_file) # Double click to play song
+
def play_audio_file(self):
- """Start playback of selected track & move playback slider"""
- self.current_song_filepath = self.selected_song_filepath
- url = QUrl.fromLocalFile(self.current_song_filepath) # read the file
+ """Start playback of selected track & moves playback slider"""
+ self.current_song_metadata = self.tableView.get_current_song_metadata() # get metadata
+ 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
+ # FIXME when i change tinytag to something else
+ artist = self.current_song_metadata.artist
+ album = self.current_song_metadata.album
+ title = self.current_song_metadata.title
+ # edit labels
+ self.artistLabel.setText(artist)
+ self.albumLabel.setText(album)
+ self.titleLabel.setText(title)
+
def update_audio_visualization(self):
"""Handles upading points on the pyqtgraph visual"""
self.clear_audio_visualization()
@@ -149,10 +139,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
else:
self.play_audio_file()
self.playButton.setText("⏸️")
-
- def set_clicked_cell_filepath(self):
- """Sets the filepath of the currently selected song"""
- self.selected_song_filepath = self.tableView.currentIndex().siblingAtColumn(6).data()
def on_previous_clicked(self):
""""""
@@ -178,7 +164,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
+ print(f'main.py app: {app}')
qdarktheme.setup_theme()
- ui = ApplicationWindow()
+ ui = ApplicationWindow(app)
ui.show()
sys.exit(app.exec_())
\ No newline at end of file
diff --git a/ui.py b/ui.py
index 84c9289..cbcd2d4 100644
--- a/ui.py
+++ b/ui.py
@@ -14,12 +14,12 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
- MainWindow.resize(1061, 795)
+ MainWindow.resize(1062, 795)
MainWindow.setStatusTip("")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.frame = QtWidgets.QFrame(self.centralwidget)
- self.frame.setGeometry(QtCore.QRect(0, 160, 1061, 501))
+ self.frame.setGeometry(QtCore.QRect(0, 160, 1061, 461))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -28,8 +28,8 @@ class Ui_MainWindow(object):
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
- self.tableView = QtWidgets.QTableView(self.frame)
- self.tableView.setGeometry(QtCore.QRect(0, 0, 1061, 501))
+ self.tableView = MusicTable(self.frame)
+ self.tableView.setGeometry(QtCore.QRect(0, 0, 1061, 461))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -37,6 +37,7 @@ class Ui_MainWindow(object):
self.tableView.setSizePolicy(sizePolicy)
self.tableView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.tableView.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
+ self.tableView.setEditTriggers(QtWidgets.QAbstractItemView.AnyKeyPressed|QtWidgets.QAbstractItemView.EditKeyPressed)
self.tableView.setAlternatingRowColors(True)
self.tableView.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
@@ -77,37 +78,15 @@ class Ui_MainWindow(object):
self.PlotWidget = PlotWidget(self.frame_4)
self.PlotWidget.setGeometry(QtCore.QRect(0, 0, 521, 121))
self.PlotWidget.setObjectName("PlotWidget")
- self.horizontalLayoutWidget_2 = QtWidgets.QWidget(self.centralwidget)
- self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(0, 660, 1061, 60))
- self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2")
- self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2)
- self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_2.setObjectName("horizontalLayout_2")
- self.previousButton = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
- font = QtGui.QFont()
- font.setPointSize(28)
- self.previousButton.setFont(font)
- self.previousButton.setObjectName("previousButton")
- self.horizontalLayout_2.addWidget(self.previousButton)
- self.playButton = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
- font = QtGui.QFont()
- font.setPointSize(28)
- self.playButton.setFont(font)
- self.playButton.setObjectName("playButton")
- self.horizontalLayout_2.addWidget(self.playButton)
- self.nextButton = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
- font = QtGui.QFont()
- font.setPointSize(28)
- self.nextButton.setFont(font)
- self.nextButton.setObjectName("nextButton")
- self.horizontalLayout_2.addWidget(self.nextButton)
self.frame_3 = QtWidgets.QFrame(self.centralwidget)
- self.frame_3.setGeometry(QtCore.QRect(0, 720, 1061, 31))
+ self.frame_3.setGeometry(QtCore.QRect(0, 680, 1061, 61))
self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_3.setObjectName("frame_3")
self.volumeSlider = QtWidgets.QSlider(self.frame_3)
- self.volumeSlider.setGeometry(QtCore.QRect(10, 0, 181, 31))
+ self.volumeSlider.setGeometry(QtCore.QRect(10, 10, 181, 31))
+ self.volumeSlider.setMaximum(100)
+ self.volumeSlider.setProperty("value", 50)
self.volumeSlider.setOrientation(QtCore.Qt.Horizontal)
self.volumeSlider.setObjectName("volumeSlider")
self.frame_5 = QtWidgets.QFrame(self.centralwidget)
@@ -144,9 +123,33 @@ class Ui_MainWindow(object):
self.albumLabel.setFont(font)
self.albumLabel.setObjectName("albumLabel")
self.verticalLayout.addWidget(self.albumLabel)
+ self.horizontalLayoutWidget_2 = QtWidgets.QWidget(self.centralwidget)
+ self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(0, 620, 1061, 60))
+ self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2")
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2)
+ self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.previousButton = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
+ font = QtGui.QFont()
+ font.setPointSize(28)
+ self.previousButton.setFont(font)
+ self.previousButton.setObjectName("previousButton")
+ self.horizontalLayout_2.addWidget(self.previousButton)
+ self.playButton = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
+ font = QtGui.QFont()
+ font.setPointSize(28)
+ self.playButton.setFont(font)
+ self.playButton.setObjectName("playButton")
+ self.horizontalLayout_2.addWidget(self.playButton)
+ self.nextButton = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
+ font = QtGui.QFont()
+ font.setPointSize(28)
+ self.nextButton.setFont(font)
+ self.nextButton.setObjectName("nextButton")
+ self.horizontalLayout_2.addWidget(self.nextButton)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
- self.menubar.setGeometry(QtCore.QRect(0, 0, 1061, 24))
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 1062, 24))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
@@ -183,12 +186,12 @@ class Ui_MainWindow(object):
self.startTimeLabel.setText(_translate("MainWindow", "00:00"))
self.slashLabel.setText(_translate("MainWindow", "/"))
self.endTimeLabel.setText(_translate("MainWindow", "00:00"))
- self.previousButton.setText(_translate("MainWindow", "⏮️"))
- self.playButton.setText(_translate("MainWindow", "▶️"))
- self.nextButton.setText(_translate("MainWindow", "⏭️"))
self.artistLabel.setText(_translate("MainWindow", "artist"))
self.titleLabel.setText(_translate("MainWindow", "song title"))
self.albumLabel.setText(_translate("MainWindow", "album"))
+ self.previousButton.setText(_translate("MainWindow", "⏮️"))
+ self.playButton.setText(_translate("MainWindow", "▶️"))
+ self.nextButton.setText(_translate("MainWindow", "⏭️"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.menuEdit.setTitle(_translate("MainWindow", "Edit"))
self.menuView.setTitle(_translate("MainWindow", "View"))
@@ -197,4 +200,5 @@ class Ui_MainWindow(object):
self.actionPreferences.setStatusTip(_translate("MainWindow", "Open preferences"))
self.actionScanLibraries.setText(_translate("MainWindow", "Scan libraries"))
self.actionClearDatabase.setText(_translate("MainWindow", "Clear Database"))
+from components import MusicTable
from pyqtgraph import PlotWidget
diff --git a/ui.ui b/ui.ui
index 1b1a938..0e7da19 100644
--- a/ui.ui
+++ b/ui.ui
@@ -6,7 +6,7 @@
0
0
- 1061
+ 1062
795
@@ -23,7 +23,7 @@
0
160
1061
- 501
+ 461
@@ -38,13 +38,13 @@
QFrame::Raised
-
+
0
0
1061
- 501
+ 461
@@ -59,6 +59,9 @@
QAbstractScrollArea::AdjustToContents
+
+ QAbstractItemView::AnyKeyPressed|QAbstractItemView::EditKeyPressed
+
true
@@ -165,61 +168,13 @@
-
-
-
- 0
- 660
- 1061
- 60
-
-
-
- -
-
-
-
- 28
-
-
-
- ⏮️
-
-
-
- -
-
-
-
- 28
-
-
-
- ▶️
-
-
-
- -
-
-
-
- 28
-
-
-
- ⏭️
-
-
-
-
-
0
- 720
+ 680
1061
- 31
+ 61
@@ -232,11 +187,17 @@
10
- 0
+ 10
181
31
+
+ 100
+
+
+ 50
+
Qt::Horizontal
@@ -311,13 +272,61 @@
+
+
+
+ 0
+ 620
+ 1061
+ 60
+
+
+
+ -
+
+
+
+ 28
+
+
+
+ ⏮️
+
+
+
+ -
+
+
+
+ 28
+
+
+
+ ▶️
+
+
+
+ -
+
+
+
+ 28
+
+
+
+ ⏭️
+
+
+
+
+