diff --git a/DBA.py b/DBA.py index 048a175..5e5b29e 100644 --- a/DBA.py +++ b/DBA.py @@ -1,14 +1,18 @@ import sqlite3 +import logging from configparser import ConfigParser class DBAccess: def __init__(self, db_name=None): + logging.info('Instantiating DBAccess') config = ConfigParser() config.read('config.ini') if db_name is None: db_name = config.get('db', 'database') - self._conn = sqlite3.connect(db_name) - self._cursor = self._conn.cursor() + self._conn: sqlite3.Connection = sqlite3.connect(db_name) + logging.info(f'DBAccess | self._conn = [\n{type(self._conn)}\n{self._conn}\n]') + self._cursor: sqlite3.Cursor = self._conn.cursor() + logging.info(f'DBAccess | self._cursor = [\n{type(self._cursor)}\n{self._cursor}\n]') def __enter__(self): return self diff --git a/README.md b/README.md index eebe302..7cc7821 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ # MusicPom -iTunes-like music player built with PyQt5. - -I am longing for a linux version of MusicBee, so I created this app for myself that will have all the features I want. +PyQt5 music player inspired by MusicBee & iTunes ## Todo: -- [ ] Delete songs from library +- [ ] Delete songs from library (del key || right-click delete) +- [x] Right-click menu +- [ ] .wav, .ogg, .flac convertor - [ ] Editable lyrics textbox -- [ ] .wav, .ogg, .flac conversions diff --git a/components/MusicTable.py b/components/MusicTable.py index 023744d..3f44336 100644 --- a/components/MusicTable.py +++ b/components/MusicTable.py @@ -7,7 +7,7 @@ from PyQt5.QtGui import ( QDragEnterEvent, QDropEvent, ) -from PyQt5.QtWidgets import QTableView, QShortcut, QMessageBox, QAbstractItemView +from PyQt5.QtWidgets import QAction, QMenu, QTableView, QShortcut, QMessageBox, QAbstractItemView from PyQt5.QtCore import QModelIndex, Qt, pyqtSignal, QTimer from utils import add_files_to_library from utils import update_song_in_library @@ -56,8 +56,8 @@ class MusicTable(QTableView): self.database_columns = str(self.config["table"]["columns"]).split(",") self.vertical_scroll_position = 0 self.songChanged = None - self.selected_song_filepath = None - self.current_song_filepath = None + self.selected_song_filepath = '' + self.current_song_filepath = '' # 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 @@ -68,6 +68,19 @@ class MusicTable(QTableView): self.model.dataChanged.connect(self.on_cell_data_changed) # editing cells self.model.layoutChanged.connect(self.restore_scroll_position) + def contextMenuEvent(self, event): + """Show a context menu when you right-click a row""" + menu = QMenu(self) + delete_action = QAction("Delete", self) + delete_action.triggered.connect(self.delete_selected_rows) + menu.addAction(delete_action) + menu.exec_(event.globalPos()) + + def delete_selected_rows(self): + selected_rows = self.selectionModel().selectedRows() + for index in selected_rows: + self.model().removeRow(index.row()) + def dragEnterEvent(self, event: QDragEnterEvent): if event.mimeData().hasUrls(): event.accept() @@ -255,7 +268,7 @@ class MusicTable(QTableView): """Returns the selected songs filepath""" return self.selected_song_filepath - def get_selected_song_metadata(self) -> dict: + def get_selected_song_metadata(self) -> EasyID3 | dict: """Returns the selected song's ID3 tags""" return get_id3_tags(self.selected_song_filepath) @@ -263,11 +276,11 @@ class MusicTable(QTableView): """Returns the currently playing song filepath""" return self.current_song_filepath - def get_current_song_metadata(self) -> dict: + def get_current_song_metadata(self) -> EasyID3 | dict: """Returns the currently playing song's ID3 tags""" return get_id3_tags(self.current_song_filepath) - def get_current_song_album_art(self) -> None: + def get_current_song_album_art(self) -> bytes: """Returns the APIC data (album art lol) for the currently playing song""" return get_album_art(self.current_song_filepath) diff --git a/utils/add_files_to_library.py b/utils/add_files_to_library.py index 3a2bfda..3cc6297 100644 --- a/utils/add_files_to_library.py +++ b/utils/add_files_to_library.py @@ -21,6 +21,8 @@ def add_files_to_library(files): if any(filepath.lower().endswith(ext) for ext in extensions): filename = filepath.split("/")[-1] audio = get_id3_tags(filepath) + print('add_files_to_library audio:') + print(audio) # Skip if no title is found (but should never happen if "title" not in audio: continue diff --git a/utils/get_id3_tags.py b/utils/get_id3_tags.py index da79c01..7206308 100644 --- a/utils/get_id3_tags.py +++ b/utils/get_id3_tags.py @@ -11,22 +11,32 @@ def get_id3_tags(file): dict of all id3 tags if all tags are empty, at minimum fill in the 'title' """ + + is_easy_id3 = False try: + is_easy_id3 = True audio = EasyID3(file) - # Check if all tags are empty - tags_are_empty = all(not values for values in audio.values()) - if tags_are_empty: - # split on / to get just the filename - # os.path.splitext to get name without extension - audio['title'] = [os.path.splitext(file.split('/')[-1])[0]] - if audio['title'] is None: # I guess a song could have other tags - # without a title, so i make sure to have title - audio['title'] = [os.path.splitext(file.split('/')[-1])[0]] - audio.save() - return audio except Exception as e: - print(f"Error: {e}") - return {} + is_easy_id3 = False + audio = {} + + print('get_id3_tags audio:') + print(audio) + + # Check if all tags are empty + tags_are_empty = all(not values for values in audio.values()) + if tags_are_empty: + # split on / to get just the filename + # os.path.splitext to get name without extension + audio['title'] = [os.path.splitext(file.split('/')[-1])[0]] + + if audio['title'] is None: # I guess a song could have other tags + # without a title, so i make sure to have title + audio['title'] = [os.path.splitext(file.split('/')[-1])[0]] + + if is_easy_id3: # i can ignore this error because of this check + audio.save() # type: ignore + return audio # import sys # my_file = sys.argv[1]