diff --git a/components/MusicTable.py b/components/MusicTable.py index c31d59b..08c4c89 100644 --- a/components/MusicTable.py +++ b/components/MusicTable.py @@ -1,12 +1,12 @@ import DBA -from PyQt5.QtGui import QStandardItem, QStandardItemModel -from PyQt5.QtWidgets import QTableView -from PyQt5.QtCore import QTimer, Qt, pyqtSignal -from tinytag import TinyTag +from PyQt5.QtGui import QStandardItem, QStandardItemModel, QKeySequence +from PyQt5.QtWidgets import QTableView, QShortcut +from PyQt5.QtCore import Qt, pyqtSignal from utils import add_files_to_library from utils import get_id3_tags from utils import get_album_art import logging +import configparser class MusicTable(QTableView): @@ -19,12 +19,32 @@ class MusicTable(QTableView): self.selected_song_filepath = None self.current_song_filepath = None self.qapp = None + self.config = configparser.ConfigParser() + self.config.read('config.ini') # self.tableView.resizeColumnsToContents() self.clicked.connect(self.set_selected_song_filepath) # doubleClicked is a built in event for QTableView - we listen for this event and run set_current_song_filepath self.doubleClicked.connect(self.set_current_song_filepath) self.enterKey.connect(self.set_current_song_filepath) self.fetch_library() + self.setup_keyboard_shortcuts() + + def setup_keyboard_shortcuts(self): + """Setup shortcuts here""" + shortcut = QShortcut(QKeySequence("Ctrl+Shift+R"), self) + shortcut.activated.connect(self.reorganize_selected_files) + + def reorganize_selected_files(self): + """Ctrl+Shift+R = Reorganize""" + filepaths = self.get_selected_songs_filepaths() + # right now this just prints the filepaths to the songs obv. + print(f'yay: {filepaths}') + # TODO + # Get user confirmation screen (default yes, so i can press enter and go) + # Get target directory + # Copy files to new dir + # delete files from current dir + # add new files to library def keyPressEvent(self, event): """Press a key. Do a thing""" @@ -51,34 +71,45 @@ class MusicTable(QTableView): if not self.current_song_filepath: self.set_current_song_filepath() self.playPauseSignal.emit() - - 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 song""" # Setting the current song filepath automatically plays that song # self.tableView listens to this function and plays the audio file located at self.current_song_filepath self.current_song_filepath = self.currentIndex().siblingAtColumn(self.headers.index('path')).data() print(f'Current song: {self.current_song_filepath}') - + + def get_selected_rows(self): + """Returns a list of indexes for every selected row""" + selection_model = self.selectionModel() + return [index.row() for index in selection_model.selectedRows()] + # rows = [] + # for idx in self.selectionModel().siblingAtColumn(): + # rows.append(idx.row()) + # return rows + + def get_selected_songs_filepaths(self): + """Returns a list of the filepaths for the currently selected songs""" + selected_rows = self.get_selected_rows() + filepaths = [] + for row in selected_rows: + idx = self.model.index(row, self.headers.index('path')) + filepaths.append(idx.data()) + return filepaths + def get_selected_song_filepath(self): """Returns the selected songs filepath""" return self.selected_song_filepath - + def get_selected_song_metadata(self): """Returns the selected song's ID3 tags""" return get_id3_tags(self.selected_song_filepath) - + def get_current_song_filepath(self): """Returns the currently playing song filepath""" return self.current_song_filepath @@ -86,12 +117,11 @@ class MusicTable(QTableView): def get_current_song_metadata(self): """Returns the currently playing song's ID3 tags""" return get_id3_tags(self.current_song_filepath) - + def get_current_song_album_art(self): """Returns the APIC data (album art lol) for the currently playing song""" return get_album_art(self.current_song_filepath) - - + def fetch_library(self): """Initialize the tableview model""" self.model = QStandardItemModel() @@ -107,7 +137,7 @@ class MusicTable(QTableView): self.setModel(self.model) # self.update() self.viewport().update() - + def add_files(self, files): """When song(s) added to the library, update the tableview model - Drag & Drop song(s) on tableView @@ -117,11 +147,9 @@ class MusicTable(QTableView): number_of_files_added = add_files_to_library(files) if number_of_files_added: self.fetch_library() - - + def load_qapp(self, qapp): # why was this necessary again? :thinking: self.qapp = qapp - diff --git a/main.py b/main.py index 6ad0c9d..45078c7 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ from ui import Ui_MainWindow -from PyQt5.QtWidgets import QMainWindow, QApplication, QGraphicsScene, QHeaderView, QGraphicsPixmapItem +from PyQt5.QtWidgets import QMainWindow, QApplication, QGraphicsScene, \ + QHeaderView, QGraphicsPixmapItem import qdarktheme from PyQt5.QtCore import QUrl, QTimer, QEvent, Qt from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QAudioProbe @@ -14,6 +15,7 @@ import configparser # Create ui.py file from Qt Designer # pyuic5 ui.ui -o ui.py + class ApplicationWindow(QMainWindow, Ui_MainWindow): def __init__(self, qapp): super(ApplicationWindow, self).__init__() @@ -29,24 +31,21 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.tableView.load_qapp(self.qapp) self.config = configparser.ConfigParser() self.config.read('config.ini') - global stopped stopped = False - # Initialization - self.player = QMediaPlayer() # Audio player - self.probe = QAudioProbe() # Get audio data - self.timer = QTimer(self) # Audio timing things + 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.audio_visualizer = AudioVisualizer(self.player) self.current_volume = 50 self.player.setVolume(self.current_volume) - # Audio probe for processing audio signal in real time # Provides faster updates than move_slider self.probe.setSource(self.player) self.probe.audioBufferProbed.connect(self.process_probe) - + # 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) @@ -56,7 +55,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.PlotWidget.setYRange(0,0.3,padding=0) # y axis range self.PlotWidget.getAxis('bottom').setTicks([]) # Remove x-axis ticks self.PlotWidget.getAxis('bottom').setLabel('') # Remove x-axis label - self.PlotWidget.setLogMode(False,False) + self.PlotWidget.setLogMode(False, False) # Remove y-axis labels and decorations self.PlotWidget.getAxis('left').setTicks([]) # Remove y-axis ticks self.PlotWidget.getAxis('left').setLabel('') # Remove y-axis label @@ -80,7 +79,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.tableView.playPauseSignal.connect(self.on_play_clicked) # Spacebar toggle play/pause signal self.tableView.viewport().installEventFilter(self) # for drag & drop functionality # self.tableView.model.layoutChanged() - ### set column widths + # set column widths table_view_column_widths = str(self.config['table']['column_widths']).split(',') for i in range(self.tableView.model.columnCount()): self.tableView.setColumnWidth(i, int(table_view_column_widths[i])) @@ -88,15 +87,14 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.tableView.horizontalHeader().setStretchLastSection(False) - def eventFilter(self, source, event): """Handles events""" # tableView (drag & drop) if (source is self.tableView.viewport() and (event.type() == QEvent.DragEnter or - event.type() == QEvent.DragMove or - event.type() == QEvent.Drop) and - event.mimeData().hasUrls()): + event.type() == QEvent.DragMove or + event.type() == QEvent.Drop) and + event.mimeData().hasUrls()): files = [] if event.type() == QEvent.Drop: for url in event.mimeData().urls(): @@ -206,7 +204,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.startTimeLabel.setText(f"{int(current_minutes):02d}:{int(current_seconds):02d}") self.endTimeLabel.setText(f"{int(duration_minutes):02d}:{int(duration_seconds):02d}") - + def volume_changed(self): """Handles volume changes""" try: @@ -214,7 +212,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): self.player.setVolume(self.current_volume) except Exception as e: print(f"Changing volume error: {e}") - + def on_play_clicked(self): """Updates the Play & Pause buttons when clicked""" if self.player.state() == QMediaPlayer.PlayingState: @@ -227,31 +225,30 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow): else: self.play_audio_file() self.playButton.setText("⏸️") - + def on_previous_clicked(self): """""" print('previous') - + def on_next_clicked(self): print('next') - + def actionPreferencesClicked(self): preferences_window = PreferencesWindow(self.config) preferences_window.exec_() # Display the preferences window modally + def scan_libraries(self): scan_for_music() self.tableView.fetch_library() - + def clear_database(self): initialize_library_database() self.tableView.fetch_library() - + def process_probe(self, buff): buff.startTime() self.update_audio_visualization() - - - + if __name__ == "__main__": import sys