added remove all item from queue
This commit is contained in:
parent
4dba4db344
commit
18faf3fe91
File diff suppressed because it is too large
Load Diff
@ -232,6 +232,40 @@ async def clear_failed(
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/pending", status_code=status.HTTP_200_OK)
|
||||
async def clear_pending(
|
||||
_: dict = Depends(require_auth),
|
||||
download_service: DownloadService = Depends(get_download_service),
|
||||
):
|
||||
"""Clear all pending downloads from the queue.
|
||||
|
||||
Removes all pending download items from the queue. This is useful for
|
||||
clearing the entire queue at once instead of removing items one by one.
|
||||
|
||||
Requires authentication.
|
||||
|
||||
Returns:
|
||||
dict: Status message with count of cleared items
|
||||
|
||||
Raises:
|
||||
HTTPException: 401 if not authenticated, 500 on service error
|
||||
"""
|
||||
try:
|
||||
cleared_count = await download_service.clear_pending()
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"message": f"Removed {cleared_count} pending item(s)",
|
||||
"count": cleared_count,
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to clear pending items: {str(e)}",
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def remove_from_queue(
|
||||
item_id: str = Path(..., description="Download item ID to remove"),
|
||||
|
||||
@ -27,9 +27,9 @@ class DownloadStatus(str, Enum):
|
||||
class DownloadPriority(str, Enum):
|
||||
"""Priority level for download queue items."""
|
||||
|
||||
LOW = "low"
|
||||
NORMAL = "normal"
|
||||
HIGH = "high"
|
||||
LOW = "LOW"
|
||||
NORMAL = "NORMAL"
|
||||
HIGH = "HIGH"
|
||||
|
||||
|
||||
class EpisodeIdentifier(BaseModel):
|
||||
@ -175,9 +175,9 @@ class DownloadRequest(BaseModel):
|
||||
@field_validator('priority', mode='before')
|
||||
@classmethod
|
||||
def normalize_priority(cls, v):
|
||||
"""Normalize priority to lowercase for case-insensitive matching."""
|
||||
"""Normalize priority to uppercase for case-insensitive matching."""
|
||||
if isinstance(v, str):
|
||||
return v.lower()
|
||||
return v.upper()
|
||||
return v
|
||||
|
||||
|
||||
|
||||
@ -600,6 +600,34 @@ class DownloadService:
|
||||
|
||||
return count
|
||||
|
||||
async def clear_pending(self) -> int:
|
||||
"""Clear all pending downloads from the queue.
|
||||
|
||||
Returns:
|
||||
Number of items cleared
|
||||
"""
|
||||
count = len(self._pending_queue)
|
||||
self._pending_queue.clear()
|
||||
self._pending_items_by_id.clear()
|
||||
logger.info("Cleared pending items", count=count)
|
||||
|
||||
# Save queue state
|
||||
self._save_queue()
|
||||
|
||||
# Broadcast queue status update
|
||||
if count > 0:
|
||||
queue_status = await self.get_queue_status()
|
||||
await self._broadcast_update(
|
||||
"queue_status",
|
||||
{
|
||||
"action": "pending_cleared",
|
||||
"cleared_count": count,
|
||||
"queue_status": queue_status.model_dump(mode="json"),
|
||||
},
|
||||
)
|
||||
|
||||
return count
|
||||
|
||||
async def retry_failed(
|
||||
self, item_ids: Optional[List[str]] = None
|
||||
) -> List[str]:
|
||||
|
||||
@ -142,6 +142,10 @@ class QueueManager {
|
||||
this.clearQueue('failed');
|
||||
});
|
||||
|
||||
document.getElementById('clear-pending-btn').addEventListener('click', () => {
|
||||
this.clearQueue('pending');
|
||||
});
|
||||
|
||||
document.getElementById('retry-all-btn').addEventListener('click', () => {
|
||||
this.retryAllFailed();
|
||||
});
|
||||
@ -442,6 +446,14 @@ class QueueManager {
|
||||
const hasFailed = (data.failed_downloads || []).length > 0;
|
||||
const hasCompleted = (data.completed_downloads || []).length > 0;
|
||||
|
||||
console.log('Button states update:', {
|
||||
hasPending,
|
||||
pendingCount: (data.pending_queue || []).length,
|
||||
hasActive,
|
||||
hasFailed,
|
||||
hasCompleted
|
||||
});
|
||||
|
||||
// Enable start button only if there are pending items and no active downloads
|
||||
document.getElementById('start-queue-btn').disabled = !hasPending || hasActive;
|
||||
|
||||
@ -458,17 +470,28 @@ class QueueManager {
|
||||
document.getElementById('retry-all-btn').disabled = !hasFailed;
|
||||
document.getElementById('clear-completed-btn').disabled = !hasCompleted;
|
||||
document.getElementById('clear-failed-btn').disabled = !hasFailed;
|
||||
|
||||
// Update clear pending button if it exists
|
||||
const clearPendingBtn = document.getElementById('clear-pending-btn');
|
||||
if (clearPendingBtn) {
|
||||
clearPendingBtn.disabled = !hasPending;
|
||||
console.log('Clear pending button updated:', { disabled: !hasPending, hasPending });
|
||||
} else {
|
||||
console.error('Clear pending button not found in DOM');
|
||||
}
|
||||
}
|
||||
|
||||
async clearQueue(type) {
|
||||
const titles = {
|
||||
completed: 'Clear Completed Downloads',
|
||||
failed: 'Clear Failed Downloads'
|
||||
failed: 'Clear Failed Downloads',
|
||||
pending: 'Remove All Pending Downloads'
|
||||
};
|
||||
|
||||
const messages = {
|
||||
completed: 'Are you sure you want to clear all completed downloads?',
|
||||
failed: 'Are you sure you want to clear all failed downloads?'
|
||||
failed: 'Are you sure you want to clear all failed downloads?',
|
||||
pending: 'Are you sure you want to remove all pending downloads from the queue?'
|
||||
};
|
||||
|
||||
const confirmed = await this.showConfirmModal(titles[type], messages[type]);
|
||||
@ -495,6 +518,16 @@ class QueueManager {
|
||||
|
||||
this.showToast(`Cleared ${data.count} failed downloads`, 'success');
|
||||
this.loadQueueData();
|
||||
} else if (type === 'pending') {
|
||||
const response = await this.makeAuthenticatedRequest('/api/queue/pending', {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (!response) return;
|
||||
const data = await response.json();
|
||||
|
||||
this.showToast(`Removed ${data.count} pending downloads`, 'success');
|
||||
this.loadQueueData();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
||||
@ -124,6 +124,10 @@
|
||||
Download Queue (<span id="queue-count">0</span>)
|
||||
</h2>
|
||||
<div class="section-actions">
|
||||
<button id="clear-pending-btn" class="btn btn-secondary" disabled>
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
Remove All
|
||||
</button>
|
||||
<button id="start-queue-btn" class="btn btn-primary" disabled>
|
||||
<i class="fas fa-play"></i>
|
||||
Start
|
||||
|
||||
@ -335,6 +335,22 @@ async def test_clear_completed(authenticated_client, mock_download_service):
|
||||
mock_download_service.clear_completed.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clear_pending(authenticated_client, mock_download_service):
|
||||
"""Test DELETE /api/queue/pending endpoint."""
|
||||
mock_download_service.clear_pending = AsyncMock(return_value=3)
|
||||
|
||||
response = await authenticated_client.delete("/api/queue/pending")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
assert data["status"] == "success"
|
||||
assert data["count"] == 3
|
||||
|
||||
mock_download_service.clear_pending.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_retry_failed(authenticated_client, mock_download_service):
|
||||
"""Test POST /api/queue/retry endpoint."""
|
||||
|
||||
@ -340,6 +340,37 @@ class TestQueueControl:
|
||||
assert count == 1
|
||||
assert len(download_service._completed_items) == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_clear_pending(self, download_service):
|
||||
"""Test clearing all pending downloads from the queue."""
|
||||
# Add multiple items to the queue
|
||||
await download_service.add_to_queue(
|
||||
serie_id="series-1",
|
||||
serie_folder="test-series-1",
|
||||
serie_name="Test Series 1",
|
||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||
)
|
||||
await download_service.add_to_queue(
|
||||
serie_id="series-2",
|
||||
serie_folder="test-series-2",
|
||||
serie_name="Test Series 2",
|
||||
episodes=[
|
||||
EpisodeIdentifier(season=1, episode=2),
|
||||
EpisodeIdentifier(season=1, episode=3),
|
||||
],
|
||||
)
|
||||
|
||||
# Verify items were added
|
||||
assert len(download_service._pending_queue) == 3
|
||||
|
||||
# Clear pending queue
|
||||
count = await download_service.clear_pending()
|
||||
|
||||
# Verify all pending items were cleared
|
||||
assert count == 3
|
||||
assert len(download_service._pending_queue) == 0
|
||||
assert len(download_service._pending_items_by_id) == 0
|
||||
|
||||
|
||||
class TestPersistence:
|
||||
"""Test queue persistence functionality."""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user