#!/usr/bin/env node /** * Script to fetch specific missing media IDs from WordPress * Uses the WordPress REST API to get media URLs and download them */ const fs = require('fs'); const path = require('path'); const https = require('https'); // Load environment variables require('dotenv').config(); const BASE_URL = process.env.WOOCOMMERCE_URL; const APP_PASSWORD = process.env.WORDPRESS_APP_PASSWORD; // Validate environment if (!BASE_URL || !APP_PASSWORD) { console.error('āŒ Missing required environment variables'); console.error('Please check .env file for:'); console.error(' - WOOCOMMERCE_URL'); console.error(' - WORDPRESS_APP_PASSWORD'); process.exit(1); } // Configuration const MISSING_MEDIA_IDS = [10432, 10440, 10382, 10616, 10615, 45569, 10638, 5767]; const MEDIA_DIR = path.join(__dirname, '..', 'public', 'media'); const RAW_DATA_DIR = path.join(__dirname, '..', 'data', 'raw', '2025-12-30T15-21-49-331Z'); // Create media directory if it doesn't exist if (!fs.existsSync(MEDIA_DIR)) { fs.mkdirSync(MEDIA_DIR, { recursive: true }); } // WordPress Auth Header function buildWordPressAuth() { return { 'Authorization': `Basic ${Buffer.from(`admin:${APP_PASSWORD}`).toString('base64')}`, 'Content-Type': 'application/json' }; } // Make HTTPS request function makeRequest(url, headers = {}) { return new Promise((resolve, reject) => { const options = { headers: { 'User-Agent': 'WordPress-Missing-Media-Fetcher/1.0', ...headers } }; https.get(url, options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { if (res.statusCode >= 200 && res.statusCode < 300) { try { resolve(JSON.parse(data)); } catch (e) { resolve(data); } } else { reject(new Error(`HTTP ${res.statusCode}: ${data}`)); } }); }).on('error', reject); }); } // Fetch single media item async function fetchMedia(mediaId) { const url = `${BASE_URL}/wp-json/wp/v2/media/${mediaId}`; try { console.log(`šŸ“„ Fetching media ${mediaId}...`); const media = await makeRequest(url, buildWordPressAuth()); return media; } catch (error) { console.error(`āŒ Error fetching media ${mediaId}:`, error.message); return null; } } // Download media file function downloadMedia(url, filename) { return new Promise((resolve, reject) => { const filePath = path.join(MEDIA_DIR, filename); // Check if file already exists if (fs.existsSync(filePath)) { console.log(`āœ… Media already exists: ${filename}`); resolve(filePath); return; } const file = fs.createWriteStream(filePath); https.get(url, (res) => { if (res.statusCode === 200) { res.pipe(file); file.on('finish', () => { console.log(`āœ… Downloaded: ${filename}`); resolve(filePath); }); } else { reject(new Error(`Failed to download: ${res.statusCode}`)); } }).on('error', (err) => { fs.unlink(filePath, () => {}); reject(err); }); }); } // Main function async function main() { console.log('šŸ” Fetching Missing Media IDs'); console.log('=============================='); console.log(`Target: ${BASE_URL}`); console.log(`Output: ${MEDIA_DIR}`); console.log(`Missing IDs: ${MISSING_MEDIA_IDS.join(', ')}`); console.log(''); const mediaManifest = []; const downloadPromises = []; for (const mediaId of MISSING_MEDIA_IDS) { const media = await fetchMedia(mediaId); if (media && media.source_url) { const originalFilename = media.source_url.split('/').pop(); const filename = `${mediaId}-${originalFilename}`; // Add to manifest mediaManifest.push({ id: mediaId, url: media.source_url, filename: filename, alt: media.alt_text || '', width: media.media_details?.width, height: media.media_details?.height, mime_type: media.mime_type }); // Download file downloadPromises.push( downloadMedia(media.source_url, filename).catch(err => { console.warn(`āš ļø Failed to download media ${mediaId}:`, err.message); }) ); } else { console.warn(`āš ļø Could not fetch media ${mediaId}`); } } // Wait for all downloads await Promise.all(downloadPromises); // Update media.json const mediaJsonPath = path.join(RAW_DATA_DIR, 'media.json'); if (fs.existsSync(mediaJsonPath)) { const existingMedia = JSON.parse(fs.readFileSync(mediaJsonPath, 'utf8')); const updatedMedia = [...existingMedia, ...mediaManifest]; fs.writeFileSync( mediaJsonPath, JSON.stringify(updatedMedia, null, 2) ); console.log(`āœ… Updated media.json with ${mediaManifest.length} new items`); } else { console.warn('āš ļø media.json not found, creating new file'); fs.writeFileSync( mediaJsonPath, JSON.stringify(mediaManifest, null, 2) ); } // Update assets.json if needed const assetsJsonPath = path.join(RAW_DATA_DIR, 'assets.json'); if (fs.existsSync(assetsJsonPath)) { const assets = JSON.parse(fs.readFileSync(assetsJsonPath, 'utf8')); console.log('āœ… Current assets.json:', assets); } console.log('\nšŸŽ‰ Missing Media Fetch Complete!'); console.log('=============================='); console.log(`šŸ“„ Fetched: ${mediaManifest.length} items`); console.log(`šŸ“ Directory: public/media/`); console.log(`šŸ“„ Updated: data/raw/2025-12-30T15-21-49-331Z/media.json`); console.log(''); console.log('Media items fetched:'); mediaManifest.forEach(item => { console.log(` - ${item.id}: ${item.filename}`); }); } // Run if called directly if (require.main === module) { main().catch(error => { console.error('\nāŒ Script failed:', error.message); process.exit(1); }); } module.exports = { fetchMedia, downloadMedia, main };