web: update to interface
This commit is contained in:
@@ -51,6 +51,24 @@
|
|||||||
<main class="main-content">
|
<main class="main-content">
|
||||||
<!-- Dashboard Tab -->
|
<!-- Dashboard Tab -->
|
||||||
<div class="tab-content active" id="dashboard">
|
<div class="tab-content active" id="dashboard">
|
||||||
|
<!-- Scan Status Banner -->
|
||||||
|
<div class="scan-status-banner" id="dashboard-scan-status" style="display: none;">
|
||||||
|
<div class="scan-status-content">
|
||||||
|
<div class="scan-status-icon">
|
||||||
|
<i class="fas fa-sync fa-spin"></i>
|
||||||
|
</div>
|
||||||
|
<div class="scan-status-info">
|
||||||
|
<h4>Scan in Progress</h4>
|
||||||
|
<p id="dashboard-scan-text">Processing media files...</p>
|
||||||
|
<div class="scan-progress-mini">
|
||||||
|
<div class="progress-bar-mini">
|
||||||
|
<div class="progress-fill-mini" id="dashboard-scan-progress"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="dashboard-grid">
|
<div class="dashboard-grid">
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<div class="stat-icon movies">
|
<div class="stat-icon movies">
|
||||||
@@ -298,7 +316,70 @@
|
|||||||
<h2><i class="fas fa-tools"></i> Database Tools</h2>
|
<h2><i class="fas fa-tools"></i> Database Tools</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Scan Status Display -->
|
||||||
|
<div class="scan-status-card" id="scan-status" style="display: none;">
|
||||||
|
<div class="scan-status-header">
|
||||||
|
<h3><i class="fas fa-sync fa-spin"></i> Scan in Progress</h3>
|
||||||
|
<div class="scan-progress">
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill" id="scan-progress"></div>
|
||||||
|
</div>
|
||||||
|
<span class="progress-text" id="scan-progress-text">Initializing...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tools-grid">
|
<div class="tools-grid">
|
||||||
|
<!-- Manual Scan Tools -->
|
||||||
|
<div class="tool-card">
|
||||||
|
<h3><i class="fas fa-search"></i> Manual Scan</h3>
|
||||||
|
<p>Run manual scans on your media library</p>
|
||||||
|
<form id="manual-scan-form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Scan Type:</label>
|
||||||
|
<select id="scan-type" required>
|
||||||
|
<option value="both">Both (Movies & TV)</option>
|
||||||
|
<option value="movies">Movies Only</option>
|
||||||
|
<option value="tv">TV Series Only</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Scan Mode:</label>
|
||||||
|
<select id="scan-mode" required>
|
||||||
|
<option value="smart">Smart (Recommended)</option>
|
||||||
|
<option value="full">Full Scan</option>
|
||||||
|
<option value="incomplete">Incomplete Items Only</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn-primary">
|
||||||
|
<i class="fas fa-play"></i> Start Scan
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tool-card">
|
||||||
|
<h3><i class="fas fa-folder"></i> Custom Directory Scan</h3>
|
||||||
|
<p>Scan a specific directory or path</p>
|
||||||
|
<form id="custom-scan-form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Directory Path:</label>
|
||||||
|
<input type="text" id="scan-path" placeholder="/media/Movies/specific-folder" />
|
||||||
|
<small>Enter the full path to scan (will be auto-formatted)</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Scan Type:</label>
|
||||||
|
<select id="custom-scan-type" required>
|
||||||
|
<option value="both">Auto-detect</option>
|
||||||
|
<option value="movies">Movies</option>
|
||||||
|
<option value="tv">TV Series</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn-primary">
|
||||||
|
<i class="fas fa-search"></i> Scan Directory
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tool-card">
|
<div class="tool-card">
|
||||||
<h3><i class="fas fa-exchange-alt"></i> Bulk Source Update</h3>
|
<h3><i class="fas fa-exchange-alt"></i> Bulk Source Update</h3>
|
||||||
<p>Change source for multiple items at once</p>
|
<p>Change source for multiple items at once</p>
|
||||||
|
|||||||
@@ -76,6 +76,13 @@ function initializeEventListeners() {
|
|||||||
// Forms
|
// Forms
|
||||||
document.getElementById('edit-form').addEventListener('submit', handleEditSubmit);
|
document.getElementById('edit-form').addEventListener('submit', handleEditSubmit);
|
||||||
document.getElementById('bulk-update-form').addEventListener('submit', handleBulkUpdate);
|
document.getElementById('bulk-update-form').addEventListener('submit', handleBulkUpdate);
|
||||||
|
|
||||||
|
// Manual scan forms
|
||||||
|
document.getElementById('manual-scan-form').addEventListener('submit', handleManualScan);
|
||||||
|
document.getElementById('custom-scan-form').addEventListener('submit', handleCustomScan);
|
||||||
|
|
||||||
|
// Custom directory input auto-formatting
|
||||||
|
document.getElementById('custom-directory').addEventListener('input', handleDirectoryFormatting);
|
||||||
}
|
}
|
||||||
|
|
||||||
// API calls
|
// API calls
|
||||||
@@ -1435,3 +1442,186 @@ async function logout() {
|
|||||||
showToast('❌ Logout error', 'error');
|
showToast('❌ Logout error', 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===========================
|
||||||
|
// Manual Scan Functions
|
||||||
|
// ===========================
|
||||||
|
|
||||||
|
async function handleManualScan(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const scanType = document.getElementById('scan-type').value;
|
||||||
|
const scanMode = document.getElementById('scan-mode').value;
|
||||||
|
|
||||||
|
if (!scanType || !scanMode) {
|
||||||
|
showToast('Please select both scan type and mode', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
showToast('🔍 Starting manual scan...', 'info');
|
||||||
|
updateScanStatus('Starting manual scan...', true);
|
||||||
|
|
||||||
|
const result = await apiCall('/manual/scan', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
scan_type: scanType,
|
||||||
|
scan_mode: scanMode
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
showToast(`✅ Manual scan initiated: ${result.message}`, 'success');
|
||||||
|
|
||||||
|
// Start polling for scan status
|
||||||
|
startScanStatusPolling();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Manual scan failed:', error);
|
||||||
|
showToast(`❌ Manual scan failed: ${error.message}`, 'error');
|
||||||
|
updateScanStatus('Scan failed', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCustomScan(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const customDirectory = document.getElementById('custom-directory').value.trim();
|
||||||
|
const customScanMode = document.getElementById('custom-scan-mode').value;
|
||||||
|
|
||||||
|
if (!customDirectory) {
|
||||||
|
showToast('Please enter a directory path', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!customScanMode) {
|
||||||
|
showToast('Please select a scan mode', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
showToast('🔍 Starting custom directory scan...', 'info');
|
||||||
|
updateScanStatus('Starting custom directory scan...', true);
|
||||||
|
|
||||||
|
const result = await apiCall('/manual/scan', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
directory: customDirectory,
|
||||||
|
scan_mode: customScanMode
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
showToast(`✅ Custom scan initiated: ${result.message}`, 'success');
|
||||||
|
|
||||||
|
// Start polling for scan status
|
||||||
|
startScanStatusPolling();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Custom scan failed:', error);
|
||||||
|
showToast(`❌ Custom scan failed: ${error.message}`, 'error');
|
||||||
|
updateScanStatus('Scan failed', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDirectoryFormatting(event) {
|
||||||
|
const input = event.target;
|
||||||
|
let value = input.value;
|
||||||
|
|
||||||
|
// Auto-format common directory patterns
|
||||||
|
if (value && !value.startsWith('/')) {
|
||||||
|
// Add leading slash for absolute paths
|
||||||
|
value = '/' + value;
|
||||||
|
input.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove multiple consecutive slashes
|
||||||
|
value = value.replace(/\/+/g, '/');
|
||||||
|
|
||||||
|
// Remove trailing slash unless it's just '/'
|
||||||
|
if (value.length > 1 && value.endsWith('/')) {
|
||||||
|
value = value.slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================
|
||||||
|
// Scan Status Functions
|
||||||
|
// ===========================
|
||||||
|
|
||||||
|
let scanStatusInterval = null;
|
||||||
|
|
||||||
|
function updateScanStatus(message, isActive = false) {
|
||||||
|
const statusBanner = document.getElementById('scan-status-banner');
|
||||||
|
const statusText = document.getElementById('scan-status-text');
|
||||||
|
|
||||||
|
if (!statusBanner || !statusText) {
|
||||||
|
console.log('Scan status elements not found, skipping update');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
statusText.textContent = message;
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
statusBanner.className = 'scan-status-banner active';
|
||||||
|
statusBanner.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
statusBanner.className = 'scan-status-banner';
|
||||||
|
// Don't hide completely, just mark as inactive
|
||||||
|
setTimeout(() => {
|
||||||
|
if (statusBanner.className === 'scan-status-banner') {
|
||||||
|
statusBanner.style.display = 'none';
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkScanStatus() {
|
||||||
|
try {
|
||||||
|
const status = await apiCall('/api/scan/status');
|
||||||
|
|
||||||
|
if (status.scanning) {
|
||||||
|
updateScanStatus(status.message || 'Scan in progress...', true);
|
||||||
|
return true; // Continue polling
|
||||||
|
} else {
|
||||||
|
updateScanStatus(status.message || 'No scan in progress', false);
|
||||||
|
return false; // Stop polling
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to check scan status:', error);
|
||||||
|
updateScanStatus('Unable to check scan status', false);
|
||||||
|
return false; // Stop polling on error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startScanStatusPolling() {
|
||||||
|
// Clear any existing interval
|
||||||
|
if (scanStatusInterval) {
|
||||||
|
clearInterval(scanStatusInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check status every 2 seconds
|
||||||
|
scanStatusInterval = setInterval(async () => {
|
||||||
|
const shouldContinue = await checkScanStatus();
|
||||||
|
|
||||||
|
if (!shouldContinue) {
|
||||||
|
clearInterval(scanStatusInterval);
|
||||||
|
scanStatusInterval = null;
|
||||||
|
|
||||||
|
// Refresh dashboard data after scan completes
|
||||||
|
if (currentTab === 'dashboard') {
|
||||||
|
setTimeout(loadDashboard, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
// Initial status check
|
||||||
|
checkScanStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopScanStatusPolling() {
|
||||||
|
if (scanStatusInterval) {
|
||||||
|
clearInterval(scanStatusInterval);
|
||||||
|
scanStatusInterval = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user