scan files thread

This commit is contained in:
billypom on debian 2025-07-20 20:45:57 -04:00
parent be9f17a89d
commit 5adb760d83
8 changed files with 44 additions and 45 deletions

2
DBA.py
View File

@ -15,7 +15,7 @@ class DBAccess:
) )
config.read(cfg_file) config.read(cfg_file)
if db_name is None: if db_name is None:
db_name = config.get("db", "database") db_name = config.get("settings", "db")
self._conn: sqlite3.Connection = sqlite3.connect(db_name) self._conn: sqlite3.Connection = sqlite3.connect(db_name)
self._cursor: sqlite3.Cursor = self._conn.cursor() self._cursor: sqlite3.Cursor = self._conn.cursor()

View File

@ -84,3 +84,4 @@ QMultimedia.EncodingMode / Encoding quality...
- edit metadata, get metadata in another thread (freezing) - edit metadata, get metadata in another thread (freezing)
- on save metadata modal, run save in another thread (freezing) - on save metadata modal, run save in another thread (freezing)
- on save metadata modal, return to previous state in table (jump to current song/restore scroll position) - on save metadata modal, return to previous state in table (jump to current song/restore scroll position)
- on add to playlist, check if song already exists - prompt user for duplicate?

View File

@ -27,10 +27,9 @@ class ExportPlaylistWindow(QDialog):
self.setMinimumSize(600, 400) self.setMinimumSize(600, 400)
self.load_config() self.load_config()
self.relative_path: str = self.config.get( self.relative_path: str = self.config.get(
"directories", "playlist_relative_path" "settings", "playlist_content_relative_path"
) )
self.current_relative_path: str = self.relative_path self.export_path: str = self.config.get("settings", "playlist_export_path")
self.export_path: str = self.config.get("directories", "playlist_export_path")
self.selected_playlist_name: str = "my-playlist.m3u" self.selected_playlist_name: str = "my-playlist.m3u"
self.chosen_list_widget_item: QListWidgetItem | None = None self.chosen_list_widget_item: QListWidgetItem | None = None
layout = self.setup_ui() layout = self.setup_ui()
@ -85,8 +84,8 @@ class ExportPlaylistWindow(QDialog):
layout.addWidget(label) layout.addWidget(label)
# Playlist file save path line edit widget # Playlist file save path line edit widget
self.input_m3u_path = QLineEdit(self.export_path) # not needed self.export_m3u_path = QLineEdit(self.config.get("settings", "playlist_export_path"))
layout.addWidget(self.input_m3u_path) layout.addWidget(self.export_m3u_path)
# Save button # Save button
self.save_button = QPushButton("Export") self.save_button = QPushButton("Export")
@ -122,12 +121,14 @@ class ExportPlaylistWindow(QDialog):
# Create the filename for the playlist to be exported # Create the filename for the playlist to be exported
self.selected_playlist_name = self.chosen_list_widget_item.text() + ".m3u" self.selected_playlist_name = self.chosen_list_widget_item.text() + ".m3u"
# get the db id? i guess?
# get the db id
self.selected_playlist_db_id = self.item_dict[ self.selected_playlist_db_id = self.item_dict[
self.chosen_list_widget_item.text() self.chosen_list_widget_item.text()
] ]
# alter line edit text for playlist path # alter line edit text for playlist path
# Make the thing react and show the correct thing or whatever
current_text: list = self.input_m3u_path.text().split("/") current_text: list = self.input_m3u_path.text().split("/")
if "." in current_text[-1]: if "." in current_text[-1]:
current_text = current_text[:-1] current_text = current_text[:-1]
@ -179,13 +180,13 @@ class ExportPlaylistWindow(QDialog):
for song in db_paths: for song in db_paths:
artist, album = get_reorganize_vars(song) artist, album = get_reorganize_vars(song)
write_path = os.path.join( write_path = os.path.join(
relative_path, artist, album, song.split("/")[-1], "\n" relative_path, artist, album, song.split("/")[-1] + "\n"
) )
write_paths.append(str(write_path)) write_paths.append(str(write_path))
else: else:
# Normal paths # Normal paths
for song in db_paths: for song in db_paths:
write_paths.append(song) write_paths.append(song + "\n")
# Write playlist file TODO: add threading # Write playlist file TODO: add threading
os.makedirs(os.path.dirname(output_filename), exist_ok=True) os.makedirs(os.path.dirname(output_filename), exist_ok=True)

View File

@ -783,8 +783,8 @@ class MusicTable(QTableView):
self.current_song_qmodel_index = real_index self.current_song_qmodel_index = real_index
self.model2.layoutChanged.emit() # emits a signal that the view should be updated self.model2.layoutChanged.emit() # emits a signal that the view should be updated
db_name: str = self.config.get("db", "database").split("/").pop() db_name: str = self.config.get("settings", "db").split("/").pop()
db_filename = self.config.get("db", "database") db_filename = self.config.get("settings", "db")
self.playlistStatsSignal.emit( self.playlistStatsSignal.emit(
f"Songs: {row_count} | Total time: {total_time} | {db_name} | {db_filename}" f"Songs: {row_count} | Total time: {total_time} | {db_name} | {db_filename}"
) )

10
main.py
View File

@ -662,8 +662,10 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
Scans for new files in the configured library folder Scans for new files in the configured library folder
then, refreshes the datagridview then, refreshes the datagridview
""" """
scan_for_music() worker = Worker(scan_for_music)
self.tableView.load_music_table() worker.signals.signal_finished.connect(self.tableView.load_music_table)
worker.signals.signal_progress.connect(self.handle_progress)
self.threadpool.start(worker)
def delete_database(self) -> None: def delete_database(self) -> None:
"""Deletes the entire database""" """Deletes the entire database"""
@ -689,7 +691,7 @@ def update_database_file() -> bool:
cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom"))) cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom")))
config = ConfigParser() config = ConfigParser()
config.read(cfg_file) config.read(cfg_file)
db_filepath: str = config.get("db", "database") db_filepath: str = config.get("settings", "db")
# If the database location isnt set at the config location, move it # If the database location isnt set at the config location, move it
if not db_filepath.startswith(cfg_path): if not db_filepath.startswith(cfg_path):
@ -702,7 +704,7 @@ def update_database_file() -> bool:
with open(cfg_file, "w") as configfile: with open(cfg_file, "w") as configfile:
config.write(configfile) config.write(configfile)
config.read(cfg_file) config.read(cfg_file)
db_filepath: str = config.get("db", "database") db_filepath: str = config.get("settings", "db")
db_path = db_filepath.split("/") db_path = db_filepath.split("/")
db_path.pop() db_path.pop()

View File

@ -1,17 +1,10 @@
[db] [settings]
# The library database file db = library.db
database = db/library.db
[directories]
# Useful paths to have stored
library = /path/to/music library = /path/to/music
reorganize_destination = /where/to/reorganize/to reorganize_destination = /where/to/reorganize/to
playlist_auto_export_enabled = 0 playlist_auto_export_enabled = 0
playlist_export_path = /where/to/export/to playlist_export_path = /where/to/export/to
playlist_relative_path = /relative/prefix playlist_relative_path = /relative/prefix
[settings]
# Which file types are scanned
extensions = mp3,wav,ogg,flac extensions = mp3,wav,ogg,flac
volume = 100 volume = 100
window_size=1152,894 window_size=1152,894

View File

@ -31,10 +31,8 @@ def add_files_to_database(files, progress_callback=None):
failed_dict = {} failed_dict = {}
insert_data = [] # To store data for batch insert insert_data = [] # To store data for batch insert
for filepath in files: for filepath in files:
try: if progress_callback:
progress_callback.emit(filepath) progress_callback.emit(filepath)
except Exception:
pass
filename = filepath.split("/")[-1] filename = filepath.split("/")[-1]
tags, details = get_tags(filepath) tags, details = get_tags(filepath)

View File

@ -1,29 +1,33 @@
import os import os
from PyQt5.QtCore import pyqtSignal
from utils.add_files_to_database import add_files_to_database from utils.add_files_to_database import add_files_to_database
from configparser import ConfigParser from configparser import ConfigParser
from pathlib import Path from pathlib import Path
from appdirs import user_config_dir from appdirs import user_config_dir
import glob
from concurrent.futures import ThreadPoolExecutor
def scan_for_music():
def scan_for_music(progress_callback=None):
""" """
Scans the user-defined library directory (defined in config file) Scans for audio files in user-defined paths
Looks for audio files with specific extensions (defined in config file) - Paths are defined in config file
Adds found files to the database/primary library (songs table - which holds all songs :o) - Accepted file extensions are defined in config file
- Adds found file to database
""" """
if progress_callback:
progress_callback.emit('Scanning libraries...')
config = ConfigParser() config = ConfigParser()
cfg_file = ( config.read(Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini")
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini" libraries = [path.strip() for path in config.get("settings", "library_path").split(',')]
)
config.read(cfg_file)
root_dir = config.get("directories", "library")
extensions = config.get("settings", "extensions").split(",") extensions = config.get("settings", "extensions").split(",")
# Use each library as root dir, walk the dir and find files
for library in libraries:
files_to_add = [] files_to_add = []
# for dirpath, dirnames, filenames ... for dirpath, _, filenames in os.walk(library):
for dirpath, _, filenames in os.walk(root_dir):
for file in filenames: for file in filenames:
filename = os.path.join(dirpath, file) filename = os.path.join(dirpath, file)
if any(filename.lower().endswith(ext) for ext in extensions): if any(filename.lower().endswith(ext) for ext in extensions):
files_to_add.append(filename) files_to_add.append(filename)
add_files_to_database(files_to_add) add_files_to_database(files_to_add, progress_callback)