dashboard cancel button

pull/8/head
Broque Thomas 6 months ago
parent 5e4552f46d
commit 502b0ba01d

@ -296,6 +296,7 @@ class DownloadMissingWishlistTracksModal(QDialog):
self.download_in_progress = False
self.cancel_requested = False
self.permanently_failed_tracks = []
self.cancelled_tracks = set() # Track indices of cancelled tracks
self.analysis_results = []
self.missing_tracks = []
self.active_workers = []
@ -481,19 +482,22 @@ class DownloadMissingWishlistTracksModal(QDialog):
layout.setContentsMargins(15, 15, 15, 15)
self.track_table = QTableWidget()
# Change column count from 5 to 4
self.track_table.setColumnCount(4)
# Remove "Duration" from the labels
self.track_table.setHorizontalHeaderLabels(["Track", "Artist", "Matched", "Status"])
# Change column count from 4 to 5 for Cancel column
self.track_table.setColumnCount(5)
# Add "Cancel" column (no Duration column)
self.track_table.setHorizontalHeaderLabels(["Track", "Artist", "Matched", "Status", "Cancel"])
# Adjust resize modes for new column indices
# Adjust resize modes for column indices
self.track_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.track_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Interactive) # "Matched" is now column 2
self.track_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Interactive) # "Matched" is column 2
self.track_table.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.Fixed) # "Cancel" is column 4
self.track_table.setColumnWidth(2, 140) # Set width for "Matched" column
self.track_table.setColumnWidth(4, 70) # Set width for "Cancel" column
self.track_table.setStyleSheet("QTableWidget { background-color: #3a3a3a; alternate-background-color: #424242; selection-background-color: #1db954; gridline-color: #555; color: #fff; border: 1px solid #555; font-size: 12px; } QHeaderView::section { background-color: #1db954; color: #000; font-weight: bold; font-size: 13px; padding: 12px 8px; border: none; } QTableWidget::item { padding: 12px 8px; border-bottom: 1px solid #4a4a4a; }")
self.track_table.setAlternatingRowColors(True)
self.track_table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.track_table.verticalHeader().setDefaultSectionSize(50)
self.track_table.verticalHeader().setVisible(False)
layout.addWidget(self.track_table)
@ -519,7 +523,16 @@ class DownloadMissingWishlistTracksModal(QDialog):
status_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.track_table.setItem(i, 3, status_item)
# Loop over 4 columns instead of 5
# Create empty container for cancel button (will be populated later for missing tracks only)
container = QWidget()
container.setStyleSheet("background: transparent;")
layout = QVBoxLayout(container)
layout.setContentsMargins(5, 5, 5, 5)
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.track_table.setCellWidget(i, 4, container)
# Loop over 4 columns instead of 5 (don't include cancel column)
for col in range(4):
item = self.track_table.item(i, col)
if item:
@ -529,6 +542,107 @@ class DownloadMissingWishlistTracksModal(QDialog):
if not duration_ms: return "0:00"
seconds = duration_ms // 1000
return f"{seconds // 60}:{seconds % 60:02d}"
def add_cancel_button_to_row(self, row):
"""Add cancel button to a specific row (only for missing tracks)"""
container = self.track_table.cellWidget(row, 4)
if container and container.layout().count() == 0: # Only add if container is empty
cancel_button = QPushButton("×")
cancel_button.setFixedSize(20, 20)
cancel_button.setMinimumSize(20, 20)
cancel_button.setMaximumSize(20, 20)
cancel_button.setStyleSheet("""
QPushButton {
background-color: #dc3545;
color: white;
border: 1px solid #c82333;
border-radius: 3px;
font-size: 14px;
font-weight: bold;
padding: 0px;
margin: 0px;
text-align: center;
min-width: 20px;
max-width: 20px;
width: 20px;
}
QPushButton:hover {
background-color: #c82333;
border-color: #bd2130;
}
QPushButton:pressed {
background-color: #bd2130;
border-color: #b21f2d;
}
QPushButton:disabled {
background-color: #28a745;
color: white;
border-color: #1e7e34;
}
""")
cancel_button.setFocusPolicy(Qt.FocusPolicy.NoFocus)
cancel_button.clicked.connect(lambda checked, row_idx=row: self.cancel_track(row_idx))
layout = container.layout()
layout.addWidget(cancel_button)
def hide_cancel_button_for_row(self, row):
"""Hide cancel button for a specific row (when track is downloaded)"""
container = self.track_table.cellWidget(row, 4)
if container:
layout = container.layout()
if layout and layout.count() > 0:
cancel_button = layout.itemAt(0).widget()
if cancel_button:
cancel_button.setVisible(False)
print(f"🫥 Hidden cancel button for downloaded track at row {row}")
def cancel_track(self, row):
"""Cancel a specific track - works at any phase"""
# Get cancel button and disable it
container = self.track_table.cellWidget(row, 4)
if container:
layout = container.layout()
if layout and layout.count() > 0:
cancel_button = layout.itemAt(0).widget()
if cancel_button:
cancel_button.setEnabled(False)
cancel_button.setText("")
# Update status to cancelled (column 3 for dashboard)
self.track_table.setItem(row, 3, QTableWidgetItem("🚫 Cancelled"))
# Add to cancelled tracks set
if not hasattr(self, 'cancelled_tracks'):
self.cancelled_tracks = set()
self.cancelled_tracks.add(row)
track = self.wishlist_tracks[row]
print(f"🚫 Track cancelled: {track.name} (row {row})")
# If downloads are active, also handle active download cancellation
download_index = None
# Check active_downloads list
if hasattr(self, 'active_downloads'):
for download in self.active_downloads:
if download.get('table_index') == row:
download_index = download.get('download_index', row)
print(f"🚫 Found active download {download_index} for cancelled track")
break
# Check parallel_search_tracking for download index
if download_index is None and hasattr(self, 'parallel_search_tracking'):
for idx, track_info in self.parallel_search_tracking.items():
if track_info.get('table_index') == row:
download_index = idx
print(f"🚫 Found parallel tracking {download_index} for cancelled track")
break
# If we found an active download, trigger completion to free up the worker
if download_index is not None and hasattr(self, 'on_parallel_track_completed'):
print(f"🚫 Triggering completion for active download {download_index}")
self.on_parallel_track_completed(download_index, success=False)
def create_buttons(self):
button_frame = QFrame(styleSheet="background-color: transparent; padding: 10px;")
@ -617,6 +731,7 @@ class DownloadMissingWishlistTracksModal(QDialog):
def on_track_analyzed(self, track_index, result):
self.analysis_progress.setValue(track_index)
row_index = track_index - 1
if result.exists_in_plex:
matched_text = f"✅ Found ({result.confidence:.1f})"
self.matched_tracks_count += 1
@ -633,7 +748,9 @@ class DownloadMissingWishlistTracksModal(QDialog):
matched_text = "❌ Missing"
self.tracks_to_download_count += 1
self.download_count_label.setText(str(self.tracks_to_download_count))
self.track_table.setItem(track_index - 1, 2, QTableWidgetItem(matched_text))
# Add cancel button for missing tracks only
self.add_cancel_button_to_row(row_index)
self.track_table.setItem(row_index, 2, QTableWidgetItem(matched_text))
def on_analysis_completed(self, results):
@ -677,6 +794,13 @@ class DownloadMissingWishlistTracksModal(QDialog):
track = track_result.spotify_track
track_index = self.find_track_index_in_playlist(track)
if track_index != -1:
# Skip if track was cancelled
if hasattr(self, 'cancelled_tracks') and track_index in self.cancelled_tracks:
print(f"🚫 Skipping cancelled track at index {track_index}: {track.name}")
self.download_queue_index += 1
self.completed_downloads += 1
continue
# FIX: Changed column index from 4 to 3 to target the "Status" column.
self.track_table.setItem(track_index, 3, QTableWidgetItem("🔍 Searching..."))
self.search_and_download_track_parallel(track, self.download_queue_index, track_index)
@ -852,11 +976,16 @@ class DownloadMissingWishlistTracksModal(QDialog):
self.start_validated_download_parallel(next_candidate, track_info['spotify_track'], track_info['track_index'], track_info['table_index'], download_index)
def on_parallel_track_completed(self, download_index, success):
if not hasattr(self, 'parallel_search_tracking'):
print(f"⚠️ parallel_search_tracking not initialized yet, skipping completion for download {download_index}")
return
track_info = self.parallel_search_tracking.get(download_index)
if not track_info or track_info.get('completed', False): return
track_info['completed'] = True
if success:
self.track_table.setItem(track_info['table_index'], 3, QTableWidgetItem("✅ Downloaded"))
# Hide cancel button since track is now downloaded
self.hide_cancel_button_for_row(track_info['table_index'])
self.downloaded_tracks_count += 1
self.downloaded_count_label.setText(str(self.downloaded_tracks_count))
self.successful_downloads += 1
@ -866,10 +995,16 @@ class DownloadMissingWishlistTracksModal(QDialog):
logger.info(f"Successfully downloaded and removed '{track_info['spotify_track'].name}' from wishlist.")
else:
self.track_table.setItem(track_info['table_index'], 3, QTableWidgetItem("❌ Failed"))
# Check if track was cancelled (don't overwrite cancelled status)
table_index = track_info['table_index']
current_status = self.track_table.item(table_index, 3)
if current_status and "🚫 Cancelled" in current_status.text():
print(f"🔧 Track {download_index} was cancelled - preserving cancelled status")
else:
self.track_table.setItem(table_index, 3, QTableWidgetItem("❌ Failed"))
if track_info not in self.permanently_failed_tracks:
self.permanently_failed_tracks.append(track_info)
self.failed_downloads += 1
if track_info not in self.permanently_failed_tracks:
self.permanently_failed_tracks.append(track_info)
self.update_failed_matches_button()
self.completed_downloads += 1
self.active_parallel_downloads -= 1
@ -911,6 +1046,44 @@ class DownloadMissingWishlistTracksModal(QDialog):
if self.successful_downloads > 0 and hasattr(self.parent_dashboard, 'scan_manager') and self.parent_dashboard.scan_manager:
self.parent_dashboard.scan_manager.request_scan(f"Wishlist download completed ({self.successful_downloads} tracks)")
# Add cancelled tracks that were missing from Plex to permanently_failed_tracks for wishlist re-addition
if hasattr(self, 'cancelled_tracks') and hasattr(self, 'missing_tracks'):
for cancelled_row in self.cancelled_tracks:
# Check if this cancelled track was actually missing from Plex
cancelled_track = self.wishlist_tracks[cancelled_row]
missing_track_result = None
# Find the corresponding missing track result
for missing_result in self.missing_tracks:
if missing_result.spotify_track.id == cancelled_track.id:
missing_track_result = missing_result
break
# Only add to wishlist if track was actually missing from Plex AND not successfully downloaded
if missing_track_result:
# Check if track was successfully downloaded (don't re-add downloaded tracks to wishlist)
status_item = self.track_table.item(cancelled_row, 3)
current_status = status_item.text() if status_item else ""
if "✅ Downloaded" in current_status:
print(f"🚫 Cancelled track {cancelled_track.name} was already downloaded, skipping wishlist re-addition")
else:
cancelled_track_info = {
'download_index': cancelled_row,
'table_index': cancelled_row,
'track': cancelled_track,
'track_name': cancelled_track.name,
'artist_name': cancelled_track.artists[0] if cancelled_track.artists else "Unknown",
'retry_count': 0,
'spotify_track': missing_track_result.spotify_track # Include the spotify track for wishlist
}
# Check if not already in permanently_failed_tracks
if not any(t.get('table_index') == cancelled_row for t in self.permanently_failed_tracks):
self.permanently_failed_tracks.append(cancelled_track_info)
print(f"🚫 Added cancelled missing track {cancelled_track.name} to failed list for wishlist re-addition")
else:
print(f"🚫 Cancelled track {cancelled_track.name} was not missing from Plex, skipping wishlist re-addition")
wishlist_added_count = 0
if self.permanently_failed_tracks:
source_context = {'added_from': 'wishlist_modal', 'timestamp': datetime.now().isoformat()}

Loading…
Cancel
Save