layouts, mutagen id3 tags, table drag & drop, double click to play

This commit is contained in:
billypom on debian 2024-01-28 10:44:11 -05:00
parent 76c1aa554b
commit a982a025fe
7 changed files with 68 additions and 45 deletions

View File

@ -4,7 +4,6 @@ from PyQt5.QtWidgets import QTableView
from PyQt5.QtCore import QTimer from PyQt5.QtCore import QTimer
from tinytag import TinyTag from tinytag import TinyTag
from utils import add_files_to_library from utils import add_files_to_library
from utils import get_id3_tags
import logging import logging
@ -57,9 +56,6 @@ class MusicTable(QTableView):
"""Sets the filepath of the currently selected song""" """Sets the filepath of the currently selected song"""
self.selected_song_filepath = self.currentIndex().siblingAtColumn(self.headers.index('path')).data() self.selected_song_filepath = self.currentIndex().siblingAtColumn(self.headers.index('path')).data()
print(f'Selected song: {self.selected_song_filepath}') print(f'Selected song: {self.selected_song_filepath}')
print('TAGS:')
print(get_id3_tags(self.selected_song_filepath))
print('END TAGS')
def set_current_song_filepath(self): def set_current_song_filepath(self):
"""Sets the filepath of the currently playing/chosen song""" """Sets the filepath of the currently playing/chosen song"""

View File

@ -69,7 +69,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.nextButton.clicked.connect(self.on_next_clicked) # Click to next song self.nextButton.clicked.connect(self.on_next_clicked) # Click to next song
self.actionPreferences.triggered.connect(self.actionPreferencesClicked) # Open preferences menu self.actionPreferences.triggered.connect(self.actionPreferencesClicked) # Open preferences menu
self.actionScanLibraries.triggered.connect(self.scan_libraries) # Scan library self.actionScanLibraries.triggered.connect(self.scan_libraries) # Scan library
self.actionClearDatabase.triggered.connect(initialize_library_database) # Clear database self.actionClearDatabase.triggered.connect(self.clear_database) # Clear database
## tableView ## tableView
# self.tableView.clicked.connect(self.set_clicked_cell_filepath) # self.tableView.clicked.connect(self.set_clicked_cell_filepath)
self.tableView.doubleClicked.connect(self.play_audio_file) # Double click to play song self.tableView.doubleClicked.connect(self.play_audio_file) # Double click to play song
@ -194,7 +194,11 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
def scan_libraries(self): def scan_libraries(self):
scan_for_music() scan_for_music()
# refresh datatable self.tableView.fetch_library()
def clear_database(self):
initialize_library_database()
self.tableView.fetch_library()
def process_probe(self, buff): def process_probe(self, buff):
buff.startTime() buff.startTime()

View File

@ -1,3 +1,4 @@
from .safe_get import safe_get
from .get_id3_tags import get_id3_tags from .get_id3_tags import get_id3_tags
from .initialize_library_database import initialize_library_database from .initialize_library_database import initialize_library_database
from .scan_for_music import scan_for_music from .scan_for_music import scan_for_music

View File

@ -1,6 +1,7 @@
import DBA import DBA
from configparser import ConfigParser from configparser import ConfigParser
from utils import get_id3_tags from utils import get_id3_tags
from utils import safe_get
config = ConfigParser() config = ConfigParser()
config.read("config.ini") config.read("config.ini")
@ -11,37 +12,47 @@ def add_files_to_library(files):
`files` | list() | List of fully qualified paths to audio file(s) `files` | list() | List of fully qualified paths to audio file(s)
Returns a count of records added Returns a count of records added
""" """
print(f'utils | adding files to library: {files}') print(f"utils | adding files to library: {files}")
extensions = config.get('settings', 'extensions').split(',') extensions = config.get("settings", "extensions").split(",")
insert_data = [] # To store data for batch insert insert_data = [] # To store data for batch insert
for file in files: for filepath in files:
if any(file.lower().endswith(ext) for ext in extensions): if any(filepath.lower().endswith(ext) for ext in extensions):
filename = file.split("/")[-1] filename = filepath.split("/")[-1]
audio = get_id3_tags(file) audio = get_id3_tags(filepath)
if "title" not in audio:
return
# Append data tuple to insert_data list # Append data tuple to insert_data list
insert_data.append( insert_data.append(
( (
file, filepath,
audio.title, safe_get(audio, "title", [])[0],
audio.album, safe_get(audio, "album", [])[0] if "album" in audio else None,
audio.artist, safe_get(audio, "artist", [])[0] if "artist" in audio else None,
audio.genre, ",".join(safe_get(audio, "genre", []))
if "genre" in audio
else None,
filename.split(".")[-1], filename.split(".")[-1],
audio.year, safe_get(audio, "date", [])[0] if "date" in audio else None,
audio.bitrate, safe_get(audio, "bitrate", [])[0] if "birate" in audio else None,
) )
) )
# Check if batch size is reached # Check if batch size is reached
if len(insert_data) >= 1000: if len(insert_data) >= 1000:
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.executemany('INSERT OR IGNORE INTO library (filepath, title, album, artist, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', insert_data) db.executemany(
"INSERT OR IGNORE INTO library (filepath, title, album, artist, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
insert_data,
)
insert_data = [] # Reset the insert_data list insert_data = [] # Reset the insert_data list
# Insert any remaining data # Insert any remaining data
if insert_data: if insert_data:
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.executemany('INSERT OR IGNORE INTO library (filepath, title, album, artist, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', insert_data) db.executemany(
"INSERT OR IGNORE INTO library (filepath, title, album, artist, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
insert_data,
)
return True return True

View File

@ -11,11 +11,8 @@ def get_id3_tags(file):
""" """
try: try:
audio = EasyID3(file) audio = EasyID3(file)
print(f'ID3 Tags: {audio}')
return audio return audio
except Exception as e: except Exception as e:
print(f"Error: {e}") print(f"Error: {e}")
return {} return {}
filepath = '/home/billy/Music/songs/meanings/blah99/H.mp3'
id3_tags = get_id3_tags(filepath)
print(id3_tags)

3
utils/safe_get.py Normal file
View File

@ -0,0 +1,3 @@
# Define a function to safely access dictionary keys
def safe_get(dictionary, key, default=None):
return dictionary.get(key, default)

View File

@ -2,14 +2,15 @@ import os
import DBA import DBA
from configparser import ConfigParser from configparser import ConfigParser
from utils import get_id3_tags from utils import get_id3_tags
from utils import safe_get
config = ConfigParser() config = ConfigParser()
config.read('config.ini') config.read("config.ini")
def scan_for_music(): def scan_for_music():
root_dir = config.get('directories', 'library') root_dir = config.get("directories", "library")
extensions = config.get('settings', 'extensions').split(',') extensions = config.get("settings", "extensions").split(",")
insert_data = [] # To store data for batch insert insert_data = [] # To store data for batch insert
for dirpath, dirnames, filenames in os.walk(root_dir): for dirpath, dirnames, filenames in os.walk(root_dir):
@ -17,29 +18,39 @@ def scan_for_music():
if any(filename.lower().endswith(ext) for ext in extensions): if any(filename.lower().endswith(ext) for ext in extensions):
filepath = os.path.join(dirpath, filename) filepath = os.path.join(dirpath, filename)
audio = get_id3_tags(filepath) audio = get_id3_tags(filepath)
if "title" not in audio:
return
# Append data tuple to insert_data list # Append data tuple to insert_data list
insert_data.append(( insert_data.append(
filepath, (
audio.title, filepath,
audio.album, safe_get(audio, "title", [])[0],
audio.artist, safe_get(audio, "album", [])[0] if "album" in audio else None,
audio.genre, safe_get(audio, "artist", [])[0] if "artist" in audio else None,
filename.split('.')[-1], ",".join(safe_get(audio, "genre", [])) if "genre" in audio else None,
audio.year, filename.split(".")[-1],
audio.bitrate safe_get(audio, "date", [])[0] if "date" in audio else None,
)) safe_get(audio, "bitrate", [])[0] if "birate" in audio else None,
)
)
# Check if batch size is reached # Check if batch size is reached
if len(insert_data) >= 1000: if len(insert_data) >= 1000:
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.executemany('INSERT OR IGNORE INTO library (filepath, title, album, artist, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', insert_data) db.executemany(
"INSERT OR IGNORE INTO library (filepath, title, album, artist, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
insert_data,
)
insert_data = [] # Reset the insert_data list insert_data = [] # Reset the insert_data list
# Insert any remaining data # Insert any remaining data
if insert_data: if insert_data:
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
db.executemany('INSERT OR IGNORE INTO library (filepath, title, album, artist, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', insert_data) db.executemany(
"INSERT OR IGNORE INTO library (filepath, title, album, artist, genre, codec, album_date, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
insert_data,
)
# id int unsigned auto_increment, # id int unsigned auto_increment,