batch delete files from table and db
This commit is contained in:
parent
00d1c01e9f
commit
705407f3a3
@ -33,6 +33,9 @@ from components.AddToPlaylistWindow import AddToPlaylistWindow
|
||||
from components.MetadataWindow import MetadataWindow
|
||||
|
||||
from main import Worker
|
||||
from utils.batch_delete_filepaths_from_database import (
|
||||
batch_delete_filepaths_from_database,
|
||||
)
|
||||
from utils.delete_song_id_from_database import delete_song_id_from_database
|
||||
from utils.add_files_to_library import add_files_to_library
|
||||
from utils.get_reorganize_vars import get_reorganize_vars
|
||||
@ -163,32 +166,31 @@ class MusicTable(QTableView):
|
||||
QMessageBox.Yes,
|
||||
)
|
||||
if reply:
|
||||
try:
|
||||
self.model.dataChanged.disconnect(self.on_cell_data_changed)
|
||||
except Exception:
|
||||
pass
|
||||
selected_filepaths = self.get_selected_songs_filepaths()
|
||||
selected_indices = self.get_selected_rows()
|
||||
# FIXME: this should be batch delete with a worker thread
|
||||
# probably pass selected_filepaths to a worker thread
|
||||
worker = Worker(batch_delete_filepaths_from_database, selected_filepaths)
|
||||
worker.signals.signal_progress.connect(self.qapp.handle_progress)
|
||||
worker.signals.signal_finished.connect(self.remove_selected_row_indices)
|
||||
worker.signals.signal_finished.connect(self.load_music_table)
|
||||
if self.qapp:
|
||||
threadpool = self.qapp.threadpool
|
||||
threadpool.start(worker)
|
||||
|
||||
for file in selected_filepaths:
|
||||
with DBA.DBAccess() as db:
|
||||
song_id = db.query(
|
||||
"SELECT id FROM song WHERE filepath = ?", (file,)
|
||||
)[0][0]
|
||||
delete_song_id_from_database(song_id)
|
||||
# This part cannot be thread...i think? bcus its Q stuff happening
|
||||
for index in selected_indices:
|
||||
try:
|
||||
self.model.removeRow(index)
|
||||
except Exception as e:
|
||||
logging.info(f" delete_songs() failed | {e}")
|
||||
def remove_selected_row_indices(self):
|
||||
"""Removes rows from the QTableView based on a list of indices"""
|
||||
selected_indices = self.get_selected_rows()
|
||||
try:
|
||||
self.model.dataChanged.disconnect(self.on_cell_data_changed)
|
||||
except Exception:
|
||||
pass
|
||||
for index in selected_indices:
|
||||
try:
|
||||
self.model.dataChanged.connect(self.on_cell_data_changed)
|
||||
except Exception:
|
||||
pass
|
||||
self.load_music_table()
|
||||
self.model.removeRow(index)
|
||||
except Exception as e:
|
||||
logging.info(f" delete_songs() failed | {e}")
|
||||
try:
|
||||
self.model.dataChanged.connect(self.on_cell_data_changed)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def open_directory(self):
|
||||
"""Opens the currently selected song in the system file manager"""
|
||||
@ -358,7 +360,7 @@ class MusicTable(QTableView):
|
||||
worker.signals.signal_progress.connect(self.qapp.handle_progress)
|
||||
self.qapp.threadpool.start(worker)
|
||||
|
||||
def reorganize_selected_files(self, progress_callback):
|
||||
def reorganize_selected_files(self, progress_callback=None):
|
||||
"""Ctrl+Shift+R = Reorganize"""
|
||||
filepaths = self.get_selected_songs_filepaths()
|
||||
# Confirmation screen (yes, no)
|
||||
@ -376,7 +378,8 @@ class MusicTable(QTableView):
|
||||
if str(filepath).startswith((target_dir)):
|
||||
continue
|
||||
try:
|
||||
progress_callback.emit(filepath)
|
||||
if progress_callback:
|
||||
progress_callback.emit(f"Organizing: {filepath}")
|
||||
# Read file metadata
|
||||
artist, album = get_reorganize_vars(filepath)
|
||||
# Determine the new path that needs to be made
|
||||
|
||||
10
main.py
10
main.py
@ -61,11 +61,11 @@ from components import (
|
||||
|
||||
class WorkerSignals(QObject):
|
||||
"""
|
||||
How to use signals for a QRunnable class; unlike most cases where signals
|
||||
are defined as class attributes directly in the class, here we define a
|
||||
class that inherits from QObject and define the signals as class
|
||||
attributes in that class. Then we can instantiate that class and use it
|
||||
as a signal object.
|
||||
How to use signals for a QRunnable class;
|
||||
Unlike most cases where signals are defined as class attributes directly in the class,
|
||||
here we define a class that inherits from QObject
|
||||
and define the signals as class attributes in that class.
|
||||
Then we can instantiate that class and use it as a signal object.
|
||||
"""
|
||||
|
||||
# 1)
|
||||
|
||||
@ -7,6 +7,7 @@ from .get_id3_tags import get_id3_tags
|
||||
from .get_reorganize_vars import get_reorganize_vars
|
||||
from .set_id3_tag import set_id3_tag
|
||||
from .delete_song_id_from_database import delete_song_id_from_database
|
||||
from .batch_delete_filepaths_from_database import batch_delete_filepaths_from_database
|
||||
from .delete_and_create_library_database import delete_and_create_library_database
|
||||
from .update_song_in_database import update_song_in_database
|
||||
from .scan_for_music import scan_for_music
|
||||
|
||||
50
utils/batch_delete_filepaths_from_database.py
Normal file
50
utils/batch_delete_filepaths_from_database.py
Normal file
@ -0,0 +1,50 @@
|
||||
import DBA
|
||||
from components.ErrorDialog import ErrorDialog
|
||||
|
||||
|
||||
def batch_delete_filepaths_from_database(
|
||||
files: list[str], chunk_size=1000, progress_callback=None
|
||||
) -> bool:
|
||||
"""
|
||||
Handles deleting many songs from the database by filepath
|
||||
Accounts for playlists and other song-linked tables
|
||||
|
||||
Returns True on success
|
||||
False on failure/error
|
||||
"""
|
||||
# Get song IDs from filepaths
|
||||
try:
|
||||
with DBA.DBAccess() as db:
|
||||
placeholders = ", ".join("?" for _ in files)
|
||||
query = f"SELECT id FROM song WHERE filepath in ({placeholders});"
|
||||
result = db.query(query, files)
|
||||
song_ids = [item[0] for item in result]
|
||||
except Exception as e:
|
||||
dialog = ErrorDialog(
|
||||
f"batch_delete_filepaths_from_database.py | An error occurred during retrieval of song_ids: {e}"
|
||||
)
|
||||
dialog.exec_()
|
||||
return False
|
||||
try:
|
||||
with DBA.DBAccess() as db:
|
||||
# Batch delete in chunks
|
||||
for i in range(0, len(song_ids), chunk_size):
|
||||
chunk = song_ids[i : i + chunk_size]
|
||||
placeholders = ", ".join("?" for _ in chunk)
|
||||
|
||||
# Delete from playlists
|
||||
query = f"DELETE FROM song_playlist WHERE song_id IN ({placeholders});"
|
||||
db.execute(query, chunk)
|
||||
|
||||
# Delete from library
|
||||
query = f"DELETE FROM song WHERE id in ({placeholders});"
|
||||
db.execute(query, chunk)
|
||||
if progress_callback:
|
||||
progress_callback.emit(f"Deleting songs: {i}")
|
||||
except Exception as e:
|
||||
dialog = ErrorDialog(
|
||||
f"batch_delete_filepaths_from_database.py | An error occurred during batch processing: {e}"
|
||||
)
|
||||
dialog.exec_()
|
||||
return False
|
||||
return True
|
||||
Loading…
x
Reference in New Issue
Block a user