first time run auto-config + update readme

This commit is contained in:
tsi-billypom 2024-05-30 11:34:27 -04:00
parent 5b93f81e05
commit 767ce3fa9c
6 changed files with 79 additions and 22 deletions

11
DBA.py
View File

@ -2,17 +2,16 @@ import sqlite3
import logging import logging
from configparser import ConfigParser from configparser import ConfigParser
class DBAccess: class DBAccess:
def __init__(self, db_name=None): def __init__(self, db_name=None):
logging.info('Instantiating DBAccess') logging.info("Instantiating DBAccess")
config = ConfigParser() config = ConfigParser()
config.read('config.ini') config.read("config.ini")
if db_name is None: if db_name is None:
db_name = config.get('db', 'database') db_name = config.get("db", "database")
self._conn: sqlite3.Connection = sqlite3.connect(db_name) 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() self._cursor: sqlite3.Cursor = self._conn.cursor()
logging.info(f'DBAccess | self._cursor = [\n{type(self._cursor)}\n{self._cursor}\n]')
def __enter__(self): def __enter__(self):
return self return self
@ -40,7 +39,7 @@ class DBAccess:
self.cursor.execute(sql, params or ()) self.cursor.execute(sql, params or ())
def executemany(self, sql, seq_of_params): def executemany(self, sql, seq_of_params):
self.cursor.executemany(sql, seq_of_params) #sqlite has execute many i guess? self.cursor.executemany(sql, seq_of_params) # sqlite has execute many i guess?
def fetchall(self): def fetchall(self):
return self.cursor.fetchall() return self.cursor.fetchall()

View File

@ -2,6 +2,29 @@
PyQt5 music player inspired by MusicBee & iTunes PyQt5 music player inspired by MusicBee & iTunes
## Installation:
clone the repo
```
git clone https://github.com/billypom/musicpom
```
install system packages
```
sudo apt install ffmpeg
sudo apt install python3-pyqt5
```
create environment
```
cd musicpom
virtualenv venv
cd ..
cd musicpom
pip install -r requirements.txt
```
run the program
```
python3 main.py
```
## Todo: ## Todo:
- [ ] Delete songs from library (del key || right-click delete) - [ ] Delete songs from library (del key || right-click delete)

View File

@ -7,14 +7,23 @@ from PyQt5.QtGui import (
QDragEnterEvent, QDragEnterEvent,
QDropEvent, QDropEvent,
) )
from PyQt5.QtWidgets import QAction, QMenu, QTableView, QShortcut, QMessageBox, QAbstractItemView from PyQt5.QtWidgets import (
QAction,
QMenu,
QTableView,
QShortcut,
QMessageBox,
QAbstractItemView,
)
from PyQt5.QtCore import QModelIndex, Qt, pyqtSignal, QTimer from PyQt5.QtCore import QModelIndex, Qt, pyqtSignal, QTimer
from utils import add_files_to_library from utils import add_files_to_library
from utils import update_song_in_library from utils import update_song_in_library
from utils import get_id3_tags from utils import get_id3_tags
from utils import get_album_art from utils import get_album_art
from utils import set_id3_tag from utils import set_id3_tag
from utils import delete_and_create_library_database
from subprocess import Popen from subprocess import Popen
from sqlite3 import OperationalError
import logging import logging
import configparser import configparser
import os import os
@ -57,8 +66,8 @@ class MusicTable(QTableView):
self.database_columns = str(self.config["table"]["columns"]).split(",") self.database_columns = str(self.config["table"]["columns"]).split(",")
self.vertical_scroll_position = 0 self.vertical_scroll_position = 0
self.songChanged = None self.songChanged = None
self.selected_song_filepath = '' self.selected_song_filepath = ""
self.current_song_filepath = '' self.current_song_filepath = ""
# self.tableView.resizeColumnsToContents() # self.tableView.resizeColumnsToContents()
self.clicked.connect(self.set_selected_song_filepath) 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 # doubleClicked is a built in event for QTableView - we listen for this event and run set_current_song_filepath
@ -104,12 +113,12 @@ class MusicTable(QTableView):
# self.model().removeRow(index) # self.model().removeRow(index)
for file in selected_filepaths: for file in selected_filepaths:
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.execute('DELETE FROM library WHERE filepath = ?', (file,)) db.execute("DELETE FROM library WHERE filepath = ?", (file,))
def open_directory(self): def open_directory(self):
filepath = self.get_selected_song_filepath().split('/') filepath = self.get_selected_song_filepath().split("/")
filepath.pop() filepath.pop()
path = '/'.join(filepath) path = "/".join(filepath)
Popen(["xdg-open", path]) Popen(["xdg-open", path])
def show_lyrics_menu(self): def show_lyrics_menu(self):
@ -241,7 +250,7 @@ class MusicTable(QTableView):
self.playPauseSignal.emit() self.playPauseSignal.emit()
def fetch_library(self): def fetch_library(self):
"""Initialize the tableview model""" """Initializes the tableview model"""
self.vertical_scroll_position = ( self.vertical_scroll_position = (
self.verticalScrollBar().value() self.verticalScrollBar().value()
) # Get my scroll position before clearing ) # Get my scroll position before clearing
@ -249,18 +258,22 @@ class MusicTable(QTableView):
self.model.clear() self.model.clear()
self.model.setHorizontalHeaderLabels(self.table_headers) self.model.setHorizontalHeaderLabels(self.table_headers)
# Fetch library data # Fetch library data
try:
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
data = db.query( data = db.query(
"SELECT id, title, artist, album, genre, codec, album_date, filepath FROM library;", "SELECT id, title, artist, album, genre, codec, album_date, filepath FROM library;",
(), (),
) )
except Exception as e:
logging.warning(f"MusicTable.py | fetch_library | Unhandled exception: {e}")
return
# Populate the model # Populate the model
for row_data in data: for row_data in data:
id, *rest_of_data = row_data id, *rest_of_data = row_data
items = [QStandardItem(str(item)) for item in rest_of_data] items = [QStandardItem(str(item)) for item in rest_of_data]
self.model.appendRow(items) self.model.appendRow(items)
# store id using setData - useful for later faster db fetching # store id using setData - useful for later faster db fetching
row = self.model.rowCount() - 1 # row = self.model.rowCount() - 1
for item in items: for item in items:
item.setData(id, Qt.UserRole) item.setData(id, Qt.UserRole)
# Update the viewport/model # Update the viewport/model

22
main.py
View File

@ -1,10 +1,13 @@
import os import os
import configparser import configparser
import sys import sys
from subprocess import run
import qdarktheme import qdarktheme
from pyqtgraph import mkBrush from pyqtgraph import mkBrush
from mutagen.id3 import ID3, APIC, error from mutagen.id3 import ID3, APIC, error
from mutagen.mp3 import MP3 from mutagen.mp3 import MP3
from configparser import ConfigParser
import DBA
from ui import Ui_MainWindow from ui import Ui_MainWindow
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QMainWindow, QMainWindow,
@ -337,6 +340,25 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
if __name__ == "__main__": if __name__ == "__main__":
# First run initialization
if not os.path.exists("config.ini"):
# Create config file from sample
run(["cp", "sample_config.ini", "config.ini"])
config = ConfigParser()
config.read("config.ini")
db_name = config.get("db", "database")
db_path = db_name.split("/")
db_path.pop()
path_as_string = "/".join(db_path)
if not os.path.exists(path_as_string):
os.makedirs(path_as_string)
# Create database on first run
with DBA.DBAccess() as db:
with open("utils/delete_and_create_library.sql", "r") as file:
lines = file.read()
for statement in lines.split(";"):
print(f"executing [{statement}]")
db.execute(statement, ())
# Allow for dynamic imports of my custom classes and utilities # Allow for dynamic imports of my custom classes and utilities
project_root = os.path.abspath(os.path.dirname(__file__)) project_root = os.path.abspath(os.path.dirname(__file__))
sys.path.append(project_root) sys.path.append(project_root)

View File

@ -1,6 +1,6 @@
[db] [db]
# The library database file # The library database file
library = db/library.db database = db/library.db
[directories] [directories]
# Useful paths to have stored # Useful paths to have stored