diff --git a/archivebox/core/views.py b/archivebox/core/views.py index 4a104b45..f0410846 100644 --- a/archivebox/core/views.py +++ b/archivebox/core/views.py @@ -565,6 +565,29 @@ def live_progress_view(request): archiveresults_succeeded = ArchiveResult.objects.filter(status=ArchiveResult.StatusChoices.SUCCEEDED).count() archiveresults_failed = ArchiveResult.objects.filter(status=ArchiveResult.StatusChoices.FAILED).count() + # Get recently completed ArchiveResults with thumbnails (last 20 succeeded results) + recent_thumbnails = [] + recent_results = ArchiveResult.objects.filter( + status=ArchiveResult.StatusChoices.SUCCEEDED, + ).select_related('snapshot').order_by('-end_ts')[:20] + + for ar in recent_results: + embed = ar.embed_path() + if embed: + # Only include results with embeddable image/media files + ext = embed.lower().split('.')[-1] if '.' in embed else '' + is_embeddable = ext in ('png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'ico', 'pdf', 'html') + if is_embeddable or ar.plugin in ('screenshot', 'favicon', 'dom'): + recent_thumbnails.append({ + 'id': str(ar.id), + 'plugin': ar.plugin, + 'snapshot_id': str(ar.snapshot_id), + 'snapshot_url': ar.snapshot.url[:60] if ar.snapshot else '', + 'embed_path': embed, + 'archive_path': f'/archive/{ar.snapshot.timestamp}/{embed}' if ar.snapshot else '', + 'end_ts': ar.end_ts.isoformat() if ar.end_ts else None, + }) + # Build hierarchical active crawls with nested snapshots and archive results from django.db.models import Prefetch @@ -689,6 +712,7 @@ def live_progress_view(request): 'archiveresults_succeeded': archiveresults_succeeded, 'archiveresults_failed': archiveresults_failed, 'active_crawls': active_crawls, + 'recent_thumbnails': recent_thumbnails, 'server_time': timezone.now().isoformat(), }) except Exception as e: @@ -708,6 +732,7 @@ def live_progress_view(request): 'archiveresults_succeeded': 0, 'archiveresults_failed': 0, 'active_crawls': [], + 'recent_thumbnails': [], 'server_time': timezone.now().isoformat(), }, status=500) diff --git a/archivebox/templates/admin/progress_monitor.html b/archivebox/templates/admin/progress_monitor.html index acc7ebdf..266afb70 100644 --- a/archivebox/templates/admin/progress_monitor.html +++ b/archivebox/templates/admin/progress_monitor.html @@ -423,6 +423,102 @@ color: #6e7681; } + /* Thumbnail Strip */ + #progress-monitor .thumbnail-strip { + display: flex; + gap: 8px; + padding: 10px 16px; + background: rgba(0,0,0,0.15); + border-top: 1px solid #21262d; + overflow-x: auto; + scrollbar-width: thin; + scrollbar-color: #30363d #0d1117; + } + #progress-monitor .thumbnail-strip::-webkit-scrollbar { + height: 6px; + } + #progress-monitor .thumbnail-strip::-webkit-scrollbar-track { + background: #0d1117; + } + #progress-monitor .thumbnail-strip::-webkit-scrollbar-thumb { + background: #30363d; + border-radius: 3px; + } + #progress-monitor .thumbnail-strip::-webkit-scrollbar-thumb:hover { + background: #484f58; + } + #progress-monitor .thumbnail-strip.empty { + display: none; + } + #progress-monitor .thumbnail-item { + flex-shrink: 0; + position: relative; + width: 64px; + height: 48px; + border-radius: 4px; + overflow: hidden; + border: 1px solid #30363d; + background: #161b22; + cursor: pointer; + transition: transform 0.2s, border-color 0.2s, box-shadow 0.2s; + } + #progress-monitor .thumbnail-item:hover { + transform: scale(1.1); + border-color: #58a6ff; + box-shadow: 0 0 12px rgba(88, 166, 255, 0.3); + z-index: 10; + } + #progress-monitor .thumbnail-item.new { + animation: thumbnail-pop 0.4s ease-out; + } + @keyframes thumbnail-pop { + 0% { transform: scale(0.5); opacity: 0; } + 50% { transform: scale(1.15); } + 100% { transform: scale(1); opacity: 1; } + } + #progress-monitor .thumbnail-item img { + width: 100%; + height: 100%; + object-fit: cover; + } + #progress-monitor .thumbnail-item .thumbnail-fallback { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + color: #8b949e; + background: linear-gradient(135deg, #21262d 0%, #161b22 100%); + } + #progress-monitor .thumbnail-item .thumbnail-plugin { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 2px 4px; + font-size: 8px; + font-weight: 600; + text-transform: uppercase; + color: #fff; + background: rgba(0,0,0,0.7); + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + #progress-monitor .thumbnail-label { + display: flex; + align-items: center; + gap: 6px; + padding: 0 4px; + color: #8b949e; + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.5px; + flex-shrink: 0; + } +