feat: Implement image fetching and storage system
Some checks failed
Deploy to BeePC / deploy (push) Has been cancelled

- Add image-fetcher module for downloading and saving images from various sources.
- Create storage module for managing image files, including downloading, verifying integrity, and cleaning up orphaned files.
- Develop gallery HTML page for displaying images with sorting and filtering options.
- Set up RESTful API routes for image management, including fetching, adding tags, and deleting images.
- Introduce setup script for initializing the database and configuring image sources.
- Implement a batch process for verifying image integrity and cleaning up old images.
- Add setup batch script for easy installation and configuration of the image storage system.
This commit is contained in:
2026-02-12 13:13:36 -05:00
parent ea6cc3fc85
commit 9c72b00b1b
19 changed files with 3004 additions and 71 deletions

199
setup.js Normal file
View File

@@ -0,0 +1,199 @@
#!/usr/bin/env node
/**
* HomeBase Image Storage Setup and Configuration Script
* This script helps you configure image sources and test the storage system
*/
const fs = require('fs');
const path = require('path');
const database = require('./lib/database');
const storage = require('./lib/storage');
const imageFetcher = require('./lib/image-fetcher');
const axios = require('axios');
const CONFIG_FILE = path.join(__dirname, 'image-sources.json');
/**
* Create default configuration file
*/
async function createDefaultConfig() {
const defaultConfig = {
sources: [
{
name: "Example Source",
url: "https://picsum.photos/800/600?random=1",
tags: ["example", "test"],
enabled: false
}
],
fetchInterval: 0.033
};
fs.writeFileSync(CONFIG_FILE, JSON.stringify(defaultConfig, null, 2));
console.log(`✅ Created default configuration at: ${CONFIG_FILE}`);
console.log(' Edit this file to add your image sources');
console.log(' fetchInterval: 0.033 = 2 seconds. Adjust as needed (0.0167 = 1s, 2.5 = 2.5min)');
return defaultConfig;
}
/**
* Load configuration
*/
function loadConfig() {
if (!fs.existsSync(CONFIG_FILE)) {
return createDefaultConfig();
}
try {
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
} catch (err) {
console.error('❌ Error reading configuration:', err.message);
process.exit(1);
}
}
/**
* Get enabled sources from configuration
*/
function getEnabledSources(config) {
return config.sources.filter(source => source.enabled);
}
/**
* Initialize storage directories and database
*/
async function initialize() {
console.log('\n🚀 Initializing HomeBase Image Storage System...\n');
try {
// Initialize database
console.log('📦 Setting up database...');
await database.initializeDatabase();
console.log(' ✅ Database initialized');
// Check storage directory
console.log('\n💾 Checking storage...');
const stats = await storage.getStorageStats();
console.log(` ✅ Storage directory: ${stats.dataDir}`);
console.log(` 📊 Current usage: ${stats.totalSizeGB} GB (${stats.fileCount} files)`);
// Load configuration
console.log('\n⚙ Loading configuration...');
const config = loadConfig();
const enabledSources = getEnabledSources(config);
console.log(` ✅ Configuration loaded`);
console.log(` 📍 Image sources configured: ${config.sources.length}`);
console.log(` ✨ Enabled sources: ${enabledSources.length}`);
// Test image fetch if enabled sources exist
if (enabledSources.length > 0) {
console.log('\n🧪 Testing image fetch...');
const testSource = enabledSources[0];
console.log(` Fetching from: ${testSource.url}`);
const result = await imageFetcher.fetchImage(testSource.url, testSource.tags);
if (result.success) {
console.log(` ✅ Successfully fetched and stored image`);
console.log(` 📄 Filename: ${result.filename}`);
console.log(` 💾 Size: ${(result.filesize / 1024).toFixed(2)} KB`);
} else {
console.log(` ⚠️ Failed to fetch: ${result.error}`);
}
} else {
console.log('\n⚠ No enabled image sources found');
console.log(' Edit image-sources.json and set "enabled": true to enable sources');
}
console.log('\n✨ Initialization complete!\n');
console.log('📖 API Endpoints:');
console.log(' GET /api/images - List all images');
console.log(' POST /api/images - Fetch and save new image');
console.log(' GET /api/images/{id} - Get image details');
console.log(' POST /api/images/{id}/tags - Add tags to image');
console.log(' GET /api/tags - List all tags');
console.log(' GET /api/stats - Storage statistics');
console.log(' POST /api/verify - Verify image integrity');
console.log(' POST /api/cleanup - Clean up old images');
console.log('\n');
} catch (err) {
console.error('❌ Initialization failed:', err.message);
process.exit(1);
} finally {
await database.closeDatabase();
}
}
/**
* Test image fetch
*/
async function testFetch(url, tags = []) {
console.log('\n🧪 Testing Image Fetch\n');
try {
await database.initializeDatabase();
console.log(`Fetching from: ${url}`);
console.log(`Tags: ${tags.join(', ') || 'none'}\n`);
const result = await imageFetcher.fetchImage(url, tags);
if (result.success) {
console.log('✅ Success!');
console.log(` Image ID: ${result.imageId}`);
console.log(` Filename: ${result.filename}`);
console.log(` Size: ${(result.filesize / 1024).toFixed(2)} KB`);
const image = await database.getImage(result.imageId);
console.log(` Hash: ${image.file_hash}`);
} else {
console.log(`❌ Failed: ${result.error}`);
}
} catch (err) {
console.error('❌ Error:', err.message);
} finally {
await database.closeDatabase();
}
}
/**
* Show usage information
*/
function showUsage() {
console.log('\nHomeBase Image Storage CLI\n');
console.log('Usage:');
console.log(' node setup.js init - Initialize system');
console.log(' node setup.js test <url> [tags] - Test fetch from URL');
console.log(' node setup.js config - Show configuration');
console.log(' node setup.js help - Show this help\n');
}
// Main
const command = process.argv[2];
switch (command) {
case 'init':
initialize();
break;
case 'test':
const url = process.argv[3];
const tags = process.argv.slice(4).join(' ').split(',').map(t => t.trim()).filter(t => t);
if (!url) {
console.error('❌ URL required: node setup.js test <url> [tags]');
process.exit(1);
}
testFetch(url, tags);
break;
case 'config':
const config = loadConfig();
console.log('\nCurrent Configuration:\n');
console.log(JSON.stringify(config, null, 2));
break;
case 'help':
default:
showUsage();
break;
}