udpate add bulk update of TV eps
Local Docker Build (Dev) / build-dev (push) Successful in 5s

This commit is contained in:
2025-11-03 15:52:42 -05:00
parent 1e292434c0
commit 3e3957234d
4 changed files with 229 additions and 6 deletions
+1 -1
View File
@@ -711,6 +711,6 @@
<!-- Toast Notifications -->
<div class="toast-container" id="toast-container"></div>
<script src="/static/js/app.js?v=2.9.7-status-format-fix"></script>
<script src="/static/js/app.js?v=2.9.8-bulk-date-update"></script>
</body>
</html>
+154 -3
View File
@@ -509,10 +509,44 @@ function showEpisodesModal(data) {
<button id="bulk-select-all" class="btn btn-sm btn-secondary" onclick="toggleSelectAll()">
<i class="fas fa-check-square"></i> Select All
</button>
<button id="bulk-update-dates" class="btn btn-sm btn-primary" onclick="showBulkUpdateModal()" style="margin-left: 10px;" disabled>
<i class="fas fa-calendar"></i> Update Dates (<span id="update-count">0</span>)
</button>
<button id="bulk-delete-selected" class="btn btn-sm btn-danger" onclick="bulkDeleteSelected()" style="margin-left: 10px;" disabled>
<i class="fas fa-trash"></i> Delete Selected (<span id="selected-count">0</span>)
</button>
</div>
<!-- Bulk Update Dates Modal -->
<div id="bulk-update-modal" class="modal" style="display: none;">
<div class="modal-content" style="max-width: 500px;">
<div class="modal-header">
<h3>Bulk Update Episode Dates</h3>
<button class="close-button" onclick="closeBulkUpdateModal()">&times;</button>
</div>
<div class="modal-body">
<p>Update <strong><span id="modal-selected-count">0</span></strong> selected episode(s) to:</p>
<div class="form-group">
<label>Date Source:</label>
<select id="bulk-date-source" class="form-control">
<option value="airdate">Air Date (from Sonarr)</option>
<option value="import">Import Date (from Sonarr history)</option>
<option value="custom">Custom Date</option>
</select>
</div>
<div id="custom-date-input" style="display: none; margin-top: 10px;">
<label>Custom Date:</label>
<input type="datetime-local" id="bulk-custom-date" class="form-control">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" onclick="closeBulkUpdateModal()">Cancel</button>
<button class="btn btn-primary" onclick="executeBulkUpdate()">
<i class="fas fa-save"></i> Update Dates
</button>
</div>
</div>
</div>
<div class="table-container">
<table class="data-table sortable-table">
<thead>
@@ -1670,16 +1704,26 @@ function updateBulkDeleteButton() {
const selectedCheckboxes = document.querySelectorAll('.episode-checkbox:checked');
const selectedCount = selectedCheckboxes.length;
const bulkDeleteButton = document.getElementById('bulk-delete-selected');
const bulkUpdateButton = document.getElementById('bulk-update-dates');
const selectedCountSpan = document.getElementById('selected-count');
const updateCountSpan = document.getElementById('update-count');
if (selectedCountSpan) {
selectedCountSpan.textContent = selectedCount;
}
if (updateCountSpan) {
updateCountSpan.textContent = selectedCount;
}
if (bulkDeleteButton) {
bulkDeleteButton.disabled = selectedCount === 0;
}
if (bulkUpdateButton) {
bulkUpdateButton.disabled = selectedCount === 0;
}
// Update select all checkbox state
const selectAllCheckbox = document.getElementById('select-all-checkbox');
const allCheckboxes = document.querySelectorAll('.episode-checkbox');
@@ -1754,6 +1798,113 @@ async function bulkDeleteSelected() {
}
}
// Bulk update dates functions
function showBulkUpdateModal() {
const selectedCheckboxes = document.querySelectorAll('.episode-checkbox:checked');
const selectedCount = selectedCheckboxes.length;
if (selectedCount === 0) {
showToast('❌ No episodes selected', 'error');
return;
}
const modal = document.getElementById('bulk-update-modal');
const modalSelectedCount = document.getElementById('modal-selected-count');
const dateSourceSelect = document.getElementById('bulk-date-source');
const customDateInput = document.getElementById('custom-date-input');
if (modalSelectedCount) {
modalSelectedCount.textContent = selectedCount;
}
// Show/hide custom date input based on selection
if (dateSourceSelect) {
dateSourceSelect.onchange = function() {
if (customDateInput) {
customDateInput.style.display = this.value === 'custom' ? 'block' : 'none';
}
};
}
if (modal) {
modal.style.display = 'flex';
}
}
function closeBulkUpdateModal() {
const modal = document.getElementById('bulk-update-modal');
if (modal) {
modal.style.display = 'none';
}
}
async function executeBulkUpdate() {
const selectedCheckboxes = document.querySelectorAll('.episode-checkbox:checked');
const selectedCount = selectedCheckboxes.length;
const dateSource = document.getElementById('bulk-date-source').value;
const customDate = document.getElementById('bulk-custom-date').value;
if (selectedCount === 0) {
showToast('❌ No episodes selected', 'error');
return;
}
if (dateSource === 'custom' && !customDate) {
showToast('❌ Please enter a custom date', 'error');
return;
}
// Close modal
closeBulkUpdateModal();
// Collect selected episodes
const episodes = [];
selectedCheckboxes.forEach(checkbox => {
const row = checkbox.closest('tr');
episodes.push({
imdb_id: row.getAttribute('data-imdb'),
season: parseInt(row.getAttribute('data-season')),
episode: parseInt(row.getAttribute('data-episode'))
});
});
// Show progress
showToast(`⏳ Updating ${selectedCount} episode(s)...`, 'info');
try {
const response = await apiCall('/api/episodes/bulk-update-dates', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
episodes: episodes,
date_source: dateSource,
custom_date: customDate || null
})
});
if (response.success) {
showToast(`✅ Successfully updated ${response.updated || selectedCount} episode(s)`, 'success');
// Reload the current series to show updated dates
const currentImdbId = currentTVSeries;
if (currentImdbId) {
loadEpisodes(currentImdbId);
}
// Clear selections
selectedCheckboxes.forEach(checkbox => checkbox.checked = false);
updateBulkDeleteButton();
} else {
showToast(`${response.message || 'Failed to update episodes'}`, 'error');
}
} catch (error) {
console.error('Bulk update error:', error);
showToast('❌ Error updating episodes', 'error');
}
}
// ==================== Database Population Functions ====================
let populatePollingInterval = null;