const storage = require('./storage'); const database = require('./database'); const axios = require('axios'); let fetchInterval = null; let isRunning = false; /** * Fetch a single image from URL */ async function fetchImage(sourceUrl, tags = []) { try { console.log(`[Image Fetcher] Fetching from: ${sourceUrl}`); // Download and save image const downloadResult = await storage.downloadAndSaveImage(sourceUrl); if (!downloadResult.success) { console.error(`[Image Fetcher] Failed to download: ${downloadResult.error}`); return { success: false, error: downloadResult.error }; } // Insert into database const imageRecord = await database.insertImage({ filename: downloadResult.filename, source_url: sourceUrl, file_path: downloadResult.file_path, filesize: downloadResult.filesize, file_hash: downloadResult.file_hash, mime_type: downloadResult.mime_type }); // Add tags if provided if (tags && tags.length > 0) { await database.addTags(imageRecord.id, tags); } console.log(`[Image Fetcher] Saved image: ${downloadResult.filename} (ID: ${imageRecord.id})`); return { success: true, imageId: imageRecord.id, filename: downloadResult.filename, filesize: downloadResult.filesize }; } catch (err) { console.error('[Image Fetcher] Error:', err.message); return { success: false, error: err.message }; } } /** * Verify all images in database for corruption */ async function verifyAllImages() { try { console.log('[Image Fetcher] Starting verification of all images...'); const images = await database.getImages({ limit: 10000 }); let corruptCount = 0; for (const image of images) { const verification = await storage.verifyImageIntegrity(image.file_path, image.file_hash); if (!verification.valid) { console.warn(`[Image Fetcher] Corrupted image detected: ${image.filename} - ${verification.reason}`); await database.markAsCorrupted(image.id); corruptCount++; } } if (corruptCount > 0) { console.log(`[Image Fetcher] Found and marked ${corruptCount} corrupted images`); } else { console.log('[Image Fetcher] Verification complete - all images intact'); } return { checked: images.length, corrupted: corruptCount }; } catch (err) { console.error('[Image Fetcher] Verification error:', err.message); } } /** * Fetch from multiple sources */ async function fetchFromMultipleSources(sources) { console.log(`[Image Fetcher] Fetching from ${sources.length} source(s)...`); const results = []; for (const source of sources) { const sourceUrl = typeof source === 'string' ? source : source.url; const tags = source.tags || []; const result = await fetchImage(sourceUrl, tags); results.push(result); } return results; } /** * Start periodic image fetching */ function startFetcher(sources, intervalMinutes = 2.5) { if (isRunning) { console.log('[Image Fetcher] Fetcher already running'); return; } isRunning = true; const intervalMs = intervalMinutes * 60 * 1000; console.log(`[Image Fetcher] Starting fetcher with ${intervalMinutes} minute interval`); console.log(`[Image Fetcher] Will fetch from ${sources.length} source(s)`); // Do initial fetch immediately fetchFromMultipleSources(sources); // Then set up interval fetchInterval = setInterval(() => { fetchFromMultipleSources(sources); }, intervalMs); return { status: 'running', interval: intervalMinutes, sources: sources.length, nextFetch: new Date(Date.now() + intervalMs) }; } /** * Stop the fetcher */ function stopFetcher() { if (fetchInterval) { clearInterval(fetchInterval); fetchInterval = null; isRunning = false; console.log('[Image Fetcher] Fetcher stopped'); } } /** * Get fetcher status */ function getStatus() { return { running: isRunning, nextFetch: fetchInterval ? 'scheduled' : 'not running' }; } module.exports = { fetchImage, fetchFromMultipleSources, startFetcher, stopFetcher, verifyAllImages, getStatus };