← back to YOLO Progress Viewer
detailed-viewer.html
607 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🔍 Detailed Scraper Monitor | Real-Time Loading</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Cascadia Code', 'Fira Code', monospace;
background: #0a0e27;
color: #00ff41;
min-height: 100vh;
overflow-x: hidden;
}
.matrix-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(0deg, transparent 24%, rgba(0, 255, 65, 0.02) 25%, rgba(0, 255, 65, 0.02) 26%, transparent 27%, transparent 74%, rgba(0, 255, 65, 0.02) 75%, rgba(0, 255, 65, 0.02) 76%, transparent 77%, transparent);
background-size: 50px 50px;
z-index: -1;
}
.container {
max-width: 1600px;
margin: 0 auto;
padding: 20px;
position: relative;
}
.header {
background: rgba(0, 20, 40, 0.9);
border: 2px solid #00ff41;
border-radius: 10px;
padding: 20px;
margin-bottom: 30px;
box-shadow: 0 0 20px rgba(0, 255, 65, 0.3);
}
.title {
font-size: 2.5rem;
text-align: center;
text-shadow: 0 0 10px #00ff41;
margin-bottom: 10px;
}
.subtitle {
text-align: center;
color: #00cc33;
font-size: 1.1rem;
}
.main-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 30px;
}
@media (max-width: 1200px) {
.main-grid {
grid-template-columns: 1fr;
}
}
.panel {
background: rgba(0, 20, 40, 0.9);
border: 1px solid #00ff41;
border-radius: 8px;
padding: 20px;
box-shadow: 0 0 15px rgba(0, 255, 65, 0.2);
}
.panel-title {
font-size: 1.3rem;
margin-bottom: 15px;
color: #00ff41;
border-bottom: 1px solid #00ff41;
padding-bottom: 10px;
}
.function-list {
max-height: 400px;
overflow-y: auto;
font-size: 0.9rem;
}
.function-item {
padding: 8px;
margin-bottom: 5px;
background: rgba(0, 255, 65, 0.05);
border-left: 3px solid transparent;
transition: all 0.3s ease;
display: flex;
justify-content: space-between;
align-items: center;
}
.function-item.loading {
border-left-color: #ffaa00;
background: rgba(255, 170, 0, 0.1);
animation: pulse 1s infinite;
}
.function-item.success {
border-left-color: #00ff41;
background: rgba(0, 255, 65, 0.1);
}
.function-item.error {
border-left-color: #ff0040;
background: rgba(255, 0, 64, 0.1);
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
.function-name {
font-weight: bold;
}
.function-status {
font-size: 0.8rem;
padding: 2px 8px;
border-radius: 12px;
background: rgba(0, 0, 0, 0.3);
}
.scraper-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 15px;
}
.scraper-card {
background: rgba(0, 30, 50, 0.9);
border: 1px solid #00ff41;
border-radius: 6px;
padding: 15px;
transition: all 0.3s ease;
}
.scraper-card:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 255, 65, 0.3);
}
.scraper-name {
font-weight: bold;
color: #00ff41;
margin-bottom: 8px;
font-size: 0.95rem;
}
.scraper-info {
font-size: 0.8rem;
color: #00cc33;
line-height: 1.4;
}
.scraper-status {
display: inline-block;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.75rem;
margin-top: 5px;
}
.status-active {
background: rgba(0, 255, 65, 0.2);
color: #00ff41;
}
.status-pending {
background: rgba(255, 170, 0, 0.2);
color: #ffaa00;
}
.status-error {
background: rgba(255, 0, 64, 0.2);
color: #ff0040;
}
.console-log {
background: #000;
border: 1px solid #00ff41;
border-radius: 6px;
padding: 15px;
height: 300px;
overflow-y: auto;
font-family: 'Courier New', monospace;
font-size: 0.85rem;
margin-bottom: 20px;
}
.log-entry {
margin-bottom: 5px;
padding: 3px 0;
border-bottom: 1px solid rgba(0, 255, 65, 0.1);
}
.log-time {
color: #666;
margin-right: 10px;
}
.log-message {
color: #00ff41;
}
.log-error {
color: #ff0040;
}
.log-warning {
color: #ffaa00;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.stat-card {
background: rgba(0, 40, 80, 0.9);
border: 1px solid #00ff41;
border-radius: 8px;
padding: 15px;
text-align: center;
}
.stat-value {
font-size: 2rem;
font-weight: bold;
color: #00ff41;
text-shadow: 0 0 10px rgba(0, 255, 65, 0.5);
}
.stat-label {
font-size: 0.9rem;
color: #00cc33;
margin-top: 5px;
}
.progress-bar {
background: rgba(0, 0, 0, 0.5);
border: 1px solid #00ff41;
border-radius: 20px;
height: 30px;
overflow: hidden;
margin-bottom: 20px;
position: relative;
}
.progress-fill {
background: linear-gradient(90deg, #00ff41, #00cc33);
height: 100%;
transition: width 0.5s ease;
display: flex;
align-items: center;
justify-content: center;
color: #000;
font-weight: bold;
}
.file-tree {
background: rgba(0, 0, 0, 0.5);
border: 1px solid #00ff41;
border-radius: 6px;
padding: 15px;
max-height: 500px;
overflow-y: auto;
}
.tree-item {
padding: 3px 0;
padding-left: 20px;
cursor: pointer;
transition: background 0.2s;
}
.tree-item:hover {
background: rgba(0, 255, 65, 0.1);
}
.tree-folder {
font-weight: bold;
color: #ffaa00;
}
.tree-file {
color: #00ff41;
}
.tree-file.md {
color: #00ccff;
}
.tree-file.ts {
color: #ff00ff;
}
.tree-file.js {
color: #ffff00;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.3);
}
::-webkit-scrollbar-thumb {
background: #00ff41;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #00cc33;
}
</style>
</head>
<body>
<div class="matrix-bg"></div>
<div class="container">
<div class="header">
<h1 class="title">🔍 Detailed Scraper Monitor</h1>
<p class="subtitle">Real-Time Function Loading & MD Scraper File Tracking</p>
</div>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value" id="totalScrapers">0</div>
<div class="stat-label">Total Scrapers</div>
</div>
<div class="stat-card">
<div class="stat-value" id="loadedFunctions">0</div>
<div class="stat-label">Functions Loaded</div>
</div>
<div class="stat-card">
<div class="stat-value" id="activeProcesses">0</div>
<div class="stat-label">Active Processes</div>
</div>
<div class="stat-card">
<div class="stat-value" id="mdFiles">0</div>
<div class="stat-label">MD Files</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" id="mainProgress" style="width: 0%">
<span id="progressText">0%</span>
</div>
</div>
<div class="main-grid">
<div class="panel">
<h2 class="panel-title">📂 Scraper Files</h2>
<div class="file-tree" id="fileTree">
<div class="tree-item tree-folder">📁 /lib/scrapers/</div>
<div id="scraperFileList"></div>
<div class="tree-item tree-folder" style="margin-top: 10px;">📁 /docs/</div>
<div id="mdFileList"></div>
</div>
</div>
<div class="panel">
<h2 class="panel-title">⚡ Function Loading Status</h2>
<div class="function-list" id="functionList">
<!-- Functions will be populated here -->
</div>
</div>
</div>
<div class="panel">
<h2 class="panel-title">📊 Console Output</h2>
<div class="console-log" id="consoleLog">
<!-- Console logs will appear here -->
</div>
</div>
<div class="panel">
<h2 class="panel-title">🤖 Active Scrapers</h2>
<div class="scraper-grid" id="scraperGrid">
<!-- Scraper cards will be populated here -->
</div>
</div>
</div>
<script>
// Mock data for demonstration - replace with real WebSocket connection
const scraperFiles = [
'1838-wallcoverings-new-sku-scraper.ts',
'aesthetics-wall-new-sku-scraper.ts',
'ananbo-new-sku-scraper.ts',
'andrew-martin-new-sku-scraper.ts',
'arbor-wood-new-sku-scraper.ts',
'arc-com-digital-solutions-new-sku-scraper.ts',
'arte-new-sku-scraper.ts',
'aux-abris-new-sku-scraper.ts',
'belarte-studio-new-sku-scraper.ts',
'bradbury-bradbury-new-sku-scraper.ts',
'brunschwig-new-sku-scraper.ts',
'carnegie-fabrics-new-sku-scraper.ts',
'chivasso-new-sku-scraper.ts',
'cole-and-son-new-sku-scraper.ts',
'colefax-and-fowler-new-sku-scraper.ts'
];
const mdFiles = [
'SCRAPER-GUIDE.md',
'VENDOR-CONFIG.md',
'API-DOCUMENTATION.md',
'TROUBLESHOOTING.md',
'RATE-LIMIT-FIX.md'
];
const functions = [
{ name: 'initializePlaywright()', status: 'loading', time: '2025-12-09 02:05:01' },
{ name: 'loadVendorConfig()', status: 'success', time: '2025-12-09 02:05:02' },
{ name: 'extractProductInfo()', status: 'loading', time: '2025-12-09 02:05:03' },
{ name: 'testVendor()', status: 'loading', time: '2025-12-09 02:05:04' },
{ name: 'scanAllVendors()', status: 'loading', time: '2025-12-09 02:05:05' },
{ name: 'deployAgents()', status: 'pending', time: '2025-12-09 02:05:06' },
{ name: 'sendProgressReport()', status: 'pending', time: '2025-12-09 02:05:07' },
{ name: 'startYoloMode()', status: 'success', time: '2025-12-09 02:05:08' }
];
let logIndex = 0;
let progressValue = 0;
function initializeFileTree() {
// Populate scraper files
const scraperList = document.getElementById('scraperFileList');
scraperFiles.forEach((file, index) => {
setTimeout(() => {
const div = document.createElement('div');
div.className = 'tree-item tree-file ts';
div.innerHTML = ` 📄 ${file}`;
scraperList.appendChild(div);
updateStats();
addLog(`Loaded scraper: ${file}`, 'info');
}, index * 100);
});
// Populate MD files
const mdList = document.getElementById('mdFileList');
mdFiles.forEach((file, index) => {
setTimeout(() => {
const div = document.createElement('div');
div.className = 'tree-item tree-file md';
div.innerHTML = ` 📝 ${file}`;
mdList.appendChild(div);
updateStats();
addLog(`Loaded documentation: ${file}`, 'info');
}, (index + scraperFiles.length) * 100);
});
}
function initializeFunctions() {
const functionList = document.getElementById('functionList');
functions.forEach((func, index) => {
setTimeout(() => {
const div = document.createElement('div');
div.className = `function-item ${func.status}`;
div.innerHTML = `
<span class="function-name">${func.name}</span>
<span class="function-status">${func.status.toUpperCase()}</span>
`;
functionList.appendChild(div);
// Simulate loading completion
if (func.status === 'loading') {
setTimeout(() => {
div.classList.remove('loading');
div.classList.add('success');
div.querySelector('.function-status').textContent = 'SUCCESS';
addLog(`✅ ${func.name} loaded successfully`, 'success');
updateProgress();
}, 2000 + Math.random() * 3000);
}
}, index * 300);
});
}
function initializeScrapers() {
const scraperGrid = document.getElementById('scraperGrid');
const activeScrapers = scraperFiles.slice(0, 8);
activeScrapers.forEach((scraper, index) => {
setTimeout(() => {
const vendorName = scraper.replace('-new-sku-scraper.ts', '');
const card = document.createElement('div');
card.className = 'scraper-card';
card.innerHTML = `
<div class="scraper-name">${vendorName}</div>
<div class="scraper-info">
Status: <span class="scraper-status status-active">ACTIVE</span><br>
Products: ${Math.floor(Math.random() * 50)}<br>
Last Run: ${new Date().toLocaleTimeString()}
</div>
`;
scraperGrid.appendChild(card);
addLog(`🤖 Activated scraper: ${vendorName}`, 'info');
}, index * 500);
});
}
function updateStats() {
document.getElementById('totalScrapers').textContent =
document.querySelectorAll('.tree-file.ts').length;
document.getElementById('loadedFunctions').textContent =
document.querySelectorAll('.function-item.success').length;
document.getElementById('activeProcesses').textContent =
document.querySelectorAll('.scraper-status.status-active').length;
document.getElementById('mdFiles').textContent =
document.querySelectorAll('.tree-file.md').length;
}
function updateProgress() {
progressValue = Math.min(progressValue + 10, 100);
document.getElementById('mainProgress').style.width = progressValue + '%';
document.getElementById('progressText').textContent = progressValue + '%';
}
function addLog(message, type = 'info') {
const consoleLog = document.getElementById('consoleLog');
const entry = document.createElement('div');
entry.className = 'log-entry';
const time = new Date().toLocaleTimeString();
let messageClass = 'log-message';
if (type === 'error') messageClass = 'log-error';
if (type === 'warning') messageClass = 'log-warning';
entry.innerHTML = `
<span class="log-time">[${time}]</span>
<span class="${messageClass}">${message}</span>
`;
consoleLog.appendChild(entry);
consoleLog.scrollTop = consoleLog.scrollHeight;
}
// Real-time WebSocket connection for actual deployment
function connectToServer() {
const ws = new WebSocket('ws://45.61.58.125:3040');
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
// Update UI with real data
if (data.type === 'function_load') {
addLog(`Loading function: ${data.function}`, 'info');
}
if (data.type === 'scraper_status') {
addLog(`Scraper ${data.vendor}: ${data.status}`, data.success ? 'success' : 'error');
}
};
}
// Initialize everything
document.addEventListener('DOMContentLoaded', () => {
addLog('🚀 System initializing...', 'info');
initializeFileTree();
initializeFunctions();
initializeScrapers();
// Simulate real-time updates
setInterval(() => {
const randomLog = [
'Checking vendor API...',
'Loading Playwright browser...',
'Extracting product data...',
'Saving to database...',
'Updating cache...'
];
addLog(randomLog[Math.floor(Math.random() * randomLog.length)], 'info');
updateStats();
}, 5000);
// Try to connect to real server
try {
connectToServer();
} catch (e) {
addLog('Running in demo mode (no server connection)', 'warning');
}
});
</script>
</body>
</html>