first time run auto-config + update readme
This commit is contained in:
parent
5b93f81e05
commit
767ce3fa9c
13
DBA.py
13
DBA.py
@ -2,17 +2,16 @@ import sqlite3
|
||||
import logging
|
||||
from configparser import ConfigParser
|
||||
|
||||
|
||||
class DBAccess:
|
||||
def __init__(self, db_name=None):
|
||||
logging.info('Instantiating DBAccess')
|
||||
logging.info("Instantiating DBAccess")
|
||||
config = ConfigParser()
|
||||
config.read('config.ini')
|
||||
config.read("config.ini")
|
||||
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)
|
||||
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
|
||||
@ -38,9 +37,9 @@ class DBAccess:
|
||||
|
||||
def execute(self, sql, params):
|
||||
self.cursor.execute(sql, params or ())
|
||||
|
||||
|
||||
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):
|
||||
return self.cursor.fetchall()
|
||||
|
||||
23
README.md
23
README.md
@ -2,6 +2,29 @@
|
||||
|
||||
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:
|
||||
|
||||
- [ ] Delete songs from library (del key || right-click delete)
|
||||
|
||||
@ -7,14 +7,23 @@ from PyQt5.QtGui import (
|
||||
QDragEnterEvent,
|
||||
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 utils import add_files_to_library
|
||||
from utils import update_song_in_library
|
||||
from utils import get_id3_tags
|
||||
from utils import get_album_art
|
||||
from utils import set_id3_tag
|
||||
from utils import delete_and_create_library_database
|
||||
from subprocess import Popen
|
||||
from sqlite3 import OperationalError
|
||||
import logging
|
||||
import configparser
|
||||
import os
|
||||
@ -57,8 +66,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 = ''
|
||||
self.current_song_filepath = ''
|
||||
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
|
||||
@ -104,12 +113,12 @@ class MusicTable(QTableView):
|
||||
# self.model().removeRow(index)
|
||||
for file in selected_filepaths:
|
||||
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):
|
||||
filepath = self.get_selected_song_filepath().split('/')
|
||||
filepath = self.get_selected_song_filepath().split("/")
|
||||
filepath.pop()
|
||||
path = '/'.join(filepath)
|
||||
path = "/".join(filepath)
|
||||
Popen(["xdg-open", path])
|
||||
|
||||
def show_lyrics_menu(self):
|
||||
@ -241,7 +250,7 @@ class MusicTable(QTableView):
|
||||
self.playPauseSignal.emit()
|
||||
|
||||
def fetch_library(self):
|
||||
"""Initialize the tableview model"""
|
||||
"""Initializes the tableview model"""
|
||||
self.vertical_scroll_position = (
|
||||
self.verticalScrollBar().value()
|
||||
) # Get my scroll position before clearing
|
||||
@ -249,18 +258,22 @@ class MusicTable(QTableView):
|
||||
self.model.clear()
|
||||
self.model.setHorizontalHeaderLabels(self.table_headers)
|
||||
# Fetch library data
|
||||
with DBA.DBAccess() as db:
|
||||
data = db.query(
|
||||
"SELECT id, title, artist, album, genre, codec, album_date, filepath FROM library;",
|
||||
(),
|
||||
)
|
||||
try:
|
||||
with DBA.DBAccess() as db:
|
||||
data = db.query(
|
||||
"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
|
||||
for row_data in data:
|
||||
id, *rest_of_data = row_data
|
||||
items = [QStandardItem(str(item)) for item in rest_of_data]
|
||||
self.model.appendRow(items)
|
||||
# store id using setData - useful for later faster db fetching
|
||||
row = self.model.rowCount() - 1
|
||||
# row = self.model.rowCount() - 1
|
||||
for item in items:
|
||||
item.setData(id, Qt.UserRole)
|
||||
# Update the viewport/model
|
||||
|
||||
22
main.py
22
main.py
@ -1,10 +1,13 @@
|
||||
import os
|
||||
import configparser
|
||||
import sys
|
||||
from subprocess import run
|
||||
import qdarktheme
|
||||
from pyqtgraph import mkBrush
|
||||
from mutagen.id3 import ID3, APIC, error
|
||||
from mutagen.mp3 import MP3
|
||||
from configparser import ConfigParser
|
||||
import DBA
|
||||
from ui import Ui_MainWindow
|
||||
from PyQt5.QtWidgets import (
|
||||
QMainWindow,
|
||||
@ -337,6 +340,25 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
||||
|
||||
|
||||
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
|
||||
project_root = os.path.abspath(os.path.dirname(__file__))
|
||||
sys.path.append(project_root)
|
||||
|
||||
@ -4,4 +4,4 @@ pyqt5
|
||||
pydub
|
||||
pyqtdarktheme
|
||||
pyqtgraph
|
||||
scipy
|
||||
scipy
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[db]
|
||||
# The library database file
|
||||
library = db/library.db
|
||||
database = db/library.db
|
||||
|
||||
[directories]
|
||||
# Useful paths to have stored
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user